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. 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
  2. Was heisst denn Server? •Offiziell: •Ubuntu 16.04 •Ubuntu 15.10 •Ubuntu

    14.04 •Inoffiziell: •Linux: Debian, Arch, Fedora, CentOS, ..? •BSD: FreeBSD 11.0
  3. •Ruby •Python •Java •Javascript / Node.JS •Go •Clojure •Elixir •Rust

    •Lua •Scala •Kotlin •C++ •Haskell •PHP •Hack •Ur •Groovy •usw.
  4. “There’s a real desire among developers for less fractionalization in

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

    sparen •Weniger Fehler •Wissens-Transfer (GCD, Foundation, Standard Library)
  7. 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
  8. Was ist ein Web Framework •Ähnlich wie Cocoa / Cocoa

    Touch •Unterstützung der Web-Entwicklung •Bündelung oft genutzter Web-Funktionalität
  9. Perfect •~8500 Github Sterne •Toolbox, Framework, und Application Server •Linux,

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

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

    für Web Services •IBM / Kitura arbeitet auch stark am Swift Linux Support
  12. 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)
  13. 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
  14. 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
  15. User Authentifizierung •Einen User einloggen, ausloggen, ablegen und abrufen •Registrierung

    via Email oder oAuth (GitHub, Facebook, Twitter, etc) •Perfect, Vapor
  16. 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
  17. 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)
  18. Middleware •Registrieren von Funktionen die vor und nach dem Request

    ausgeführt werden •Beispiele •Authentifizierung •Sicherheit •Caching
  19. 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
  20. 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
  21. 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
  22. 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
  23. •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)
  24. 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
  25. 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”
  26. 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
  27. 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
  28. 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
  29. Fazit •Swift verbraucht deutlich weniger Speicher als Ruby, Python, Django,

    JVM (Java, Scala, Kotlin, Clojure, etc) •Aber, Go, Rust, Lua sind ebenfalls extrem sparsam
  30. 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
  31. 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)
  32. import Vapor let drop = Droplet() drop.get("/number", Int.self) { req,

    number in return "Hello World \(number)" } drop.run()
  33. 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) ]) }
  34. 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 }
  35. 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 }
  36. 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 }
  37. 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 } }
  38. 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 } }
  39. 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
  40. 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
  41. struct MyData { let value: Int = 42 } extension

    MyData: ResponseRepresentable { func makeResponse() throws -> Response { return Response(status: .ok, body: "Magic Value: \(value)") } }
  42. 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() }
  43. 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() } }
  44. 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) } } } }
  45. 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) } } } }
  46. 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) } } } }
  47. 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() }
  48. /// 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 }
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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
  54. 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
  55. IDE / Editor Support • macOS • Xcode • Atom

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