Functional Core, Reactive Shell
-
Upload
giovanni-lodi -
Category
Software
-
view
23.021 -
download
0
Transcript of Functional Core, Reactive Shell
![Page 1: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/1.jpg)
Functional CoreReactive Shell
YOW! West 2016
@mokagio
![Page 2: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/2.jpg)
Spaghetti
![Page 3: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/3.jpg)
Spaghetti Architecture
![Page 4: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/4.jpg)
Lasagna
![Page 5: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/5.jpg)
Lasagna Architecture
![Page 6: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/6.jpg)
Ravioli
![Page 7: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/7.jpg)
Ravioli Architecture
![Page 8: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/8.jpg)
Pizza
![Page 9: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/9.jpg)
Back to thelasagna...
![Page 10: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/10.jpg)
Consumer POV
![Page 11: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/11.jpg)
Unit Tests POV
![Page 12: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/12.jpg)
Dependencies Tree
![Page 13: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/13.jpg)
Side Effects
![Page 14: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/14.jpg)
Stubs & Mocks
![Page 15: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/15.jpg)
StubTest Double
Indirect Inputs
![Page 16: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/16.jpg)
Use a stub for the dependencies
![Page 17: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/17.jpg)
MockTest Double
Indirect Outputs
![Page 18: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/18.jpg)
Use a mock to verify a side effect
![Page 19: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/19.jpg)
Is this a goodidea?
![Page 20: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/20.jpg)
Mocks Tell Lies
![Page 21: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/21.jpg)
NotProduction
Code!
![Page 22: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/22.jpg)
func sum(a: Int, b: Int) ->Int
![Page 23: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/23.jpg)
mock(+)or
expect(sum(1, 2)) == 3
![Page 24: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/24.jpg)
Ken Scambler"To Kill a Mockingtest"
"Mocks & Stubs"
![Page 25: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/25.jpg)
Many Dependencies
&
Side Effects
![Page 26: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/26.jpg)
Gary BernhardtBoundaries
![Page 27: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/27.jpg)
Objects >> Values
![Page 28: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/28.jpg)
func sum(a: Int, b: Int) ->Int
![Page 29: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/29.jpg)
Pure Function
![Page 30: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/30.jpg)
But I do need I/O...
![Page 31: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/31.jpg)
Decisionvs
Action
![Page 32: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/32.jpg)
ExampleInsert object in DB if
<condition>
![Page 33: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/33.jpg)
Standard Approachclass DatabaseService { func insertObjects(objects: [DBObject], updatedAfter date: NSDate) { // 1. Filter objects array based on criteria // 2. For each remainig object // 2.1 Insert object in DB } }
![Page 34: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/34.jpg)
Split Approach: Decisionstruct DBAction { enum Mode { case Insert case Update case Delete }
let objects: [DBObject] let mode: Mode}
func persistObjectsAction(objects: [DBObject], updatedAfter updatedDate: NSDate) -> // 1. Filter object based on date // 2. Create action value using objects and insert mode }
![Page 35: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/35.jpg)
Split Approach: Decision
Easy to test using in memory values
No DB setup needed
Really does only one thing
![Page 36: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/36.jpg)
Split Approach: Actionclass DatabaseService { func performAction(action: DBAction) { // for each object switch on mode and perform mode action } }
![Page 37: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/37.jpg)
Split Approach: Action
Testable using simple scenarios
"Once and for all"
![Page 38: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/38.jpg)
Toppings
![Page 39: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/39.jpg)
Functional CoreImperative Shell
Gary Bernhardt
![Page 40: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/40.jpg)
Functional Core, Imperative Shell
![Page 41: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/41.jpg)
Pizza!
![Page 42: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/42.jpg)
Functional CoreImperative ShellReactive Shell
![Page 43: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/43.jpg)
Functional Core, Reactive Shell
![Page 44: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/44.jpg)
ExampleApp fetching stuff from
network and cache
![Page 45: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/45.jpg)
Functional Corestruct Stuff { let id: String let text: String let number: Int }
extension Stuff { init?(json: [String: AnyObject]) { /* ... */ }}
extension Stuff { init(realmObject: RealmStuff) { /* ... */ } }
![Page 46: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/46.jpg)
Functional Coredescribe("Stuff from JSON dictionary") { context("when the dictionary contains all the valid keys") { it("it returns an instance configured with the values in the dictionary") { let anyId = "any id" let anyText = "any text" let anyNumber = 42 let dict: [String: AnyObject] = ["id": anyId, "text": anyText, "number": anyNumber]
let stuff = Stuff(json: dict)
expect(stuff?.id) == anyId expect(stuff?.text) == anyText expect(stuff?.number) == anyNumber } } }
describe("Stuff model from Realm object") { it("sets its properties based on the Realm object one") { let realmObject = RealmStuff.test_fixture()
let sut = Stuff(realmObject: realmObject)
expect(sut.id) == realmObject.id expect(sut.number) == realmObject.number expect(sut.text) == realmObject.text } }
![Page 47: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/47.jpg)
Functional Coreextension CellViewModel { init(stuff: Stuff) { self.text = "\(stuff.id) - \(stuff.text) (\(stuff.number))" } }
describe("CellViewModel") { context("when initialized with a Stuff model") { it("sets the text using the stuff properties") { let stuff = Stuff(id: "123", text: "any text", number: 42)
let sut = CellViewModel(stuff: stuff)
expect(sut.text) == "123 - any text (42)" } } }
![Page 48: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/48.jpg)
Side Effect Codeclass ViewController: UIViewController { enum Effect { case UpdateView(viewModels: [CellViewModel]) case PresentAlert(error: ErrorType) }
func performEffect(effect: Effect) { switch effect {
case .UpdateView(let viewModels): self.viewModels = viewModels tableView.reloadData()
case .PresentAlert(let error): presentErrorAlert(error) } } }
![Page 49: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/49.jpg)
Reactive Shellmerge([ databaseService.allStuff() .map { $0.map { Stuff(realmObject: $0) } },
networkService.performRequest(toEndpoint: .GetStuff) .flatMapLatest { JSON in return Stuff.stuffProducer(withJSON: JSON) } ]) .map { stuffArray in stuffArray.map { CellViewModel(stuff: $0) } } .map { viewModels in Effect.UpdateView(viewModels: viewModels) } .observeOnMainThread() .on( failed: { [weak self] error in self?.performEffect(Effect.PresentAlert(error: error)) }, next: { [weak self] effect in self?.performEffect(effect) } ) .start()
![Page 50: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/50.jpg)
Good Idea?
![Page 51: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/51.jpg)
ConsLearning curve
Long and awkward reactive shell
![Page 52: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/52.jpg)
ProsReactive shell tells the story
Higher code mobility
Learning is GOOD
![Page 53: Functional Core, Reactive Shell](https://reader033.fdocuments.in/reader033/viewer/2022050613/5a6df7817f8b9a22298b4d9b/html5/thumbnails/53.jpg)
Gio@mokagio
http://mokacoding.com