SlideShare a Scribd company logo
1 of 53
Download to read offline
CocoaHeads
@v_pradeilles | Medium | LinkedIn
From async to Rx, with little to
no work
Swift
Swift
Quick recap on how functions are typed:
// a function that takes an Int and returns Void
let f: (Int) -> Void
// a function that takes an Int and returns a function that takes a String
and returns Void
let g: (Int) -> (String) -> Void
g(2)("Foo")
// and so on…
let h: (T) -> (U) -> (V) -> W
Async Programming
Completion Handlers
Completion handlers are an easy way to pass data asynchronously
// a function that takes a completion handler
func request(arg1: String, arg2: Int, completionHandler: @escaping (String) -> Void)
// and how it is actually called
request(arg1: "Foo", arg2: 0, completionHandler: { result in
// do something with result
})
Completion Handlers
This pattern is great, until you need to chain calls.
When you do, it leads to nested callbacks, which are hard to read and
reason about.
This situation is often known as « callback hell ».
Rx
Rx
Rx is a library that allows to write asynchronous code through the use
of Observables.
// same function, written using RxSwift
func request(arg1: String, arg2: Int) -> Observable<String>
// and you use it like this
request("Foo", 42).subscribe(onNext: { result in
// do something with result
})
Rx makes it easier to work with asynchronous code, so what about
converting legacy or vendor API that uses completion handlers to new
API that return Observables?
We can try doing it by hand:
func observableRequest(arg1: String, arg2: Int) -> Observable<String> {
return Observable.create { (observer) -> Disposable in
request(arg1: arg1, arg2: arg2, completionHandler: { result in
observer.onNext(result)
observer.onCompleted()
})
return Disposables.create()
}
}
Requires a lot of boiler plate & duplicated code 😞
Functional programming
Functional programming
Currying is a fundamental primitive of functional programming.
It allows us to mangle with a function signature.
// this is how you call a standard function
add(arg1: 2, arg2: 3) // returns 5
// this is how you call a curried function
let curriedAdd = curry(add(arg1:arg2:))
curriedAdd(2)(3) // returns 5
How to implement curry
Easier than it seems:
func curry<A, B, C>(_ function: @escaping (A, B) -> C) -> (A) -> (B) -> C {
return { (a: A) -> (B) -> C in { (b: B) -> C in function(a, b) } }
}
Basically, we wrap the function in a succession of lambdas that will
each receive one of the argument before finally calling the wrapped
function.
Putting the pieces together
Base case
func fromAsync(_ asyncRequest: @escaping ((Element) -> Void) -> Void) -> Observable<Element> {
return Observable.create({ (o) -> Disposable in
asyncRequest({ (result) in
o.onNext(result)
o.onCompleted()
})
return Disposables.create()
})
}
Recursion
func fromAsync<T>(_ asyncRequest: @escaping (T, (Element) -> Void) -> Void) -> (T) ->
Observable<Element> {
return { (a: T) in Observable.fromAsync(curry(asyncRequest)(a)) }
}
func fromAsync<T, U>(_ asyncRequest: @escaping (T, U, (Element) -> Void) -> Void) ->
(T, U) -> Observable<Element> {
return { (a: T, b: U) in Observable.fromAsync(curry(asyncRequest)(a)(b)) }
}
How to use it
// let’s bridge this function
func request(arg1: String, arg2: Int, completionHandler: @escaping (String) -> Void)
fromAsync(request(arg1:arg2:completionHandler:))("Foo", 3)
.subscribe(onNext: { (result) in
// do something with result
})
Performances
Nothing comes for free and this technique comes at some performance costs.
Still, there’s nothing we can’t manage.
• Currying function that takes many parameters (> 6) can take sometime to
compile, due to generics and type inference.
=> The bridging code can be placed in a compiled dependency
• Recursive approaches can reduce performances when applied to resource-
demanding code.
=> Profile execution to identify what is running slow, and do the bridging
manually (via boiler plate code) if needed.
It’s even easier in JS!
Currying in JS
JavaScript exposes primitives that allow to manipulate more directly
the arguments list, thus allowing for a real curry function.
function curry( fn ) {
var arity = fn.length;
return (function resolver() {
var memory = Array.prototype.slice.call( arguments );
return function() {
var local = memory.slice(), next;
Array.prototype.push.apply( local, arguments );
next = local.length >= arity ? fn : resolver;
return next.apply( null, local );
};
}());
}
Bonus
Bonus #1
Async functions (regardless of pattern) are great for UI-based code…
…but they’re a pain when it comes to units testing
func async(_ completionHandler: @escaping (String) -> Void) {
sleep(2)
completionHandler("Foo")
}
assert(/* ??? */ == "Foo")
Bonus #1
Good news is, Foundation has all the primitives required to convert
async to sync:
func sync() -> String {
let dispatchGroup = DispatchGroup()
var result: String? = nil
dispatchGroup.enter()
async {
result = $0
dispatchGroup.leave()
}
dispatchGroup.wait()
return result!
}
assert(sync() == "Foo") // 🎉
Bonus #1
By factoring out the boiler plate code, we create a new base case for
bridging:
func toSync<E>(_ async: @escaping ( @escaping (E) -> Void) -> Void) -> () -> E {
return {
let dispatchGroup = DispatchGroup()
var result: E? = nil
dispatchGroup.enter()
async {
result = $0
dispatchGroup.leave()
}
dispatchGroup.wait()
return result!
}
}
Bonus #2
struct MaximumValidator {
private let max: Int
private let strict: Bool
init(max: Int, strict: Bool) {
self.max = max
self.strict = strict
}
func validate(_ value: Int) -> Bool {
if strict {
return value < max
} else {
return value <= max
}
}
}
Bonus #2
By leveraging currying, we can store a much more relevant artifact to
perform the validation:
struct MaximumValidator {
let validate: (_ max: Int) -> Bool
init(max: Int, strict: Bool) {
self.validate = strict ? { $0 < max } : { $0 <= max }
}
}
Recap
What can currying bring to your code ?
• Bridge functions by operating on their signature
• Build alternate version of a function more appropriate to a given
context
• Specialize functions by binding some parameters to constant
values
Questions? 🤔
Thanks!
• Detailed explanation: https://medium.com/@vin.pradeilles/from-
async-api-to-rx-api-with-little-to-no-work-ba725b53a1e0 👏
• Use it in production: https://github.com/RxSwiftCommunity/
RxSwiftExt#fromasync
💪
A pattern to easily enforce
external data validation in Swift
Real world situation
let accountNumber: String = getAccountNumberFromUser()
// .... some code
if !isValidAccountNumber(accountNumber) { return }
// .... some more code
performBusinessLogic(with: accountNumber)
Real world situation
The validation is indeed performed… for now ⏳
But it is lost in a possibly big chunk of code, so:
- It’s easy to break 🚨
- Hard to enforce in review 🤔
➜ We need to figure out a tighter system
Model-driven security
Model-driven security
Wrap data in business objects:
struct AccountNumber {
let number: String
init?(untrustedAccountNumber: String) {
guard isValidAccountNumber(untrustedAccountNumber) else { return nil }
self.number = untrustedAccountNumber
}
}
Model-driven security
And allow business services to only read data from such objects:
func performBusinessLogic(with accountNumber: AccountNumber) {
// ...
}
That’s better, but not enough
struct Transfer {
let creditAccount: String
let debitAccount: String
let amount: Int
init?(untrustedCreditAccount: String,
untrustedDebitAccount: String,
untrustedAmount: Int) {
guard isValidAccountNumber(untrustedCreditAccount),
isValidAccountNumber(untrustedCreditAccount),
isValidAmount(untrustedAmount) else { return nil }
self.creditAccount = untrustedCreditAccount
self.debitAccount = untrustedDebitAccount
self.amount = untrustedAmount
}
}
That’s better, but not enough
struct Transfer {
let creditAccount: String
let debitAccount: String
let amount: Int
init?(untrustedCreditAccount: String,
untrustedDebitAccount: String,
untrustedAmount: Int) {
guard isValidAccountNumber(untrustedCreditAccount),
isValidAccountNumber(untrustedCreditAccount),
isValidAmount(untrustedAmount) else { return nil }
self.creditAccount = untrustedCreditAccount
self.debitAccount = untrustedDebitAccount
self.amount = untrustedAmount
}
}
That’s better, but not enough
The untrusted value can still be accessed without passing the
validation.
That gives a lot of room for nasty bugs, especially in places where
copy/paste tends to be heavily relied on.
The Validator pattern
The Validator pattern
public struct Untrusted<T> {
fileprivate let value: T
public init(_ value: T) {
self.value = value
}
}
The Validator pattern
public struct Untrusted<T> {
fileprivate let value: T
public init(_ value: T) {
self.value = value
}
}
public protocol Validator {
associatedtype T
static func validation(value: T) -> Bool
}
The Validator pattern
extension Validator {
public static func validate(untrusted: Untrusted<T>) -> T? {
if self.validation(value: untrusted.value) {
return untrusted.value
} else {
return nil
}
}
}
We’re still in the
same file!
Let’s see it in action
Let’s see it in action
struct AccountNumberValidator: Validator {
static func validation(value: String) -> Bool {
return isValidAccountNumber(value)
}
}
Let’s see it in action
struct AccountNumberValidator: Validator {
static func validation(value: String) -> Bool {
return isValidAccountNumber(value)
}
}
struct AccountNumber {
let number: String
init?(untrustedAccountNumber: Untrusted<String>) {
guard let validAccountNumber = AccountNumberValidator.validate(untrusted: untrustedAccountNumber)
else {
return nil
}
self.number = validAccountNumber
}
}
Finally, some coding
guidelines
Finally, some coding guidelines
Whenever external data is retrieved, it must be immediately stored in
an Untrusted container => easy to enforce in code review ✅
Initializer of business objects can take as arguments either other
business objects or Untrusted containers, never primitive types =>
easy to enforce in code review ✅
Business logic can only operate with business objects, never with
primitive types => easy to enforce in code review ✅
Questions? 🤔
Thanks, again!
• Detailed explanation: https://medium.com/@vin.pradeilles/a-pattern-
to-easily-enforce-external-data-validation-in-swift-8bc1d5917bfd 👏
• For some more content about secure coding : https://
www.youtube.com/watch?v=oqd9bxy5Hvc (2016 GOTO
conference)
🍞🥤

More Related Content

What's hot

Operator Overloading & Type Conversions
Operator Overloading & Type ConversionsOperator Overloading & Type Conversions
Operator Overloading & Type ConversionsRokonuzzaman Rony
 
Introduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoaIntroduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoaFlorent Pillet
 
Bca 2nd sem u-4 operator overloading
Bca 2nd sem u-4 operator overloadingBca 2nd sem u-4 operator overloading
Bca 2nd sem u-4 operator overloadingRai University
 
Operator overloading
Operator overloadingOperator overloading
Operator overloadingabhay singh
 
operator overloading & type conversion in cpp over view || c++
operator overloading & type conversion in cpp over view || c++operator overloading & type conversion in cpp over view || c++
operator overloading & type conversion in cpp over view || c++gourav kottawar
 
C++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo JobyC++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo JobyGrejoJoby1
 
ReactiveCocoa in Practice
ReactiveCocoa in PracticeReactiveCocoa in Practice
ReactiveCocoa in PracticeOutware Mobile
 
ReactiveCocoa Goodness - Part I of II
ReactiveCocoa Goodness - Part I of IIReactiveCocoa Goodness - Part I of II
ReactiveCocoa Goodness - Part I of IImanuelmaly
 
Presentation on overloading
Presentation on overloading Presentation on overloading
Presentation on overloading Charndeep Sekhon
 
Swift Sequences & Collections
Swift Sequences & CollectionsSwift Sequences & Collections
Swift Sequences & CollectionsCocoaHeads France
 
Découvrir dtrace en ligne de commande.
Découvrir dtrace en ligne de commande.Découvrir dtrace en ligne de commande.
Découvrir dtrace en ligne de commande.CocoaHeads France
 
Functional programming in Javascript
Functional programming in JavascriptFunctional programming in Javascript
Functional programming in JavascriptKnoldus Inc.
 
operator overloading
operator overloadingoperator overloading
operator overloadingNishant Joshi
 
Learn You a ReactiveCocoa for Great Good
Learn You a ReactiveCocoa for Great GoodLearn You a ReactiveCocoa for Great Good
Learn You a ReactiveCocoa for Great GoodJason Larsen
 
Operator Overloading
Operator OverloadingOperator Overloading
Operator OverloadingNilesh Dalvi
 

What's hot (20)

Operator Overloading & Type Conversions
Operator Overloading & Type ConversionsOperator Overloading & Type Conversions
Operator Overloading & Type Conversions
 
Map kit light
Map kit lightMap kit light
Map kit light
 
Operator overloading
Operator overloadingOperator overloading
Operator overloading
 
Introduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoaIntroduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoa
 
JavaScript Core
JavaScript CoreJavaScript Core
JavaScript Core
 
Bca 2nd sem u-4 operator overloading
Bca 2nd sem u-4 operator overloadingBca 2nd sem u-4 operator overloading
Bca 2nd sem u-4 operator overloading
 
Operator overloading
Operator overloadingOperator overloading
Operator overloading
 
Overloading
OverloadingOverloading
Overloading
 
expression in cpp
expression in cppexpression in cpp
expression in cpp
 
operator overloading & type conversion in cpp over view || c++
operator overloading & type conversion in cpp over view || c++operator overloading & type conversion in cpp over view || c++
operator overloading & type conversion in cpp over view || c++
 
C++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo JobyC++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo Joby
 
ReactiveCocoa in Practice
ReactiveCocoa in PracticeReactiveCocoa in Practice
ReactiveCocoa in Practice
 
ReactiveCocoa Goodness - Part I of II
ReactiveCocoa Goodness - Part I of IIReactiveCocoa Goodness - Part I of II
ReactiveCocoa Goodness - Part I of II
 
Presentation on overloading
Presentation on overloading Presentation on overloading
Presentation on overloading
 
Swift Sequences & Collections
Swift Sequences & CollectionsSwift Sequences & Collections
Swift Sequences & Collections
 
Découvrir dtrace en ligne de commande.
Découvrir dtrace en ligne de commande.Découvrir dtrace en ligne de commande.
Découvrir dtrace en ligne de commande.
 
Functional programming in Javascript
Functional programming in JavascriptFunctional programming in Javascript
Functional programming in Javascript
 
operator overloading
operator overloadingoperator overloading
operator overloading
 
Learn You a ReactiveCocoa for Great Good
Learn You a ReactiveCocoa for Great GoodLearn You a ReactiveCocoa for Great Good
Learn You a ReactiveCocoa for Great Good
 
Operator Overloading
Operator OverloadingOperator Overloading
Operator Overloading
 

Viewers also liked

L'intégration continue avec Bitrise
L'intégration continue avec BitriseL'intégration continue avec Bitrise
L'intégration continue avec BitriseCocoaHeads France
 
Tout savoir pour devenir Freelance
Tout savoir pour devenir FreelanceTout savoir pour devenir Freelance
Tout savoir pour devenir FreelanceFlorent Douine
 
CONTINUOUS DELIVERY WITH FASTLANE
CONTINUOUS DELIVERY WITH FASTLANECONTINUOUS DELIVERY WITH FASTLANE
CONTINUOUS DELIVERY WITH FASTLANECocoaHeads France
 
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017Carol Smith
 

Viewers also liked (10)

Handle the error
Handle the errorHandle the error
Handle the error
 
L'intégration continue avec Bitrise
L'intégration continue avec BitriseL'intégration continue avec Bitrise
L'intégration continue avec Bitrise
 
Make Acccessibility Great Again
Make Acccessibility Great AgainMake Acccessibility Great Again
Make Acccessibility Great Again
 
Super combinators
Super combinatorsSuper combinators
Super combinators
 
Tout savoir pour devenir Freelance
Tout savoir pour devenir FreelanceTout savoir pour devenir Freelance
Tout savoir pour devenir Freelance
 
Design like a developer
Design like a developerDesign like a developer
Design like a developer
 
Cocoaheads
CocoaheadsCocoaheads
Cocoaheads
 
Quoi de neuf dans iOS 10.3
Quoi de neuf dans iOS 10.3Quoi de neuf dans iOS 10.3
Quoi de neuf dans iOS 10.3
 
CONTINUOUS DELIVERY WITH FASTLANE
CONTINUOUS DELIVERY WITH FASTLANECONTINUOUS DELIVERY WITH FASTLANE
CONTINUOUS DELIVERY WITH FASTLANE
 
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017
 

Similar to Cocoa heads 09112017

Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jscacois
 
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
 
C++aptitude questions and answers
C++aptitude questions and answersC++aptitude questions and answers
C++aptitude questions and answerssheibansari
 
Object oriented programming system with C++
Object oriented programming system with C++Object oriented programming system with C++
Object oriented programming system with C++msharshitha03s
 
Inline function
Inline functionInline function
Inline functionTech_MX
 
掀起 Swift 的面紗
掀起 Swift 的面紗掀起 Swift 的面紗
掀起 Swift 的面紗Pofat Tseng
 
CPP-overviews notes variable data types notes
CPP-overviews notes variable data types notesCPP-overviews notes variable data types notes
CPP-overviews notes variable data types notesSukhpreetSingh519414
 
Designing REST API automation tests in Kotlin
Designing REST API automation tests in KotlinDesigning REST API automation tests in Kotlin
Designing REST API automation tests in KotlinDmitriy Sobko
 
Our challenge for Bulkload reliability improvement
Our challenge for Bulkload reliability  improvementOur challenge for Bulkload reliability  improvement
Our challenge for Bulkload reliability improvementSatoshi Akama
 
20145-5SumII_CSC407_assign1.htmlCSC 407 Computer Systems II.docx
20145-5SumII_CSC407_assign1.htmlCSC 407 Computer Systems II.docx20145-5SumII_CSC407_assign1.htmlCSC 407 Computer Systems II.docx
20145-5SumII_CSC407_assign1.htmlCSC 407 Computer Systems II.docxeugeniadean34240
 
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)jeffz
 
C++ Interview Question And Answer
C++ Interview Question And AnswerC++ Interview Question And Answer
C++ Interview Question And AnswerJagan Mohan Bishoyi
 
C++ questions And Answer
C++ questions And AnswerC++ questions And Answer
C++ questions And Answerlavparmar007
 
cppt-170218053903 (1).pptx
cppt-170218053903 (1).pptxcppt-170218053903 (1).pptx
cppt-170218053903 (1).pptxWatchDog13
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Dhaval Dalal
 
C optimization notes
C optimization notesC optimization notes
C optimization notesFyaz Ghaffar
 

Similar to Cocoa heads 09112017 (20)

Lambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter LawreyLambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter Lawrey
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.js
 
CGI.ppt
CGI.pptCGI.ppt
CGI.ppt
 
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
 
C++aptitude questions and answers
C++aptitude questions and answersC++aptitude questions and answers
C++aptitude questions and answers
 
Object oriented programming system with C++
Object oriented programming system with C++Object oriented programming system with C++
Object oriented programming system with C++
 
Inline function
Inline functionInline function
Inline function
 
Blazing Fast Windows 8 Apps using Visual C++
Blazing Fast Windows 8 Apps using Visual C++Blazing Fast Windows 8 Apps using Visual C++
Blazing Fast Windows 8 Apps using Visual C++
 
Lecture2.ppt
Lecture2.pptLecture2.ppt
Lecture2.ppt
 
掀起 Swift 的面紗
掀起 Swift 的面紗掀起 Swift 的面紗
掀起 Swift 的面紗
 
CPP-overviews notes variable data types notes
CPP-overviews notes variable data types notesCPP-overviews notes variable data types notes
CPP-overviews notes variable data types notes
 
Designing REST API automation tests in Kotlin
Designing REST API automation tests in KotlinDesigning REST API automation tests in Kotlin
Designing REST API automation tests in Kotlin
 
Our challenge for Bulkload reliability improvement
Our challenge for Bulkload reliability  improvementOur challenge for Bulkload reliability  improvement
Our challenge for Bulkload reliability improvement
 
20145-5SumII_CSC407_assign1.htmlCSC 407 Computer Systems II.docx
20145-5SumII_CSC407_assign1.htmlCSC 407 Computer Systems II.docx20145-5SumII_CSC407_assign1.htmlCSC 407 Computer Systems II.docx
20145-5SumII_CSC407_assign1.htmlCSC 407 Computer Systems II.docx
 
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
 
C++ Interview Question And Answer
C++ Interview Question And AnswerC++ Interview Question And Answer
C++ Interview Question And Answer
 
C++ questions And Answer
C++ questions And AnswerC++ questions And Answer
C++ questions And Answer
 
cppt-170218053903 (1).pptx
cppt-170218053903 (1).pptxcppt-170218053903 (1).pptx
cppt-170218053903 (1).pptx
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)
 
C optimization notes
C optimization notesC optimization notes
C optimization notes
 

More from Vincent Pradeilles

The underestimated power of KeyPaths
The underestimated power of KeyPathsThe underestimated power of KeyPaths
The underestimated power of KeyPathsVincent Pradeilles
 
Solving callback hell with good old function composition
Solving callback hell with good old function compositionSolving callback hell with good old function composition
Solving callback hell with good old function compositionVincent Pradeilles
 
Taking the boilerplate out of your tests with Sourcery
Taking the boilerplate out of your tests with SourceryTaking the boilerplate out of your tests with Sourcery
Taking the boilerplate out of your tests with SourceryVincent Pradeilles
 
How to build a debug view almost for free
How to build a debug view almost for freeHow to build a debug view almost for free
How to build a debug view almost for freeVincent Pradeilles
 
An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testingVincent Pradeilles
 
Implementing pseudo-keywords through Functional Programing
Implementing pseudo-keywords through Functional ProgramingImplementing pseudo-keywords through Functional Programing
Implementing pseudo-keywords through Functional ProgramingVincent Pradeilles
 
Property Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become JavaProperty Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become JavaVincent Pradeilles
 

More from Vincent Pradeilles (8)

On-Boarding New Engineers
On-Boarding New EngineersOn-Boarding New Engineers
On-Boarding New Engineers
 
The underestimated power of KeyPaths
The underestimated power of KeyPathsThe underestimated power of KeyPaths
The underestimated power of KeyPaths
 
Solving callback hell with good old function composition
Solving callback hell with good old function compositionSolving callback hell with good old function composition
Solving callback hell with good old function composition
 
Taking the boilerplate out of your tests with Sourcery
Taking the boilerplate out of your tests with SourceryTaking the boilerplate out of your tests with Sourcery
Taking the boilerplate out of your tests with Sourcery
 
How to build a debug view almost for free
How to build a debug view almost for freeHow to build a debug view almost for free
How to build a debug view almost for free
 
An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testing
 
Implementing pseudo-keywords through Functional Programing
Implementing pseudo-keywords through Functional ProgramingImplementing pseudo-keywords through Functional Programing
Implementing pseudo-keywords through Functional Programing
 
Property Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become JavaProperty Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become Java
 

Recently uploaded

Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....kzayra69
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 

Recently uploaded (20)

Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 

Cocoa heads 09112017

  • 2. From async to Rx, with little to no work
  • 4. Swift Quick recap on how functions are typed: // a function that takes an Int and returns Void let f: (Int) -> Void // a function that takes an Int and returns a function that takes a String and returns Void let g: (Int) -> (String) -> Void g(2)("Foo") // and so on… let h: (T) -> (U) -> (V) -> W
  • 6. Completion Handlers Completion handlers are an easy way to pass data asynchronously // a function that takes a completion handler func request(arg1: String, arg2: Int, completionHandler: @escaping (String) -> Void) // and how it is actually called request(arg1: "Foo", arg2: 0, completionHandler: { result in // do something with result })
  • 7. Completion Handlers This pattern is great, until you need to chain calls. When you do, it leads to nested callbacks, which are hard to read and reason about. This situation is often known as « callback hell ».
  • 8. Rx
  • 9. Rx Rx is a library that allows to write asynchronous code through the use of Observables. // same function, written using RxSwift func request(arg1: String, arg2: Int) -> Observable<String> // and you use it like this request("Foo", 42).subscribe(onNext: { result in // do something with result })
  • 10. Rx makes it easier to work with asynchronous code, so what about converting legacy or vendor API that uses completion handlers to new API that return Observables?
  • 11. We can try doing it by hand: func observableRequest(arg1: String, arg2: Int) -> Observable<String> { return Observable.create { (observer) -> Disposable in request(arg1: arg1, arg2: arg2, completionHandler: { result in observer.onNext(result) observer.onCompleted() }) return Disposables.create() } }
  • 12. Requires a lot of boiler plate & duplicated code 😞
  • 14. Functional programming Currying is a fundamental primitive of functional programming. It allows us to mangle with a function signature. // this is how you call a standard function add(arg1: 2, arg2: 3) // returns 5 // this is how you call a curried function let curriedAdd = curry(add(arg1:arg2:)) curriedAdd(2)(3) // returns 5
  • 15. How to implement curry Easier than it seems: func curry<A, B, C>(_ function: @escaping (A, B) -> C) -> (A) -> (B) -> C { return { (a: A) -> (B) -> C in { (b: B) -> C in function(a, b) } } } Basically, we wrap the function in a succession of lambdas that will each receive one of the argument before finally calling the wrapped function.
  • 16. Putting the pieces together
  • 17. Base case func fromAsync(_ asyncRequest: @escaping ((Element) -> Void) -> Void) -> Observable<Element> { return Observable.create({ (o) -> Disposable in asyncRequest({ (result) in o.onNext(result) o.onCompleted() }) return Disposables.create() }) }
  • 18. Recursion func fromAsync<T>(_ asyncRequest: @escaping (T, (Element) -> Void) -> Void) -> (T) -> Observable<Element> { return { (a: T) in Observable.fromAsync(curry(asyncRequest)(a)) } } func fromAsync<T, U>(_ asyncRequest: @escaping (T, U, (Element) -> Void) -> Void) -> (T, U) -> Observable<Element> { return { (a: T, b: U) in Observable.fromAsync(curry(asyncRequest)(a)(b)) } }
  • 19. How to use it // let’s bridge this function func request(arg1: String, arg2: Int, completionHandler: @escaping (String) -> Void) fromAsync(request(arg1:arg2:completionHandler:))("Foo", 3) .subscribe(onNext: { (result) in // do something with result })
  • 20. Performances Nothing comes for free and this technique comes at some performance costs. Still, there’s nothing we can’t manage. • Currying function that takes many parameters (> 6) can take sometime to compile, due to generics and type inference. => The bridging code can be placed in a compiled dependency • Recursive approaches can reduce performances when applied to resource- demanding code. => Profile execution to identify what is running slow, and do the bridging manually (via boiler plate code) if needed.
  • 22. Currying in JS JavaScript exposes primitives that allow to manipulate more directly the arguments list, thus allowing for a real curry function. function curry( fn ) { var arity = fn.length; return (function resolver() { var memory = Array.prototype.slice.call( arguments ); return function() { var local = memory.slice(), next; Array.prototype.push.apply( local, arguments ); next = local.length >= arity ? fn : resolver; return next.apply( null, local ); }; }()); }
  • 23. Bonus
  • 24. Bonus #1 Async functions (regardless of pattern) are great for UI-based code… …but they’re a pain when it comes to units testing func async(_ completionHandler: @escaping (String) -> Void) { sleep(2) completionHandler("Foo") } assert(/* ??? */ == "Foo")
  • 25. Bonus #1 Good news is, Foundation has all the primitives required to convert async to sync: func sync() -> String { let dispatchGroup = DispatchGroup() var result: String? = nil dispatchGroup.enter() async { result = $0 dispatchGroup.leave() } dispatchGroup.wait() return result! } assert(sync() == "Foo") // 🎉
  • 26. Bonus #1 By factoring out the boiler plate code, we create a new base case for bridging: func toSync<E>(_ async: @escaping ( @escaping (E) -> Void) -> Void) -> () -> E { return { let dispatchGroup = DispatchGroup() var result: E? = nil dispatchGroup.enter() async { result = $0 dispatchGroup.leave() } dispatchGroup.wait() return result! } }
  • 27. Bonus #2 struct MaximumValidator { private let max: Int private let strict: Bool init(max: Int, strict: Bool) { self.max = max self.strict = strict } func validate(_ value: Int) -> Bool { if strict { return value < max } else { return value <= max } } }
  • 28. Bonus #2 By leveraging currying, we can store a much more relevant artifact to perform the validation: struct MaximumValidator { let validate: (_ max: Int) -> Bool init(max: Int, strict: Bool) { self.validate = strict ? { $0 < max } : { $0 <= max } } }
  • 29. Recap What can currying bring to your code ? • Bridge functions by operating on their signature • Build alternate version of a function more appropriate to a given context • Specialize functions by binding some parameters to constant values
  • 31. Thanks! • Detailed explanation: https://medium.com/@vin.pradeilles/from- async-api-to-rx-api-with-little-to-no-work-ba725b53a1e0 👏 • Use it in production: https://github.com/RxSwiftCommunity/ RxSwiftExt#fromasync
  • 32. 💪
  • 33. A pattern to easily enforce external data validation in Swift
  • 34. Real world situation let accountNumber: String = getAccountNumberFromUser() // .... some code if !isValidAccountNumber(accountNumber) { return } // .... some more code performBusinessLogic(with: accountNumber)
  • 35. Real world situation The validation is indeed performed… for now ⏳ But it is lost in a possibly big chunk of code, so: - It’s easy to break 🚨 - Hard to enforce in review 🤔 ➜ We need to figure out a tighter system
  • 37. Model-driven security Wrap data in business objects: struct AccountNumber { let number: String init?(untrustedAccountNumber: String) { guard isValidAccountNumber(untrustedAccountNumber) else { return nil } self.number = untrustedAccountNumber } }
  • 38. Model-driven security And allow business services to only read data from such objects: func performBusinessLogic(with accountNumber: AccountNumber) { // ... }
  • 39. That’s better, but not enough struct Transfer { let creditAccount: String let debitAccount: String let amount: Int init?(untrustedCreditAccount: String, untrustedDebitAccount: String, untrustedAmount: Int) { guard isValidAccountNumber(untrustedCreditAccount), isValidAccountNumber(untrustedCreditAccount), isValidAmount(untrustedAmount) else { return nil } self.creditAccount = untrustedCreditAccount self.debitAccount = untrustedDebitAccount self.amount = untrustedAmount } }
  • 40. That’s better, but not enough struct Transfer { let creditAccount: String let debitAccount: String let amount: Int init?(untrustedCreditAccount: String, untrustedDebitAccount: String, untrustedAmount: Int) { guard isValidAccountNumber(untrustedCreditAccount), isValidAccountNumber(untrustedCreditAccount), isValidAmount(untrustedAmount) else { return nil } self.creditAccount = untrustedCreditAccount self.debitAccount = untrustedDebitAccount self.amount = untrustedAmount } }
  • 41. That’s better, but not enough The untrusted value can still be accessed without passing the validation. That gives a lot of room for nasty bugs, especially in places where copy/paste tends to be heavily relied on.
  • 43. The Validator pattern public struct Untrusted<T> { fileprivate let value: T public init(_ value: T) { self.value = value } }
  • 44. The Validator pattern public struct Untrusted<T> { fileprivate let value: T public init(_ value: T) { self.value = value } } public protocol Validator { associatedtype T static func validation(value: T) -> Bool }
  • 45. The Validator pattern extension Validator { public static func validate(untrusted: Untrusted<T>) -> T? { if self.validation(value: untrusted.value) { return untrusted.value } else { return nil } } } We’re still in the same file!
  • 46. Let’s see it in action
  • 47. Let’s see it in action struct AccountNumberValidator: Validator { static func validation(value: String) -> Bool { return isValidAccountNumber(value) } }
  • 48. Let’s see it in action struct AccountNumberValidator: Validator { static func validation(value: String) -> Bool { return isValidAccountNumber(value) } } struct AccountNumber { let number: String init?(untrustedAccountNumber: Untrusted<String>) { guard let validAccountNumber = AccountNumberValidator.validate(untrusted: untrustedAccountNumber) else { return nil } self.number = validAccountNumber } }
  • 50. Finally, some coding guidelines Whenever external data is retrieved, it must be immediately stored in an Untrusted container => easy to enforce in code review ✅ Initializer of business objects can take as arguments either other business objects or Untrusted containers, never primitive types => easy to enforce in code review ✅ Business logic can only operate with business objects, never with primitive types => easy to enforce in code review ✅
  • 52. Thanks, again! • Detailed explanation: https://medium.com/@vin.pradeilles/a-pattern- to-easily-enforce-external-data-validation-in-swift-8bc1d5917bfd 👏 • For some more content about secure coding : https:// www.youtube.com/watch?v=oqd9bxy5Hvc (2016 GOTO conference)