SlideShare ist ein Scribd-Unternehmen logo
1 von 190
Downloaden Sie, um offline zu lesen
The Joy Of Server Side
Swift Development
In 1943 Konrad Zuse invented
Plankalkül
1940s
9 Programming languages
1950s
...
- Fortran(concept)
- Fortran II
- ALGOL 58(IAL)
- LISP(implementation)
...
1950s
58 Programming languages
1960s
...
- ALGOL 60
- COBOL 61(implementation)
- FORTRAN IV
- APL(concept)
- Simula(concept) - SNOBOL - CPL - SNOBOL3
- ALGOL 68(concept)
- BASIC
...
1960s
113 Programming languages
1970s
...
- Pascal
- Smalltalk
- C
- Prolog
- Structured Query language ( SQL)
- Bourne Shell(sh)
- Modula-2
- AWK
...
1970s
170 Programming languages
1980s
...
- Ada 80(MIL-STD-1815)
- GW-BASIC
- Turbo Pascal
- Objective-C
- C++
- Eiffel
- Erlang
...
1980s
231 Programming languages
1990s
...
- AMOS BASIC
- Haskell
- Python
- Visual Basic
- Brainfuck
- Borland Delphi
- Java
- PHP
- Ruby
- JavaScript
- Standard C++
...
1990s
292 Programming languages
2000s
...
- ActionScript
- C#
- D
- Scala
- Groovy
- F#
- Clojure
- Go
...
2000s
339 Programming languages
2010s
...
- Rust
- Elm
- Kotlin
- Elixir
- Hack
- C++14
...
2010s
354 Programming languages
and then...
355
Do we really need another
programming language?
Who Am I?
@giordanoscalzo
https://github.com/gscalzo
A developer
After one year
For Real!
Officially, only Linux is
Supported
Being Open-Source...
Server side development
without a web framework?
We have a few...
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)
"Perfect is a complete and
powerful toolbox,
framework, and application
server for Linux, iOS, and
macOS"
They got money
(Even without React.js!)
Open-source-ish, but
enterprise-ish...
Sean Stephens
Chief Executive Officer
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 = 8181
server.documentRoot = "./webroot"
configureServer(server)
do {
try server.start()
} catch PerfectError.networkError(let err, let msg) {
print("Network error thrown: (err) (msg)")
}
4 Laravel inspired
4 Easy to setup
4 Fantastic Command Line Tool
let drop = Droplet()
drop.get("/") { request in
return try drop.view.make("welcome.html")
}
drop.get("plaintext") { request in
return "Hello, World!"
}
drop.serve()
4 Backed by IBM
4 Express.js-like
4 Perfectly integrated in IBM cloud solution BlueMix
import Kitura
let router = Router()
router.get("/") {
request, response, next in
response.send("Hello, World!")
next()
}
Kitura.addHTTPServer(onPort: 8080, with: router)
Kitura.run()
Let's talk now of...
Performance!
Benchmarks are difficult
and useless...
Swift Frameworks
Benchmarks
Fair Enough
Let's do some code
You can write Basic in
Swift...
You can write Haskell-ish
in Swift...
The sense of Swift
An Isomorphic Swift App!
A Universal Swift App!
Introducing
Mr Drizzle!
An hyper local weather app
MrDrizzle Server Requirements:
4 Convert from Wunderground Models to MrDrizzle
Model
4 Refresh cache every hour
MrDrizzle Server
mkdir MrDrizzleServer
cd MrDrizzleServer
swift package init --type executable
Swift Package Manager
import PackageDescription
let package = Package(
name: "MrDrizzleServer",
dependencies: [
.Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 0)
]
)
Let's make it run
// main.swift
import Foundation
import HTTP
import Vapor
let wheaterUndergroundKey = "KEY"
let wheaterUndergroundDomain = "api.wunderground.com"
let drop = Droplet()
drop.get("/hello") { _ in
return "Hello World"
}
drop.run()
$ 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
> 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
$ swift package generate-xcodeproj
> generated: ./MrDrizzleServer.xcodeproj
Hello World for dummies
This version:
drop.get("/hello") { _ in
return "Hello World"
}
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)
}
}
Go back to
MrDrizzleServer
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)
//...
]
Let's define a schema for
our models
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
}
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;
}
protobuf
Invented by Apple
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;
}
/*
* 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 ""}
//...
}
We extend these structs to
instantiate from the
wunderground JSON
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"
},
...
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)
}
}
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))
}
}
Retrieving from
Wunderground Server
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)
}
}
Refreshing every hour
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)
}
}
}
private extension Stations {
func refreshed(given stationsInfo: [StationInfo],
client: ClientProtocol.Type) -> Stations {
return Stations(stations: stationsInfo.flatMap {
Station(stationInfo: $0, client: client)
})
}
}
Putting everything
together
//main.swift
let 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()
Job done!
MrDrizzle Client
Networking classes from
https://talk.objc.io/
episodes/S01E01-
networking
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)
})
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()
}
}
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)
}
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)
}
It's ok :-)
Recap
However...
Apps are so 2014!
Let's do something modern
A Deep Learning Functional
Reactive Chatbot!
Story behind it
Diagram of a Facebook
Messenger ChatBot
Chat Flow
Let's do it
import PackageDescription
let package = Package(
name: "UncleLucio",
dependencies: [
.Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 0)
]
)
// main.swift
import Foundation
import Vapor
import 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()
// main.swift
drop.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")
}
}
// main.swift
drop.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()
// ChatMessage.swift
import Foundation
import Vapor
import HTTP
struct ChatMessage {
let sender: String
let recipient: String
let text: String?
}
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"
}
}
]
}
]
}
// ChatMessage.swift
extension 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
}
}
// ChatMessage.swift
extension 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
]),
])
}
}
// UncleLucio.swift
class UncleLucio {
private let jokesDB: JokesDB
private var sessions = [String: State]()
init(jokesDB: JokesDB) {
self.jokesDB = jokesDB
}
func message(after chatMessage: ChatMessage) -> ChatMessage {
//...
return replyMessage
}
}
// 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
}
// UncleLucio.swift
protocol State {
func nextState(when message: String) -> (String, State)
}
// 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)
}
}
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))
}
}
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))
}
}
struct Done: State {
func nextState(when message: String) -> (String, State) {
return ("pota", Done())
}
}
Really easy to test
func testInStart_ReceivingGarbage_SaysSlogan_GoesStart() {
let state = StartState(joke: joke())
let (text, nextState) = state.nextState(when: "foobar")
XCTAssertEqual(text, "pota")
XCTAssertTrue(nextState is StartState)
}
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)
}
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()
}
}
extension Array {
func randomItem() -> Element {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
https://github.com/gscalzo/UncleLucio
Finally...
A reason for using Swift in
Server...
Often in our job...
But sometimes...
"Everything in Its Right
Place" (cit.)
Thank You!

Weitere ähnliche Inhalte

Was ist angesagt?

Inside the ABC's new Media Transcoding system, Metro
Inside the ABC's new Media Transcoding system, MetroInside the ABC's new Media Transcoding system, Metro
Inside the ABC's new Media Transcoding system, MetroDaphne Chong
 
JIT compilation for CPython
JIT compilation for CPythonJIT compilation for CPython
JIT compilation for CPythondelimitry
 
Video Transcoding at Scale for ABC iview (NDC Sydney)
Video Transcoding at Scale for ABC iview (NDC Sydney)Video Transcoding at Scale for ABC iview (NDC Sydney)
Video Transcoding at Scale for ABC iview (NDC Sydney)Daphne Chong
 
Introduction to Stockfish bitboard representation and magic bitboard
Introduction to Stockfish bitboard representation and magic bitboardIntroduction to Stockfish bitboard representation and magic bitboard
Introduction to Stockfish bitboard representation and magic bitboardTaiyou Kuo
 
Video Transcoding at the ABC with Microservices at GOTO Chicago
Video Transcoding at the ABC with Microservices at GOTO ChicagoVideo Transcoding at the ABC with Microservices at GOTO Chicago
Video Transcoding at the ABC with Microservices at GOTO ChicagoDaphne Chong
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드NAVER Engineering
 
Node Classifier Fundamentals - PuppetConf 2014
Node Classifier Fundamentals - PuppetConf 2014Node Classifier Fundamentals - PuppetConf 2014
Node Classifier Fundamentals - PuppetConf 2014Puppet
 
Intro2 Cuda Moayad
Intro2 Cuda MoayadIntro2 Cuda Moayad
Intro2 Cuda MoayadMoayadhn
 
Groovy: to Infinity and Beyond -- JavaOne 2010 -- Guillaume Laforge
Groovy: to Infinity and Beyond -- JavaOne 2010 -- Guillaume LaforgeGroovy: to Infinity and Beyond -- JavaOne 2010 -- Guillaume Laforge
Groovy: to Infinity and Beyond -- JavaOne 2010 -- Guillaume LaforgeGuillaume Laforge
 
Introduction to RevKit
Introduction to RevKitIntroduction to RevKit
Introduction to RevKitMathias Soeken
 
Low-level Shader Optimization for Next-Gen and DX11 by Emil Persson
Low-level Shader Optimization for Next-Gen and DX11 by Emil PerssonLow-level Shader Optimization for Next-Gen and DX11 by Emil Persson
Low-level Shader Optimization for Next-Gen and DX11 by Emil PerssonAMD Developer Central
 
Reversible Logic Synthesis and RevKit
Reversible Logic Synthesis and RevKitReversible Logic Synthesis and RevKit
Reversible Logic Synthesis and RevKitMathias Soeken
 
Multicloud connectivity using OpenNHRP
Multicloud connectivity using OpenNHRPMulticloud connectivity using OpenNHRP
Multicloud connectivity using OpenNHRPBob Melander
 
C++ How I learned to stop worrying and love metaprogramming
C++ How I learned to stop worrying and love metaprogrammingC++ How I learned to stop worrying and love metaprogramming
C++ How I learned to stop worrying and love metaprogrammingcppfrug
 
General Purpose Computing using Graphics Hardware
General Purpose Computing using Graphics HardwareGeneral Purpose Computing using Graphics Hardware
General Purpose Computing using Graphics HardwareDaniel Blezek
 
from Binary to Binary: How Qemu Works
from Binary to Binary: How Qemu Worksfrom Binary to Binary: How Qemu Works
from Binary to Binary: How Qemu WorksZhen Wei
 

Was ist angesagt? (19)

Inside the ABC's new Media Transcoding system, Metro
Inside the ABC's new Media Transcoding system, MetroInside the ABC's new Media Transcoding system, Metro
Inside the ABC's new Media Transcoding system, Metro
 
JIT compilation for CPython
JIT compilation for CPythonJIT compilation for CPython
JIT compilation for CPython
 
tokyotalk
tokyotalktokyotalk
tokyotalk
 
Video Transcoding at Scale for ABC iview (NDC Sydney)
Video Transcoding at Scale for ABC iview (NDC Sydney)Video Transcoding at Scale for ABC iview (NDC Sydney)
Video Transcoding at Scale for ABC iview (NDC Sydney)
 
Introduction to Stockfish bitboard representation and magic bitboard
Introduction to Stockfish bitboard representation and magic bitboardIntroduction to Stockfish bitboard representation and magic bitboard
Introduction to Stockfish bitboard representation and magic bitboard
 
Video Transcoding at the ABC with Microservices at GOTO Chicago
Video Transcoding at the ABC with Microservices at GOTO ChicagoVideo Transcoding at the ABC with Microservices at GOTO Chicago
Video Transcoding at the ABC with Microservices at GOTO Chicago
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
 
Node Classifier Fundamentals - PuppetConf 2014
Node Classifier Fundamentals - PuppetConf 2014Node Classifier Fundamentals - PuppetConf 2014
Node Classifier Fundamentals - PuppetConf 2014
 
Machine Trace Metrics
Machine Trace MetricsMachine Trace Metrics
Machine Trace Metrics
 
Intro2 Cuda Moayad
Intro2 Cuda MoayadIntro2 Cuda Moayad
Intro2 Cuda Moayad
 
Groovy: to Infinity and Beyond -- JavaOne 2010 -- Guillaume Laforge
Groovy: to Infinity and Beyond -- JavaOne 2010 -- Guillaume LaforgeGroovy: to Infinity and Beyond -- JavaOne 2010 -- Guillaume Laforge
Groovy: to Infinity and Beyond -- JavaOne 2010 -- Guillaume Laforge
 
Introduction to RevKit
Introduction to RevKitIntroduction to RevKit
Introduction to RevKit
 
Low-level Shader Optimization for Next-Gen and DX11 by Emil Persson
Low-level Shader Optimization for Next-Gen and DX11 by Emil PerssonLow-level Shader Optimization for Next-Gen and DX11 by Emil Persson
Low-level Shader Optimization for Next-Gen and DX11 by Emil Persson
 
Reversible Logic Synthesis and RevKit
Reversible Logic Synthesis and RevKitReversible Logic Synthesis and RevKit
Reversible Logic Synthesis and RevKit
 
Multicloud connectivity using OpenNHRP
Multicloud connectivity using OpenNHRPMulticloud connectivity using OpenNHRP
Multicloud connectivity using OpenNHRP
 
C++ How I learned to stop worrying and love metaprogramming
C++ How I learned to stop worrying and love metaprogrammingC++ How I learned to stop worrying and love metaprogramming
C++ How I learned to stop worrying and love metaprogramming
 
General Purpose Computing using Graphics Hardware
General Purpose Computing using Graphics HardwareGeneral Purpose Computing using Graphics Hardware
General Purpose Computing using Graphics Hardware
 
Introduction to Data Oriented Design
Introduction to Data Oriented DesignIntroduction to Data Oriented Design
Introduction to Data Oriented Design
 
from Binary to Binary: How Qemu Works
from Binary to Binary: How Qemu Worksfrom Binary to Binary: How Qemu Works
from Binary to Binary: How Qemu Works
 

Ähnlich wie The Joy Of Server Side Swift Development

Intravert Server side processing for Cassandra
Intravert Server side processing for CassandraIntravert Server side processing for Cassandra
Intravert Server side processing for CassandraEdward Capriolo
 
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"DataStax Academy
 
Emerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonEmerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonAlex Payne
 
The Ring programming language version 1.3 book - Part 84 of 88
The Ring programming language version 1.3 book - Part 84 of 88The Ring programming language version 1.3 book - Part 84 of 88
The Ring programming language version 1.3 book - Part 84 of 88Mahmoud Samir Fayed
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 HourCouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 HourPeter Friese
 
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이GangSeok Lee
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android UpdateGarth Gilmour
 
Introduction to Spark with Scala
Introduction to Spark with ScalaIntroduction to Spark with Scala
Introduction to Spark with ScalaHimanshu Gupta
 
Introduction to Coding
Introduction to CodingIntroduction to Coding
Introduction to CodingFabio506452
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomyDongmin Yu
 
Kotlin, smarter development for the jvm
Kotlin, smarter development for the jvmKotlin, smarter development for the jvm
Kotlin, smarter development for the jvmArnaud Giuliani
 
Bolt C++ Standard Template Libary for HSA by Ben Sanders, AMD
Bolt C++ Standard Template Libary for HSA  by Ben Sanders, AMDBolt C++ Standard Template Libary for HSA  by Ben Sanders, AMD
Bolt C++ Standard Template Libary for HSA by Ben Sanders, AMDHSA Foundation
 
Flux and InfluxDB 2.0 by Paul Dix
Flux and InfluxDB 2.0 by Paul DixFlux and InfluxDB 2.0 by Paul Dix
Flux and InfluxDB 2.0 by Paul DixInfluxData
 
Building and Deploying Application to Apache Mesos
Building and Deploying Application to Apache MesosBuilding and Deploying Application to Apache Mesos
Building and Deploying Application to Apache MesosJoe Stein
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsBartosz Kosarzycki
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016STX Next
 
Android RenderScript on LLVM
Android RenderScript on LLVMAndroid RenderScript on LLVM
Android RenderScript on LLVMJohn Lee
 
Codepot - Pig i Hive: szybkie wprowadzenie / Pig and Hive crash course
Codepot - Pig i Hive: szybkie wprowadzenie / Pig and Hive crash courseCodepot - Pig i Hive: szybkie wprowadzenie / Pig and Hive crash course
Codepot - Pig i Hive: szybkie wprowadzenie / Pig and Hive crash courseSages
 

Ähnlich wie The Joy Of Server Side Swift Development (20)

Intravert Server side processing for Cassandra
Intravert Server side processing for CassandraIntravert Server side processing for Cassandra
Intravert Server side processing for Cassandra
 
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
 
Emerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonEmerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the Horizon
 
The Ring programming language version 1.3 book - Part 84 of 88
The Ring programming language version 1.3 book - Part 84 of 88The Ring programming language version 1.3 book - Part 84 of 88
The Ring programming language version 1.3 book - Part 84 of 88
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 HourCouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 Hour
 
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이
[2012 CodeEngn Conference 06] pwn3r - Secuinside 2012 CTF 예선 문제풀이
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android Update
 
Introduction to Spark with Scala
Introduction to Spark with ScalaIntroduction to Spark with Scala
Introduction to Spark with Scala
 
Shrink to grow
Shrink to growShrink to grow
Shrink to grow
 
Introduction to Coding
Introduction to CodingIntroduction to Coding
Introduction to Coding
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
 
Kotlin, smarter development for the jvm
Kotlin, smarter development for the jvmKotlin, smarter development for the jvm
Kotlin, smarter development for the jvm
 
Bolt C++ Standard Template Libary for HSA by Ben Sanders, AMD
Bolt C++ Standard Template Libary for HSA  by Ben Sanders, AMDBolt C++ Standard Template Libary for HSA  by Ben Sanders, AMD
Bolt C++ Standard Template Libary for HSA by Ben Sanders, AMD
 
Flux and InfluxDB 2.0 by Paul Dix
Flux and InfluxDB 2.0 by Paul DixFlux and InfluxDB 2.0 by Paul Dix
Flux and InfluxDB 2.0 by Paul Dix
 
Building and Deploying Application to Apache Mesos
Building and Deploying Application to Apache MesosBuilding and Deploying Application to Apache Mesos
Building and Deploying Application to Apache Mesos
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projects
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
 
Android RenderScript on LLVM
Android RenderScript on LLVMAndroid RenderScript on LLVM
Android RenderScript on LLVM
 
Codepot - Pig i Hive: szybkie wprowadzenie / Pig and Hive crash course
Codepot - Pig i Hive: szybkie wprowadzenie / Pig and Hive crash courseCodepot - Pig i Hive: szybkie wprowadzenie / Pig and Hive crash course
Codepot - Pig i Hive: szybkie wprowadzenie / Pig and Hive crash course
 
Lambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter LawreyLambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter Lawrey
 

Mehr von Giordano Scalzo

How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftGiordano Scalzo
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to SwiftGiordano Scalzo
 
Better Software: introduction to good code
Better Software: introduction to good codeBetter Software: introduction to good code
Better Software: introduction to good codeGiordano Scalzo
 
Tame Accidental Complexity with Ruby and MongoMapper
Tame Accidental Complexity with Ruby and MongoMapperTame Accidental Complexity with Ruby and MongoMapper
Tame Accidental Complexity with Ruby and MongoMapperGiordano Scalzo
 
JavaScript Survival Guide
JavaScript Survival GuideJavaScript Survival Guide
JavaScript Survival GuideGiordano Scalzo
 
Better Software Developers
Better Software DevelopersBetter Software Developers
Better Software DevelopersGiordano Scalzo
 
Agile Iphone Development
Agile Iphone DevelopmentAgile Iphone Development
Agile Iphone DevelopmentGiordano Scalzo
 
XpUg Coding Dojo: KataYahtzee in Ocp way
XpUg Coding Dojo: KataYahtzee in Ocp wayXpUg Coding Dojo: KataYahtzee in Ocp way
XpUg Coding Dojo: KataYahtzee in Ocp wayGiordano Scalzo
 
Bdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infiniteBdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infiniteGiordano Scalzo
 
10 minutes of me: Giordano Scalzo's Visual Resume
10 minutes of me: Giordano Scalzo's Visual Resume10 minutes of me: Giordano Scalzo's Visual Resume
10 minutes of me: Giordano Scalzo's Visual ResumeGiordano Scalzo
 

Mehr von Giordano Scalzo (14)

How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in Swift
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to Swift
 
Better Software: introduction to good code
Better Software: introduction to good codeBetter Software: introduction to good code
Better Software: introduction to good code
 
Tame Accidental Complexity with Ruby and MongoMapper
Tame Accidental Complexity with Ruby and MongoMapperTame Accidental Complexity with Ruby and MongoMapper
Tame Accidental Complexity with Ruby and MongoMapper
 
JavaScript Survival Guide
JavaScript Survival GuideJavaScript Survival Guide
JavaScript Survival Guide
 
Code kata
Code kataCode kata
Code kata
 
JavaScript Patterns
JavaScript PatternsJavaScript Patterns
JavaScript Patterns
 
Tdd iPhone For Dummies
Tdd iPhone For DummiesTdd iPhone For Dummies
Tdd iPhone For Dummies
 
Better Software Developers
Better Software DevelopersBetter Software Developers
Better Software Developers
 
Agile Iphone Development
Agile Iphone DevelopmentAgile Iphone Development
Agile Iphone Development
 
XpUg Coding Dojo: KataYahtzee in Ocp way
XpUg Coding Dojo: KataYahtzee in Ocp wayXpUg Coding Dojo: KataYahtzee in Ocp way
XpUg Coding Dojo: KataYahtzee in Ocp way
 
Bdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infiniteBdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infinite
 
10 minutes of me: Giordano Scalzo's Visual Resume
10 minutes of me: Giordano Scalzo's Visual Resume10 minutes of me: Giordano Scalzo's Visual Resume
10 minutes of me: Giordano Scalzo's Visual Resume
 
Scrum in an hour
Scrum in an hourScrum in an hour
Scrum in an hour
 

Kürzlich hochgeladen

5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 

Kürzlich hochgeladen (20)

5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 

The Joy Of Server Side Swift Development

  • 1. The Joy Of Server Side Swift Development
  • 2. In 1943 Konrad Zuse invented Plankalkül
  • 4. 1950s ... - Fortran(concept) - Fortran II - ALGOL 58(IAL) - LISP(implementation) ...
  • 6. 1960s ... - ALGOL 60 - COBOL 61(implementation) - FORTRAN IV - APL(concept) - Simula(concept) - SNOBOL - CPL - SNOBOL3 - ALGOL 68(concept) - BASIC ...
  • 8. 1970s ... - Pascal - Smalltalk - C - Prolog - Structured Query language ( SQL) - Bourne Shell(sh) - Modula-2 - AWK ...
  • 10. 1980s ... - Ada 80(MIL-STD-1815) - GW-BASIC - Turbo Pascal - Objective-C - C++ - Eiffel - Erlang ...
  • 12. 1990s ... - AMOS BASIC - Haskell - Python - Visual Basic - Brainfuck - Borland Delphi - Java - PHP - Ruby - JavaScript - Standard C++ ...
  • 14. 2000s ... - ActionScript - C# - D - Scala - Groovy - F# - Clojure - Go ...
  • 16. 2010s ... - Rust - Elm - Kotlin - Elixir - Hack - C++14 ...
  • 19.
  • 20. 355
  • 21. Do we really need another programming language?
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 29.
  • 30.
  • 32.
  • 33.
  • 34.
  • 35. Officially, only Linux is Supported
  • 37.
  • 38.
  • 39.
  • 41. We have a few...
  • 42. 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)
  • 43.
  • 44. "Perfect is a complete and powerful toolbox, framework, and application server for Linux, iOS, and macOS"
  • 45. They got money (Even without React.js!)
  • 46.
  • 48.
  • 50. 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 = 8181 server.documentRoot = "./webroot" configureServer(server) do { try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: (err) (msg)") }
  • 51.
  • 52. 4 Laravel inspired 4 Easy to setup 4 Fantastic Command Line Tool
  • 53.
  • 54. let drop = Droplet() drop.get("/") { request in return try drop.view.make("welcome.html") } drop.get("plaintext") { request in return "Hello, World!" } drop.serve()
  • 55.
  • 56.
  • 57. 4 Backed by IBM 4 Express.js-like 4 Perfectly integrated in IBM cloud solution BlueMix
  • 58.
  • 59. import Kitura let router = Router() router.get("/") { request, response, next in response.send("Hello, World!") next() } Kitura.addHTTPServer(onPort: 8080, with: router) Kitura.run()
  • 60. Let's talk now of...
  • 63.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 71.
  • 74. You can write Basic in Swift...
  • 75. You can write Haskell-ish in Swift...
  • 76. The sense of Swift
  • 79.
  • 80.
  • 82. An hyper local weather app
  • 83.
  • 84.
  • 85.
  • 86.
  • 87. MrDrizzle Server Requirements: 4 Convert from Wunderground Models to MrDrizzle Model 4 Refresh cache every hour
  • 89.
  • 90. mkdir MrDrizzleServer cd MrDrizzleServer swift package init --type executable
  • 91.
  • 92. Swift Package Manager import PackageDescription let package = Package( name: "MrDrizzleServer", dependencies: [ .Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 0) ] )
  • 93. Let's make it run // main.swift import Foundation import HTTP import Vapor let wheaterUndergroundKey = "KEY" let wheaterUndergroundDomain = "api.wunderground.com" let drop = Droplet() drop.get("/hello") { _ in return "Hello World" } drop.run()
  • 94. $ 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
  • 95. > 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
  • 96.
  • 97.
  • 98. $ swift package generate-xcodeproj > generated: ./MrDrizzleServer.xcodeproj
  • 99.
  • 100. Hello World for dummies
  • 101. This version: drop.get("/hello") { _ in return "Hello World" }
  • 102. 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) } }
  • 104. 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) //... ]
  • 105. Let's define a schema for our models
  • 106. 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 }
  • 107. 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; }
  • 109.
  • 110. 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; }
  • 111. /* * 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 ""} //... }
  • 112. We extend these structs to instantiate from the wunderground JSON
  • 113. 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" }, ...
  • 114. 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) } }
  • 115. 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)) } }
  • 117. 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) } }
  • 119. 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) } } }
  • 120. private extension Stations { func refreshed(given stationsInfo: [StationInfo], client: ClientProtocol.Type) -> Stations { return Stations(stations: stationsInfo.flatMap { Station(stationInfo: $0, client: client) }) } }
  • 122. //main.swift let 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()
  • 126. 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) })
  • 127. 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() } }
  • 128. 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) }
  • 129. 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) }
  • 130.
  • 132. Recap
  • 133.
  • 134.
  • 136. Apps are so 2014!
  • 138. A Deep Learning Functional Reactive Chatbot!
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146. Diagram of a Facebook Messenger ChatBot
  • 147.
  • 148.
  • 150.
  • 151.
  • 152.
  • 153.
  • 155.
  • 156. import PackageDescription let package = Package( name: "UncleLucio", dependencies: [ .Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 0) ] )
  • 157. // main.swift import Foundation import Vapor import 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()
  • 158. // main.swift drop.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") } }
  • 159. // main.swift drop.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()
  • 160. // ChatMessage.swift import Foundation import Vapor import HTTP struct ChatMessage { let sender: String let recipient: String let text: String? }
  • 161. 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" } } ] } ] }
  • 162. // ChatMessage.swift extension 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 } }
  • 163. // ChatMessage.swift extension 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 ]), ]) } }
  • 164.
  • 165. // UncleLucio.swift class UncleLucio { private let jokesDB: JokesDB private var sessions = [String: State]() init(jokesDB: JokesDB) { self.jokesDB = jokesDB } func message(after chatMessage: ChatMessage) -> ChatMessage { //... return replyMessage } }
  • 166. // 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 }
  • 167. // UncleLucio.swift protocol State { func nextState(when message: String) -> (String, State) }
  • 168. // 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) } }
  • 169. 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)) } }
  • 170. 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)) } }
  • 171. struct Done: State { func nextState(when message: String) -> (String, State) { return ("pota", Done()) } }
  • 172. Really easy to test
  • 173. func testInStart_ReceivingGarbage_SaysSlogan_GoesStart() { let state = StartState(joke: joke()) let (text, nextState) = state.nextState(when: "foobar") XCTAssertEqual(text, "pota") XCTAssertTrue(nextState is StartState) }
  • 174. 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) }
  • 175. 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() } }
  • 176. extension Array { func randomItem() -> Element { let index = Int(arc4random_uniform(UInt32(self.count))) return self[index] } }
  • 179. A reason for using Swift in Server...
  • 180. Often in our job...
  • 181.
  • 182.
  • 183.
  • 185.
  • 186.
  • 187.
  • 188. "Everything in Its Right Place" (cit.)
  • 189.