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.

Fea6d57cccac4021b6c8acbfaa468965?s=128

Benedikt Terhechte

October 02, 2016
Tweet

Transcript

  1. Macoun ⌘

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

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

  4. Einleitung

  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
  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
  7. Swift auf dem Server Warum??

  8. •Ruby •Python •Java •Javascript / Node.JS •Go •Clojure •Elixir •Rust

    •Lua •Scala •Kotlin •C++ •Haskell •PHP •Hack •Ur •Groovy •usw.
  9. 3 Gründe

  10. “There’s a real desire among developers for less fractionalization in

    programming” - Kyle Jessup (Gründer, Perfekt Framework)
  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
  12. 2. Code Teilen •Libraries oder Strukturen zwischen Projekten teilen •Zeit

    sparen •Weniger Fehler •Wissens-Transfer (GCD, Foundation, Standard Library)
  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
  14. Web Frameworks

  15. Was ist ein Web Framework •Ähnlich wie Cocoa / Cocoa

    Touch •Unterstützung der Web-Entwicklung •Bündelung oft genutzter Web-Funktionalität
  16. Keine Frontend-Frameworks •Angular •React •Ember •usw.

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

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

    chart
  19. Swift Web Frameworks

  20. Perfect •~8500 Github Sterne •Toolbox, Framework, und Application Server •Linux,

    iOS, macOS •$1.2 Mio Funding bekommen •~3 Haupt-Entwickler
  21. Vapor •~6500 Github Sterne •Pures, modulares Web Framework •Linux, iOS,

    macOS •Finanziert durch Nodes (“London’s leading App Agency”)
  22. Kitura •~4500 Github Sterne •Von IBM •Web Framework & Server

    für Web Services •IBM / Kitura arbeitet auch stark am Swift Linux Support
  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)
  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
  25. Web Framework Features

  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
  27. User Authentifizierung •Einen User einloggen, ausloggen, ablegen und abrufen •Registrierung

    via Email oder oAuth (GitHub, Facebook, Twitter, etc) •Perfect, Vapor
  28. Datenbankunterstützung Feature MySQL PostgreSQL MongoDB Redis RethinkDB Cassandra CouchDB Filemaker

    Perfect Vapor Kitura Zewo
  29. ORM •Datenbank-Abstraktions-Ebene ähnlich wie Core Data •Erspart SQL •Abstrahiert Datenbank-Typen

    •Strenge Typen für Relationale Abhängigkeiten •Vapor
  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
  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)
  32. Sessions •Temporäre Speicherung von User-Informationen •Automatisch über Cookies an User

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

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

  35. Middleware •Registrieren von Funktionen die vor und nach dem Request

    ausgeführt werden •Beispiele •Authentifizierung •Sicherheit •Caching
  36. Lokalisierung •Unterstützung für die Lokalisierung in mehrere Sprachen •Vapor

  37. Web Sockets •Full-Duplex Kanäle über die TCP-Verbindung •Für Echtzeit-Verbindungen Client

    / Server •Push, Chat, etc •Perfect, Vapor, Zewo
  38. Deployment Method Heroku Docker AWS Apache Nginx Bluemix DigitalOcean Perfect

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

    Zewo
  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
  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
  42. Geschwindigkeit

  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
  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
  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)
  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
  47. 0 70000 140000 210000 280000 Swift: Vapor Swift: Kitura Swift:

    Perfect Plaintext Die Swift Frameworks
  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”
  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
  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
  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
  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
  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
  54. Vapor

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

  56. Demo Anlegen eines Vapor Projektes

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

  58. Code Beispiele

  59. import Vapor let drop = Droplet() drop.get("/") { request in

    return "Hello World" } drop.run()
  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)
  61. import Vapor let drop = Droplet() drop.get("/number", Int.self) { req,

    number in return "Hello World \(number)" } drop.run()
  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) ]) }
  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 }
  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 }
  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 }
  66. Droplet(availableMiddleware: ["Controlling": middleware])

  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 } }
  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 } }
  69. let auth = AuthMiddleware(user: User.self) let drop = Droplet(availableMiddleware: ["Auth":

    auth])
  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
  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
  72. struct MyData { let value: Int = 42 }

  73. struct MyData { let value: Int = 42 } extension

    MyData: ResponseRepresentable { func makeResponse() throws -> Response { return Response(status: .ok, body: "Magic Value: \(value)") } }
  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() }
  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() } }
  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) } } } }
  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) } } } }
  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) } } } }
  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() }
  80. Code Sharing mit macOS Projekt

  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 }
  82. public struct Answer { public let questionIdentifier: Identifier public let

    answer: String }
  83. /// A simple result type public struct Result { public

    let value: Bool }
  84. Mac App Server Mac App Server Mac App Frage? Question

    Answer Result
  85. Demo

  86. Swift auf dem Server?

  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
  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
  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
  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
  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
  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
  93. IDE / Editor Support • macOS • Xcode • Atom

    / Sublime / Emacs / Vim mit SourceKittenDaemon • Nuclide • Linux • SourceKit-Support is coming • Swift kompilieren & libide-test
  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
  95. Fragen?

  96. Vielen Dank

  97. Macoun ⌘

  98. Macoun ⌘