SlideShare a Scribd company logo
otlin
Serverless
(Shengyou Fan)
JCConf 2020
2020/11/19
Photo by Cam Adams on Unsplash
—
• Serverless
• FaaS Kotlin
• Kotless
•
—
Develop Build/Pack Deploy Scale Up
Operation …
!
Kotlin
Serverless
—
from Wikipedia
Serverless computing is a cloud computing execution
model in which the cloud provider runs the server,
and dynamically manages the allocation of machine
resources.
Serverless
—
Image source: Serverless Development With Kotlin and Kotless by Vlaadislav Tankov
Serverless
—
•
•
•
•
FaaS Java
—
Kotlin
"
Kotlin
—
?query=param
①
②
③
④
Client
FaaS
Local Development
Kotlin Functions
HTTP Request
—
GET http://localhost:8001/?amount={n}
Accept: application/json
1. n Contact
2. JSON
HTTP Response
—
{
"data": [
{
"id": ...,
"name": "...",
"email": "...",
"createdAt": "yyyy-MM-dd HH:mm:ss.nnnnnn",
"updatedAt": "yyyy-MM-dd HH:mm:ss.nnnnnn"
},
// ...
]
}
1. n
2. JSON
3. data
Data Class
—
// Data Class
data class Contact(
val id: Long?,
val name: String,
val email: String,
val createdAt: String,
val updatedAt: String
)
// JSON
{
"id": 1,
"name": "...",
"email": "...",
"createdAt": "yyyy-MM-dd HH:mm:ss.nnnnnn",
"updatedAt": "yyyy-MM-dd HH:mm:ss.nnnnnn"
}
• JSON Data Class
class ContactService() {
// ...
@ExperimentalTime
fun generate(amount: Int = 10): List<Contact> {
return (1..amount).map {
Contact(
// ...
)
}
}
}
Service Class
—
Service
• javafaker datetime
serilization library
•
•
JetBrains Package Search
—
Packages Tool Window
—
Lorem ipsum dolor sit amet, ad nam alterum copiosae facilisis, ad vis detracto vituperata, an
errem oblique discere qui. Vim noster dolorem legendos no. Cu lorem dicta docendi mei, has
an causae facilis abhorreant. Ex ornatus similique eum, et diam regione consetetur vix. Mea
id paulo vituperata, nam laoreet luptatum delicatissimi id. Fugit primis ullamcorper no qui,
nusquam accusamus temporibus sit ad.
Vis iudico commodo ne, ad eam quas legimus, esse dicant explicari has in. Eum ocurreret
interesset appellantur ei, quo cu timeam euismod laoreet. Per ne nisl justo. An vel laboramus
efficiantur deterruisset, nec ne mandamus scripserit, vix id rebum dicta dictas. Mel suscipit
periculis similique in.
// build.gradle
dependencies {
implementation "com.github.javafaker:javafaker:1.0.2"
}
// io.kraftsman.services.ContactService
val faker = Faker(Locale("en"))
Contact(
id = it.toLong(),
name = faker.name().fullName(),
email = faker.internet().emailAddress(),
createdAt = ...,
updatedAt = ...
)
Java Faker
—
• Java Faker
• Faker
kotlinx.datetime
• repository
•
// build.gradle
repositories {
maven { url "https://kotlin.bintray.com/kotlinx/" }
}
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-datetime:$ver"
}
// io.kraftsman.services.ContactService
val current = Clock.System.now()
val tz = TimeZone.of("Asia/Taipei")
Contact(
// ...
createdAt = current
.toLocalDateTime(tz).toString(),
updatedAt = (current + x.hours + y.minutes)
.toLocalDateTime(tz).toString()
)
Datetime
—
kotlinx.datetime
•
•
• (x + y )
•
// build.gradle
plugins {
id 'org.jetbrains.kotlin.plugin.serialization' version '1.4.10'
}
repositories {
jcenter()
}
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$ver"
}
• Gradle Plugin
Serialization (pt.1)
—
• Repository
•
// io.kraftsman.dtos.Contact
@Serializable
data class Contact(
// ...
)
// io.kraftsman.functions.Handler
val contacts: List<Contact> = ContactService().generate(amount)
Json.encodeToString(
mapOf("data" to contacts)
)
Serialization (pt.2)
—
• Annotation
JSON
• List Map data
• Map JSON
Cloud Functions
—
• IntelliJ IDEA
• JDK 11
• gcloud CLI
Repository: https://github.com/shengyou/gcp-cloud-functions-kotlin
$ brew cask install google-cloud-sdk
$ gcloud auth login
$ gcloud projects list
$ gcloud config set project PROJECT_ID
/ gcloud
—
• gcloud CLI
• GCP
• GCP Project
• GCP Project
1. Kotlin
2. Gradle
3. JDK 11
—
configurations {
invoker
}
dependencies {
implementation "...:functions-framework-api:$ver"
invoker "...:java-function-invoker:$ver"
}
tasks.register("runFunction", JavaExec) {
main = '...'
classpath(configurations.invoker)
inputs.files(..., ...)
args(
'--target', ...Property('runFunction.target') ?: '',
'--port', ...Property('runFunction.port') ?: ...
)
doFirst {
args('--classpath', ...)
}
}
Gradle
—
Cloud Function
• functions-framework-api
• java-function-invoker
Gradle Task
$ gradle runFunction
Java Invoker
class Handler: HttpFunction {
@Throws(IOException::class)
override fun service(req: HttpRequest, res: HttpResponse) {
}
}
Handler
—
• Class
• HttpFunction (
functions-framework-api)
• service()
• req res
class Handler: HttpFunction {
@Throws(IOException::class)
override fun service(req: HttpRequest, res: HttpResponse) {
val param = request.getFirstQueryParameter("amount")
.orElse("")
val amount = param.toIntOrNull() ?: 10
}
}
Query
—
• HttpRequest Query
•
class Handler: HttpFunction {
@Throws(IOException::class)
override fun service(req: HttpRequest, res: HttpResponse) {
val param = request.getFirstQueryParameter("amount")
.orElse("")
val amount = param.toIntOrNull() ?: 10
val contacts = ContactService().generate(amount)
val jsonString = Json.encodeToString(
mapOf("data" to contacts)
)
}
}
/
—
• Service
• JSON
class Handler: HttpFunction {
@Throws(IOException::class)
override fun service(req: HttpRequest, res: HttpResponse) {
val param = request.getFirstQueryParameter("amount")
.orElse("")
val amount = param.toIntOrNull() ?: 10
val contacts = ContactService().generate(amount)
val jsonString = Json.encodeToString(
mapOf("data" to contacts)
)
with(res) {
setStatusCode(HttpURLConnection.HTTP_OK)
setContentType("application/json")
writer.write(jsonString)
}
}
}
Response
—
• HTTP Status Code
• Content-Type
• JSON
$ ./gradlew runFunction 
-PrunFunction.target=CLASS 
-PrunFunction.port=PORT
—
• Gradle Task
• Run Configuration
$ gcloud functions deploy PUBLIC_PATH 
--region REGION 
--runtime java11 
--trigger-http 
--memory 256MB 
--entry-point ENTRY_POINT_CLASS 
--allow-unauthenticated
—
• gcloud
Azure Functions
—
• IntelliJ IDEA + Plugins
• JDK 8
• Azure CLI
• Azure Functions Core Tools
Repository: https://github.com/shengyou/microsoft-azure-functions-kotlin
$ brew update
$ brew install azure-cli
$ az login
$ az account -a SUBSCRIPTION_ID
$ brew tap azure/functions
$ brew installazure-function-core-tools@3
—
• Azure CLI
• Azure
• Azure Functions Core Tools
• Azure Toolkit for IntelliJ
1. Azure Functions
2. Gradle
3. JDK 8
—
1. Azure Functions
2. Gradle
3. JDK 8
Kotlin
— ①
②
③
④
1. Project
2. Class
3.
Kotlin Class
—
class Handler {
@FunctionName("...")
fun run(
@HttpTrigger(
name = "...",
route = "...",
methods = [HttpMethod.GET],
authLevel = AuthorizationLevel.ANONYMOUS
)
request: HttpRequestMessage<Optional<String?>>,
context: ExecutionContext
): HttpResponseMessage {
// ...
}
}
Handler
—
• Class Method
• Annotation
• route methods
• request context
class Handler {
@FunctionName("...")
fun run(/* . . . */): HttpResponseMessage {
val query = request.queryParameters["amount"]
val amount = query?.toIntOrNull() ?: 10
}
}
Query
—
• request Query
•
class Handler {
@FunctionName("...")
fun run(/* . . . */): HttpResponseMessage {
val query = request.queryParameters["amount"]
val amount = query?.toIntOrNull() ?: 10
val contacts = ContactService().generate(amount)
val jsonString = Json.encodeToString(
mapOf("data" to contacts)
)
}
}
/
—
• Service
• JSON
class Handler {
@FunctionName("...")
fun run(/* . . . */): HttpResponseMessage {
val query = request.queryParameters["amount"]
val amount = query?.toIntOrNull() ?: 10
val contacts = ContactService().generate(amount)
val jsonString = Json.encodeToString(
mapOf("data" to contacts)
)
return request.createResponseBuilder(HttpStatus.OK)
.header("Content-Type", "application/json")
.body(jsonString)
.build()
}
}
Response
—
• HTTP Status Code
• Content-Type
• JSON
—
• Gradle Task
azurefunctions {
subscription = '...'
resourceGroup = '...'
appName = '...'
pricingTier = 'Consumption'
region = '...'
runtime {
os = 'linux'
}
authentication {
type = 'azure_cli'
}
}
—
• Azure Gradle
• Gradle Task
AWS Lambda
—
• IntelliJ IDEA + Plugin
• JDK 11
• Docker
• AWS CLI
• AWS SAM CLI
Repository: https://github.com/shengyou/amazon-lambda-kotlin
$ brew update
$ brew install awscli
$ aws configure
$ aws sts get-caller-identity
$ brew tap aws/tap
$ brew install aws-sam-cli
—
• AWS CLI
• AWS
• Account ID
• IAM (User & Role)
• AWS SAM CLI
• AWS Toolkit
1. Kotlin
2. Gradle
3. JDK 11
—
1. AWS
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '6.1.0'
}
dependencies {
implementation "...:aws-lambda-java-core:1.2.1"
implementation "...:aws-lambda-java-events:3.1.0"
runtimeOnly "...:aws-lambda-java-log4j2:1.2.0"
}
Gradle
—
AWS Lambda
• aws-lambda-java-core
• aws-lambda-java-events
• aws-lambda-java-log4j2
Gradle Plugin
• java
• shadow
class Handler : RequestHandler <
APIGatewayProxyRequestEvent,
APIGatewayProxyResponseEvent
> {
@Throws(IOException::class)
override fun handleRequest(
request: APIGatewayProxyRequestEvent,
context: Context
): APIGatewayProxyResponseEvent {
// ...
}
}
Handler
—
• Class Method
• RequestHandler ( aws-
lambda-java-core)
• Handler Method
• reqest context
class Handler : RequestHandler <...> {
@Throws(IOException::class)
override fun method(/* ... */): ...ResponseEvent {
val param = request.queryStringParameters["amount"]
val amount = param?.toIntOrNull() ?: 10
}
}
Query
—
• request Query
•
class Handler : RequestHandler <...> {
@Throws(IOException::class)
override fun method(/* ... */): ...ResponseEvent {
val param = request.queryStringParameters["amount"]
val amount = param?.toIntOrNull() ?: 10
val contacts = ContactService().generate(amount)
val jsonString = Json.encodeToString(
mapOf("data" to contacts)
)
}
}
/
—
• Service
• JSON
class Handler : RequestHandler <...> {
@Throws(IOException::class)
override fun method(/* ... */): ...ResponseEvent {
val param = request.queryStringParameters["amount"]
val amount = param?.toIntOrNull() ?: 10
val contacts = ContactService().generate(amount)
val jsonString = Json.encodeToString(
mapOf("data" to contacts)
)
return APIGatewayProxyResponseEvent()
.withStatusCode(HttpURLConnection.HTTP_OK)
.withHeaders(
mapOf("Content-Type" to "application/json")
)
.withBody(jsonString)
}
}
Response
—
• HTTP Status Code
• Content-Type
• JSON
$ aws lambda create-function --function-name NAME 
--zip-file fileb://build/libs/SHADOWJAR.jar 
--handler CLASS::METHOD 
--runtime java11
--timeout 15
--memory-size 128
--role ROLE
—
• aws
• AWS Console
API Gateway
—
• Trigger
JDK 11 8 11
IntelliJ Plugin ✗ ✓ ✓
Gradle ✓ ✓
Framework ✓ ✓ ✓
+
—
#
…
Cloud Configuration
Vendor Lock-in…
Kotless
—
https://site.kotless.io/
• Serverless Framework
• Kotless DSL
• Gradle Plugin
• Developed by Vladislav Tankov
from JetBrains
• Open Source (Apache 2.0)
—
Image source: Serverless Development With Kotlin and Kotless by Vlaadislav Tankov
1. Kotlin
2. Gradle Kotlin ❤
3. JDK 11
—
plugins {
kotlin("jvm") version "1.3.72" apply true
kotlin("plugin.serialization") version "1.3.72"
id("io.kotless") version "0.1.6" apply true
}
dependencies {
implementation("io.kotless", "kotless-lang", "0.1.6")
}
Gradle
—
Gradle Plugins
• Kotlin 1.3.72
• Serialization 1.3.72
• Kotless 0.1.6
• Kotless
@Get("/")
fun handler(): HttpResponse {
val dom = """
// ...
""".trimIndent()
return html(dom)
}
Function
—
• Function
• Annotation Route
• HttpResponse
@Get("/...")
fun handler(): HttpResponse {
val param = KotlessContext.HTTP.request.params?.get("amount")
val amount = param?.toIntOrNull() ?: 10
}
Query
—
• KotlessContext Query
•
@Get("/...")
fun handler(): HttpResponse {
val param = KotlessContext.HTTP.request.params?.get("amount")
val amount = param?.toIntOrNull() ?: 10
val contacts = ContactService().generate(amount)
val json = Json(JsonConfiguration.Stable)
val jsonString = json.stringify(
Contact.serializer(), contacts
)
}
/
—
• Service
• JSON
@Get("/...")
fun handler(): HttpResponse {
val param = KotlessContext.HTTP.request.params?.get("amount")
val amount = param?.toIntOrNull() ?: 10
val contacts = ContactService().generate(amount)
val json = Json(JsonConfiguration.Stable)
val jsonString = json.stringify(
Contact.serializer(), contacts
)
return json(jsonString)
}
Response
—
• JSON
—
• Gradle Task
kotless {
config {
bucket = "..."
terraform {
profile = "..."
region = "..."
}
}
}
—
• AWS CLI Credentials
• S3 Bucket
• AWS Gradle
• Gradle Task
#
…
Serverless
Kotless
—
Image source: Serverless Development With Kotlin and Kotless by Vlaadislav Tankov
1. Ktor (1.3.2)
2. Gradle Kotlin ❤
3. JDK 11
4. Server Features
• Routing
• ContentNegotiation
• Jackson
Ktor
—
plugins {
id("io.kotless") version "0.1.6" apply true
}
dependencies {
// ...
implementation("io.ktor:ktor-server-netty:$ktor_version")
// ...
implementation("io.kotless", "ktor-lang", “0.1.6")
// ...
}
Gradle
—
Gradle Plugins
• Kotless 0.1.6
• Netty
• Kotless for Ktor
class Server : Kotless() {
override fun prepare(app: Application) {
app.install(ContentNegotiation) {
jackson {
enable(SerializationFeature.INDENT_OUTPUT)
}
}
app.routing {
// ...
}
}
}
Kotless App
—
Kotless App
• Kotless
• prepare()
• Ktor app
// Application.kt
@Suppress("unused")
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
// ...
}
// resources/application.conf
ktor {
deployment {
port = 8080
port = ${?PORT}
}
application {
modules = [ io.kraftsman.Server.prepare ]
}
}
—
• Application.kt
•
Roadmap
—
Image source: Serverless Development With Kotlin and Kotless by Vlaadislav Tankov
% & %
Repository: https://github.com/shengyou/jetbrains-kotless-framework
Repository: https://github.com/shengyou/jetbrains-ktor-with-kotless
—
• Serverless
• Kotlin Serverless
• Kotless Framework
• Kotless
Serverless
—
• IBM Bluemix
• Cloudflare Workers
• Alibaba Cloud
• Huawei Cloud
• …
Serverless
—
• Fat Jar
• Container
• Kotlin/JS
Serverless
—
• Spring Cloud Function
• Micronaut
• Osiris
• Nimbus
• …
—
• Mobile Backend (API …)
• Webhook ( API …)
• ( …)
—
•
•
•
•
Image source: The Definition of Framework by Francesco Strazzullo
https://tw.kotlin.tips
Tips
—
https://tw.intellij.tips
—
Coding
Kraftsman
(Shengyou Fan)
shengyou.fan@jetbrains.com
Q&A
—
otlin
Serverless

More Related Content

What's hot

Kotlin
KotlinKotlin
Kotlin
Rory Preddy
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and Fold
Philip Schwarz
 
History of asynchronous in .NET
History of asynchronous in .NETHistory of asynchronous in .NET
History of asynchronous in .NET
Marcin Tyborowski
 
The Xtext Grammar Language
The Xtext Grammar LanguageThe Xtext Grammar Language
The Xtext Grammar Language
Dr. Jan Köhnlein
 
PHP, Under The Hood - DPC
PHP, Under The Hood - DPCPHP, Under The Hood - DPC
PHP, Under The Hood - DPC
Anthony Ferrara
 
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Philip Schwarz
 
The Power of Composition
The Power of CompositionThe Power of Composition
The Power of Composition
Scott Wlaschin
 
老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具
Shengyou Fan
 
Techical Workflow for a Startup
Techical Workflow for a StartupTechical Workflow for a Startup
Techical Workflow for a Startup
Sébastien Saunier
 
Cucumber and Spock Primer
Cucumber and Spock PrimerCucumber and Spock Primer
Cucumber and Spock Primer
John Ferguson Smart Limited
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous Javascript
Garrett Welson
 
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
Shengyou Fan
 
The lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsThe lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of tests
Scott Wlaschin
 
Part 2 :: Spring Boot testing
Part 2 :: Spring Boot testingPart 2 :: Spring Boot testing
Part 2 :: Spring Boot testing
Somkiat Puisungnoen
 
API for Beginners
API for BeginnersAPI for Beginners
API for Beginners
Sébastien Saunier
 
Advanced JavaScript
Advanced JavaScriptAdvanced JavaScript
Advanced JavaScript
Nascenia IT
 
Grails custom tag lib
Grails custom tag libGrails custom tag lib
Grails custom tag lib
NexThoughts Technologies
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
Scott Wlaschin
 
Kotlin as a Better Java
Kotlin as a Better JavaKotlin as a Better Java
Kotlin as a Better Java
Garth Gilmour
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
intelliyole
 

What's hot (20)

Kotlin
KotlinKotlin
Kotlin
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and Fold
 
History of asynchronous in .NET
History of asynchronous in .NETHistory of asynchronous in .NET
History of asynchronous in .NET
 
The Xtext Grammar Language
The Xtext Grammar LanguageThe Xtext Grammar Language
The Xtext Grammar Language
 
PHP, Under The Hood - DPC
PHP, Under The Hood - DPCPHP, Under The Hood - DPC
PHP, Under The Hood - DPC
 
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
 
The Power of Composition
The Power of CompositionThe Power of Composition
The Power of Composition
 
老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具
 
Techical Workflow for a Startup
Techical Workflow for a StartupTechical Workflow for a Startup
Techical Workflow for a Startup
 
Cucumber and Spock Primer
Cucumber and Spock PrimerCucumber and Spock Primer
Cucumber and Spock Primer
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous Javascript
 
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
 
The lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsThe lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of tests
 
Part 2 :: Spring Boot testing
Part 2 :: Spring Boot testingPart 2 :: Spring Boot testing
Part 2 :: Spring Boot testing
 
API for Beginners
API for BeginnersAPI for Beginners
API for Beginners
 
Advanced JavaScript
Advanced JavaScriptAdvanced JavaScript
Advanced JavaScript
 
Grails custom tag lib
Grails custom tag libGrails custom tag lib
Grails custom tag lib
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
Kotlin as a Better Java
Kotlin as a Better JavaKotlin as a Better Java
Kotlin as a Better Java
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
 

Similar to [JCConf 2020] 用 Kotlin 跨入 Serverless 世代

Painless Persistence in a Disconnected World
Painless Persistence in a Disconnected WorldPainless Persistence in a Disconnected World
Painless Persistence in a Disconnected World
Christian Melchior
 
[HKOSCon 2020] Build an api service using ktor rapidly
[HKOSCon 2020] Build an api service using ktor rapidly[HKOSCon 2020] Build an api service using ktor rapidly
[HKOSCon 2020] Build an api service using ktor rapidly
Shengyou Fan
 
Kotlin 在 Web 方面的应用
Kotlin 在 Web 方面的应用Kotlin 在 Web 方面的应用
Kotlin 在 Web 方面的应用
Shengyou Fan
 
Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010Ismael Celis
 
Use Kotlin scripts and Clova SDK to build your Clova extension
Use Kotlin scripts and Clova SDK to build your Clova extensionUse Kotlin scripts and Clova SDK to build your Clova extension
Use Kotlin scripts and Clova SDK to build your Clova extension
LINE Corporation
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web development
Johannes Brodwall
 
RoR vs-nodejs-by-jcskyting
RoR vs-nodejs-by-jcskytingRoR vs-nodejs-by-jcskyting
RoR vs-nodejs-by-jcskyting
Sky Wang
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry PiMonitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
InfluxData
 
Lift 2 0
Lift 2 0Lift 2 0
Lift 2 0SO
 
Yesplan: 10 Years later
Yesplan: 10 Years laterYesplan: 10 Years later
Yesplan: 10 Years later
Pharo
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
Ben Lesh
 
Writing RESTful web services using Node.js
Writing RESTful web services using Node.jsWriting RESTful web services using Node.js
Writing RESTful web services using Node.js
FDConf
 
Cross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineCross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App Engine
Andy McKay
 
JSON Schema: Your API's Secret Weapon
JSON Schema: Your API's Secret WeaponJSON Schema: Your API's Secret Weapon
JSON Schema: Your API's Secret WeaponPete Gamache
 
Re:Invent 2018 Database Announcements
Re:Invent 2018 Database AnnouncementsRe:Invent 2018 Database Announcements
Re:Invent 2018 Database Announcements
Steven Ensslen
 
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun..."ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
Julia Cherniak
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017
Matthew Groves
 

Similar to [JCConf 2020] 用 Kotlin 跨入 Serverless 世代 (20)

Painless Persistence in a Disconnected World
Painless Persistence in a Disconnected WorldPainless Persistence in a Disconnected World
Painless Persistence in a Disconnected World
 
[HKOSCon 2020] Build an api service using ktor rapidly
[HKOSCon 2020] Build an api service using ktor rapidly[HKOSCon 2020] Build an api service using ktor rapidly
[HKOSCon 2020] Build an api service using ktor rapidly
 
Kotlin 在 Web 方面的应用
Kotlin 在 Web 方面的应用Kotlin 在 Web 方面的应用
Kotlin 在 Web 方面的应用
 
Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010
 
huhu
huhuhuhu
huhu
 
Use Kotlin scripts and Clova SDK to build your Clova extension
Use Kotlin scripts and Clova SDK to build your Clova extensionUse Kotlin scripts and Clova SDK to build your Clova extension
Use Kotlin scripts and Clova SDK to build your Clova extension
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web development
 
RoR vs-nodejs-by-jcskyting
RoR vs-nodejs-by-jcskytingRoR vs-nodejs-by-jcskyting
RoR vs-nodejs-by-jcskyting
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry PiMonitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
 
Lift 2 0
Lift 2 0Lift 2 0
Lift 2 0
 
Yesplan: 10 Years later
Yesplan: 10 Years laterYesplan: 10 Years later
Yesplan: 10 Years later
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
 
Writing RESTful web services using Node.js
Writing RESTful web services using Node.jsWriting RESTful web services using Node.js
Writing RESTful web services using Node.js
 
Cross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineCross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App Engine
 
Os Pruett
Os PruettOs Pruett
Os Pruett
 
JSON Schema: Your API's Secret Weapon
JSON Schema: Your API's Secret WeaponJSON Schema: Your API's Secret Weapon
JSON Schema: Your API's Secret Weapon
 
Re:Invent 2018 Database Announcements
Re:Invent 2018 Database AnnouncementsRe:Invent 2018 Database Announcements
Re:Invent 2018 Database Announcements
 
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun..."ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
"ClojureScript journey: from little script, to CLI program, to AWS Lambda fun...
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017
 

More from Shengyou Fan

[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
Shengyou Fan
 
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
Shengyou Fan
 
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
Shengyou Fan
 
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
Shengyou Fan
 
Using the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseUsing the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your Database
Shengyou Fan
 
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
Shengyou Fan
 
[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園
Shengyou Fan
 
初探 Kotlin Multiplatform
初探 Kotlin Multiplatform初探 Kotlin Multiplatform
初探 Kotlin Multiplatform
Shengyou Fan
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
Shengyou Fan
 
[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南
Shengyou Fan
 
Composer 經典食譜
Composer 經典食譜Composer 經典食譜
Composer 經典食譜
Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
Shengyou Fan
 
用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手
Shengyou Fan
 
Kotlin 讀書會第三梯次第一章
Kotlin 讀書會第三梯次第一章Kotlin 讀書會第三梯次第一章
Kotlin 讀書會第三梯次第一章
Shengyou Fan
 
用 OPENRNDR 將 Chatbot 訊息視覺化
用 OPENRNDR 將 Chatbot 訊息視覺化用 OPENRNDR 將 Chatbot 訊息視覺化
用 OPENRNDR 將 Chatbot 訊息視覺化
Shengyou Fan
 
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
Shengyou Fan
 
Ktor 部署攻略 - 老派 Fat Jar 大法
Ktor 部署攻略 - 老派 Fat Jar 大法Ktor 部署攻略 - 老派 Fat Jar 大法
Ktor 部署攻略 - 老派 Fat Jar 大法
Shengyou Fan
 

More from Shengyou Fan (20)

[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
 
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
 
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
 
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
 
Using the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseUsing the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your Database
 
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
 
[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園
 
初探 Kotlin Multiplatform
初探 Kotlin Multiplatform初探 Kotlin Multiplatform
初探 Kotlin Multiplatform
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
 
[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南
 
Composer 經典食譜
Composer 經典食譜Composer 經典食譜
Composer 經典食譜
 
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
 
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
 
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
 
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
 
用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手
 
Kotlin 讀書會第三梯次第一章
Kotlin 讀書會第三梯次第一章Kotlin 讀書會第三梯次第一章
Kotlin 讀書會第三梯次第一章
 
用 OPENRNDR 將 Chatbot 訊息視覺化
用 OPENRNDR 將 Chatbot 訊息視覺化用 OPENRNDR 將 Chatbot 訊息視覺化
用 OPENRNDR 將 Chatbot 訊息視覺化
 
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
 
Ktor 部署攻略 - 老派 Fat Jar 大法
Ktor 部署攻略 - 老派 Fat Jar 大法Ktor 部署攻略 - 老派 Fat Jar 大法
Ktor 部署攻略 - 老派 Fat Jar 大法
 

Recently uploaded

This 7-second Brain Wave Ritual Attracts Money To You.!
This 7-second Brain Wave Ritual Attracts Money To You.!This 7-second Brain Wave Ritual Attracts Money To You.!
This 7-second Brain Wave Ritual Attracts Money To You.!
nirahealhty
 
The+Prospects+of+E-Commerce+in+China.pptx
The+Prospects+of+E-Commerce+in+China.pptxThe+Prospects+of+E-Commerce+in+China.pptx
The+Prospects+of+E-Commerce+in+China.pptx
laozhuseo02
 
Multi-cluster Kubernetes Networking- Patterns, Projects and Guidelines
Multi-cluster Kubernetes Networking- Patterns, Projects and GuidelinesMulti-cluster Kubernetes Networking- Patterns, Projects and Guidelines
Multi-cluster Kubernetes Networking- Patterns, Projects and Guidelines
Sanjeev Rampal
 
急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
3ipehhoa
 
test test test test testtest test testtest test testtest test testtest test ...
test test  test test testtest test testtest test testtest test testtest test ...test test  test test testtest test testtest test testtest test testtest test ...
test test test test testtest test testtest test testtest test testtest test ...
Arif0071
 
原版仿制(uob毕业证书)英国伯明翰大学毕业证本科学历证书原版一模一样
原版仿制(uob毕业证书)英国伯明翰大学毕业证本科学历证书原版一模一样原版仿制(uob毕业证书)英国伯明翰大学毕业证本科学历证书原版一模一样
原版仿制(uob毕业证书)英国伯明翰大学毕业证本科学历证书原版一模一样
3ipehhoa
 
History+of+E-commerce+Development+in+China-www.cfye-commerce.shop
History+of+E-commerce+Development+in+China-www.cfye-commerce.shopHistory+of+E-commerce+Development+in+China-www.cfye-commerce.shop
History+of+E-commerce+Development+in+China-www.cfye-commerce.shop
laozhuseo02
 
ER(Entity Relationship) Diagram for online shopping - TAE
ER(Entity Relationship) Diagram for online shopping - TAEER(Entity Relationship) Diagram for online shopping - TAE
ER(Entity Relationship) Diagram for online shopping - TAE
Himani415946
 
BASIC C++ lecture NOTE C++ lecture 3.pptx
BASIC C++ lecture NOTE C++ lecture 3.pptxBASIC C++ lecture NOTE C++ lecture 3.pptx
BASIC C++ lecture NOTE C++ lecture 3.pptx
natyesu
 
guildmasters guide to ravnica Dungeons & Dragons 5...
guildmasters guide to ravnica Dungeons & Dragons 5...guildmasters guide to ravnica Dungeons & Dragons 5...
guildmasters guide to ravnica Dungeons & Dragons 5...
Rogerio Filho
 
1.Wireless Communication System_Wireless communication is a broad term that i...
1.Wireless Communication System_Wireless communication is a broad term that i...1.Wireless Communication System_Wireless communication is a broad term that i...
1.Wireless Communication System_Wireless communication is a broad term that i...
JeyaPerumal1
 
How to Use Contact Form 7 Like a Pro.pptx
How to Use Contact Form 7 Like a Pro.pptxHow to Use Contact Form 7 Like a Pro.pptx
How to Use Contact Form 7 Like a Pro.pptx
Gal Baras
 
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
3ipehhoa
 
Living-in-IT-era-Module-7-Imaging-and-Design-for-Social-Impact.pptx
Living-in-IT-era-Module-7-Imaging-and-Design-for-Social-Impact.pptxLiving-in-IT-era-Module-7-Imaging-and-Design-for-Social-Impact.pptx
Living-in-IT-era-Module-7-Imaging-and-Design-for-Social-Impact.pptx
TristanJasperRamos
 
Latest trends in computer networking.pptx
Latest trends in computer networking.pptxLatest trends in computer networking.pptx
Latest trends in computer networking.pptx
JungkooksNonexistent
 
Output determination SAP S4 HANA SAP SD CC
Output determination SAP S4 HANA SAP SD CCOutput determination SAP S4 HANA SAP SD CC
Output determination SAP S4 HANA SAP SD CC
ShahulHameed54211
 

Recently uploaded (16)

This 7-second Brain Wave Ritual Attracts Money To You.!
This 7-second Brain Wave Ritual Attracts Money To You.!This 7-second Brain Wave Ritual Attracts Money To You.!
This 7-second Brain Wave Ritual Attracts Money To You.!
 
The+Prospects+of+E-Commerce+in+China.pptx
The+Prospects+of+E-Commerce+in+China.pptxThe+Prospects+of+E-Commerce+in+China.pptx
The+Prospects+of+E-Commerce+in+China.pptx
 
Multi-cluster Kubernetes Networking- Patterns, Projects and Guidelines
Multi-cluster Kubernetes Networking- Patterns, Projects and GuidelinesMulti-cluster Kubernetes Networking- Patterns, Projects and Guidelines
Multi-cluster Kubernetes Networking- Patterns, Projects and Guidelines
 
急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
 
test test test test testtest test testtest test testtest test testtest test ...
test test  test test testtest test testtest test testtest test testtest test ...test test  test test testtest test testtest test testtest test testtest test ...
test test test test testtest test testtest test testtest test testtest test ...
 
原版仿制(uob毕业证书)英国伯明翰大学毕业证本科学历证书原版一模一样
原版仿制(uob毕业证书)英国伯明翰大学毕业证本科学历证书原版一模一样原版仿制(uob毕业证书)英国伯明翰大学毕业证本科学历证书原版一模一样
原版仿制(uob毕业证书)英国伯明翰大学毕业证本科学历证书原版一模一样
 
History+of+E-commerce+Development+in+China-www.cfye-commerce.shop
History+of+E-commerce+Development+in+China-www.cfye-commerce.shopHistory+of+E-commerce+Development+in+China-www.cfye-commerce.shop
History+of+E-commerce+Development+in+China-www.cfye-commerce.shop
 
ER(Entity Relationship) Diagram for online shopping - TAE
ER(Entity Relationship) Diagram for online shopping - TAEER(Entity Relationship) Diagram for online shopping - TAE
ER(Entity Relationship) Diagram for online shopping - TAE
 
BASIC C++ lecture NOTE C++ lecture 3.pptx
BASIC C++ lecture NOTE C++ lecture 3.pptxBASIC C++ lecture NOTE C++ lecture 3.pptx
BASIC C++ lecture NOTE C++ lecture 3.pptx
 
guildmasters guide to ravnica Dungeons & Dragons 5...
guildmasters guide to ravnica Dungeons & Dragons 5...guildmasters guide to ravnica Dungeons & Dragons 5...
guildmasters guide to ravnica Dungeons & Dragons 5...
 
1.Wireless Communication System_Wireless communication is a broad term that i...
1.Wireless Communication System_Wireless communication is a broad term that i...1.Wireless Communication System_Wireless communication is a broad term that i...
1.Wireless Communication System_Wireless communication is a broad term that i...
 
How to Use Contact Form 7 Like a Pro.pptx
How to Use Contact Form 7 Like a Pro.pptxHow to Use Contact Form 7 Like a Pro.pptx
How to Use Contact Form 7 Like a Pro.pptx
 
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
 
Living-in-IT-era-Module-7-Imaging-and-Design-for-Social-Impact.pptx
Living-in-IT-era-Module-7-Imaging-and-Design-for-Social-Impact.pptxLiving-in-IT-era-Module-7-Imaging-and-Design-for-Social-Impact.pptx
Living-in-IT-era-Module-7-Imaging-and-Design-for-Social-Impact.pptx
 
Latest trends in computer networking.pptx
Latest trends in computer networking.pptxLatest trends in computer networking.pptx
Latest trends in computer networking.pptx
 
Output determination SAP S4 HANA SAP SD CC
Output determination SAP S4 HANA SAP SD CCOutput determination SAP S4 HANA SAP SD CC
Output determination SAP S4 HANA SAP SD CC
 

[JCConf 2020] 用 Kotlin 跨入 Serverless 世代

  • 2. — • Serverless • FaaS Kotlin • Kotless •
  • 5. Serverless — from Wikipedia Serverless computing is a cloud computing execution model in which the cloud provider runs the server, and dynamically manages the allocation of machine resources. Serverless
  • 6. — Image source: Serverless Development With Kotlin and Kotless by Vlaadislav Tankov
  • 11. HTTP Request — GET http://localhost:8001/?amount={n} Accept: application/json 1. n Contact 2. JSON
  • 12. HTTP Response — { "data": [ { "id": ..., "name": "...", "email": "...", "createdAt": "yyyy-MM-dd HH:mm:ss.nnnnnn", "updatedAt": "yyyy-MM-dd HH:mm:ss.nnnnnn" }, // ... ] } 1. n 2. JSON 3. data
  • 13. Data Class — // Data Class data class Contact( val id: Long?, val name: String, val email: String, val createdAt: String, val updatedAt: String ) // JSON { "id": 1, "name": "...", "email": "...", "createdAt": "yyyy-MM-dd HH:mm:ss.nnnnnn", "updatedAt": "yyyy-MM-dd HH:mm:ss.nnnnnn" } • JSON Data Class
  • 14. class ContactService() { // ... @ExperimentalTime fun generate(amount: Int = 10): List<Contact> { return (1..amount).map { Contact( // ... ) } } } Service Class — Service • javafaker datetime serilization library • •
  • 16. Packages Tool Window — Lorem ipsum dolor sit amet, ad nam alterum copiosae facilisis, ad vis detracto vituperata, an errem oblique discere qui. Vim noster dolorem legendos no. Cu lorem dicta docendi mei, has an causae facilis abhorreant. Ex ornatus similique eum, et diam regione consetetur vix. Mea id paulo vituperata, nam laoreet luptatum delicatissimi id. Fugit primis ullamcorper no qui, nusquam accusamus temporibus sit ad. Vis iudico commodo ne, ad eam quas legimus, esse dicant explicari has in. Eum ocurreret interesset appellantur ei, quo cu timeam euismod laoreet. Per ne nisl justo. An vel laboramus efficiantur deterruisset, nec ne mandamus scripserit, vix id rebum dicta dictas. Mel suscipit periculis similique in.
  • 17. // build.gradle dependencies { implementation "com.github.javafaker:javafaker:1.0.2" } // io.kraftsman.services.ContactService val faker = Faker(Locale("en")) Contact( id = it.toLong(), name = faker.name().fullName(), email = faker.internet().emailAddress(), createdAt = ..., updatedAt = ... ) Java Faker — • Java Faker • Faker
  • 18. kotlinx.datetime • repository • // build.gradle repositories { maven { url "https://kotlin.bintray.com/kotlinx/" } } dependencies { implementation "org.jetbrains.kotlinx:kotlinx-datetime:$ver" } // io.kraftsman.services.ContactService val current = Clock.System.now() val tz = TimeZone.of("Asia/Taipei") Contact( // ... createdAt = current .toLocalDateTime(tz).toString(), updatedAt = (current + x.hours + y.minutes) .toLocalDateTime(tz).toString() ) Datetime — kotlinx.datetime • • • (x + y ) •
  • 19. // build.gradle plugins { id 'org.jetbrains.kotlin.plugin.serialization' version '1.4.10' } repositories { jcenter() } dependencies { implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$ver" } • Gradle Plugin Serialization (pt.1) — • Repository •
  • 20. // io.kraftsman.dtos.Contact @Serializable data class Contact( // ... ) // io.kraftsman.functions.Handler val contacts: List<Contact> = ContactService().generate(amount) Json.encodeToString( mapOf("data" to contacts) ) Serialization (pt.2) — • Annotation JSON • List Map data • Map JSON
  • 21. Cloud Functions — • IntelliJ IDEA • JDK 11 • gcloud CLI Repository: https://github.com/shengyou/gcp-cloud-functions-kotlin
  • 22. $ brew cask install google-cloud-sdk $ gcloud auth login $ gcloud projects list $ gcloud config set project PROJECT_ID / gcloud — • gcloud CLI • GCP • GCP Project • GCP Project
  • 24. configurations { invoker } dependencies { implementation "...:functions-framework-api:$ver" invoker "...:java-function-invoker:$ver" } tasks.register("runFunction", JavaExec) { main = '...' classpath(configurations.invoker) inputs.files(..., ...) args( '--target', ...Property('runFunction.target') ?: '', '--port', ...Property('runFunction.port') ?: ... ) doFirst { args('--classpath', ...) } } Gradle — Cloud Function • functions-framework-api • java-function-invoker Gradle Task $ gradle runFunction Java Invoker
  • 25. class Handler: HttpFunction { @Throws(IOException::class) override fun service(req: HttpRequest, res: HttpResponse) { } } Handler — • Class • HttpFunction ( functions-framework-api) • service() • req res
  • 26. class Handler: HttpFunction { @Throws(IOException::class) override fun service(req: HttpRequest, res: HttpResponse) { val param = request.getFirstQueryParameter("amount") .orElse("") val amount = param.toIntOrNull() ?: 10 } } Query — • HttpRequest Query •
  • 27. class Handler: HttpFunction { @Throws(IOException::class) override fun service(req: HttpRequest, res: HttpResponse) { val param = request.getFirstQueryParameter("amount") .orElse("") val amount = param.toIntOrNull() ?: 10 val contacts = ContactService().generate(amount) val jsonString = Json.encodeToString( mapOf("data" to contacts) ) } } / — • Service • JSON
  • 28. class Handler: HttpFunction { @Throws(IOException::class) override fun service(req: HttpRequest, res: HttpResponse) { val param = request.getFirstQueryParameter("amount") .orElse("") val amount = param.toIntOrNull() ?: 10 val contacts = ContactService().generate(amount) val jsonString = Json.encodeToString( mapOf("data" to contacts) ) with(res) { setStatusCode(HttpURLConnection.HTTP_OK) setContentType("application/json") writer.write(jsonString) } } } Response — • HTTP Status Code • Content-Type • JSON
  • 29. $ ./gradlew runFunction -PrunFunction.target=CLASS -PrunFunction.port=PORT — • Gradle Task • Run Configuration
  • 30. $ gcloud functions deploy PUBLIC_PATH --region REGION --runtime java11 --trigger-http --memory 256MB --entry-point ENTRY_POINT_CLASS --allow-unauthenticated — • gcloud
  • 31. Azure Functions — • IntelliJ IDEA + Plugins • JDK 8 • Azure CLI • Azure Functions Core Tools Repository: https://github.com/shengyou/microsoft-azure-functions-kotlin
  • 32. $ brew update $ brew install azure-cli $ az login $ az account -a SUBSCRIPTION_ID $ brew tap azure/functions $ brew installazure-function-core-tools@3 — • Azure CLI • Azure • Azure Functions Core Tools • Azure Toolkit for IntelliJ
  • 33. 1. Azure Functions 2. Gradle 3. JDK 8 —
  • 34. 1. Azure Functions 2. Gradle 3. JDK 8 Kotlin — ① ② ③ ④
  • 36. class Handler { @FunctionName("...") fun run( @HttpTrigger( name = "...", route = "...", methods = [HttpMethod.GET], authLevel = AuthorizationLevel.ANONYMOUS ) request: HttpRequestMessage<Optional<String?>>, context: ExecutionContext ): HttpResponseMessage { // ... } } Handler — • Class Method • Annotation • route methods • request context
  • 37. class Handler { @FunctionName("...") fun run(/* . . . */): HttpResponseMessage { val query = request.queryParameters["amount"] val amount = query?.toIntOrNull() ?: 10 } } Query — • request Query •
  • 38. class Handler { @FunctionName("...") fun run(/* . . . */): HttpResponseMessage { val query = request.queryParameters["amount"] val amount = query?.toIntOrNull() ?: 10 val contacts = ContactService().generate(amount) val jsonString = Json.encodeToString( mapOf("data" to contacts) ) } } / — • Service • JSON
  • 39. class Handler { @FunctionName("...") fun run(/* . . . */): HttpResponseMessage { val query = request.queryParameters["amount"] val amount = query?.toIntOrNull() ?: 10 val contacts = ContactService().generate(amount) val jsonString = Json.encodeToString( mapOf("data" to contacts) ) return request.createResponseBuilder(HttpStatus.OK) .header("Content-Type", "application/json") .body(jsonString) .build() } } Response — • HTTP Status Code • Content-Type • JSON
  • 41. azurefunctions { subscription = '...' resourceGroup = '...' appName = '...' pricingTier = 'Consumption' region = '...' runtime { os = 'linux' } authentication { type = 'azure_cli' } } — • Azure Gradle • Gradle Task
  • 42. AWS Lambda — • IntelliJ IDEA + Plugin • JDK 11 • Docker • AWS CLI • AWS SAM CLI Repository: https://github.com/shengyou/amazon-lambda-kotlin
  • 43. $ brew update $ brew install awscli $ aws configure $ aws sts get-caller-identity $ brew tap aws/tap $ brew install aws-sam-cli — • AWS CLI • AWS • Account ID • IAM (User & Role) • AWS SAM CLI • AWS Toolkit
  • 44. 1. Kotlin 2. Gradle 3. JDK 11 — 1. AWS
  • 45. plugins { id 'java' id 'com.github.johnrengelman.shadow' version '6.1.0' } dependencies { implementation "...:aws-lambda-java-core:1.2.1" implementation "...:aws-lambda-java-events:3.1.0" runtimeOnly "...:aws-lambda-java-log4j2:1.2.0" } Gradle — AWS Lambda • aws-lambda-java-core • aws-lambda-java-events • aws-lambda-java-log4j2 Gradle Plugin • java • shadow
  • 46. class Handler : RequestHandler < APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent > { @Throws(IOException::class) override fun handleRequest( request: APIGatewayProxyRequestEvent, context: Context ): APIGatewayProxyResponseEvent { // ... } } Handler — • Class Method • RequestHandler ( aws- lambda-java-core) • Handler Method • reqest context
  • 47. class Handler : RequestHandler <...> { @Throws(IOException::class) override fun method(/* ... */): ...ResponseEvent { val param = request.queryStringParameters["amount"] val amount = param?.toIntOrNull() ?: 10 } } Query — • request Query •
  • 48. class Handler : RequestHandler <...> { @Throws(IOException::class) override fun method(/* ... */): ...ResponseEvent { val param = request.queryStringParameters["amount"] val amount = param?.toIntOrNull() ?: 10 val contacts = ContactService().generate(amount) val jsonString = Json.encodeToString( mapOf("data" to contacts) ) } } / — • Service • JSON
  • 49. class Handler : RequestHandler <...> { @Throws(IOException::class) override fun method(/* ... */): ...ResponseEvent { val param = request.queryStringParameters["amount"] val amount = param?.toIntOrNull() ?: 10 val contacts = ContactService().generate(amount) val jsonString = Json.encodeToString( mapOf("data" to contacts) ) return APIGatewayProxyResponseEvent() .withStatusCode(HttpURLConnection.HTTP_OK) .withHeaders( mapOf("Content-Type" to "application/json") ) .withBody(jsonString) } } Response — • HTTP Status Code • Content-Type • JSON
  • 50. $ aws lambda create-function --function-name NAME --zip-file fileb://build/libs/SHADOWJAR.jar --handler CLASS::METHOD --runtime java11 --timeout 15 --memory-size 128 --role ROLE — • aws • AWS Console
  • 52. JDK 11 8 11 IntelliJ Plugin ✗ ✓ ✓ Gradle ✓ ✓ Framework ✓ ✓ ✓ + —
  • 54. Kotless — https://site.kotless.io/ • Serverless Framework • Kotless DSL • Gradle Plugin • Developed by Vladislav Tankov from JetBrains • Open Source (Apache 2.0)
  • 55. — Image source: Serverless Development With Kotlin and Kotless by Vlaadislav Tankov
  • 56. 1. Kotlin 2. Gradle Kotlin ❤ 3. JDK 11 —
  • 57. plugins { kotlin("jvm") version "1.3.72" apply true kotlin("plugin.serialization") version "1.3.72" id("io.kotless") version "0.1.6" apply true } dependencies { implementation("io.kotless", "kotless-lang", "0.1.6") } Gradle — Gradle Plugins • Kotlin 1.3.72 • Serialization 1.3.72 • Kotless 0.1.6 • Kotless
  • 58. @Get("/") fun handler(): HttpResponse { val dom = """ // ... """.trimIndent() return html(dom) } Function — • Function • Annotation Route • HttpResponse
  • 59. @Get("/...") fun handler(): HttpResponse { val param = KotlessContext.HTTP.request.params?.get("amount") val amount = param?.toIntOrNull() ?: 10 } Query — • KotlessContext Query •
  • 60. @Get("/...") fun handler(): HttpResponse { val param = KotlessContext.HTTP.request.params?.get("amount") val amount = param?.toIntOrNull() ?: 10 val contacts = ContactService().generate(amount) val json = Json(JsonConfiguration.Stable) val jsonString = json.stringify( Contact.serializer(), contacts ) } / — • Service • JSON
  • 61. @Get("/...") fun handler(): HttpResponse { val param = KotlessContext.HTTP.request.params?.get("amount") val amount = param?.toIntOrNull() ?: 10 val contacts = ContactService().generate(amount) val json = Json(JsonConfiguration.Stable) val jsonString = json.stringify( Contact.serializer(), contacts ) return json(jsonString) } Response — • JSON
  • 63. kotless { config { bucket = "..." terraform { profile = "..." region = "..." } } } — • AWS CLI Credentials • S3 Bucket • AWS Gradle • Gradle Task
  • 65. Kotless — Image source: Serverless Development With Kotlin and Kotless by Vlaadislav Tankov
  • 66. 1. Ktor (1.3.2) 2. Gradle Kotlin ❤ 3. JDK 11 4. Server Features • Routing • ContentNegotiation • Jackson Ktor —
  • 67. plugins { id("io.kotless") version "0.1.6" apply true } dependencies { // ... implementation("io.ktor:ktor-server-netty:$ktor_version") // ... implementation("io.kotless", "ktor-lang", “0.1.6") // ... } Gradle — Gradle Plugins • Kotless 0.1.6 • Netty • Kotless for Ktor
  • 68. class Server : Kotless() { override fun prepare(app: Application) { app.install(ContentNegotiation) { jackson { enable(SerializationFeature.INDENT_OUTPUT) } } app.routing { // ... } } } Kotless App — Kotless App • Kotless • prepare() • Ktor app
  • 69. // Application.kt @Suppress("unused") @kotlin.jvm.JvmOverloads fun Application.module(testing: Boolean = false) { // ... } // resources/application.conf ktor { deployment { port = 8080 port = ${?PORT} } application { modules = [ io.kraftsman.Server.prepare ] } } — • Application.kt •
  • 70. Roadmap — Image source: Serverless Development With Kotlin and Kotless by Vlaadislav Tankov
  • 71. % & % Repository: https://github.com/shengyou/jetbrains-kotless-framework Repository: https://github.com/shengyou/jetbrains-ktor-with-kotless
  • 72. — • Serverless • Kotlin Serverless • Kotless Framework • Kotless
  • 73. Serverless — • IBM Bluemix • Cloudflare Workers • Alibaba Cloud • Huawei Cloud • …
  • 74. Serverless — • Fat Jar • Container • Kotlin/JS
  • 75. Serverless — • Spring Cloud Function • Micronaut • Osiris • Nimbus • …
  • 76. — • Mobile Backend (API …) • Webhook ( API …) • ( …)
  • 77. — • • • • Image source: The Definition of Framework by Francesco Strazzullo