the joy of serverside swift development

190
The Joy Of Ser ver Side Swif t Development

Upload: giordano-scalzo

Post on 23-Jan-2018

515 views

Category:

Mobile


7 download

TRANSCRIPT

Page 1: The Joy  of ServerSide Swift Development

The Joy Of Server Side Swift Development

Page 2: The Joy  of ServerSide Swift Development

In 1943 Konrad Zuse invented Plankalkül

Page 3: The Joy  of ServerSide Swift Development

1940s

9 Programming languages

Page 4: The Joy  of ServerSide Swift Development

1950s

... - Fortran(concept) - Fortran II - ALGOL 58(IAL) - LISP(implementation) ...

Page 5: The Joy  of ServerSide Swift Development

1950s

58 Programming languages

Page 6: The Joy  of ServerSide Swift Development

1960s

...- ALGOL 60 - COBOL 61(implementation) - FORTRAN IV - APL(concept) - Simula(concept) - SNOBOL - CPL - SNOBOL3 - ALGOL 68(concept) - BASIC ...

Page 7: The Joy  of ServerSide Swift Development

1960s

113 Programming languages

Page 8: The Joy  of ServerSide Swift Development

1970s

... - Pascal - Smalltalk - C - Prolog - Structured Query language ( SQL) - Bourne Shell(sh) - Modula-2 - AWK...

Page 9: The Joy  of ServerSide Swift Development

1970s

170 Programming languages

Page 10: The Joy  of ServerSide Swift Development

1980s

... - Ada 80(MIL-STD-1815) - GW-BASIC - Turbo Pascal - Objective-C - C++ - Eiffel - Erlang...

Page 11: The Joy  of ServerSide Swift Development

1980s

231 Programming languages

Page 12: The Joy  of ServerSide Swift Development

1990s

... - AMOS BASIC - Haskell - Python - Visual Basic - Brainfuck - Borland Delphi - Java - PHP - Ruby - JavaScript - Standard C++...

Page 13: The Joy  of ServerSide Swift Development

1990s

292 Programming languages

Page 14: The Joy  of ServerSide Swift Development

2000s

...- ActionScript- C#- D- Scala- Groovy- F#- Clojure- Go...

Page 15: The Joy  of ServerSide Swift Development

2000s

339 Programming languages

Page 16: The Joy  of ServerSide Swift Development

2010s

... - Rust - Elm - Kotlin - Elixir - Hack - C++14 ...

Page 17: The Joy  of ServerSide Swift Development

2010s

354 Programming languages

Page 18: The Joy  of ServerSide Swift Development

and then...

Page 19: The Joy  of ServerSide Swift Development
Page 20: The Joy  of ServerSide Swift Development

355

Page 21: The Joy  of ServerSide Swift Development

Do we really need another programming language?

Page 22: The Joy  of ServerSide Swift Development

Who Am I?@giordanoscalzohttps://github.com/gscalzo

A developer

Page 23: The Joy  of ServerSide Swift Development
Page 24: The Joy  of ServerSide Swift Development
Page 25: The Joy  of ServerSide Swift Development
Page 26: The Joy  of ServerSide Swift Development
Page 27: The Joy  of ServerSide Swift Development
Page 28: The Joy  of ServerSide Swift Development

After one year

Page 29: The Joy  of ServerSide Swift Development
Page 30: The Joy  of ServerSide Swift Development
Page 31: The Joy  of ServerSide Swift Development

For Real!

Page 32: The Joy  of ServerSide Swift Development
Page 33: The Joy  of ServerSide Swift Development
Page 34: The Joy  of ServerSide Swift Development
Page 35: The Joy  of ServerSide Swift Development

Officially, only Linux is Supported

Page 36: The Joy  of ServerSide Swift Development

Being Open-Source...

Page 37: The Joy  of ServerSide Swift Development
Page 38: The Joy  of ServerSide Swift Development
Page 39: The Joy  of ServerSide Swift Development
Page 40: The Joy  of ServerSide Swift Development

Server side development without a web framework?

Page 41: The Joy  of ServerSide Swift Development

We have a few...

Page 42: The Joy  of ServerSide Swift Development

Perfect: github.github.com/PerfectlySoft/Perfect (8829) Vapor: github.com/vapor/vapor (6763) Kitura: github.com/IBM-Swift/Kitura (4578) Swifton: github.com/necolt/Swifton (2016) Zewo: github.com/Zewo/Zewo (1358) Blackfish: github.com/elliottminns/blackfish (932) Slimane: github.com/noppoMan/Slimane (61) Tailor: github.com/brownleej/tailor (55) Kunugi: github.com/novi/Kunugi (35) Quark: github.com/QuarkX/Quark (33)

Page 43: The Joy  of ServerSide Swift Development
Page 44: The Joy  of ServerSide Swift Development

"Perfect is a complete and powerful toolbox,

framework, and application server for Linux, iOS, and

macOS"

Page 45: The Joy  of ServerSide Swift Development

They got money(Even without React. js!)

Page 46: The Joy  of ServerSide Swift Development
Page 47: The Joy  of ServerSide Swift Development

Open-source-ish, but enterprise-ish...

Page 48: The Joy  of ServerSide Swift Development
Page 49: The Joy  of ServerSide Swift Development

Sean StephensChief Executive Officer

Page 50: The Joy  of ServerSide Swift Development

let server = HTTPServer()

var routes = Routes()routes.add(method: .get, uri: "/", handler: { request, response in response.setHeader(.contentType, value: "text/html") response.appendBody(string: "<html><title>Hello, world!</title><body>Hello, world!</body></html>") response.completed() })

server.addRoutes(routes)server.serverPort = 8181server.documentRoot = "./webroot"configureServer(server)

do { try server.start()} catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)")}

Page 51: The Joy  of ServerSide Swift Development
Page 52: The Joy  of ServerSide Swift Development

4 Laravel inspired

4 Easy to setup

4 Fantastic Command Line Tool

Page 53: The Joy  of ServerSide Swift Development
Page 54: The Joy  of ServerSide Swift Development

let drop = Droplet()drop.get("/") { request in return try drop.view.make("welcome.html")}drop.get("plaintext") { request in return "Hello, World!"}drop.serve()

Page 55: The Joy  of ServerSide Swift Development
Page 56: The Joy  of ServerSide Swift Development
Page 57: The Joy  of ServerSide Swift Development

4 Backed by IBM

4 Express.js-like

4 Perfectly integrated in IBM cloud solution BlueMix

Page 58: The Joy  of ServerSide Swift Development
Page 59: The Joy  of ServerSide Swift Development

import Kitura

let router = Router()

router.get("/") { request, response, next in response.send("Hello, World!") next()}

Kitura.addHTTPServer(onPort: 8080, with: router)Kitura.run()

Page 60: The Joy  of ServerSide Swift Development

Let's talk now of...

Page 61: The Joy  of ServerSide Swift Development

Performance!

Page 62: The Joy  of ServerSide Swift Development

Benchmarks are difficult

Page 63: The Joy  of ServerSide Swift Development
Page 64: The Joy  of ServerSide Swift Development

and useless...

Page 65: The Joy  of ServerSide Swift Development
Page 66: The Joy  of ServerSide Swift Development
Page 67: The Joy  of ServerSide Swift Development
Page 68: The Joy  of ServerSide Swift Development
Page 69: The Joy  of ServerSide Swift Development
Page 70: The Joy  of ServerSide Swift Development

Swift Frameworks Benchmarks

Page 71: The Joy  of ServerSide Swift Development
Page 72: The Joy  of ServerSide Swift Development

Fair Enough

Page 73: The Joy  of ServerSide Swift Development

Let's do some code

Page 74: The Joy  of ServerSide Swift Development

You can write Basic in Swift...

Page 75: The Joy  of ServerSide Swift Development

You can write Haskell-ish in Swift...

Page 76: The Joy  of ServerSide Swift Development

The sense of Swift

Page 77: The Joy  of ServerSide Swift Development

An Isomorphic Swift App!

Page 78: The Joy  of ServerSide Swift Development

A Universal Swift App!

Page 79: The Joy  of ServerSide Swift Development
Page 80: The Joy  of ServerSide Swift Development
Page 81: The Joy  of ServerSide Swift Development

Introducing

Mr Drizzle!

Page 82: The Joy  of ServerSide Swift Development

An hyper local weather app

Page 83: The Joy  of ServerSide Swift Development
Page 84: The Joy  of ServerSide Swift Development
Page 85: The Joy  of ServerSide Swift Development
Page 86: The Joy  of ServerSide Swift Development
Page 87: The Joy  of ServerSide Swift Development

MrDrizzle Server Requirements:4 Convert from Wunderground Models to MrDrizzle

Model

4 Refresh cache every hour

Page 88: The Joy  of ServerSide Swift Development

MrDrizzle Server

Page 89: The Joy  of ServerSide Swift Development
Page 90: The Joy  of ServerSide Swift Development

mkdir MrDrizzleServercd MrDrizzleServerswift package init --type executable

Page 91: The Joy  of ServerSide Swift Development
Page 92: The Joy  of ServerSide Swift Development

Swift Package Managerimport PackageDescription

let package = Package( name: "MrDrizzleServer", dependencies: [ .Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 0) ])

Page 93: The Joy  of ServerSide Swift Development

Let's make it run

// main.swiftimport Foundationimport HTTPimport Vapor

let wheaterUndergroundKey = "KEY"let wheaterUndergroundDomain = "api.wunderground.com"

let drop = Droplet()

drop.get("/hello") { _ in return "Hello World"}

drop.run()

Page 94: The Joy  of ServerSide Swift Development

$ swift build

> Cloning https://github.com/vapor/vapor.git> HEAD is now at 453f7cf Merge pull request #628> Resolved version: 1.0.3> Cloning https://github.com/vapor/crypto.git> HEAD is now at 0aaa68b Merge pull request #15> Resolved version: 1.0.1> Cloning https://github.com/vapor/core.git........> Compile Swift Module 'TypeSafeRouting' (3 sources)> Compile Swift Module 'Vapor' (83 sources)> Compile Swift Module 'MrDrizzleServer' (1 sources)> Linking ./.build/debug/MrDrizzleServer

$ .build/debug/MrDrizzleServer

Page 95: The Joy  of ServerSide Swift Development

> Could not load localization files> No cipher key was set, using blank key.> Chacha20 cipher requires an initialization > No command supplied, defaulting to serve> No preparations.> No servers.json configuration found.> Starting server at 0.0.0.0:8080

Page 96: The Joy  of ServerSide Swift Development
Page 97: The Joy  of ServerSide Swift Development
Page 98: The Joy  of ServerSide Swift Development

$ swift package generate-xcodeproj> generated: ./MrDrizzleServer.xcodeproj

Page 99: The Joy  of ServerSide Swift Development
Page 100: The Joy  of ServerSide Swift Development

Hello World for dummies

Page 101: The Joy  of ServerSide Swift Development

This version:

drop.get("/hello") { _ in return "Hello World"}

Page 102: The Joy  of ServerSide Swift Development

Is equivalent to:

func handler(request: Request) throws -> ResponseRepresentable { return Response(status: .ok, body: "Hello, World")}drop.get("/hello", handler: handler)

because:

extension Swift.String: ResponseRepresentable { public func makeResponse() -> Response { return Response(body: self.bytes) }}

Page 103: The Joy  of ServerSide Swift Development

Go back to MrDrizzleServer

Page 104: The Joy  of ServerSide Swift Development

The list of the stations:

struct StationInfo { let name: String let stationId: String let lat: Float let lon: Float}

let stationsInfo = [ StationInfo(name: "Chelsea", stationId: "ILONDON330", lat: 51.479633, lon:-0.180277), StationInfo(name: "Westminster", stationId: "ILONDON120", lat: 51.65343, lon:-0.183732) //...]

Page 105: The Joy  of ServerSide Swift Development

Let's define a schema for our models

Page 106: The Joy  of ServerSide Swift Development

Model schema in pseudocode

object Stations { Array of Station stations }object Station { string id float lat float lon string name Array of HourlyMeasure measures}object HourlyMeasure { int32 hour float temp_f float temp_c}

Page 107: The Joy  of ServerSide Swift Development

syntax = "proto3";

message Stations { repeated Station stations = 1;}message Station { string id = 1; float lat = 2; float lon = 3; string name = 4; repeated HourlyMeasure measures = 5;}message HourlyMeasure { int32 hour = 1; float temp_f = 2; float temp_c = 3;}

Page 108: The Joy  of ServerSide Swift Development

protobuf

Invented by Apple

Page 109: The Joy  of ServerSide Swift Development
Page 110: The Joy  of ServerSide Swift Development

Given this:

syntax = "proto3";

message Stations { repeated Station stations = 1;}message Station { string id = 1; float lat = 2; float lon = 3; string name = 4; repeated HourlyMeasure measures = 5;}message HourlyMeasure { int32 hour = 1; float temp_f = 2; float temp_c = 3;}

Page 111: The Joy  of ServerSide Swift Development

/* * DO NOT EDIT. * * Generated by the protocol buffer compiler. * Source: mrdrizzle.proto * */

public struct Stations: ProtobufGeneratedMessage { public var swiftClassName: String {return "Stations"} public var protoMessageName: String {return "Stations"} public var protoPackageName: String {return ""} //...}

public struct Station: ProtobufGeneratedMessage { public var swiftClassName: String {return "Station"} public var protoMessageName: String {return "Station"} public var protoPackageName: String {return ""} //...}

public struct HourlyMeasure: ProtobufGeneratedMessage { public var swiftClassName: String {return "HourlyMeasure"} public var protoMessageName: String {return "HourlyMeasure"} public var protoPackageName: String {return ""}

//...}

Page 112: The Joy  of ServerSide Swift Development

We extend these structs to instantiate from the wunderground JSON

Page 113: The Joy  of ServerSide Swift Development

Wheater Underground JSON:

{ "response": { "version": "0.1", }, "hourly_forecast": [ { "FCTTIME": { "hour": "22", "mday": "19", "mday_padded": "19", "yday": "292", "isdst": "1", "age": "", "UTCDATE": "" }, "temp": { "english": "52", "metric": "11" }, "condition": "Clear", "icon": "clear", "metric": "-9999" }, ...

Page 114: The Joy  of ServerSide Swift Development

extension Station { init?(stationInfo: StationInfo, json: JSON) { guard let hourly_forecast = json["hourly_forecast"]?.array as? [JSON] else { return nil }

let measures = hourly_forecast.flatMap { HourlyMeasure(json: $0) }

self.init(lat: stationInfo.lat, lon: stationInfo.lon, name: stationInfo.name, measures: measures) }}

Page 115: The Joy  of ServerSide Swift Development

extension HourlyMeasure { init?(json: JSON) { guard let fctTime = json["FCTTIME"]?.object, let hour = fctTime["hour"]?.string, let temp = json["temp"]?.object, let tempF = temp["english"]?.string, let tempC = temp["metric"]?.string else { return nil }

self.init(hour: Int32(hour), tempF: Float(tempF), tempC: Float(tempC)) }}

Page 116: The Joy  of ServerSide Swift Development

Retrieving from Wunderground Server

Page 117: The Joy  of ServerSide Swift Development

extension Station { init?(stationInfo: StationInfo, client: ClientProtocol.Type) { let url = "http://\(wheaterUndergroundDomain)/api/" + "\(wheaterUndergroundKey)/hourly/q/pws:" + "\(stationInfo.stationId).json" guard let response = try? client.get(url), case .data(let bytes) = response.body, let json = try? JSON(bytes: bytes) else { return nil }

self.init(stationInfo: stationInfo, json: json) } }

Page 118: The Joy  of ServerSide Swift Development

Refreshing every hour

Page 119: The Joy  of ServerSide Swift Development

We cannot use URLSession :-(class WeatherService { private let refreshQueue = DispatchQueue(label: "com.mrdrizzle.refresh") private(set) var stations = Stations()

init(stationsInfo: [StationInfo], client: ClientProtocol.Type) { refresh(stationsInfo: stationsInfo, client: client) }

private func refresh(stationsInfo: [StationInfo], client: ClientProtocol.Type) { stations = stations.refreshed(given: stationsInfo, client: client) refreshQueue.asyncAfter(deadline: .now() + 3600) { [weak self] in self?.refresh(stationsInfo: stationsInfo, client: client) } } }

Page 120: The Joy  of ServerSide Swift Development

private extension Stations { func refreshed(given stationsInfo: [StationInfo], client: ClientProtocol.Type) -> Stations { return Stations(stations: stationsInfo.flatMap { Station(stationInfo: $0, client: client) }) }}

Page 121: The Joy  of ServerSide Swift Development

Putting everything together

Page 122: The Joy  of ServerSide Swift Development

//main.swiftlet drop = Droplet()

let stationsInfo = [ StationInfo(name: "Chelsea", stationId: "ILONDON330", lat: 51.479633, lon:-0.180277), StationInfo(name: "Westminster", stationId: "ILONDON120", lat: 51.65343, lon:-0.183732) //...]

let weatherService = WeatherService(stationsInfo: stationsInfo, client: drop.client)

drop.get("/api/weather") { _ in let stations = weatherService.stations

guard let data = try? stations.serializeProtobuf(), let bytes = try? data.makeBytes() else { throw Abort.serverError }

return Response(status: .ok, body: .data(bytes))}

drop.run()

Page 123: The Joy  of ServerSide Swift Development

Job done!

Page 124: The Joy  of ServerSide Swift Development

MrDrizzle Client

Page 125: The Joy  of ServerSide Swift Development

Networking classes from

https://talk.objc.io/episodes/S01E01-

networking

Page 126: The Joy  of ServerSide Swift Development

struct Resource<A> { let url: URL let parse: (Data) -> A?}

for example:

let url = URL(string: "http://mrdrizzle.com:8080/hello")!let helloResource = Resource<String>(url: url, parse: { data in return String(data: data, encoding: .utf8)})

Page 127: The Joy  of ServerSide Swift Development

class ApiService { func load<A>(resource: Resource<A>, completion: @escaping (A?) -> ()) { URLSession.shared.dataTask(with: resource.url) { data, response, error in guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200, let data = data else { completion(nil) return }

completion(resource.parse(data)) }.resume() }}

Page 128: The Joy  of ServerSide Swift Development

let url = URL(string: "http://mrdrizzle.com:8080/hello")!let helloResource = Resource<String>(url: url) { data in return String(data: data, encoding: .utf8)}

ApiService().load(resource: helloResource) { guard let hello = $0 else { print("ERROR - Hello") return }

print(hello)}

Page 129: The Joy  of ServerSide Swift Development

let url = URL(string: "http://mrdrizzle.com:8080/hello")!let stationResources = Resource<Stations>(url: url) { data in return try? Stations(protobuf: data)}

ApiService().load(resource: stationResources) { guard let stations = $0 else { print("ERROR - Stations") return }

print(stations)}

Page 130: The Joy  of ServerSide Swift Development
Page 131: The Joy  of ServerSide Swift Development

It's ok :-)

Page 132: The Joy  of ServerSide Swift Development

Recap

Page 133: The Joy  of ServerSide Swift Development
Page 134: The Joy  of ServerSide Swift Development
Page 135: The Joy  of ServerSide Swift Development

However...

Page 136: The Joy  of ServerSide Swift Development

Apps are so 2014!

Page 137: The Joy  of ServerSide Swift Development

Let's do something modern

Page 138: The Joy  of ServerSide Swift Development

A Deep Learning Functional Reactive Chatbot!

Page 139: The Joy  of ServerSide Swift Development

Story behind it

Page 140: The Joy  of ServerSide Swift Development
Page 141: The Joy  of ServerSide Swift Development
Page 142: The Joy  of ServerSide Swift Development
Page 143: The Joy  of ServerSide Swift Development
Page 144: The Joy  of ServerSide Swift Development
Page 145: The Joy  of ServerSide Swift Development
Page 146: The Joy  of ServerSide Swift Development

Diagram of a Facebook Messenger ChatBot

Page 147: The Joy  of ServerSide Swift Development
Page 148: The Joy  of ServerSide Swift Development
Page 149: The Joy  of ServerSide Swift Development

Chat Flow

Page 150: The Joy  of ServerSide Swift Development
Page 151: The Joy  of ServerSide Swift Development
Page 152: The Joy  of ServerSide Swift Development
Page 153: The Joy  of ServerSide Swift Development
Page 154: The Joy  of ServerSide Swift Development

Let's do it

Page 155: The Joy  of ServerSide Swift Development
Page 156: The Joy  of ServerSide Swift Development

import PackageDescription

let package = Package( name: "UncleLucio", dependencies: [ .Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 0) ])

Page 157: The Joy  of ServerSide Swift Development

// main.swiftimport Foundationimport Vaporimport HTTP

let PAGE_ACCESS_TOKEN = "STUFF"let fbURL = "https://graph.facebook.com/v2.6/me/messages?access_token=" + PAGE_ACCESS_TOKEN

let uncleLucio = UncleLucio(jokesDB: JokesDB())let drop = Droplet()

Page 158: The Joy  of ServerSide Swift Development

// main.swiftdrop.get("fbwebhook") { request in guard let token = request.data["hub.verify_token"]?.string, let response = request.data["hub.challenge"]?.string else { throw Abort.badRequest }

if token == "UNCLELUCIO_VERIFICATION_TOKEN" { return response // Response(status: .ok, text: response) } else { return "Error, invalid token"//Response(status: .ok, text: "Error, invalid token") }}

Page 159: The Joy  of ServerSide Swift Development

// main.swiftdrop.post("fbwebhook") { request in

request.log()

guard let jsonBody = request.json, let chatMessage = ChatMessage(message: jsonBody) else { throw Abort.badRequest }

let replyMessage = uncleLucio.message(after: chatMessage) return try drop.client.post(fbURL, headers: ["Content-Type": "application/json; charset=utf-8"], body: replyMessage.toJSON())}

drop.run()

Page 160: The Joy  of ServerSide Swift Development

// ChatMessage.swiftimport Foundationimport Vaporimport HTTP

struct ChatMessage { let sender: String let recipient: String let text: String?}

Page 161: The Joy  of ServerSide Swift Development

Payload send by Facebook callback

{ "object": "page", "entry": [ { "id": "1677732245875632", "time": 1476209402183, "messaging": [ { "sender": { "id": "1243544059050238" }, "recipient": { "id": "1677732245875632" }, "timestamp": 1476209402090, "message": { "mid": "mid.1476209402075:82aff934133d72d746", "seq": 17, "text": "Knock knock" } } ] } ]}

Page 162: The Joy  of ServerSide Swift Development

// ChatMessage.swiftextension ChatMessage { init?(message: JSON) { guard let entry = message["entry"]?.array?.first as? JSON else { return nil }

guard let messaging = entry["messaging"]?.array?.first as? JSON else { return nil }

guard let senderWrapper = messaging["sender"]?.object, let sender = senderWrapper["id"]?.string else { return nil } self.sender = sender guard let recipientWrapper = messaging["recipient"]?.object, let recipient = recipientWrapper["id"]?.string else { return nil } self.recipient = recipient guard let message = messaging["message"]?.object else { return nil } self.text = message["text"]?.string }}

Page 163: The Joy  of ServerSide Swift Development

// ChatMessage.swiftextension ChatMessage { func toJSON() throws -> JSON { return try JSON(node: [ "sender": try JSON(node: [ "id": sender ]), "recipient": try JSON(node: [ "id": recipient ]), "message": try JSON(node: [ "text": text ]), ]) }}

Page 164: The Joy  of ServerSide Swift Development
Page 165: The Joy  of ServerSide Swift Development

// UncleLucio.swiftclass UncleLucio { private let jokesDB: JokesDB private var sessions = [String: State]()

init(jokesDB: JokesDB) { self.jokesDB = jokesDB }

func message(after chatMessage: ChatMessage) -> ChatMessage { //... return replyMessage }}

Page 166: The Joy  of ServerSide Swift Development

// UncleLucio.swift func message(after chatMessage: ChatMessage) -> ChatMessage { let state = sessions[chatMessage.sender] ?? StartState(joke: jokesDB.randomJoke())

let (text, newState) = state.nextState(when: chatMessage.text ?? "pota")

if newState is Done { sessions.removeValue(forKey: chatMessage.sender) } else { sessions[chatMessage.sender] = newState } let replyMessage = ChatMessage(sender: chatMessage.recipient, recipient: chatMessage.sender, text: text) return replyMessage }

Page 167: The Joy  of ServerSide Swift Development

// UncleLucio.swift

protocol State { func nextState(when message: String) -> (String, State)}

Page 168: The Joy  of ServerSide Swift Development

// UncleLucio.swift

struct StartState: State { let joke: Joke func nextState(when message: String) -> (String, State) { if message.lowercased().contains("joke") { return ("Knock Knock", WaitingForReplyState(joke: joke)) } return ("pota", self) }}

Page 169: The Joy  of ServerSide Swift Development

struct WaitingForReplyState: State { let joke: Joke func nextState(when message: String) -> (String, State) { let text = message.lowercased() if text.contains("who's there") || text.contains("who is there") { return ("\(joke.subject)!", WaitingForSubjectReplyState(joke: joke)) } return ("pota", StartState(joke: joke)) }}

Page 170: The Joy  of ServerSide Swift Development

struct WaitingForSubjectReplyState: State { let joke: Joke func nextState(when message: String) -> (String, State) { let text = message.lowercased() if text.contains("\(joke.subject.lowercased()) who") { return ("\(joke.punchline)\nahahah", Done()) } return ("pota", StartState(joke: joke)) }}

Page 171: The Joy  of ServerSide Swift Development

struct Done: State { func nextState(when message: String) -> (String, State) { return ("pota", Done()) }}

Page 172: The Joy  of ServerSide Swift Development

Really easy to test

Page 173: The Joy  of ServerSide Swift Development

func testInStart_ReceivingGarbage_SaysSlogan_GoesStart() { let state = StartState(joke: joke())

let (text, nextState) = state.nextState(when: "foobar") XCTAssertEqual(text, "pota")

XCTAssertTrue(nextState is StartState) }

Page 174: The Joy  of ServerSide Swift Development

func testWaitingForSubjectReply_ReceivingReply_SaysPunchline_GoesDone() { let state = WaitingForSubjectReplyState(joke: joke())

let (text, nextState) = state.nextState(when: "\(joke().subject) who") XCTAssertEqual(text, "\(joke().punchline)\nahahah") XCTAssertTrue(nextState is Done) }

Page 175: The Joy  of ServerSide Swift Development

class JokesDB { private let jokes: [Joke] = [ ("Harry", "Harry up and let me in!"), ("Wanda", "Wanda hang out with me right now?"), ("Olive", "Olive you and I don’t care who knows it!"), ("Ho-ho", "You know, your Santa impression could use a little work."), ("Hanna", "...Hanna partridge in a pear tree!"), ("Mary and Abbey", "Mary Christmas and Abbey New Year!"), ("Irish", "Irish you a Merry Christmas!"), ("Yule log", "Yule log the door after you let me in, won’t you?"), ("Ya", "I’m excited to see you too!"), ("Sherlock", "Sherlock your door shut tight!"), ("Scold", "Scold outside—let me in!"), ("Robin", "Robin you! Hand over your cash!"), ("Needle", "Needle little help gettin’ in the door."), ("Nana", "Nana your business who’s there."), ("Luke", "Luke through the keyhole to see!"), ("Isabelle", "Isabelle working, or should I keep knocking?"), ].map { Joke(subject: $0.0, punchline: $0.1) }

func randomJoke() -> Joke { return jokes.randomItem() }}

Page 176: The Joy  of ServerSide Swift Development

extension Array { func randomItem() -> Element { let index = Int(arc4random_uniform(UInt32(self.count))) return self[index] }}

Page 177: The Joy  of ServerSide Swift Development

https://github.com/gscalzo/UncleLucio

Page 178: The Joy  of ServerSide Swift Development

Finally...

Page 179: The Joy  of ServerSide Swift Development

A reason for using Swift in Server...

Page 180: The Joy  of ServerSide Swift Development

Often in our job...

Page 181: The Joy  of ServerSide Swift Development
Page 182: The Joy  of ServerSide Swift Development
Page 183: The Joy  of ServerSide Swift Development
Page 184: The Joy  of ServerSide Swift Development

But sometimes...

Page 185: The Joy  of ServerSide Swift Development
Page 186: The Joy  of ServerSide Swift Development
Page 187: The Joy  of ServerSide Swift Development
Page 188: The Joy  of ServerSide Swift Development

"Everything in Its Right Place" (cit.)

Page 189: The Joy  of ServerSide Swift Development
Page 190: The Joy  of ServerSide Swift Development

Thank You!