Slide 1

Slide 1 text

Safer Swift Code with Value Types Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 1

Slide 2

Slide 2 text

What do I mean by safety? Safe, adjective *: - involving little or no risk of mishap, error, etc. - dependable or trustworthy * Thanks to Rich Hickey for pointing out this great way to open a talk Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 2

Slide 3

Slide 3 text

Should I use a struct or a class? It depends! 4 5 6 7 8 9 9 https://www.mikeash.com/pyblog/friday-qa-2015-07-17-when-to-use-swift-structs-and-classes.html 8 http://owensd.io/2015/07/05/re-struct-or-class.html 7 http://faq.sealedabstract.com/structs_or_classes/: "when it comes time to actually save any of those models to disk, or push them over a network, or draw them to the screen, or whatever, you need a class. Classes everywhere. Not "immutable valuable types everywhere" like in the Struct Philosophy™" 6 Apple Swift Blog: "One of the primary reasons to choose value types over reference types is the ability to more easily reason about your code." 5 Apple Developer Guide: "In practice, this means that most custom data constructs should be classes, not structures" 4 GitHub Styleguide: "Unless you require functionality that can only be provided by a class (like identity or deinitializers), implement a struct instead" Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 3

Slide 4

Slide 4 text

Agenda 1. What are Value Types vs. Reference Types 2. Why is this topic relevant now? 3. How: A Practical Example of a Value Oriented Architecture Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 4

Slide 5

Slide 5 text

Values vs. References Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 5

Slide 6

Slide 6 text

Reference Types class PersonRefType { let name:String var age:Int // .. } // 1 let peter = PersonRefType(name: "Peter", age: 36) // 2 let peter2 = peter // 3 peter2.age = 25 // peter {"Peter", 25} // peter2 {"Peter", 25} Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 6

Slide 7

Slide 7 text

Value Types struct Person { let name:String var age:Int } // 1 let petra = Person(name:"Petra", age:25) // 2 var petra2 = petra // 3 petra2.age = 20 // petra {"Petra", 25} // petra2 {"Petra", 20} Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 7

Slide 8

Slide 8 text

Why now? Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 8

Slide 9

Slide 9 text

Foundation / C Types Reference Types: - NSArray - NSSet - NSData Value Types: - NSInteger - Struct Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 9

Slide 10

Slide 10 text

Swift Standard Library Reference Types: - ManagedBuffer(?) - NonObjectiveCBase(??) Value Types: - Array - String - Optional Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 10

Slide 11

Slide 11 text

We've Already Been Doing This! @property (copy) NSString *userName; Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 11

Slide 12

Slide 12 text

Case Study A Twitter Client Built on Immutable Value Types Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 12

Slide 13

Slide 13 text

Twitter Client 1. Download the latest 50 tweets and display them 2. Allow to filter tweets (RT only, favorited tweets only, etc.) 3. Allow user to favorite tweets (should be synced with server) Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 13

Slide 14

Slide 14 text

Twitter Client Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 14

Slide 15

Slide 15 text

How can we favorite Tweets? Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 15

Slide 16

Slide 16 text

It Is Very Simple with OOP tweet.favorited = true Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 16

Slide 17

Slide 17 text

It Is Simple with OOP let lockQueue = dispatch_queue_create("com.happysyncing", nil) dispatch_sync(lockQueue) { tweet.favorited = true } Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 17

Slide 18

Slide 18 text

Is It Simple with OOP? let lockQueue = dispatch_queue_create("com.happysyncing", nil) dispatch_sync(lockQueue) { tweet.favorited = true NSNotificationCenter.defaultCenter(). postNotificationName("Tweet Changed", object: tweet) } Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 18

Slide 19

Slide 19 text

Modeling Change is Hard! let lockQueue = dispatch_queue_create("com.happysyncing", nil) dispatch_sync(lockQueue) { tweet.favorited = true NSNotificationCenter.defaultCenter(). postNotificationName("Tweet Changed", object: tweet) tweetAPIClient.markFavorited(tweet.identifier) } Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 19

Slide 20

Slide 20 text

Modeling Change is Hard! — Protect against unwanted updates — Distribute new value throughout application — Understand what the underlying identity of an object is and perform update accordingly Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 20

Slide 21

Slide 21 text

Modeling Change is Hard! — Protect against unwanted updates — Distribute new value throughout application — Understand what the underlying identity of an object is and perform update accordingly -> We need to this in all places where we mutate values! Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 21

Slide 22

Slide 22 text

OOP Data Flow Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 22

Slide 23

Slide 23 text

Is the OOP Data Flow Safe? Safe, adjective: - involving little or no risk of mishap, error, etc. - dependable or trustworthy Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 23

Slide 24

Slide 24 text

Is the OOP Data Flow Safe? Safe, adjective: - involving little or no risk of mishap, error, etc. - dependable or trustworthy -> A lot of room for error Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 24

Slide 25

Slide 25 text

Modelling Change is Hard! Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 25

Slide 26

Slide 26 text

How Can We Model Change With Immutable Value Types? Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 26

Slide 27

Slide 27 text

How Can We Model Change With Immutable Value Types? Model change to values as values! Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 27

Slide 28

Slide 28 text

How Can We Model Change With Immutable Value Types? Model change to values as values: — Create a new Tweet for every change Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 28

Slide 29

Slide 29 text

How Can We Model Change With Immutable Value Types? Model change to values as values: — Create a new Tweet for every change — Save these mutations in a local change set Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 29

Slide 30

Slide 30 text

How Can We Model Change With Immutable Value Types? Model change to values as values: — Create a new Tweet for every change — Save these mutations in a local change set — Save the server state in a separate data set Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 30

Slide 31

Slide 31 text

How Can We Model Change With Immutable Value Types? Model change to values as values: — Create a new Tweet for every change — Save these mutations in a local change set — Save the server state in a separate data set — Provide a merged view on list of tweets Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 31

Slide 32

Slide 32 text

How Can We Model Change With Immutable Value Types? Model change to values as values: — Create a new Tweet for every change — Save these mutations in a local change set — Save the server state in a separate data set — Provide a merged view on list of tweets — Provide method to sync local state to server Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 32

Slide 33

Slide 33 text

Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 33

Slide 34

Slide 34 text

Where do we store state, how is new state distributed? Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 34

Slide 35

Slide 35 text

Where do we store state, how is new state distributed? Drawing inspiration from the JavaScript world 11 12: -> Unidirectional Data Flow 12 https://github.com/rackt/redux 11 https://facebook.github.io/flux/ Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 35

Slide 36

Slide 36 text

Unidirectional data flow Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 36

Slide 37

Slide 37 text

Unidirectional data flow — ActionCreator: Provides interface for business logic — Action: Represents an individual state mutation — Dispatcher: Stores state, invokes reducers, publishes new state — Reducers: Pure functions, combine current state and action to produce a new state Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 37

Slide 38

Slide 38 text

Implementing unidirectional data flow Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 38

Slide 39

Slide 39 text

Representing State — State will be stored in the Dispatcher in the following form: typealias TimelineState = (serverState: [Tweet], localState: [Tweet]) typealias TimelineMergedState = (serverState: [Tweet], localState: [Tweet], mergedState: [Tweet]) Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 39

Slide 40

Slide 40 text

Defining Actions — Each action describes an atomic mutation to the application state — Action Creators vend these Actions, Reducers implement them enum Action { case Mount case FavoriteTweet(Tweet) case UnfavoriteTweet(Tweet) //... } Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 40

Slide 41

Slide 41 text

Favoriting a Tweet Within the TimelineViewController we trigger the state change by dispatching an Action Creator: func didFavorite(tweetTableViewCell:TweetTableViewCell) { let currentTweet = tweetTableViewCell.tweet! if (currentTweet.isFavorited) { timelineDispatcher.dispatch { TimelineActionCreator.unfavoriteTweet(currentTweet) } } else { timelineDispatcher.dispatch { TimelineActionCreator.favoriteTweet(currentTweet) } } timelineDispatcher.dispatch { TimelineActionCreator.syncFavorites() } } Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 41

Slide 42

Slide 42 text

Favoriting a Tweet Within the TimelineActionCreator we generate an according action: static func favoriteTweet(tweet: Tweet) -> ActionCreator { return { state, dispatcher -> Action? in return .FavoriteTweet(tweet) } } Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 42

Slide 43

Slide 43 text

Favoriting a Tweet Within the Reducer we generate a new state based on the old one: struct TimelineReducers { //... static func favoriteTweet(var state: TimelineState, tweet: Tweet) -> TimelineState { //... } } Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 43

Slide 44

Slide 44 text

Favoriting a Tweet static func favoriteTweet(var state: TimelineState, tweet: Tweet) -> TimelineState { let newTweet = Tweet( content: tweet.content, identifier: tweet.identifier, user: tweet.user, type: tweet.type, favoriteCount: tweet.favoriteCount, isFavorited: true ) let tweetIndex = find(state.localState, tweet) if let tweetIndex = tweetIndex { // if we have stored local state for this tweet previously, override here state.localState[tweetIndex] = newTweet } else { // else append new state state.localState.append(newTweet) } return state } Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 44

Slide 45

Slide 45 text

Favoriting a Tweet Then the Dispatcher forwards the new state to its subscribers, which inlcudes the TimelineViewController: extension TimelineViewController: TimelineSubscriber { func newState(state: TimelineMergedState) { // table view is reloaded when 'tweets' is set tweets = state.mergedState } } Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 45

Slide 46

Slide 46 text

Favoriting a Tweet: Recap Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 46

Slide 47

Slide 47 text

Syncing Change Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 47

Slide 48

Slide 48 text

Syncing Change 1. Iterate over each mutation in the local change set Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 48

Slide 49

Slide 49 text

Syncing Change 1. Iterate over each mutation in the local change set 2. Generate API request that syncs that local change to server Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 49

Slide 50

Slide 50 text

Syncing Change 1. Iterate over each mutation in the local change set 2. Generate API request that syncs that local change to server 3. Upon each API response: — If success: remove tweet from local change set — If failure: leave tweet in local change set Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 50

Slide 51

Slide 51 text

A Twitter Client built on Immutable Value Types Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 51

Slide 52

Slide 52 text

Should I use a struct or a class? It's an architectural question! It's not about struct vs. class It's about: - Shared state vs. isolated state - Mutable state vs. immutable state 10 10 WWDC 2014, Session 229, Advanced iOS Application Architecture and Patterns Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 52

Slide 53

Slide 53 text

Downsides of a Value Oriented Architecture — Unconventional: can be an issue when working on larger teams — Can be difficult to integrate with frameworks that rely on reference semantics, e.g. Core Data Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 53

Slide 54

Slide 54 text

Benefits of a Value Oriented Architecture — Confidence that no one will change our data under the covers — State modification & propagation needs to be handled explicitly and can be implemented in one place — Modeling change as data opens opportunities, e.g. simpler client server sync — Easier to test Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 54

Slide 55

Slide 55 text

The Value Mindset Twitter: @benjaminencz Project & Slides: http://bit.ly/swift-values Related, great talks: Controlling Complexity 20, The Value of Values 21 21 http://www.infoq.com/presentations/Value-Values 20 https://realm.io/news/andy-matuschak-controlling-complexity/ Safer Swift Code with Value Types | @benjaminencz | 360iDev, August 2015 55