Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Macoun 2016 - Swift auf dem Server

Macoun 2016 - Swift auf dem Server

These are the German slides for my talk on Swift on the Server at the Macoun Conference in Frankfurt.

Benedikt Terhechte

October 02, 2016
Tweet

More Decks by Benedikt Terhechte

Other Decks in Programming

Transcript

  1. Macoun

    View Slide

  2. Swift auf dem Server
    Benedikt Terhechte
    @terhechte :: appventure.me

    View Slide

  3. Ablauf
    •Einführung
    •Web Frameworks
    •Features
    •Benchmarks
    •Vapor
    •Fazit

    View Slide

  4. Einleitung

    View Slide

  5. Relevanz für mich
    •Viele Jahre als Backend-Entwickler gearbeitet
    •Weiterhin interessiert beobachtet
    •Projekte in Python / Scala / Clojure / Go / Lua / PHP entwickelt
    •Mehrere aktive App-Backends in verschiedenen Sprachen

    View Slide

  6. Was heisst denn Server?
    •Offiziell:
    •Ubuntu 16.04
    •Ubuntu 15.10
    •Ubuntu 14.04
    •Inoffiziell:
    •Linux: Debian, Arch, Fedora, CentOS, ..?
    •BSD: FreeBSD 11.0

    View Slide

  7. Swift auf dem Server
    Warum??

    View Slide

  8. •Ruby
    •Python
    •Java
    •Javascript / Node.JS
    •Go
    •Clojure
    •Elixir
    •Rust
    •Lua
    •Scala
    •Kotlin
    •C++
    •Haskell
    •PHP
    •Hack
    •Ur
    •Groovy
    •usw.

    View Slide

  9. 3 Gründe

    View Slide

  10. “There’s a real desire among developers for less fractionalization in
    programming”
    - Kyle Jessup (Gründer, Perfekt Framework)

    View Slide

  11. 1. Reduktion der Sprachvielfalt
    •Server: Ruby
    •Frontend: JavaScript, HTML, CSS
    •Datenbank: SQL
    •Android: Java
    •iOS: Swift
    •= 7 Sprachen!
    •Zukunft: Neue Geräteklassen (VR) neue Sprachen

    View Slide

  12. 2. Code Teilen
    •Libraries oder Strukturen zwischen Projekten teilen
    •Zeit sparen
    •Weniger Fehler
    •Wissens-Transfer (GCD, Foundation, Standard Library)

    View Slide

  13. 3. Swift
    •Swift ist eine angenehme Sprache
    •Schneller als Ruby oder Python
    •Benötigt weniger Speicher auf dem Server
    •Starke Typisierung = Weniger Laufzeit-Fehler
    •Moderne Sprach-Features

    View Slide

  14. Web Frameworks

    View Slide

  15. Was ist ein Web Framework
    •Ähnlich wie Cocoa / Cocoa Touch
    •Unterstützung der Web-Entwicklung
    •Bündelung oft genutzter Web-Funktionalität

    View Slide

  16. Keine Frontend-Frameworks
    •Angular
    •React
    •Ember
    •usw.

    View Slide

  17. DB
    Browse Request Server Framework Code
    Request / Response flow chart

    View Slide

  18. DB
    Browse Request Server Framework Code
    Request / Response flow chart

    View Slide

  19. Swift Web Frameworks

    View Slide

  20. Perfect
    •~8500 Github Sterne
    •Toolbox, Framework, und Application Server
    •Linux, iOS, macOS
    •$1.2 Mio Funding bekommen
    •~3 Haupt-Entwickler

    View Slide

  21. Vapor
    •~6500 Github Sterne
    •Pures, modulares Web Framework
    •Linux, iOS, macOS
    •Finanziert durch Nodes (“London’s leading App Agency”)

    View Slide

  22. Kitura
    •~4500 Github Sterne
    •Von IBM
    •Web Framework & Server für Web Services
    •IBM / Kitura arbeitet auch stark am Swift Linux Support

    View Slide

  23. Viele Andere
    •Swifton: https://github.com/necolt/Swifton (1994 Sterne)
    •Zewo: https://github.com/Zewo/Zewo (1215 Sterne)
    •Blackfish: https://github.com/elliottminns/blackfish (924 Sterne)
    •Slimane: https://github.com/noppoMan/Slimane (61 Sterne)
    •Tailor: https://github.com/brownleej/tailor (55 Sterne)
    •Kunugi: https://github.com/novi/Kunugi (36 Sterne)
    •Quark: https://github.com/QuarkX/Quark (31 Sterne)

    View Slide

  24. Erster Eindruck
    •Die großen Frameworks haben zusammengenommen ~20.000 Github
    Sterne
    •Ruby on Rails hat ~31.000
    •= Interesse an Swift auf dem Server generell vorhanden

    View Slide

  25. Web Framework Features

    View Slide

  26. Feature-Differenzen
    •Nicht alle relevanten Features sind implementiert
    •Unterschiedliche Frameworks, unterschiedliche Prioritäten
    •Einiges ist nur teilweise Implementiert
    •Alle Swift Frameworks sind noch recht jung
    •Status Quo ändert sich wöchentlich

    View Slide

  27. User Authentifizierung
    •Einen User einloggen, ausloggen, ablegen und abrufen
    •Registrierung via Email oder oAuth (GitHub, Facebook, Twitter, etc)
    •Perfect, Vapor

    View Slide

  28. Datenbankunterstützung
    Feature
    MySQL
    PostgreSQL
    MongoDB
    Redis
    RethinkDB
    Cassandra
    CouchDB
    Filemaker
    Perfect Vapor Kitura Zewo

    View Slide

  29. ORM
    •Datenbank-Abstraktions-Ebene ähnlich wie Core Data
    •Erspart SQL
    •Abstrahiert Datenbank-Typen
    •Strenge Typen für Relationale Abhängigkeiten
    •Vapor

    View Slide

  30. Routing
    •Interpretation der Eingangs-URLs der Seiten-Besucher
    •Zergliedern der URL, herauslesen der Parameter
    •Browser: /users/23/posts/144/comments/12
    •Server: user_id: 23, post_id: 144, comment_id: 12
    •Perfect, Vapor, Kitura, Zewo

    View Slide

  31. CRUD
    •Create, Read, Update, Delete
    •Methode um zu ORM-Modellen automatisch Routes / REST
    Endpoints zu generieren
    •Objekt User
    •“/users/:id/delete”
    •“/users/:id/update”
    •Vapor (Begrenzt)

    View Slide

  32. Sessions
    •Temporäre Speicherung von User-Informationen
    •Automatisch über Cookies an User gebunden
    •Perfect, Vapor, Kitura, Zewo

    View Slide

  33. Logic-Freie Templates
    •Mustache
    •Keine Schleifen, keine Verzweigungen
    •Perfect, Vapor, Kitura, Zewo

    View Slide

  34. Turing-Templates
    •Einfache, oft kompilierte Sprache
    •Schleifen
    •Verzweigungen
    •Vapor

    View Slide

  35. Middleware
    •Registrieren von Funktionen die vor und nach dem Request
    ausgeführt werden
    •Beispiele
    •Authentifizierung
    •Sicherheit
    •Caching

    View Slide

  36. Lokalisierung
    •Unterstützung für die Lokalisierung in mehrere Sprachen
    •Vapor

    View Slide

  37. Web Sockets
    •Full-Duplex Kanäle über die TCP-Verbindung
    •Für Echtzeit-Verbindungen Client / Server
    •Push, Chat, etc
    •Perfect, Vapor, Zewo

    View Slide

  38. Deployment
    Method
    Heroku
    Docker
    AWS
    Apache
    Nginx
    Bluemix
    DigitalOcean
    Perfect Vapor Kitura Zewo

    View Slide

  39. Verschiedenes
    •Dateien Hochladen
    •JSON Enkodieren / Dekodieren
    •Perfect, Vapor, Kitura, Zewo

    View Slide

  40. Was Fehlt?
    •Datenbank-Migrationen
    •Asset-Pipeline / Build-System (CSS, JS Kompilieren, etc)
    •Automatisch generierte Administrations-Seiten
    •Sitemaps
    •Viele nice-to-have Kleinigkeiten
    •Automatische CSS / JS Änderungen neu laden
    •Automatisch Swift Änderungen neu laden

    View Slide

  41. Notizen
    •Alle Frameworks nutzen den Swift Package Manager
    •Vapor, Kitura & Zewo basieren auf OpenSwift
    •Standardisierte Sammlung von Protokollen
    •Requests, Responses, Middleware, und Objekte lassen sich
    austauschen

    View Slide

  42. Geschwindigkeit

    View Slide

  43. Benchmarks sind schwierig
    •Es gibt schon einige Swift Web Framework Benchmarks, jedoch
    •Teilweise unter macOS getestet
    •Teilweise nur wenige Alternativen verglichen
    •Teilweise in den Alternativen wenig optimierten Code geschrieben
    •Teilweise mit Beta-Versionen der Frameworks getestet
    •Irgendjemand ist immer mit einem Benchmark unzufrieden

    View Slide

  44. Tech Empower Benchmark
    •Vergleicht ~162 Frameworks
    •Verschiedene Sprachen, Frameworks, Implementierungen
    •Hoch-optimiert. Oft schreiben die Framework-Entwickler selbst den
    Code
    •Genaue Regeln, verschiedene Szenarien
    •www.techempower.com/benchmarks

    View Slide

  45. •Ich habe einige der Tech Empower Tests in den Swift Frameworks
    implementiert
    •Keine Datenbank- und JSON-Tests
    •Anschliessend die Performance gegen die anderen Tech Empower
    Frameworks getestet
    •Auf DigitalOcean $5 Maschine (Tech Empower nutzt ein 40 Core
    32GB Ram Monster)

    View Slide

  46. Einschränkungen
    •Swift / Linux ist noch recht neu. Swift ist noch eher für macOS
    optimiert
    •Alle Swift Web Frameworks befinden sich noch in der Entwicklung
    •Erst einmal Feature-Parität herstellen bevor optimiert wird

    View Slide

  47. 0
    70000
    140000
    210000
    280000
    Swift: Vapor Swift: Kitura Swift: Perfect
    Plaintext
    Die Swift Frameworks

    View Slide

  48. Ruby: rails-unicorn
    Rust: iron
    Groovy: grails
    Javascript: express
    Javascript: nodejs
    Clojure: http-kit
    Elixir: Cowboy
    Swift: Vapor
    Swift: Kitura
    Scala: Play2
    Swift: Perfect
    Go: falcore
    Go: gin
    Go: Raw
    0 250000 500000 750000 1000000
    Plaintext
    Swift vs. “Moderne Sprachen”

    View Slide

  49. Clojure: http-kit
    Elixir: Cowboy
    Swift: Vapor
    Swift: Kitura
    php5
    Java: Play2
    Scala: Play2
    Swift: Perfect
    Python: bottle
    Lua: lapis
    Go: falcore
    Python: falcon
    ur/web
    Go: gin
    Go: Raw
    Lua: openresty
    Java: servlet
    Java: vertx
    Java: netty
    0 1250000 2500000 3750000 5000000
    Plaintext
    Swift vs. Die Schnellsten

    View Slide

  50. PHP laravel
    Erlang: chicagoboss
    Ruby: rails-unicorn
    PHP: hhvm
    Ruby: sinatra-trinidad
    Java: ninja-standalone
    Rust: iron
    Python: flask
    Groovy: grails
    Javascript: express
    Javascript: nodejs
    Clojure: http-kit
    Elixir: Cowboy
    Swift: Vapor
    Swift: Kitura
    php5
    Java: Play2
    Scala: Play2
    Swift: Perfect
    0 75000 150000 225000 300000
    Plaintext
    Swift vs. Die Meistgenutzten

    View Slide

  51. Fazit
    •Go & Java sind jahrelang für den Linux & Server-Betrieb optimiert
    worden
    •Im Vergleich zu Ruby, Python, Javascript, Clojure, etc ist Swift jedoch
    schon die schnellere Alternative

    View Slide

  52. Fazit
    •Swift verbraucht deutlich weniger Speicher als Ruby, Python, Django,
    JVM (Java, Scala, Kotlin, Clojure, etc)
    •Aber, Go, Rust, Lua sind ebenfalls extrem sparsam

    View Slide

  53. Fazit
    •Go derzeit der stärkste Konkurrent
    •Mehr features, schneller, viele Libraries
    •Dafür bietet Swift
    •Generics & Starke Typen
    •Rosige Zukunft
    •Code-Sharing mit iOS und vielleicht irgendwann Android

    View Slide

  54. Vapor

    View Slide

  55. Warum Vapor?
    •Viele Features
    •Sauber Strukturiert
    •Sehr Modular

    View Slide

  56. Demo
    Anlegen eines Vapor Projektes

    View Slide

  57. Key Learnings
    •Command-Line Tool
    •Xcode Integration

    View Slide

  58. Code Beispiele

    View Slide

  59. import Vapor
    let drop = Droplet()
    drop.get("/") { request in
    return "Hello World"
    }
    drop.run()

    View Slide

  60. import PerfectLib
    import PerfectHTTP
    import PerfectHTTPServer
    let server = HTTPServer()
    var routes = Routes()
    routes.add(method: .get, uri: "/", handler: {
    request, response in
    response.setHeader(.contentType, value: "text/plain")
    response.appendBody(string: "Hello, World")
    response.completed()
    }
    )
    server.addRoutes(routes)
    configureServer(server)
    do {
    // Launch the HTTP server.
    try server.start()
    } catch PerfectError.networkError(let err, let msg) {
    print("Network error thrown: \(err) \(msg)")
    }
    Perfect
    (1.0)

    View Slide

  61. import Vapor
    let drop = Droplet()
    drop.get("/number", Int.self) { req, number in
    return "Hello World \(number)"
    }
    drop.run()

    View Slide

  62. drop.get { req in
    let lang = req.headers["Accept-Language"]?.string ?? “en”
    let msg = drop.localization[lang, "welcome", “title"]
    return try drop.view.make("welcome", [
    “message”: Node.string(msg)
    ])
    }

    View Slide

  63. class ControllingMiddleware: Middleware {
    func respond(to request: Request, chainingTo chain: Responder)
    throws -> Response {
    print("request: \(request)”)
    let response = try chain.respond(to: request)
    response.headers["X-Custom-Header"] = "DebugModified"
    return response
    }

    View Slide

  64. class ControllingMiddleware: Middleware {
    func respond(to request: Request, chainingTo chain: Responder)
    throws -> Response {
    print("request: \(request)”)
    let response = try chain.respond(to: request)
    response.headers["X-Custom-Header"] = "DebugModified"
    return response
    }

    View Slide

  65. class ControllingMiddleware: Middleware {
    func respond(to request: Request, chainingTo chain: Responder)
    throws -> Response {
    print("request: \(request)”)
    let response = try chain.respond(to: request)
    response.headers["X-Custom-Header"] = "DebugModified"
    return response
    }

    View Slide

  66. Droplet(availableMiddleware: ["Controlling": middleware])

    View Slide

  67. extension User: Auth.User {
    static func authenticate(credentials: Credentials)
    throws -> Auth.User {
    // do a query to see if the user exists
    throw Abort.notFound
    }
    static func register(credentials: Credentials)
    throws -> Auth.User {
    // register a new user
    throw Abort.notFound
    }
    }

    View Slide

  68. extension User: Auth.User {
    static func authenticate(credentials: Credentials)
    throws -> Auth.User {
    // do a query to see if the user exists
    throw Abort.notFound
    }
    static func register(credentials: Credentials)
    throws -> Auth.User {
    // register a new user
    throw Abort.notFound
    }
    }

    View Slide

  69. let auth = AuthMiddleware(user: User.self)
    let drop = Droplet(availableMiddleware: ["Auth": auth])

    View Slide

  70. let error = Abort.custom(status: .forbidden, message: “:-(“)
    let protect = ProtectMiddleware(error: error)
    drop.grouped(protect).group("secure") { secure in
    secure.get("about") { req in
    let user = try req.auth.user()
    return user.uniqueID
    }
    }
    # Unauthenticated: /secure/about -> :-(
    # Authenticated: /secure/about -> 122

    View Slide

  71. let error = Abort.custom(status: .forbidden, message: “:-(“)
    let protect = ProtectMiddleware(error: error)
    drop.grouped(protect).group("secure") { secure in
    secure.get("about") { req in
    let user = try req.auth.user()
    return user.uniqueID
    }
    }
    # Unauthenticated: /secure/about -> :-(
    # Authenticated: /secure/about -> 122

    View Slide

  72. struct MyData {
    let value: Int = 42
    }

    View Slide

  73. struct MyData {
    let value: Int = 42
    }
    extension MyData: ResponseRepresentable {
    func makeResponse() throws -> Response {
    return Response(status: .ok, body: "Magic Value: \(value)")
    }
    }

    View Slide

  74. struct MyData {
    let value: Int = 42
    }
    extension MyData: ResponseRepresentable {
    func makeResponse() throws -> Response {
    return Response(status: .ok, body: "Magic Value: \(value)")
    }
    }
    drop.get("/example") { req in
    return MyData()
    }

    View Slide

  75. drop.get("chunked") { request in
    return Response() { stream in
    try stream.send("Counting:")
    for i in 1 ..< 10{
    sleep(1)
    try stream.send(i)
    }
    try stream.close()
    }
    }

    View Slide

  76. drop.get("async") { request in
    return try Response.async { portal in
    _ = try background {
    do {
    let query1 = “https://api.api/search/?q=test”
    let response = try drop.client.get(query1)
    let items = response.data["sub", "i"]?.array ?? []
    let itemJSON = items { $0.string }
    let js = try! JSON(node: itemJSON)
    portal.close(with: js)
    } catch {
    portal.close(with: error)
    }
    }
    }
    }

    View Slide

  77. drop.get("async") { request in
    return try Response.async { portal in
    _ = try background {
    do {
    let query1 = “https://api.api/search/?q=test”
    let response = try drop.client.get(query1)
    let items = response.data["sub", "i"]?.array ?? []
    let itemJSON = items { $0.string }
    let js = try! JSON(node: itemJSON)
    portal.close(with: js)
    } catch {
    portal.close(with: error)
    }
    }
    }
    }

    View Slide

  78. drop.get("async") { request in
    return try Response.async { portal in
    _ = try background {
    do {
    let query1 = “https://api.api/search/?q=test”
    let response = try drop.client.get(query1)
    let items = response.data["sub", "i"]?.array ?? []
    let itemJSON = items { $0.string }
    let js = try! JSON(node: itemJSON)
    portal.close(with: js)
    } catch {
    portal.close(with: error)
    }
    }
    }
    }

    View Slide

  79. drop.socket("websocket") { req, ws in
    let top = 10
    for i in 1...top {
    sleep(1)
    try ws.send("\(i) of \(top)")
    }
    sleep(1)
    try ws.close()
    }

    View Slide

  80. Code Sharing mit macOS
    Projekt

    View Slide

  81. /// A Question as it appears to the user
    public struct Question {
    public let identifier: Identifier
    public let category: Category
    public let question: String
    public let points: Points
    }

    View Slide

  82. public struct Answer {
    public let questionIdentifier: Identifier
    public let answer: String
    }

    View Slide

  83. /// A simple result type
    public struct Result {
    public let value: Bool
    }

    View Slide

  84. Mac App Server
    Mac App Server
    Mac App
    Frage?
    Question
    Answer
    Result

    View Slide

  85. Demo

    View Slide

  86. Swift auf dem Server?

    View Slide

  87. Allgemein
    • Swift am Server ist jung aber aufregend
    • Sowohl Swift 3 als auch die Frameworks änderten sich wöchentlich
    • Die Frameworks als auch Swift werden sich auch weiterhin noch oft
    ändern
    • Fehlende Dokumentation
    • SourceKit stürzt noch öfters ab als in der iOS/macOS Entwicklung

    View Slide

  88. Sollte man Swift / Server wählen?
    • Nicht einfach. Abhängig von:
    • Wieviel Frontend-Code die Anwendung hat
    • Wieviele Sprachen die Teamkollegen schon beherrschen
    • Wieviel Code vermutlich geteilt werden kann
    • Wie gern man Swift mag
    • Auf jeden Fall werdet Ihr refactoren müssen

    View Slide

  89. Welches Framework
    • Perfect ist schneller
    • Vapor bietet mehr features, angenehmere API
    • Für funktionsreduzierte, reine REST-Server ist Perfect vielleicht die
    bessere Wahl.
    • Wenn man in Zukunft mehr features erwartet: Ansonsten Vapor
    • Aktive Entwicklung, in 1-2 Jahren mag Kitura besser sein

    View Slide

  90. Build Times
    • Python, Ruby, Scala, Java, Javascript, use instant compile & reload
    • Swift 3 / Frameworks
    • Initial etwa 1 Minute
    • Incremental etwa 1 Sekunde bei kleinen Projekten
    • Dafür könntet ihr Linux installieren und endlich schnelle Hardware
    kaufen

    View Slide

  91. Notizen
    • Keine UIKit / AppKit Abhängigkeiten heisst das man stärker
    Generics, Value Types & Protokolle verwenden kann
    • Unbedingt unter Linux testen. Foundation unterscheidet sich noch
    stark auf den beiden Plattformen
    • Die von den Web Frameworks gebotenen Abstraktionen wählen.
    Diese sind bereits plattformunabhängig.
    • Vapor hat einen ausgezeichneten, sehr lesbaren, Source-Code

    View Slide

  92. Dokumentation Finden
    • Github nach Beispiel-Projekten durchforsten (diese sind jedoch oft
    veraltet)
    • Unit-Tests lesen
    • Pull-Requests für Features anschauen. Diese enthalten oft Beispiele
    • Den Source-Code lesen

    View Slide

  93. IDE / Editor Support
    • macOS
    • Xcode
    • Atom / Sublime / Emacs / Vim mit SourceKittenDaemon
    • Nuclide
    • Linux
    • SourceKit-Support is coming
    • Swift kompilieren & libide-test

    View Slide

  94. Tips
    • Swiftenv verwenden
    • Die WWDC2016 Performance-Videos zu Swift schauen
    • Docker für Linux-Tests
    • Ich glaube Server-Swift hat viel Potential, aber die wesentlichen
    Features fehlen noch, Zeithorizont in 1-2 Jahren

    View Slide

  95. Fragen?

    View Slide

  96. Vielen Dank

    View Slide

  97. Macoun

    View Slide

  98. Macoun

    View Slide