SlideShare uma empresa Scribd logo
1 de 85
Baixar para ler offline
Kotlin Backend @ Coupang
Spring Camp 2018

debop@coupang.com
Who is @debop
• Since 1993

• Robotics, BPM Solution, Healthcare

• C/C++, Object Pascal (Delphi), C#, Java, Scala, Kotlin

• Use Kotlin since 2016.08 

• Sr. Principle Software Engineer in Coupang (2017~)
Agenda
• Kotlin - The Good, The Bad, The Ugly

• Kotlin Coroutines

• Kotlin Backend 도입 전략 / 사례

• Lesson & Learn

• Resources
Kotlin
The Good, The Bad and The Ugly
Kotlin - The Good (1/3)
• Java Interoperability (@JvmXXXX)

• Familiar Syntax (like Scala, C#, Groovy, Swift …)

• Type Inference (like Scala, C#)

• Smart Casts (`is`, `as`)

• Data Class (Scala case class, POJO with @Data)
Kotlin - The Good (1/3)
when (x) {
is Int -> print(x + 1)
is String -> print(x.length + 1)
is IntArray -> print(x.sum())
!is BigDecimal -> print(x)
1L..10L -> print(x)
}
val x: String? = y as String (Unsafe)
val x: String? = y as String? (Unsafe)
val x: String? = y as? String (Safe)
is / !is
as / as?
Kotlin - The Good (1/3)
public class User {
private String name;
private Integer age;
public User(String name) {
this(name, 0);
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {return this.name;}
public Integer getAge() {return this.age;}
public void setName(String name) {this.name = name; }
public void setAge(Integer age) {this.age = age; }
public boolean equals(Object o) { /* 생략 */ }
public int hashCode() {
return Objects.hash(name, age);
}
protected boolean canEqual(Object other) {return other instanceof User;}
public String toString() {return "User(name=" + this.getName() + ", age=" + this.getAge() + ")";}
}
Kotlin - The Good (1/3)
public class User {
private String name;
private Integer age;
public User(String name) {
this(name, 0);
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {return this.name;}
public Integer getAge() {return this.age;}
public void setName(String name) {this.name = name; }
public void setAge(Integer age) {this.age = age; }
public boolean equals(Object o) { /* 생략 */ }
public int hashCode() {
return Objects.hash(name, age);
}
protected boolean canEqual(Object other) {return other instanceof User;}
public String toString() {return "User(name=" + this.getName() + ", age=" + this.getAge() + ")";}
}
data class User(var name:String) {
var age:Int = 0
}
Kotlin - The Good (2/3)
• Default Arguments

• String Templates (Scala - string interpolation)

• Properties (C#, No Getter, Setter)
val tomAge = map["tom"] ?: 0
map["jane"] = 29
val query = """
| CREATE KEYSPACE IF NOT EXISTS $keyspaceName
| WITH replication = { 'class': '$replicationStrategy',
| 'replication_factor':$replicationFactor }
""".trimMargin()
val s = "abc"
val str = "$s.length is ${s.length}" // prints "abc.length is 3"
Kotlin - The Good (2/3)
fun read(b:ByteArray, offset:Int = 0, length:Int = b.size) {
TODO(”Not Implemented”)
}
val tomAge = map["tom"] ?: 0
map["jane"] = 29
val query = """
| CREATE KEYSPACE IF NOT EXISTS $keyspaceName
| WITH replication = { 'class': '$replicationStrategy',
| 'replication_factor':$replicationFactor }
""".trimMargin()
val s = "abc"
val str = "$s.length is ${s.length}" // prints "abc.length is 3"
Kotlin - The Good (2/3)
fun read(b:ByteArray, offset:Int = 0, length:Int = b.size) {
TODO(”Not Implemented”)
}
val tomAge = map["tom"] ?: 0
map["jane"] = 29
val query = """
| CREATE KEYSPACE IF NOT EXISTS $keyspaceName
| WITH replication = { 'class': '$replicationStrategy',
| 'replication_factor':$replicationFactor }
""".trimMargin()
val s = "abc"
val str = "$s.length is ${s.length}" // prints "abc.length is 3"
Kotlin - The Good (2/3)
fun read(b:ByteArray, offset:Int = 0, length:Int = b.size) {
TODO(”Not Implemented”)
}
val tomAge = map["tom"] ?: 0
map["jane"] = 29
val query = """
| CREATE KEYSPACE IF NOT EXISTS $keyspaceName
| WITH replication = { 'class': '$replicationStrategy',
| 'replication_factor':$replicationFactor }
""".trimMargin()
val s = "abc"
val str = "$s.length is ${s.length}" // prints "abc.length is 3"
Kotlin - The Good (2/3)
fun read(b:ByteArray, offset:Int = 0, length:Int = b.size) {
TODO(”Not Implemented”)
}
Kotlin - The Good (3/3)
• Destructuring Declarations

• Class, Property Delegates

• Extension Functions (C#)

• Null Safety (C#)

• Better Lambdas than Java (same Scala)

• Scala functional features (use arrow)

• Coroutines (kotlinx-coroutines)
Kotlin - The Good (3/3)
fun Int.millis(): Duration = Duration.ofMillis(this.toLong())
fun Int.seconds(): Duration = Duration.ofSeconds(this.toLong())
// 5.seconds() + 400.millis() —> 5400 msec
if (text != null) text.length else -1
text?.length ?: -1
suspend fun Period.daySequence(): Sequence<Int> = buildSequence {
var day = 0
val days = this@daySequence.days
while (day < days) {
yield(day++)
}
}
}
Kotlin - The Good (3/3)
if(command!=null) {
if(command.getThreadPoolProperties()!=null) {
if(command.getThreadPoolProperties().maxQueueSize()!=null) {
val x = command.getThreadPoolProperties().maxQueueSize().get()
}
}
}
val x = command?.getThreadPoolProperties()?.maxQueueSize()?.get() ?: 0
Kotlin - The Good (3/3)
if(command!=null) {
if(command.getThreadPoolProperties()!=null) {
if(command.getThreadPoolProperties().maxQueueSize()!=null) {
val x = command.getThreadPoolProperties().maxQueueSize().get()
}
}
}
Compile time
Compile time
Scala >>>>> Kotlin > Java
the bad
Kotlin - The Bad
• No namespace (package variable, methods)

• No static modifier (use companion object)
Kotlin - The Bad
class OffHeapOutputStream(private var ohm: OffHeapMemory) : OutputStream() {
companion object {
private val bax = ByteArrayTool.Factory.create()
@JvmField val EMPTY = OffHeapOutputStream(0)
}
}
@file:JvmName("Localex")
/** 지정한 Locale 이 null 이면 기본 Locale 을 반환합니다 */
fun Locale?.orDefault(): Locale = this ?: Locale.getDefault()
the ugly
Kotlin - The Ugly
• SAM conversion

• Unit returning lambdas (Use in java)

• Final by default (안정성? 성능? A bit about picking defaults) 

• Open: 50%, Final : 50%
registerCallback(() -> {
/** do stuff */
return Unit.INSTANCE;
})
Killer feature - Coroutines
• Readable, clean code 

• Escape Callback hell

• Imperative programming

• Not exclusive, Cooperative

• Lightweight thread (fiber, goroutines)

• Note: Experimental !!!
@GetMapping("/composeasync2")
DeferredResult<String> asyncCompose2() {
    DeferredResult dr = new DeferredResult();
ListenableFuture<String> f1 = myService.async();
f1.addCallback(res1 -> {
ListenableFuture<String> f2 = myService.async2(res1);
f2.addCallback(res2 -> {
    ListenableFuture<String> f3 = myService.async3(res2);
     f3.addCallback(res3 -> {
         dr.setResult(res3);
        }, e -> {
         dr.setErrorResult(e);
        });
    }, e -> {
     dr.setErrorResult(e);
    });
}, e -> {
dr.setErrorResult(e);
});
return dr;
}
@GetMapping("/composeasync2")
DeferredResult<String> asyncCompose2() {
    DeferredResult dr = new DeferredResult();
ListenableFuture<String> f1 = myService.async();
f1.addCallback(res1 -> {
ListenableFuture<String> f2 = myService.async2(res1);
f2.addCallback(res2 -> {
    ListenableFuture<String> f3 = myService.async3(res2);
     f3.addCallback(res3 -> {
         dr.setResult(res3);
        }, e -> {
         dr.setErrorResult(e);
        });
    }, e -> {
     dr.setErrorResult(e);
    });
}, e -> {
dr.setErrorResult(e);
});
return dr;
}
Callback Hell
lock.lockAsync(3000, TimeUnit.MILLISECONDS)
.thenComposeAsync(rl -> updateProductItemMapping(productId, itemId))
.thenComposeAsync(updated -> adultInverseIndex.fastPutAsync(itemId, productId))
.thenComposeAsync(added -> addItemIdToList(productId, itemId))
.whenCompleteAsync((result, error) -> lock.forceUnlock());
CompletableFuture
RxJava
Observable
.defer { Observable.just(timer.time()) }
.flatMap { timerCtx ->
external.doOnCompleted { timerCtx.stop() }
}
.subscribe { println(it) }
C# Way
async Task<String> work() {
    Thread.sleep(200);
    return “done”;
}
async Task moreWork() {
    Console.WriteLine(“Work started”);
    var str = await work();
    Console.WriteLine($“Work completed: {str}”);
}
C# Way
async Task<String> work() {
    Thread.sleep(200);
    return “done”;
}
async Task moreWork() {
    Console.WriteLine(“Work started”);
    var str = await work();
    Console.WriteLine($“Work completed: {str}”);
}
C# Way
async Task<String> work() {
    Thread.sleep(200);
    return “done”;
}
async Task moreWork() {
    Console.WriteLine(“Work started”);
    var str = await work();
    Console.WriteLine($“Work completed: {str}”);
}
C# Way
async Task<String> work() {
    Thread.sleep(200);
    return “done”;
}
async Task moreWork() {
    Console.WriteLine(“Work started”);
    var str = await work();
    Console.WriteLine($“Work completed: {str}”);
}
Kotlin Way
suspend fun work(): String {
delay(200L)
return "done"
}
fun moreWork(): Deferred<Unit> = async {
println("Work started")
val str = work()
println("Work completed. $str")
}
runBlocking {
moreWork().await()
}
Kotlin Way
suspend fun work(): String {
delay(200L)
return "done"
}
fun moreWork(): Deferred<Unit> = async {
println("Work started")
val str = work()
println("Work completed. $str")
}
runBlocking {
moreWork().await()
}
Kotlin Way
suspend fun work(): String {
delay(200L)
return "done"
}
fun moreWork(): Deferred<Unit> = async {
println("Work started")
val str = work()
println("Work completed. $str")
}
runBlocking {
moreWork().await()
}
Kotlin Way
suspend fun work(): String {
delay(200L)
return "done"
}
fun moreWork(): Deferred<Unit> = async {
println("Work started")
val str = work()
println("Work completed. $str")
}
runBlocking {
moreWork().await()
}
Go Way
runtime.GOMAXPROCS(runtime.NumCPU())
wg:= new(sync.WaitGroup)
for i:=0; i < 100000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(1000 * time.Millisecond)
print(".")
}()
}
wg.Wait()
Go Way
runtime.GOMAXPROCS(runtime.NumCPU())
wg:= new(sync.WaitGroup)
for i:=0; i < 100000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(1000 * time.Millisecond)
print(".")
}()
}
wg.Wait()
Go Way
runtime.GOMAXPROCS(runtime.NumCPU())
wg:= new(sync.WaitGroup)
for i:=0; i < 100000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(1000 * time.Millisecond)
print(".")
}()
}
wg.Wait()
Go Way
runtime.GOMAXPROCS(runtime.NumCPU())
wg:= new(sync.WaitGroup)
for i:=0; i < 100000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(1000 * time.Millisecond)
print(".")
}()
}
wg.Wait()
Quiz - How much time takes?
runBlocking {
val jobs = List(100_000) {
launch(CommonPool) {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Quiz - How much time takes?
runBlocking {
val jobs = List(100_000) {
launch(CommonPool) {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
100,000 Seconds?
Quiz - How much time takes?
runBlocking {
val jobs = List(100_000) {
launch(CommonPool) {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
100,000 Seconds? Or 1~3 seconds?
Quiz - How much time takes?
runBlocking {
val jobs = List(100_000) {
launch(CommonPool) {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
100,000 Seconds? Or 1~3 seconds?
Kotlin 도입 전략
What is our problem?
• 개발자 수준 편차가 크다

• 조직 수준은 최하위 개발자 수준의 의해 결정된다
변화를 추구하려면?
• 객관적 시각 유지

• History 및 현실 상황 대한 이해 (기술부채)

• 현 조직의 개발 역량 평가

• 동기부여 - 필요성 설득보다는 자각할 수 있도록 자극

• 충분한 학습 시간

• 변화 경험 공유

• ASP -> C#, Java -> Scala
Environments 준비
• 개발 Tool 지원 - IntelliJ IDEA

• Static code analysis - ktlint, detekt

• Test code coverage - jacoco (sample)

• Sonarcube - sonar-kotlin plugin
Kotlin Backend 도입 사례
Use cases
• Common Library (2017. 6 ~)

• Kotlin extension library

• Components (2017.08 ~ 2017.12)

• Aho-corasick, Korean Tokenizer, Kafka Client

• Standalone Web Application (2017.10~~2017.12)

• Audit Tool 

• Large scale system (2017.09~2018.01)

• Catalog creation pipeline system
1. Kotlin Extension library
• Coupang Standard Framework 보조 

• Kotlin Best practices 제공

• Object / IO / Utils / Cache / JDBC / Spring …

• Kotlin 학습 예제 제공 (Test cases / Examples)

• Based debop4k (personal project)
2. Korean Tokenizer
• 중복상품 Merge 위한 Tokenizer 필요 (명사 위주)

• Twitter 에서 개발한 open-korean-text 를 Customizing

• Scala vs Kotlin 성능 비교 

• Kotlin version is 1.5 ~ 3X faster with Coroutines

• 효과

• Full Indexing per Day 부하 감소 : 30%

• Elastic Search 질의 부하 : 80%
“제테스 MSW-3928PR 남성 비치트렁크, 95(L), 블랙블랙계열”
은전한닢 Twitter
블랙
비치
비치트렁크
계열
제테스
3928PR
블랙블랙계열
PR
MSW
,
(
)-
트렁크
3928
95
제테스
남성
“제테스 MSW-3928PR 남성 비치트렁크, 95(L), 블랙블랙계열”
은전한닢 Twitter
블랙
비치
비치트렁크
계열
제테스
3928PR
블랙블랙계열
PR
MSW
,
(
)-
트렁크
3928
95
제테스
남성
“제테스 MSW-3928PR 남성 비치트렁크, 95(L), 블랙블랙계열”
은전한닢 Twitter
블랙
비치
비치트렁크
계열
제테스
3928PR
블랙블랙계열
PR
MSW
,
(
)
L -
트렁크
3928
95
제테스
남성
Tokenizer Benchmark
은전한닢 Twitter RATIO
RPS 73.2 429.5 5.87 X
Avg Latency 626 ms 106 ms 5.91 X
Avg CPU Load 90% 55% 35 % Down
Twitter Tokenizer 는 한음절을 분석하지 못하는 단점이 있다
Scala Kotlin RATIO
Tokenize 668.620 ms 197.632 ms 3.38 X
Phrase extractor 644.902 ms 212.500 ms 3.13 X
구문 : “동해물과 백두산이 마르고 닳도록“
Benchmark by jmh

Linux Mint 18.2 Intel I7, 32GB, SSD
Why Kotlin is faster?
• Scala 의 loop는 느리다 - 아주 느릴 수 있다

• eclipse-collections 사용

• 메모리 절약

• Primitive type collection 지원

• Kotlin Coroutines

• 비동기 / Non-Blocking
3. Kafka Client - Wilson
• 동기 

• 안정된 Kafka 사용을 위해 Offset 관리가 필수

• 각 팀별 중복된 Client 구현 및 삽질

• 효과

• Message 중복 / 유실 없음 (Latest strategy)

• Retry / Circuit breaker 지원

• Metrics 를 활용한 Ack 지원

• 전사 확대 적용 중
Wilson message flows
Producer ConsumerKafka
Retry
Circuit Breaker
Metrics
Retry
Circuit Breaker
Metrics
Dead letters
Sending box
Redis
MySQL
Couchbase
Dead letters
Received box
Last sent timestamp Kafka Offset Manager
Message Managements
• Metrics
• Recovery / Retry
• Deadletter handling
Wilson Dashboard
4. Audit Tool
• 상품 정보 Audit System

• developers : 1 senior, 2 junior developer 

• Software stack

• React 

• Spring Boot 1.5 on Vitamin Framework

• jOOQ (향후 requery로 변환 예정)

• Pilot 로 시작, 개발자들의 노력으로 정식 시스템으로 승격
4. Audit Tool
Kotlin Coroutines + Spring MVC
5. Creation Pipeline System
• 상품 정보 생성 프로세스 관리 시스템

• Features

• Workflow (Heavy use Kafka)

• Asynchronous / Non-blocking System

• Need High throughput
Seller
Retail
Kafka
Deduplication
Refining
Processing
Creation
Logging
Message Dispatcher
Creation Pipeline flow
5. Creation Pipeline System
Spring Boot 1.x Kafka 0.10.x
Kotlin 1.2.x on JVM 8
Couchbase 4.x / Aurora
Zookeeper
3.x
%
%
Lesson & Learns
반성해야 하는 점
• 기본기 학습 - 닥치고 코딩 (X) 

• Java와 차이점 및 Kotlin best practices 검토 필요

• 첫 술에 배부를 수 없다 

• 실망하지 말라, Refactoring 은 필수다

• Coroutines 에 대한 학습 및 테스트

• 어차피 비동기는 어렵다. 

• Coroutines는 하나의 방법일 뿐이다
안정적 도입을 위한 Tips
• 충분한 학습 기회 & 실습

• Code Quality 중요성 인식

• Upsource 전사 활용 중

• 강력한 동기 부여

• Tech Leader의 지속적인 Leading & Coach

• 성공 사례 만들기 (작은 것부터)
효과
• Safety Code

• Readable Code

• 성능 향상

• Latency 감소, High Throughput 달성 

• Asynchronous/Non-Blocking 적용 용이

• 유지보수성 향상 (장애 감소)
언어별 Catalog Tribe 개발자 비율
(2017)
5%
Kotlin
10%
Scala
15%
Java
70%
Java Scala Kotlin Python
언어별 Catalog Tribe 개발자 비율
(2018 예상)
7%
Kotlin
25%
Scala
13%
Java
55%
Java Scala Kotlin Python
Aurora Cassandra ElasticSearch ArangoDB
JVM 8
Spring DataRequery JPA/Hibernate
Virtualization

kubernetes
Docker
Spring Framework 5.xKodein
Kotlin Coroutines with Reactor / RxJava
Services

Kafka
Redis
Spring Boot 2.x Webflux with Netty
Common Backend Stack (2018)
Boo1vsBoo2Performance
Spring MVC + Cassandra
Spring WebFlux + Cassandra Reactive
출처: Reactive Java Performance Comparison
Resources
• Kotlin Resources

• kotlinx.coroutines

• spring-kotlin-coroutine

• 20 Excellent Resources for learning Kotlin

• Books

• Kotlin in action

• Try Kotlin
Q&A
Thank you!

Mais conteúdo relacionado

Mais procurados

GCP Best Practices for SRE Team
GCP Best Practices for SRE TeamGCP Best Practices for SRE Team
GCP Best Practices for SRE TeamHuynh Thai Bao
 
Event driven autoscaling with KEDA
Event driven autoscaling with KEDAEvent driven autoscaling with KEDA
Event driven autoscaling with KEDANilesh Gule
 
Unit 1 - TypeScript & Introduction to Angular CLI.pptx
Unit 1 - TypeScript & Introduction to Angular CLI.pptxUnit 1 - TypeScript & Introduction to Angular CLI.pptx
Unit 1 - TypeScript & Introduction to Angular CLI.pptxMalla Reddy University
 
Extending kubernetes with CustomResourceDefinitions
Extending kubernetes with CustomResourceDefinitionsExtending kubernetes with CustomResourceDefinitions
Extending kubernetes with CustomResourceDefinitionsStefan Schimanski
 
Role based access control - RBAC - Kubernetes
Role based access control - RBAC - KubernetesRole based access control - RBAC - Kubernetes
Role based access control - RBAC - KubernetesMilan Das
 
stupid-simple-kubernetes-final.pdf
stupid-simple-kubernetes-final.pdfstupid-simple-kubernetes-final.pdf
stupid-simple-kubernetes-final.pdfDaniloQueirozMota
 
GitLab과 Kubernetes를 통한 CI/CD 구축
GitLab과 Kubernetes를 통한 CI/CD 구축GitLab과 Kubernetes를 통한 CI/CD 구축
GitLab과 Kubernetes를 통한 CI/CD 구축철구 김
 
Let's read code: the python-requests library
Let's read code: the python-requests libraryLet's read code: the python-requests library
Let's read code: the python-requests librarySusan Tan
 
Kubernetes Architecture - beyond a black box - Part 2
Kubernetes Architecture - beyond a black box - Part 2Kubernetes Architecture - beyond a black box - Part 2
Kubernetes Architecture - beyond a black box - Part 2Hao H. Zhang
 
Introduction to gRPC
Introduction to gRPCIntroduction to gRPC
Introduction to gRPCPrakash Divy
 
Advanced Debugging with GDB
Advanced Debugging with GDBAdvanced Debugging with GDB
Advanced Debugging with GDBDavid Khosid
 
How to Monitoring the SRE Golden Signals (E-Book)
How to Monitoring the SRE Golden Signals (E-Book)How to Monitoring the SRE Golden Signals (E-Book)
How to Monitoring the SRE Golden Signals (E-Book)Siglos
 
Introduction to kubernetes
Introduction to kubernetesIntroduction to kubernetes
Introduction to kubernetesGabriel Carro
 
Hands-On Introduction to Kubernetes at LISA17
Hands-On Introduction to Kubernetes at LISA17Hands-On Introduction to Kubernetes at LISA17
Hands-On Introduction to Kubernetes at LISA17Ryan Jarvinen
 
Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular Jalpesh Vadgama
 
The Travelling Pentester: Diaries of the Shortest Path to Compromise
The Travelling Pentester: Diaries of the Shortest Path to CompromiseThe Travelling Pentester: Diaries of the Shortest Path to Compromise
The Travelling Pentester: Diaries of the Shortest Path to CompromiseWill Schroeder
 
Kubernetes - Security Journey
Kubernetes - Security JourneyKubernetes - Security Journey
Kubernetes - Security JourneyJerry Jalava
 
Google Kubernetes Engine (GKE) deep dive
Google Kubernetes Engine (GKE) deep diveGoogle Kubernetes Engine (GKE) deep dive
Google Kubernetes Engine (GKE) deep diveAkash Agrawal
 

Mais procurados (20)

GCP Best Practices for SRE Team
GCP Best Practices for SRE TeamGCP Best Practices for SRE Team
GCP Best Practices for SRE Team
 
Event driven autoscaling with KEDA
Event driven autoscaling with KEDAEvent driven autoscaling with KEDA
Event driven autoscaling with KEDA
 
Unit 1 - TypeScript & Introduction to Angular CLI.pptx
Unit 1 - TypeScript & Introduction to Angular CLI.pptxUnit 1 - TypeScript & Introduction to Angular CLI.pptx
Unit 1 - TypeScript & Introduction to Angular CLI.pptx
 
Extending kubernetes with CustomResourceDefinitions
Extending kubernetes with CustomResourceDefinitionsExtending kubernetes with CustomResourceDefinitions
Extending kubernetes with CustomResourceDefinitions
 
Role based access control - RBAC - Kubernetes
Role based access control - RBAC - KubernetesRole based access control - RBAC - Kubernetes
Role based access control - RBAC - Kubernetes
 
stupid-simple-kubernetes-final.pdf
stupid-simple-kubernetes-final.pdfstupid-simple-kubernetes-final.pdf
stupid-simple-kubernetes-final.pdf
 
Gitlab, GitOps & ArgoCD
Gitlab, GitOps & ArgoCDGitlab, GitOps & ArgoCD
Gitlab, GitOps & ArgoCD
 
GitLab과 Kubernetes를 통한 CI/CD 구축
GitLab과 Kubernetes를 통한 CI/CD 구축GitLab과 Kubernetes를 통한 CI/CD 구축
GitLab과 Kubernetes를 통한 CI/CD 구축
 
Let's read code: the python-requests library
Let's read code: the python-requests libraryLet's read code: the python-requests library
Let's read code: the python-requests library
 
Kubernetes Architecture - beyond a black box - Part 2
Kubernetes Architecture - beyond a black box - Part 2Kubernetes Architecture - beyond a black box - Part 2
Kubernetes Architecture - beyond a black box - Part 2
 
Introduction to gRPC
Introduction to gRPCIntroduction to gRPC
Introduction to gRPC
 
Advanced Debugging with GDB
Advanced Debugging with GDBAdvanced Debugging with GDB
Advanced Debugging with GDB
 
How to Monitoring the SRE Golden Signals (E-Book)
How to Monitoring the SRE Golden Signals (E-Book)How to Monitoring the SRE Golden Signals (E-Book)
How to Monitoring the SRE Golden Signals (E-Book)
 
Introduction to kubernetes
Introduction to kubernetesIntroduction to kubernetes
Introduction to kubernetes
 
Hands-On Introduction to Kubernetes at LISA17
Hands-On Introduction to Kubernetes at LISA17Hands-On Introduction to Kubernetes at LISA17
Hands-On Introduction to Kubernetes at LISA17
 
Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular
 
The Travelling Pentester: Diaries of the Shortest Path to Compromise
The Travelling Pentester: Diaries of the Shortest Path to CompromiseThe Travelling Pentester: Diaries of the Shortest Path to Compromise
The Travelling Pentester: Diaries of the Shortest Path to Compromise
 
Kubernetes - Security Journey
Kubernetes - Security JourneyKubernetes - Security Journey
Kubernetes - Security Journey
 
REST API
REST APIREST API
REST API
 
Google Kubernetes Engine (GKE) deep dive
Google Kubernetes Engine (GKE) deep diveGoogle Kubernetes Engine (GKE) deep dive
Google Kubernetes Engine (GKE) deep dive
 

Semelhante a Kotlin @ Coupang Backend 2017

Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?Jesper Kamstrup Linnet
 
2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locatorAlberto Paro
 
2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locatorAlberto Paro
 
Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)Cody Engel
 
Thinking Functionally with JavaScript
Thinking Functionally with JavaScriptThinking Functionally with JavaScript
Thinking Functionally with JavaScriptLuis Atencio
 
The Future of JVM Languages
The Future of JVM Languages The Future of JVM Languages
The Future of JVM Languages VictorSzoltysek
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)Pavlo Baron
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019Leonardo Borges
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Arnaud Giuliani
 
AST Transformations
AST TransformationsAST Transformations
AST TransformationsHamletDRC
 
Intro to Kotlin
Intro to KotlinIntro to Kotlin
Intro to KotlinMagda Miu
 
Scala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecScala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecLoïc Descotte
 
Python 101 language features and functional programming
Python 101 language features and functional programmingPython 101 language features and functional programming
Python 101 language features and functional programmingLukasz Dynowski
 

Semelhante a Kotlin @ Coupang Backend 2017 (20)

Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?
 
Scala - en bedre Java?
Scala - en bedre Java?Scala - en bedre Java?
Scala - en bedre Java?
 
Scala in Places API
Scala in Places APIScala in Places API
Scala in Places API
 
2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator
 
2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator
 
Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)
 
Thinking Functionally with JavaScript
Thinking Functionally with JavaScriptThinking Functionally with JavaScript
Thinking Functionally with JavaScript
 
The Future of JVM Languages
The Future of JVM Languages The Future of JVM Languages
The Future of JVM Languages
 
Hadoop + Clojure
Hadoop + ClojureHadoop + Clojure
Hadoop + Clojure
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017
 
Hw09 Hadoop + Clojure
Hw09   Hadoop + ClojureHw09   Hadoop + Clojure
Hw09 Hadoop + Clojure
 
Groovy
GroovyGroovy
Groovy
 
Pune Clojure Course Outline
Pune Clojure Course OutlinePune Clojure Course Outline
Pune Clojure Course Outline
 
AST Transformations
AST TransformationsAST Transformations
AST Transformations
 
Intro to Kotlin
Intro to KotlinIntro to Kotlin
Intro to Kotlin
 
Scala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecScala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar Prokopec
 
Python 101 language features and functional programming
Python 101 language features and functional programmingPython 101 language features and functional programming
Python 101 language features and functional programming
 
ES6 is Nigh
ES6 is NighES6 is Nigh
ES6 is Nigh
 

Mais de Sunghyouk Bae

JUnit5 and TestContainers
JUnit5 and TestContainersJUnit5 and TestContainers
JUnit5 and TestContainersSunghyouk Bae
 
Introduction of failsafe
Introduction of failsafeIntroduction of failsafe
Introduction of failsafeSunghyouk Bae
 
Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backed - JetBrains Day seoul 2018Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backed - JetBrains Day seoul 2018Sunghyouk Bae
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/HibernateSunghyouk Bae
 
Kotlin coroutines and spring framework
Kotlin coroutines and spring frameworkKotlin coroutines and spring framework
Kotlin coroutines and spring frameworkSunghyouk Bae
 
Java naming strategy (자바 명명 전략)
Java naming strategy (자바 명명 전략)Java naming strategy (자바 명명 전략)
Java naming strategy (자바 명명 전략)Sunghyouk Bae
 
테스트자동화와 TDD
테스트자동화와 TDD테스트자동화와 TDD
테스트자동화와 TDDSunghyouk Bae
 
SpringBoot with MyBatis, Flyway, QueryDSL
SpringBoot with MyBatis, Flyway, QueryDSLSpringBoot with MyBatis, Flyway, QueryDSL
SpringBoot with MyBatis, Flyway, QueryDSLSunghyouk Bae
 
좋은 개발자 되기
좋은 개발자 되기좋은 개발자 되기
좋은 개발자 되기Sunghyouk Bae
 
Multithread pattern 소개
Multithread pattern 소개Multithread pattern 소개
Multithread pattern 소개Sunghyouk Bae
 

Mais de Sunghyouk Bae (16)

JUnit5 and TestContainers
JUnit5 and TestContainersJUnit5 and TestContainers
JUnit5 and TestContainers
 
Introduction of failsafe
Introduction of failsafeIntroduction of failsafe
Introduction of failsafe
 
Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backed - JetBrains Day seoul 2018Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backed - JetBrains Day seoul 2018
 
Spring data requery
Spring data requerySpring data requery
Spring data requery
 
Requery overview
Requery overviewRequery overview
Requery overview
 
measure metrics
measure metricsmeasure metrics
measure metrics
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/Hibernate
 
Kotlin coroutines and spring framework
Kotlin coroutines and spring frameworkKotlin coroutines and spring framework
Kotlin coroutines and spring framework
 
Java naming strategy (자바 명명 전략)
Java naming strategy (자바 명명 전략)Java naming strategy (자바 명명 전략)
Java naming strategy (자바 명명 전략)
 
테스트자동화와 TDD
테스트자동화와 TDD테스트자동화와 TDD
테스트자동화와 TDD
 
SpringBoot with MyBatis, Flyway, QueryDSL
SpringBoot with MyBatis, Flyway, QueryDSLSpringBoot with MyBatis, Flyway, QueryDSL
SpringBoot with MyBatis, Flyway, QueryDSL
 
JUnit & AssertJ
JUnit & AssertJJUnit & AssertJ
JUnit & AssertJ
 
좋은 개발자 되기
좋은 개발자 되기좋은 개발자 되기
좋은 개발자 되기
 
Using AdoRepository
Using AdoRepositoryUsing AdoRepository
Using AdoRepository
 
Multithread pattern 소개
Multithread pattern 소개Multithread pattern 소개
Multithread pattern 소개
 
Strategy Maps
Strategy MapsStrategy Maps
Strategy Maps
 

Último

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
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
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
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
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
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
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
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceanilsa9823
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
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.
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 

Último (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
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
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
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
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
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
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
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
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...
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 

Kotlin @ Coupang Backend 2017

  • 1. Kotlin Backend @ Coupang Spring Camp 2018 debop@coupang.com
  • 2. Who is @debop • Since 1993 • Robotics, BPM Solution, Healthcare • C/C++, Object Pascal (Delphi), C#, Java, Scala, Kotlin • Use Kotlin since 2016.08 • Sr. Principle Software Engineer in Coupang (2017~)
  • 3. Agenda • Kotlin - The Good, The Bad, The Ugly • Kotlin Coroutines • Kotlin Backend 도입 전략 / 사례 • Lesson & Learn • Resources
  • 4. Kotlin The Good, The Bad and The Ugly
  • 5.
  • 6.
  • 7.
  • 8.
  • 9. Kotlin - The Good (1/3) • Java Interoperability (@JvmXXXX) • Familiar Syntax (like Scala, C#, Groovy, Swift …) • Type Inference (like Scala, C#) • Smart Casts (`is`, `as`) • Data Class (Scala case class, POJO with @Data)
  • 10. Kotlin - The Good (1/3) when (x) { is Int -> print(x + 1) is String -> print(x.length + 1) is IntArray -> print(x.sum()) !is BigDecimal -> print(x) 1L..10L -> print(x) } val x: String? = y as String (Unsafe) val x: String? = y as String? (Unsafe) val x: String? = y as? String (Safe) is / !is as / as?
  • 11. Kotlin - The Good (1/3) public class User { private String name; private Integer age; public User(String name) { this(name, 0); } public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() {return this.name;} public Integer getAge() {return this.age;} public void setName(String name) {this.name = name; } public void setAge(Integer age) {this.age = age; } public boolean equals(Object o) { /* 생략 */ } public int hashCode() { return Objects.hash(name, age); } protected boolean canEqual(Object other) {return other instanceof User;} public String toString() {return "User(name=" + this.getName() + ", age=" + this.getAge() + ")";} }
  • 12. Kotlin - The Good (1/3) public class User { private String name; private Integer age; public User(String name) { this(name, 0); } public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() {return this.name;} public Integer getAge() {return this.age;} public void setName(String name) {this.name = name; } public void setAge(Integer age) {this.age = age; } public boolean equals(Object o) { /* 생략 */ } public int hashCode() { return Objects.hash(name, age); } protected boolean canEqual(Object other) {return other instanceof User;} public String toString() {return "User(name=" + this.getName() + ", age=" + this.getAge() + ")";} } data class User(var name:String) { var age:Int = 0 }
  • 13. Kotlin - The Good (2/3) • Default Arguments • String Templates (Scala - string interpolation) • Properties (C#, No Getter, Setter)
  • 14. val tomAge = map["tom"] ?: 0 map["jane"] = 29 val query = """ | CREATE KEYSPACE IF NOT EXISTS $keyspaceName | WITH replication = { 'class': '$replicationStrategy', | 'replication_factor':$replicationFactor } """.trimMargin() val s = "abc" val str = "$s.length is ${s.length}" // prints "abc.length is 3" Kotlin - The Good (2/3) fun read(b:ByteArray, offset:Int = 0, length:Int = b.size) { TODO(”Not Implemented”) }
  • 15. val tomAge = map["tom"] ?: 0 map["jane"] = 29 val query = """ | CREATE KEYSPACE IF NOT EXISTS $keyspaceName | WITH replication = { 'class': '$replicationStrategy', | 'replication_factor':$replicationFactor } """.trimMargin() val s = "abc" val str = "$s.length is ${s.length}" // prints "abc.length is 3" Kotlin - The Good (2/3) fun read(b:ByteArray, offset:Int = 0, length:Int = b.size) { TODO(”Not Implemented”) }
  • 16. val tomAge = map["tom"] ?: 0 map["jane"] = 29 val query = """ | CREATE KEYSPACE IF NOT EXISTS $keyspaceName | WITH replication = { 'class': '$replicationStrategy', | 'replication_factor':$replicationFactor } """.trimMargin() val s = "abc" val str = "$s.length is ${s.length}" // prints "abc.length is 3" Kotlin - The Good (2/3) fun read(b:ByteArray, offset:Int = 0, length:Int = b.size) { TODO(”Not Implemented”) }
  • 17. val tomAge = map["tom"] ?: 0 map["jane"] = 29 val query = """ | CREATE KEYSPACE IF NOT EXISTS $keyspaceName | WITH replication = { 'class': '$replicationStrategy', | 'replication_factor':$replicationFactor } """.trimMargin() val s = "abc" val str = "$s.length is ${s.length}" // prints "abc.length is 3" Kotlin - The Good (2/3) fun read(b:ByteArray, offset:Int = 0, length:Int = b.size) { TODO(”Not Implemented”) }
  • 18. Kotlin - The Good (3/3) • Destructuring Declarations • Class, Property Delegates • Extension Functions (C#) • Null Safety (C#) • Better Lambdas than Java (same Scala) • Scala functional features (use arrow) • Coroutines (kotlinx-coroutines)
  • 19.
  • 20. Kotlin - The Good (3/3) fun Int.millis(): Duration = Duration.ofMillis(this.toLong()) fun Int.seconds(): Duration = Duration.ofSeconds(this.toLong()) // 5.seconds() + 400.millis() —> 5400 msec if (text != null) text.length else -1 text?.length ?: -1 suspend fun Period.daySequence(): Sequence<Int> = buildSequence { var day = 0 val days = this@daySequence.days while (day < days) { yield(day++) } } }
  • 21. Kotlin - The Good (3/3) if(command!=null) { if(command.getThreadPoolProperties()!=null) { if(command.getThreadPoolProperties().maxQueueSize()!=null) { val x = command.getThreadPoolProperties().maxQueueSize().get() } } }
  • 22. val x = command?.getThreadPoolProperties()?.maxQueueSize()?.get() ?: 0 Kotlin - The Good (3/3) if(command!=null) { if(command.getThreadPoolProperties()!=null) { if(command.getThreadPoolProperties().maxQueueSize()!=null) { val x = command.getThreadPoolProperties().maxQueueSize().get() } } }
  • 24. Compile time Scala >>>>> Kotlin > Java
  • 26. Kotlin - The Bad • No namespace (package variable, methods) • No static modifier (use companion object)
  • 27. Kotlin - The Bad class OffHeapOutputStream(private var ohm: OffHeapMemory) : OutputStream() { companion object { private val bax = ByteArrayTool.Factory.create() @JvmField val EMPTY = OffHeapOutputStream(0) } } @file:JvmName("Localex") /** 지정한 Locale 이 null 이면 기본 Locale 을 반환합니다 */ fun Locale?.orDefault(): Locale = this ?: Locale.getDefault()
  • 29. Kotlin - The Ugly • SAM conversion • Unit returning lambdas (Use in java) • Final by default (안정성? 성능? A bit about picking defaults) • Open: 50%, Final : 50% registerCallback(() -> { /** do stuff */ return Unit.INSTANCE; })
  • 30. Killer feature - Coroutines • Readable, clean code • Escape Callback hell • Imperative programming • Not exclusive, Cooperative • Lightweight thread (fiber, goroutines)
 • Note: Experimental !!!
  • 31. @GetMapping("/composeasync2") DeferredResult<String> asyncCompose2() {     DeferredResult dr = new DeferredResult(); ListenableFuture<String> f1 = myService.async(); f1.addCallback(res1 -> { ListenableFuture<String> f2 = myService.async2(res1); f2.addCallback(res2 -> {     ListenableFuture<String> f3 = myService.async3(res2);      f3.addCallback(res3 -> {          dr.setResult(res3);         }, e -> {          dr.setErrorResult(e);         });     }, e -> {      dr.setErrorResult(e);     }); }, e -> { dr.setErrorResult(e); }); return dr; }
  • 32. @GetMapping("/composeasync2") DeferredResult<String> asyncCompose2() {     DeferredResult dr = new DeferredResult(); ListenableFuture<String> f1 = myService.async(); f1.addCallback(res1 -> { ListenableFuture<String> f2 = myService.async2(res1); f2.addCallback(res2 -> {     ListenableFuture<String> f3 = myService.async3(res2);      f3.addCallback(res3 -> {          dr.setResult(res3);         }, e -> {          dr.setErrorResult(e);         });     }, e -> {      dr.setErrorResult(e);     }); }, e -> { dr.setErrorResult(e); }); return dr; } Callback Hell
  • 33. lock.lockAsync(3000, TimeUnit.MILLISECONDS) .thenComposeAsync(rl -> updateProductItemMapping(productId, itemId)) .thenComposeAsync(updated -> adultInverseIndex.fastPutAsync(itemId, productId)) .thenComposeAsync(added -> addItemIdToList(productId, itemId)) .whenCompleteAsync((result, error) -> lock.forceUnlock()); CompletableFuture RxJava Observable .defer { Observable.just(timer.time()) } .flatMap { timerCtx -> external.doOnCompleted { timerCtx.stop() } } .subscribe { println(it) }
  • 34. C# Way async Task<String> work() {     Thread.sleep(200);     return “done”; } async Task moreWork() {     Console.WriteLine(“Work started”);     var str = await work();     Console.WriteLine($“Work completed: {str}”); }
  • 35. C# Way async Task<String> work() {     Thread.sleep(200);     return “done”; } async Task moreWork() {     Console.WriteLine(“Work started”);     var str = await work();     Console.WriteLine($“Work completed: {str}”); }
  • 36. C# Way async Task<String> work() {     Thread.sleep(200);     return “done”; } async Task moreWork() {     Console.WriteLine(“Work started”);     var str = await work();     Console.WriteLine($“Work completed: {str}”); }
  • 37. C# Way async Task<String> work() {     Thread.sleep(200);     return “done”; } async Task moreWork() {     Console.WriteLine(“Work started”);     var str = await work();     Console.WriteLine($“Work completed: {str}”); }
  • 38. Kotlin Way suspend fun work(): String { delay(200L) return "done" } fun moreWork(): Deferred<Unit> = async { println("Work started") val str = work() println("Work completed. $str") } runBlocking { moreWork().await() }
  • 39. Kotlin Way suspend fun work(): String { delay(200L) return "done" } fun moreWork(): Deferred<Unit> = async { println("Work started") val str = work() println("Work completed. $str") } runBlocking { moreWork().await() }
  • 40. Kotlin Way suspend fun work(): String { delay(200L) return "done" } fun moreWork(): Deferred<Unit> = async { println("Work started") val str = work() println("Work completed. $str") } runBlocking { moreWork().await() }
  • 41. Kotlin Way suspend fun work(): String { delay(200L) return "done" } fun moreWork(): Deferred<Unit> = async { println("Work started") val str = work() println("Work completed. $str") } runBlocking { moreWork().await() }
  • 42. Go Way runtime.GOMAXPROCS(runtime.NumCPU()) wg:= new(sync.WaitGroup) for i:=0; i < 100000; i++ { wg.Add(1) go func() { defer wg.Done() time.Sleep(1000 * time.Millisecond) print(".") }() } wg.Wait()
  • 43. Go Way runtime.GOMAXPROCS(runtime.NumCPU()) wg:= new(sync.WaitGroup) for i:=0; i < 100000; i++ { wg.Add(1) go func() { defer wg.Done() time.Sleep(1000 * time.Millisecond) print(".") }() } wg.Wait()
  • 44. Go Way runtime.GOMAXPROCS(runtime.NumCPU()) wg:= new(sync.WaitGroup) for i:=0; i < 100000; i++ { wg.Add(1) go func() { defer wg.Done() time.Sleep(1000 * time.Millisecond) print(".") }() } wg.Wait()
  • 45. Go Way runtime.GOMAXPROCS(runtime.NumCPU()) wg:= new(sync.WaitGroup) for i:=0; i < 100000; i++ { wg.Add(1) go func() { defer wg.Done() time.Sleep(1000 * time.Millisecond) print(".") }() } wg.Wait()
  • 46. Quiz - How much time takes? runBlocking { val jobs = List(100_000) { launch(CommonPool) { delay(1000L) print(".") } } jobs.forEach { it.join() } }
  • 47. Quiz - How much time takes? runBlocking { val jobs = List(100_000) { launch(CommonPool) { delay(1000L) print(".") } } jobs.forEach { it.join() } } 100,000 Seconds?
  • 48. Quiz - How much time takes? runBlocking { val jobs = List(100_000) { launch(CommonPool) { delay(1000L) print(".") } } jobs.forEach { it.join() } } 100,000 Seconds? Or 1~3 seconds?
  • 49. Quiz - How much time takes? runBlocking { val jobs = List(100_000) { launch(CommonPool) { delay(1000L) print(".") } } jobs.forEach { it.join() } } 100,000 Seconds? Or 1~3 seconds?
  • 51. What is our problem? • 개발자 수준 편차가 크다 • 조직 수준은 최하위 개발자 수준의 의해 결정된다
  • 52. 변화를 추구하려면? • 객관적 시각 유지 • History 및 현실 상황 대한 이해 (기술부채) • 현 조직의 개발 역량 평가 • 동기부여 - 필요성 설득보다는 자각할 수 있도록 자극 • 충분한 학습 시간 • 변화 경험 공유 • ASP -> C#, Java -> Scala
  • 53. Environments 준비 • 개발 Tool 지원 - IntelliJ IDEA • Static code analysis - ktlint, detekt • Test code coverage - jacoco (sample) • Sonarcube - sonar-kotlin plugin
  • 55. Use cases • Common Library (2017. 6 ~) • Kotlin extension library • Components (2017.08 ~ 2017.12) • Aho-corasick, Korean Tokenizer, Kafka Client • Standalone Web Application (2017.10~~2017.12) • Audit Tool • Large scale system (2017.09~2018.01) • Catalog creation pipeline system
  • 56. 1. Kotlin Extension library • Coupang Standard Framework 보조 • Kotlin Best practices 제공 • Object / IO / Utils / Cache / JDBC / Spring … • Kotlin 학습 예제 제공 (Test cases / Examples) • Based debop4k (personal project)
  • 57. 2. Korean Tokenizer • 중복상품 Merge 위한 Tokenizer 필요 (명사 위주) • Twitter 에서 개발한 open-korean-text 를 Customizing • Scala vs Kotlin 성능 비교 • Kotlin version is 1.5 ~ 3X faster with Coroutines • 효과 • Full Indexing per Day 부하 감소 : 30% • Elastic Search 질의 부하 : 80%
  • 58. “제테스 MSW-3928PR 남성 비치트렁크, 95(L), 블랙블랙계열” 은전한닢 Twitter 블랙 비치 비치트렁크 계열 제테스 3928PR 블랙블랙계열 PR MSW , ( )- 트렁크 3928 95 제테스 남성
  • 59. “제테스 MSW-3928PR 남성 비치트렁크, 95(L), 블랙블랙계열” 은전한닢 Twitter 블랙 비치 비치트렁크 계열 제테스 3928PR 블랙블랙계열 PR MSW , ( )- 트렁크 3928 95 제테스 남성
  • 60. “제테스 MSW-3928PR 남성 비치트렁크, 95(L), 블랙블랙계열” 은전한닢 Twitter 블랙 비치 비치트렁크 계열 제테스 3928PR 블랙블랙계열 PR MSW , ( ) L - 트렁크 3928 95 제테스 남성
  • 61. Tokenizer Benchmark 은전한닢 Twitter RATIO RPS 73.2 429.5 5.87 X Avg Latency 626 ms 106 ms 5.91 X Avg CPU Load 90% 55% 35 % Down Twitter Tokenizer 는 한음절을 분석하지 못하는 단점이 있다
  • 62. Scala Kotlin RATIO Tokenize 668.620 ms 197.632 ms 3.38 X Phrase extractor 644.902 ms 212.500 ms 3.13 X 구문 : “동해물과 백두산이 마르고 닳도록“ Benchmark by jmh Linux Mint 18.2 Intel I7, 32GB, SSD
  • 63. Why Kotlin is faster? • Scala 의 loop는 느리다 - 아주 느릴 수 있다 • eclipse-collections 사용 • 메모리 절약 • Primitive type collection 지원 • Kotlin Coroutines • 비동기 / Non-Blocking
  • 64. 3. Kafka Client - Wilson • 동기 • 안정된 Kafka 사용을 위해 Offset 관리가 필수 • 각 팀별 중복된 Client 구현 및 삽질 • 효과 • Message 중복 / 유실 없음 (Latest strategy) • Retry / Circuit breaker 지원 • Metrics 를 활용한 Ack 지원 • 전사 확대 적용 중
  • 65. Wilson message flows Producer ConsumerKafka Retry Circuit Breaker Metrics Retry Circuit Breaker Metrics Dead letters Sending box Redis MySQL Couchbase Dead letters Received box Last sent timestamp Kafka Offset Manager Message Managements • Metrics • Recovery / Retry • Deadletter handling
  • 67. 4. Audit Tool • 상품 정보 Audit System • developers : 1 senior, 2 junior developer • Software stack • React • Spring Boot 1.5 on Vitamin Framework • jOOQ (향후 requery로 변환 예정) • Pilot 로 시작, 개발자들의 노력으로 정식 시스템으로 승격
  • 68. 4. Audit Tool Kotlin Coroutines + Spring MVC
  • 69. 5. Creation Pipeline System • 상품 정보 생성 프로세스 관리 시스템 • Features • Workflow (Heavy use Kafka) • Asynchronous / Non-blocking System • Need High throughput
  • 71. 5. Creation Pipeline System Spring Boot 1.x Kafka 0.10.x Kotlin 1.2.x on JVM 8 Couchbase 4.x / Aurora Zookeeper 3.x
  • 72. %
  • 73. %
  • 75. 반성해야 하는 점 • 기본기 학습 - 닥치고 코딩 (X) • Java와 차이점 및 Kotlin best practices 검토 필요 • 첫 술에 배부를 수 없다 • 실망하지 말라, Refactoring 은 필수다 • Coroutines 에 대한 학습 및 테스트 • 어차피 비동기는 어렵다. • Coroutines는 하나의 방법일 뿐이다
  • 76. 안정적 도입을 위한 Tips • 충분한 학습 기회 & 실습 • Code Quality 중요성 인식 • Upsource 전사 활용 중 • 강력한 동기 부여 • Tech Leader의 지속적인 Leading & Coach • 성공 사례 만들기 (작은 것부터)
  • 77. 효과 • Safety Code • Readable Code • 성능 향상 • Latency 감소, High Throughput 달성 • Asynchronous/Non-Blocking 적용 용이 • 유지보수성 향상 (장애 감소)
  • 78. 언어별 Catalog Tribe 개발자 비율 (2017) 5% Kotlin 10% Scala 15% Java 70% Java Scala Kotlin Python 언어별 Catalog Tribe 개발자 비율 (2018 예상) 7% Kotlin 25% Scala 13% Java 55% Java Scala Kotlin Python
  • 79. Aurora Cassandra ElasticSearch ArangoDB JVM 8 Spring DataRequery JPA/Hibernate Virtualization kubernetes Docker Spring Framework 5.xKodein Kotlin Coroutines with Reactor / RxJava Services Kafka Redis Spring Boot 2.x Webflux with Netty Common Backend Stack (2018)
  • 81. Spring MVC + Cassandra Spring WebFlux + Cassandra Reactive 출처: Reactive Java Performance Comparison
  • 82. Resources • Kotlin Resources • kotlinx.coroutines • spring-kotlin-coroutine • 20 Excellent Resources for learning Kotlin • Books • Kotlin in action • Try Kotlin
  • 83.
  • 84. Q&A