SlideShare une entreprise Scribd logo
1  sur  50
Télécharger pour lire hors ligne
Protocol-Oriented Networking
@mostafa_amer
Starting Point
#import <AFNetworking/AFNetworking.h>
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
-(void)fetchGitHubUserWithName:(NSString *)name
completionHandler:(void(^)(id result, NSError *error))handler;
@end
Starting Point
#import <AFNetworking/AFNetworking.h>
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
-(void)fetchGitHubUserWithName:(NSString *)name
completionHandler:(void(^)(id result, NSError *error))handler;
@end
• Client has too many responsibilities
Starting Point
#import <AFNetworking/AFNetworking.h>
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
-(void)fetchGitHubUserWithName:(NSString *)name
completionHandler:(void(^)(id result, NSError *error))handler;
@end
• Client has too many responsibilities
• Client is tightly coupled to the network library
Starting Point
#import <AFNetworking/AFNetworking.h>
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
-(void)fetchGitHubUserWithName:(NSString *)name
completionHandler:(void(^)(id result, NSError *error))handler;
@end
• Client has too many responsibilities
• Client is tightly coupled to the network library
• Client is hard to test
Starting Point
#import <AFNetworking/AFNetworking.h>
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
-(void)fetchGitHubUserWithName:(NSString *)name
completionHandler:(void(^)(id result, NSError *error))handler;
@end
• Client has too many responsibilities
• Client is tightly coupled to the network library
• Client is hard to test
• Implementation details is not hidden
Decoupling
protocol NetworkServiceType {
func requestEndpoint(path: String,
method: HTTPMethod,
parameters: [String: Any]?,
handler: (Data?, Error?) -> ())
}
Decoupling
class NetworkService: AFHTTPSessionManager, NetworkServiceType {
func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?,
handler: (Data?, Error?) -> ()) {
}
}
Decoupling
class NetworkService: AFHTTPSessionManager, NetworkServiceType {
func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?,
handler: (Data?, Error?) -> ()) {
switch method {
case .GET:
get(path,
parameters: parameters,
success: {_, result in
handler(result, nil)
},
failure: {_, error in
handler(nil, error)
}
)
}
}
}
Hide Implementation
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
- (void)fetchListWithCompletionHandler:(void(^)(id result, NSError *error))handler;
@end
#import <AFNetworking/AFNetworking.h>
Hide Implementation
@interface GHAPIClient : NSObject
+ (instancetype)sharedClient;
- (void)fetchListWithCompletionHandler:(void(^)(id result, NSError *error))handler;
@end
@interface GHAPIClient()
@end
@implementation GHAPIClient
- (instancetype)initWithBaseURL:(NSURL *)baseURL {
self = [super init];
if(self) {
}
return self;
}
+ (instancetype)sharedClient {
static GHAPIClient *_instance = nil;
if(! _instance) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[GHAPIClient alloc] init];
});
}
return _instance;
}
Refactoring Client
Refactoring Client
@interface GHAPIClient()
@property (nonatomic, strong) id<NetworkServiceType> network;
@end
@implementation GHAPIClient
- (instancetype)initWithBaseURL:(NSURL *)baseURL {
self = [super init];
if(self) {
}
return self;
}
+ (instancetype)sharedClient {
static GHAPIClient *_instance = nil;
if(! _instance) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[GHAPIClient alloc] init];
});
}
return _instance;
}
Refactoring Client
@interface GHAPIClient()
@property (nonatomic, strong) id<NetworkServiceType> network;
@end
@implementation GHAPIClient
- (instancetype)initWithNetworkService:(id<NetworkServiceType>)service {
self = [super init];
if(self) {
_network = service;
}
return self;
}
+ (instancetype)sharedClient {
static GHAPIClient *_instance = nil;
if(! _instance) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[GHAPIClient alloc] init];
});
}
return _instance;
}
Refactoring Client
@interface GHAPIClient()
@property (nonatomic, strong) id<NetworkServiceType> network;
@end
@implementation GHAPIClient
- (instancetype)initWithNetworkService:(id<NetworkServiceType>)service {
self = [super init];
if(self) {
_network = service;
}
return self;
}
+ (instancetype)sharedClient {
static GHAPIClient *_instance = nil;
if(! _instance) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURL *baseURL = [NSURL URLWithString:@"https://api.github.com"];
NetworkService *service = [[NetworkService alloc] initWithBaseURL:baseURL];
_instance = [[GHAPIClient alloc] initWithNetworkService:service];
});
}
return _instance;
}
Testing Client
class NetworkMock: NetworkServiceType {
var response: Data?
var error: Error?
func requestEndpoint(path: String,
method: HTTPMethod,
parameters: [String : Any]?,
handler: (Data?, Error?) -> ()) {
handler(response, error)
}
}
class APIClientSpecs: QuickSpec {
override func spec() {
var mock: NetworkMock!
var sut: GHAPIClient!
beforeEach {
mock = NetworkMock()
sut = GHAPIClient(networkService: mock)
}
}
}
Testing Client
class NetworkMock: NetworkServiceType {
var response: Data?
var error: Error?
func requestEndpoint(path: String,
method: HTTPMethod,
parameters: [String : Any]?,
handler: (Data?, Error?) -> ()) {
handler(response, error)
}
}
Testing Client
class NetworkMock: NetworkServiceType {
var response: Data?
var error: Error?
func requestEndpoint(path: String,
method: HTTPMethod,
parameters: [String : Any]?,
handler: (Data?, Error?) -> ()) {
handler(response, error)
}
}
class APIClientSpecs: QuickSpec {
override func spec() {
var mock: NetworkMock!
var sut: GHAPIClient!
beforeEach {
mock = NetworkMock()
sut = GHAPIClient(networkService: mock)
}
it("handle error") {
mock.data = // Data from JSON file
sut.fetchGitHubUser(loginName: "mosamer") { (_, error) in
expect(error).notTo(beNil())
}
}
}
}
Client Again
- (void)fetchGitHubUser:(NSString *)name
completionHandler:(void (^)(id, NSError *))handler {
[self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name]
method:HTTPMethodGET
parameters:nil
handler:^(id result, NSError *error) {
handler(result, error);
}];
}
Client Again
- (void)fetchGitHubUser:(NSString *)name
completionHandler:(void (^)(id, NSError *))handler {
[self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name]
method:HTTPMethodGET
parameters:nil
handler:^(id result, NSError *error) {
handler(result, error);
}];
}
• Client still has too many responsibilities
Client Again
- (void)fetchGitHubUser:(NSString *)name
completionHandler:(void (^)(id, NSError *))handler {
[self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name]
method:HTTPMethodGET
parameters:nil
handler:^(id result, NSError *error) {
handler(result, error);
}];
}
• Client still has too many responsibilities
• Client lacks general handlers
More Protocols
More Protocols
protocol Resource {
var path: String { get }
var method: HTTPMethod { get }
var parameters: [String: Any]? { get }
}
More Protocols
protocol Response {}
protocol Resource {
var path: String { get }
var method: HTTPMethod { get }
var parameters: [String: Any]? { get }
associatedtype ResponseType: Response
}
More Protocols
protocol Response {}
protocol Resource {
var path: String { get }
var method: HTTPMethod { get }
var parameters: [String: Any]? { get }
associatedtype ResponseType: Response
func parse(response: Data) -> (ResponseType?, Error?)
}
Define Endpoints
struct GitHubUserEndpoint: Resource {
private let name: String
init(loginName: String) {
name = loginName
}
var path: String { return "users/(name)" }
var method: HTTPMethod { return .GET }
var parameters: [String : Any]? { return nil }
func parse(response: Data) -> ( GitHubUser?, Error?) {
// Parse JSON -> data model object
}
}
struct GitHubUser: Response {
// Define data model
}
Testing Endpoints
class GitHubUserEndpointSpecs: QuickSpec {
override func spec() {
var sut: GitHubUserEndpoint!
beforeEach {
sut = GitHubUserEndpoint(loginName: "mosamer")
}
}
}
Testing Endpoints
class GitHubUserEndpointSpecs: QuickSpec {
override func spec() {
var sut: GitHubUserEndpoint!
beforeEach {
sut = GitHubUserEndpoint(loginName: "mosamer")
}
it("build path") {
expect(sut.path) == "users/mosamer"
}
}
}
Testing Endpoints
class GitHubUserEndpointSpecs: QuickSpec {
override func spec() {
var sut: GitHubUserEndpoint!
beforeEach {
sut = GitHubUserEndpoint(loginName: "mosamer")
}
it("build path") {
expect(sut.path) == "users/mosamer"
}
it("GET method") {
expect(sut.method) == HTTPMethod.GET
}
}
}
Testing Endpoints
class GitHubUserEndpointSpecs: QuickSpec {
override func spec() {
var sut: GitHubUserEndpoint!
beforeEach {
sut = GitHubUserEndpoint(loginName: "mosamer")
}
it("build path") {
expect(sut.path) == "users/mosamer"
}
it("GET method") {
expect(sut.method) == HTTPMethod.GET
}
it("without parameters") {
expect(sut.parameters).to(beNil())
}
}
}
Testing Endpoints
class GitHubUserEndpointSpecs: QuickSpec {
override func spec() {
var sut: GitHubUserEndpoint!
beforeEach {
sut = GitHubUserEndpoint(loginName: "mosamer")
}
it("build path") {
expect(sut.path) == "users/mosamer"
}
it("GET method") {
expect(sut.method) == HTTPMethod.GET
}
it("without parameters") {
expect(sut.parameters).to(beNil())
}
it("parse response") {
let userJSON = Data() /* Data from JSON file */
let (user, _) = sut.parse(response: userJSON)
/*
Check user properties are fetched correctly
*/
}
}
}
Client One MoreTime
- (void)fetchGitHubUser:(NSString *)name
completionHandler:(void (^)(id, NSError *))handler {
[self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name]
method:HTTPMethodGET
parameters:nil
handler:^(id result, NSError *error) {
handler(result, error);
}];
}
Client One MoreTime
- (void)fetchGitHubUser:(NSString *)name
completionHandler:(void (^)(id, NSError *))handler {
[self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name]
method:HTTPMethodGET
parameters:nil
handler:^(id result, NSError *error) {
handler(result, error);
}];
}
func user(loginName: String, completionhandler: (GitHubUser?, Error?) -> ()) {
let endpoint = GitHubUserEndpoint(loginName: loginName)
request(endpoint, handler: completionhandler)
}
Client - General Handlers
private func request<R: Resource>(_ endpoint: R,
handler:(R.ResponseType?, Error?) -> ()) {
}
}
}
extension GHAPIClient {
func user(loginName: String, completionhandler: (GitHubUser?, Error?) -> ()) {
let endpoint = GitHubUserEndpoint(loginName: loginName)
request(endpoint, handler: completionhandler)
}
Client - General Handlers
private func request<R: Resource>(_ endpoint: R,
handler:(R.ResponseType?, Error?) -> ()) {
network.requestEndpoint(path: endpoint.path,
method: endpoint.method,
parameters: endpoint.parameters) { (data, error) in
if let _ = error {
handler(nil, error)
return
}
guard let data = data else {
handler(nil, nil)
return
}
let (result, error) = endpoint.parse(response: data)
handler(result, error)
}
}
}
extension GHAPIClient {
func user(loginName: String, completionhandler: (GitHubUser?, Error?) -> ()) {
let endpoint = GitHubUserEndpoint(loginName: loginName)
request(endpoint, handler: completionhandler)
}
Summary
Summary
• Client has too many responsibilities
Summary
• Client has too many responsibilities
Summary
• Client has too many responsibilities
• Client is tightly coupled to the network library
Summary
• Client has too many responsibilities
• Client is tightly coupled to the network library
Summary
• Client has too many responsibilities
• Client is tightly coupled to the network library
• Client is hard to test
Summary
• Client has too many responsibilities
• Client is tightly coupled to the network library
• Client is hard to test
Summary
• Client has too many responsibilities
• Client is tightly coupled to the network library
• Client is hard to test
• Implementation details is not hidden
Summary
• Client has too many responsibilities
• Client is tightly coupled to the network library
• Client is hard to test
• Implementation details is not hidden
Summary
• Client has too many responsibilities
• Client is tightly coupled to the network library
• Client is hard to test
• Implementation details is not hidden
• Client still has too many responsibilities
Summary
• Client has too many responsibilities
• Client is tightly coupled to the network library
• Client is hard to test
• Implementation details is not hidden
• Client still has too many responsibilities
Summary
• Client has too many responsibilities
• Client is tightly coupled to the network library
• Client is hard to test
• Implementation details is not hidden
• Client still has too many responsibilities
• Client lacks general handlers
Summary
• Client has too many responsibilities
• Client is tightly coupled to the network library
• Client is hard to test
• Implementation details is not hidden
• Client still has too many responsibilities
• Client lacks general handlers
@mostafa_amer
Questions?
ThankYou
@mostafa_amer
Questions?

Contenu connexe

Tendances

Dpilot Source Code With ScreenShots
Dpilot Source Code With ScreenShots Dpilot Source Code With ScreenShots
Dpilot Source Code With ScreenShots DeepAnshu Sharma
 
Source Code for Dpilot
Source Code for Dpilot Source Code for Dpilot
Source Code for Dpilot Nidhi Chauhan
 
Reactive Access to MongoDB from Java 8
Reactive Access to MongoDB from Java 8Reactive Access to MongoDB from Java 8
Reactive Access to MongoDB from Java 8Hermann Hueck
 
Leveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results AsynchrhonouslyLeveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results AsynchrhonouslyDavid Gómez García
 
Java script – basic auroskills (2)
Java script – basic   auroskills (2)Java script – basic   auroskills (2)
Java script – basic auroskills (2)BoneyGawande
 
Client server part 12
Client server part 12Client server part 12
Client server part 12fadlihulopi
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaHermann Hueck
 
Finagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestFinagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestPavan Chitumalla
 
Higher Order Components and Render Props
Higher Order Components and Render PropsHigher Order Components and Render Props
Higher Order Components and Render PropsNitish Phanse
 
Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript EverywherePascal Rettig
 
連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」matuura_core
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife SpringMario Fusco
 
Javascript Promises/Q Library
Javascript Promises/Q LibraryJavascript Promises/Q Library
Javascript Promises/Q Libraryasync_io
 
Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2Technopark
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsPiotr Pelczar
 

Tendances (20)

Dpilot Source Code With ScreenShots
Dpilot Source Code With ScreenShots Dpilot Source Code With ScreenShots
Dpilot Source Code With ScreenShots
 
Source Code for Dpilot
Source Code for Dpilot Source Code for Dpilot
Source Code for Dpilot
 
Reactive Access to MongoDB from Java 8
Reactive Access to MongoDB from Java 8Reactive Access to MongoDB from Java 8
Reactive Access to MongoDB from Java 8
 
Leveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results AsynchrhonouslyLeveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results Asynchrhonously
 
Jason parsing
Jason parsingJason parsing
Jason parsing
 
Java script – basic auroskills (2)
Java script – basic   auroskills (2)Java script – basic   auroskills (2)
Java script – basic auroskills (2)
 
Client server part 12
Client server part 12Client server part 12
Client server part 12
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from Scala
 
V8
V8V8
V8
 
Apache Beam de A à Z
 Apache Beam de A à Z Apache Beam de A à Z
Apache Beam de A à Z
 
Finagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestFinagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at Pinterest
 
Servlet11
Servlet11Servlet11
Servlet11
 
Higher Order Components and Render Props
Higher Order Components and Render PropsHigher Order Components and Render Props
Higher Order Components and Render Props
 
Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript Everywhere
 
連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」
 
servlets
servletsservlets
servlets
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife Spring
 
Javascript Promises/Q Library
Javascript Promises/Q LibraryJavascript Promises/Q Library
Javascript Promises/Q Library
 
Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 

Similaire à Protocol-Oriented Networking

Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019Joe Keeley
 
Server Side Swift with Swag
Server Side Swift with SwagServer Side Swift with Swag
Server Side Swift with SwagJens Ravens
 
Http Communication in Angular 2.0
Http Communication in Angular 2.0Http Communication in Angular 2.0
Http Communication in Angular 2.0Eyal Vardi
 
Net/http and the http.handler interface
Net/http and the http.handler interfaceNet/http and the http.handler interface
Net/http and the http.handler interfaceJoakim Gustin
 
Net/http and the http.handler interface
Net/http and the http.handler interfaceNet/http and the http.handler interface
Net/http and the http.handler interfaceEvolve
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
The Full Power of ASP.NET Web API
The Full Power of ASP.NET Web APIThe Full Power of ASP.NET Web API
The Full Power of ASP.NET Web APIEyal Vardi
 
async/await in Swift
async/await in Swiftasync/await in Swift
async/await in SwiftPeter Friese
 
13 networking, mobile services, and authentication
13   networking, mobile services, and authentication13   networking, mobile services, and authentication
13 networking, mobile services, and authenticationWindowsPhoneRocks
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeKAI CHU CHUNG
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8Dhaval Dalal
 
服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScriptQiangning Hong
 
Speed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsSpeed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsYakov Fain
 
Spring MVC Annotations
Spring MVC AnnotationsSpring MVC Annotations
Spring MVC AnnotationsJordan Silva
 
Laporan multiclient chatting client server
Laporan multiclient chatting client serverLaporan multiclient chatting client server
Laporan multiclient chatting client servertrilestari08
 
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docxWeb CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docxcelenarouzie
 
Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)danwrong
 

Similaire à Protocol-Oriented Networking (20)

Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019
 
Server Side Swift with Swag
Server Side Swift with SwagServer Side Swift with Swag
Server Side Swift with Swag
 
Http Communication in Angular 2.0
Http Communication in Angular 2.0Http Communication in Angular 2.0
Http Communication in Angular 2.0
 
Net/http and the http.handler interface
Net/http and the http.handler interfaceNet/http and the http.handler interface
Net/http and the http.handler interface
 
Net/http and the http.handler interface
Net/http and the http.handler interfaceNet/http and the http.handler interface
Net/http and the http.handler interface
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
java sockets
 java sockets java sockets
java sockets
 
The Full Power of ASP.NET Web API
The Full Power of ASP.NET Web APIThe Full Power of ASP.NET Web API
The Full Power of ASP.NET Web API
 
async/await in Swift
async/await in Swiftasync/await in Swift
async/await in Swift
 
13 networking, mobile services, and authentication
13   networking, mobile services, and authentication13   networking, mobile services, and authentication
13 networking, mobile services, and authentication
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8
 
Android dev 3
Android dev 3Android dev 3
Android dev 3
 
服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript
 
Speed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsSpeed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSockets
 
Spring MVC Annotations
Spring MVC AnnotationsSpring MVC Annotations
Spring MVC Annotations
 
Laporan multiclient chatting client server
Laporan multiclient chatting client serverLaporan multiclient chatting client server
Laporan multiclient chatting client server
 
Winform
WinformWinform
Winform
 
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docxWeb CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
 
Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)
 

Dernier

VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130Suhani Kapoor
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Call Girls in Nagpur High Profile
 
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).pptssuser5c9d4b1
 
HARDNESS, FRACTURE TOUGHNESS AND STRENGTH OF CERAMICS
HARDNESS, FRACTURE TOUGHNESS AND STRENGTH OF CERAMICSHARDNESS, FRACTURE TOUGHNESS AND STRENGTH OF CERAMICS
HARDNESS, FRACTURE TOUGHNESS AND STRENGTH OF CERAMICSRajkumarAkumalla
 
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...ranjana rawat
 
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptx
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptxthe ladakh protest in leh ladakh 2024 sonam wangchuk.pptx
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptxhumanexperienceaaa
 
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptx
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptxDecoding Kotlin - Your guide to solving the mysterious in Kotlin.pptx
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptxJoão Esperancinha
 
Software Development Life Cycle By Team Orange (Dept. of Pharmacy)
Software Development Life Cycle By  Team Orange (Dept. of Pharmacy)Software Development Life Cycle By  Team Orange (Dept. of Pharmacy)
Software Development Life Cycle By Team Orange (Dept. of Pharmacy)Suman Mia
 
UNIT-III FMM. DIMENSIONAL ANALYSIS
UNIT-III FMM.        DIMENSIONAL ANALYSISUNIT-III FMM.        DIMENSIONAL ANALYSIS
UNIT-III FMM. DIMENSIONAL ANALYSISrknatarajan
 
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝soniya singh
 
Porous Ceramics seminar and technical writing
Porous Ceramics seminar and technical writingPorous Ceramics seminar and technical writing
Porous Ceramics seminar and technical writingrakeshbaidya232001
 
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service Nashik
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service NashikCall Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service Nashik
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service NashikCall Girls in Nagpur High Profile
 
(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...
(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...
(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...ranjana rawat
 
IMPLICATIONS OF THE ABOVE HOLISTIC UNDERSTANDING OF HARMONY ON PROFESSIONAL E...
IMPLICATIONS OF THE ABOVE HOLISTIC UNDERSTANDING OF HARMONY ON PROFESSIONAL E...IMPLICATIONS OF THE ABOVE HOLISTIC UNDERSTANDING OF HARMONY ON PROFESSIONAL E...
IMPLICATIONS OF THE ABOVE HOLISTIC UNDERSTANDING OF HARMONY ON PROFESSIONAL E...RajaP95
 
Sheet Pile Wall Design and Construction: A Practical Guide for Civil Engineer...
Sheet Pile Wall Design and Construction: A Practical Guide for Civil Engineer...Sheet Pile Wall Design and Construction: A Practical Guide for Civil Engineer...
Sheet Pile Wall Design and Construction: A Practical Guide for Civil Engineer...Dr.Costas Sachpazis
 
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130Suhani Kapoor
 
(TARA) Talegaon Dabhade Call Girls Just Call 7001035870 [ Cash on Delivery ] ...
(TARA) Talegaon Dabhade Call Girls Just Call 7001035870 [ Cash on Delivery ] ...(TARA) Talegaon Dabhade Call Girls Just Call 7001035870 [ Cash on Delivery ] ...
(TARA) Talegaon Dabhade Call Girls Just Call 7001035870 [ Cash on Delivery ] ...ranjana rawat
 
SPICE PARK APR2024 ( 6,793 SPICE Models )
SPICE PARK APR2024 ( 6,793 SPICE Models )SPICE PARK APR2024 ( 6,793 SPICE Models )
SPICE PARK APR2024 ( 6,793 SPICE Models )Tsuyoshi Horigome
 

Dernier (20)

VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
 
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt
 
HARDNESS, FRACTURE TOUGHNESS AND STRENGTH OF CERAMICS
HARDNESS, FRACTURE TOUGHNESS AND STRENGTH OF CERAMICSHARDNESS, FRACTURE TOUGHNESS AND STRENGTH OF CERAMICS
HARDNESS, FRACTURE TOUGHNESS AND STRENGTH OF CERAMICS
 
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
 
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptx
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptxthe ladakh protest in leh ladakh 2024 sonam wangchuk.pptx
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptx
 
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptx
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptxDecoding Kotlin - Your guide to solving the mysterious in Kotlin.pptx
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptx
 
Software Development Life Cycle By Team Orange (Dept. of Pharmacy)
Software Development Life Cycle By  Team Orange (Dept. of Pharmacy)Software Development Life Cycle By  Team Orange (Dept. of Pharmacy)
Software Development Life Cycle By Team Orange (Dept. of Pharmacy)
 
Roadmap to Membership of RICS - Pathways and Routes
Roadmap to Membership of RICS - Pathways and RoutesRoadmap to Membership of RICS - Pathways and Routes
Roadmap to Membership of RICS - Pathways and Routes
 
UNIT-III FMM. DIMENSIONAL ANALYSIS
UNIT-III FMM.        DIMENSIONAL ANALYSISUNIT-III FMM.        DIMENSIONAL ANALYSIS
UNIT-III FMM. DIMENSIONAL ANALYSIS
 
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝
 
Porous Ceramics seminar and technical writing
Porous Ceramics seminar and technical writingPorous Ceramics seminar and technical writing
Porous Ceramics seminar and technical writing
 
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service Nashik
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service NashikCall Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service Nashik
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service Nashik
 
(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...
(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...
(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...
 
IMPLICATIONS OF THE ABOVE HOLISTIC UNDERSTANDING OF HARMONY ON PROFESSIONAL E...
IMPLICATIONS OF THE ABOVE HOLISTIC UNDERSTANDING OF HARMONY ON PROFESSIONAL E...IMPLICATIONS OF THE ABOVE HOLISTIC UNDERSTANDING OF HARMONY ON PROFESSIONAL E...
IMPLICATIONS OF THE ABOVE HOLISTIC UNDERSTANDING OF HARMONY ON PROFESSIONAL E...
 
Sheet Pile Wall Design and Construction: A Practical Guide for Civil Engineer...
Sheet Pile Wall Design and Construction: A Practical Guide for Civil Engineer...Sheet Pile Wall Design and Construction: A Practical Guide for Civil Engineer...
Sheet Pile Wall Design and Construction: A Practical Guide for Civil Engineer...
 
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
 
(TARA) Talegaon Dabhade Call Girls Just Call 7001035870 [ Cash on Delivery ] ...
(TARA) Talegaon Dabhade Call Girls Just Call 7001035870 [ Cash on Delivery ] ...(TARA) Talegaon Dabhade Call Girls Just Call 7001035870 [ Cash on Delivery ] ...
(TARA) Talegaon Dabhade Call Girls Just Call 7001035870 [ Cash on Delivery ] ...
 
SPICE PARK APR2024 ( 6,793 SPICE Models )
SPICE PARK APR2024 ( 6,793 SPICE Models )SPICE PARK APR2024 ( 6,793 SPICE Models )
SPICE PARK APR2024 ( 6,793 SPICE Models )
 
★ CALL US 9953330565 ( HOT Young Call Girls In Badarpur delhi NCR
★ CALL US 9953330565 ( HOT Young Call Girls In Badarpur delhi NCR★ CALL US 9953330565 ( HOT Young Call Girls In Badarpur delhi NCR
★ CALL US 9953330565 ( HOT Young Call Girls In Badarpur delhi NCR
 

Protocol-Oriented Networking

  • 2. Starting Point #import <AFNetworking/AFNetworking.h> @interface GHAPIClient : AFHTTPSessionManager + (instancetype)sharedClient; -(void)fetchGitHubUserWithName:(NSString *)name completionHandler:(void(^)(id result, NSError *error))handler; @end
  • 3. Starting Point #import <AFNetworking/AFNetworking.h> @interface GHAPIClient : AFHTTPSessionManager + (instancetype)sharedClient; -(void)fetchGitHubUserWithName:(NSString *)name completionHandler:(void(^)(id result, NSError *error))handler; @end • Client has too many responsibilities
  • 4. Starting Point #import <AFNetworking/AFNetworking.h> @interface GHAPIClient : AFHTTPSessionManager + (instancetype)sharedClient; -(void)fetchGitHubUserWithName:(NSString *)name completionHandler:(void(^)(id result, NSError *error))handler; @end • Client has too many responsibilities • Client is tightly coupled to the network library
  • 5. Starting Point #import <AFNetworking/AFNetworking.h> @interface GHAPIClient : AFHTTPSessionManager + (instancetype)sharedClient; -(void)fetchGitHubUserWithName:(NSString *)name completionHandler:(void(^)(id result, NSError *error))handler; @end • Client has too many responsibilities • Client is tightly coupled to the network library • Client is hard to test
  • 6. Starting Point #import <AFNetworking/AFNetworking.h> @interface GHAPIClient : AFHTTPSessionManager + (instancetype)sharedClient; -(void)fetchGitHubUserWithName:(NSString *)name completionHandler:(void(^)(id result, NSError *error))handler; @end • Client has too many responsibilities • Client is tightly coupled to the network library • Client is hard to test • Implementation details is not hidden
  • 7. Decoupling protocol NetworkServiceType { func requestEndpoint(path: String, method: HTTPMethod, parameters: [String: Any]?, handler: (Data?, Error?) -> ()) }
  • 8. Decoupling class NetworkService: AFHTTPSessionManager, NetworkServiceType { func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?, handler: (Data?, Error?) -> ()) { } }
  • 9. Decoupling class NetworkService: AFHTTPSessionManager, NetworkServiceType { func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?, handler: (Data?, Error?) -> ()) { switch method { case .GET: get(path, parameters: parameters, success: {_, result in handler(result, nil) }, failure: {_, error in handler(nil, error) } ) } } }
  • 10. Hide Implementation @interface GHAPIClient : AFHTTPSessionManager + (instancetype)sharedClient; - (void)fetchListWithCompletionHandler:(void(^)(id result, NSError *error))handler; @end #import <AFNetworking/AFNetworking.h>
  • 11. Hide Implementation @interface GHAPIClient : NSObject + (instancetype)sharedClient; - (void)fetchListWithCompletionHandler:(void(^)(id result, NSError *error))handler; @end
  • 12. @interface GHAPIClient() @end @implementation GHAPIClient - (instancetype)initWithBaseURL:(NSURL *)baseURL { self = [super init]; if(self) { } return self; } + (instancetype)sharedClient { static GHAPIClient *_instance = nil; if(! _instance) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[GHAPIClient alloc] init]; }); } return _instance; } Refactoring Client
  • 13. Refactoring Client @interface GHAPIClient() @property (nonatomic, strong) id<NetworkServiceType> network; @end @implementation GHAPIClient - (instancetype)initWithBaseURL:(NSURL *)baseURL { self = [super init]; if(self) { } return self; } + (instancetype)sharedClient { static GHAPIClient *_instance = nil; if(! _instance) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[GHAPIClient alloc] init]; }); } return _instance; }
  • 14. Refactoring Client @interface GHAPIClient() @property (nonatomic, strong) id<NetworkServiceType> network; @end @implementation GHAPIClient - (instancetype)initWithNetworkService:(id<NetworkServiceType>)service { self = [super init]; if(self) { _network = service; } return self; } + (instancetype)sharedClient { static GHAPIClient *_instance = nil; if(! _instance) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[GHAPIClient alloc] init]; }); } return _instance; }
  • 15. Refactoring Client @interface GHAPIClient() @property (nonatomic, strong) id<NetworkServiceType> network; @end @implementation GHAPIClient - (instancetype)initWithNetworkService:(id<NetworkServiceType>)service { self = [super init]; if(self) { _network = service; } return self; } + (instancetype)sharedClient { static GHAPIClient *_instance = nil; if(! _instance) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSURL *baseURL = [NSURL URLWithString:@"https://api.github.com"]; NetworkService *service = [[NetworkService alloc] initWithBaseURL:baseURL]; _instance = [[GHAPIClient alloc] initWithNetworkService:service]; }); } return _instance; }
  • 16. Testing Client class NetworkMock: NetworkServiceType { var response: Data? var error: Error? func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?, handler: (Data?, Error?) -> ()) { handler(response, error) } }
  • 17. class APIClientSpecs: QuickSpec { override func spec() { var mock: NetworkMock! var sut: GHAPIClient! beforeEach { mock = NetworkMock() sut = GHAPIClient(networkService: mock) } } } Testing Client class NetworkMock: NetworkServiceType { var response: Data? var error: Error? func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?, handler: (Data?, Error?) -> ()) { handler(response, error) } }
  • 18. Testing Client class NetworkMock: NetworkServiceType { var response: Data? var error: Error? func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?, handler: (Data?, Error?) -> ()) { handler(response, error) } } class APIClientSpecs: QuickSpec { override func spec() { var mock: NetworkMock! var sut: GHAPIClient! beforeEach { mock = NetworkMock() sut = GHAPIClient(networkService: mock) } it("handle error") { mock.data = // Data from JSON file sut.fetchGitHubUser(loginName: "mosamer") { (_, error) in expect(error).notTo(beNil()) } } } }
  • 19. Client Again - (void)fetchGitHubUser:(NSString *)name completionHandler:(void (^)(id, NSError *))handler { [self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name] method:HTTPMethodGET parameters:nil handler:^(id result, NSError *error) { handler(result, error); }]; }
  • 20. Client Again - (void)fetchGitHubUser:(NSString *)name completionHandler:(void (^)(id, NSError *))handler { [self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name] method:HTTPMethodGET parameters:nil handler:^(id result, NSError *error) { handler(result, error); }]; } • Client still has too many responsibilities
  • 21. Client Again - (void)fetchGitHubUser:(NSString *)name completionHandler:(void (^)(id, NSError *))handler { [self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name] method:HTTPMethodGET parameters:nil handler:^(id result, NSError *error) { handler(result, error); }]; } • Client still has too many responsibilities • Client lacks general handlers
  • 23. More Protocols protocol Resource { var path: String { get } var method: HTTPMethod { get } var parameters: [String: Any]? { get } }
  • 24. More Protocols protocol Response {} protocol Resource { var path: String { get } var method: HTTPMethod { get } var parameters: [String: Any]? { get } associatedtype ResponseType: Response }
  • 25. More Protocols protocol Response {} protocol Resource { var path: String { get } var method: HTTPMethod { get } var parameters: [String: Any]? { get } associatedtype ResponseType: Response func parse(response: Data) -> (ResponseType?, Error?) }
  • 26. Define Endpoints struct GitHubUserEndpoint: Resource { private let name: String init(loginName: String) { name = loginName } var path: String { return "users/(name)" } var method: HTTPMethod { return .GET } var parameters: [String : Any]? { return nil } func parse(response: Data) -> ( GitHubUser?, Error?) { // Parse JSON -> data model object } } struct GitHubUser: Response { // Define data model }
  • 27. Testing Endpoints class GitHubUserEndpointSpecs: QuickSpec { override func spec() { var sut: GitHubUserEndpoint! beforeEach { sut = GitHubUserEndpoint(loginName: "mosamer") } } }
  • 28. Testing Endpoints class GitHubUserEndpointSpecs: QuickSpec { override func spec() { var sut: GitHubUserEndpoint! beforeEach { sut = GitHubUserEndpoint(loginName: "mosamer") } it("build path") { expect(sut.path) == "users/mosamer" } } }
  • 29. Testing Endpoints class GitHubUserEndpointSpecs: QuickSpec { override func spec() { var sut: GitHubUserEndpoint! beforeEach { sut = GitHubUserEndpoint(loginName: "mosamer") } it("build path") { expect(sut.path) == "users/mosamer" } it("GET method") { expect(sut.method) == HTTPMethod.GET } } }
  • 30. Testing Endpoints class GitHubUserEndpointSpecs: QuickSpec { override func spec() { var sut: GitHubUserEndpoint! beforeEach { sut = GitHubUserEndpoint(loginName: "mosamer") } it("build path") { expect(sut.path) == "users/mosamer" } it("GET method") { expect(sut.method) == HTTPMethod.GET } it("without parameters") { expect(sut.parameters).to(beNil()) } } }
  • 31. Testing Endpoints class GitHubUserEndpointSpecs: QuickSpec { override func spec() { var sut: GitHubUserEndpoint! beforeEach { sut = GitHubUserEndpoint(loginName: "mosamer") } it("build path") { expect(sut.path) == "users/mosamer" } it("GET method") { expect(sut.method) == HTTPMethod.GET } it("without parameters") { expect(sut.parameters).to(beNil()) } it("parse response") { let userJSON = Data() /* Data from JSON file */ let (user, _) = sut.parse(response: userJSON) /* Check user properties are fetched correctly */ } } }
  • 32. Client One MoreTime - (void)fetchGitHubUser:(NSString *)name completionHandler:(void (^)(id, NSError *))handler { [self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name] method:HTTPMethodGET parameters:nil handler:^(id result, NSError *error) { handler(result, error); }]; }
  • 33. Client One MoreTime - (void)fetchGitHubUser:(NSString *)name completionHandler:(void (^)(id, NSError *))handler { [self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name] method:HTTPMethodGET parameters:nil handler:^(id result, NSError *error) { handler(result, error); }]; } func user(loginName: String, completionhandler: (GitHubUser?, Error?) -> ()) { let endpoint = GitHubUserEndpoint(loginName: loginName) request(endpoint, handler: completionhandler) }
  • 34. Client - General Handlers private func request<R: Resource>(_ endpoint: R, handler:(R.ResponseType?, Error?) -> ()) { } } } extension GHAPIClient { func user(loginName: String, completionhandler: (GitHubUser?, Error?) -> ()) { let endpoint = GitHubUserEndpoint(loginName: loginName) request(endpoint, handler: completionhandler) }
  • 35. Client - General Handlers private func request<R: Resource>(_ endpoint: R, handler:(R.ResponseType?, Error?) -> ()) { network.requestEndpoint(path: endpoint.path, method: endpoint.method, parameters: endpoint.parameters) { (data, error) in if let _ = error { handler(nil, error) return } guard let data = data else { handler(nil, nil) return } let (result, error) = endpoint.parse(response: data) handler(result, error) } } } extension GHAPIClient { func user(loginName: String, completionhandler: (GitHubUser?, Error?) -> ()) { let endpoint = GitHubUserEndpoint(loginName: loginName) request(endpoint, handler: completionhandler) }
  • 37. Summary • Client has too many responsibilities
  • 38. Summary • Client has too many responsibilities
  • 39. Summary • Client has too many responsibilities • Client is tightly coupled to the network library
  • 40. Summary • Client has too many responsibilities • Client is tightly coupled to the network library
  • 41. Summary • Client has too many responsibilities • Client is tightly coupled to the network library • Client is hard to test
  • 42. Summary • Client has too many responsibilities • Client is tightly coupled to the network library • Client is hard to test
  • 43. Summary • Client has too many responsibilities • Client is tightly coupled to the network library • Client is hard to test • Implementation details is not hidden
  • 44. Summary • Client has too many responsibilities • Client is tightly coupled to the network library • Client is hard to test • Implementation details is not hidden
  • 45. Summary • Client has too many responsibilities • Client is tightly coupled to the network library • Client is hard to test • Implementation details is not hidden • Client still has too many responsibilities
  • 46. Summary • Client has too many responsibilities • Client is tightly coupled to the network library • Client is hard to test • Implementation details is not hidden • Client still has too many responsibilities
  • 47. Summary • Client has too many responsibilities • Client is tightly coupled to the network library • Client is hard to test • Implementation details is not hidden • Client still has too many responsibilities • Client lacks general handlers
  • 48. Summary • Client has too many responsibilities • Client is tightly coupled to the network library • Client is hard to test • Implementation details is not hidden • Client still has too many responsibilities • Client lacks general handlers