Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Haim Yadid
Building Microservices with Kotlin
Disclaimer
• The purpose of this talk is to share our experience and
with Kotlin not to teach the language syntax. I will ...
About Me
• Developing software since 1984 (Boy, am I getting old?)
• Basic -> Pascal -> C -> C++ -> Java -> Kotlin
• Devel...
• Founded in the Beginning of 2016
• Disrupt the small businesses insurance field
• Providing online experience which is si...
Lookingforalanguage
JVM Languages
Java Scala Clojure
Groovy/
JRuby
Java8
Strongly

Typed
Loosely

Typed
OO/verbose Functional/Rich
)))))))))))...
JVM Languages
Java Scala
Groovy/
JRuby
Java8
Strongly

Typed
Loosely

Typed
OO/verbose Functional/Rich
Clojure))))))))))))...
What is Kotlin ?
• Strongly typed programming language
• For the JVM, Android and the browser (JS)
• 100% interoperable wi...
Kotlin Design Goals
• Concise
• Safe
• Versatile
• Practical
• Interoperable
Bottom Line
HugeSuccess
Kotlin Adoption
• Android official language
• 9 talks in JavaOne 2017
• Community enthusiasm ( hype ?)
We use Kotlin for
• Building our backend micro-services over DropWizard
(deployed to AWS)
• Building serverless endpoints ...
Kotlin version upgrade
• Started at 1.0.2
• Upgraded to every release of Kotlin immediately
• Migration to 1.1.0 ( Java8 s...
Onboarding
• Onboarding of new Java developers proved to be
smooth
• Java developers are capable to developing in Kotlin o...
Java Ecosystem
Java Ecosystem
• Java open source libraries works well with Kotlin.
• Just add the dependency to you build file and you are...
Kotlin Primitives
• kotlin.Int => int
• kotlin.Double => double
• kotlin.String => java.lang.String
Collections
• kotlin.HashMap = java.util.LinkedHashMap
• Underlying Java collections
• Maps and lists can be either mutabl...
Collections
val heros = mapOf("Terion" to "Lannister", "John" to "Snow")

heros["Terion"]
val chars2 = mutableMapOf<String...
Dropwizard AWS Lambda (Java)
Third Party Libraries
KotlinJDK8
log4jJersey
RDS (mysql)
JettyJackson
logback
Jackson
Jersey
...
Dropwizard AWS Lambda (Java)
Third Party Libraries
KotlinJDK8
log4jJersey
RDS (mysql)
JettyJackson
logback
Jackson
Jersey
...
Mockito Kotlin
• when -> `when` -> whenever
• Solve Null safety issues with any()
• DSL like syntax using Lambda expressio...
Project organization
• Build with kotlin-maven plugin
• Same source paths as java
• src/main/java
• src/test/java
• Depend...
Extension Functions
Extension functions
• Add functionality to a class w/o inheritance
• Only extend functionality cannot override members
• N...
ResultSet null values
• When querying a java.sql.ResultSet for a value that is
nullable
• getLong will return 0 when the v...
Measuring endpoint duration
• Write endpoint duration to log entries
• ES/Kibana (we use logz.io)
• When we report our dat...
Measuring endpoint duration
fun Logger.infoWithDuration(message: String,
vararg additionalArgs: Any){
loggerActionWithDura...
loggerActionWithDuration
inline fun Logger.loggerActionWithDuration(action: () -> Unit){
updateDurationMDCValue()
action.i...
Calculating endpoint duration
• store on MDC the transaction start time
• in this method we store the the duration from st...
Request Filter
class DurationStartFilter : ContainerRequestFilter {
override fun filter(requestContext: ContainerRequestCo...
Response Filter
class DurationFilter : ContainerResponseFilter {
val logger: Logger = LoggerFactory.getLogger(DurationFilt...
Null Safety
Null Safety
• Nullability part of the type of an object
• Option[T] Optional<T>
• Swift anyone ?









var msg : String...
Safe operator ?.
• The safe call operator ?. will result null on null receiver
• Elvis operator for default











fun...
Bang Bang !!
• The bang bang !! throws an NPE if object is null



fun funny(funnier: String?): String {

return funnier!!...
Null Pollution
• It is really easy to pollute our code with nulls
• Java code is not handling nulls properly
• map.get() o...
Require
• Our own implementation
• Extension function
• Throws a clearer exception
fun <T> Map<String, T>.require(key: Str...
getValue
• Since Kotlin 1.1
• Throws a Descriptive NoSuchElementException which
includes key name
val value = mappy.getVal...
Delegate by map
data class Person(val firstName: String,
val lastName: String,
var props: MutableMap<String, String>) {
va...
JSON Serialization
Microservices Talk
• Over HTTP
• JSON serialization













{ “firstName”: “Eddard”,
“lastName” : “Stark” }
Service

...
DTOs
• Getter and setters for all fields
• Implementation of
• Implemented hashcode() equals()
• copy()
• destructuring (co...
Evolution Season 1 Episode 9
• Adding a field should not be a breaking change
• Ability to deserialize
• With missing field
...
jackson-module-kotlin
• Introduces an introspection which do not need
annotations for most cases
• Nullable represents opt...
Delegate by map
data class Person(val firstName: String,
val lastName: String,
var props: MutableMap<String, String>) {
@g...
Inline / Reified
execution_statuses Table
id name
1 success
2 referral
3 technical_error
4 decline
6 renewal
Enum
enum class ExecutionStatuses(
override val id: Int,
override val dbName: String) : DBEnum {
SUCCESS(1, "success"),
RE...
DBEnum
interface DBEnum {
val id: Int
val dbName: String
companion object {
inline fun <reified T> fromId(id: Int): T wher...
Integration Test
inline fun <reified T> verifyValuesAreConsistent(dbIdToName:
MutableMap<Int, String>) where T : Enum<T>, ...
Integration Test DSL
TestStage
abstract class TestStage<out T> {
lateinit var testIT: UnderwritingCycleTest
lateinit var testDataSet: TestDataS...
Test
@Ignore
@Test
fun e2eFlowWithCarrierTennesseeState() {
val testDataSet = TestDataSet.build(this, PartnerTestData) {
o...
Lorem Ipsum Dolor
Questions?
Upcoming SlideShare
Loading in …5
×

Building microservices with Kotlin

3,996 views

Published on

Next Insurance was founded at the beginning of 2016, and the first lines of its production code started accumulating in May 2016. As the first back-end developer, I started writing in Java and out of curiosity was experimenting with Kotlin. Kotlin had just seen its 1.0 release two months earlier. A year later, Next Insurance’s entire back-end development team is writing all the code in Kotlin. We already have 8 microservices and several AWS lambda functions all written in Kotlin. Migration from 1.0.x to Kotlin 1.1 was smooth, and the developers are happy. This presentation covers the language’s features and why I think it is awesome and fits perfectly with my company’s architecture.

Published in: Technology
  • Login to see the comments

Building microservices with Kotlin

  1. 1. Haim Yadid Building Microservices with Kotlin
  2. 2. Disclaimer • The purpose of this talk is to share our experience and with Kotlin not to teach the language syntax. I will delve into some details for for the basics just go to the documentation (https://kotlinlang.org/docs/reference/) • While comparison between Kotlin and Scala is tempting this will not be the focus of the talk.
  3. 3. About Me • Developing software since 1984 (Boy, am I getting old?) • Basic -> Pascal -> C -> C++ -> Java -> Kotlin • Developer , architect, group manager • Independent performance expert for 8 years • Head of backend engineering in Drakaris
  4. 4. • Founded in the Beginning of 2016 • Disrupt the small businesses insurance field • Providing online experience which is simple, fast and transparent • HQ@Palo Alto RnD@Kfar Saba (Israel) • We started to write real code on May 2016
  5. 5. Lookingforalanguage
  6. 6. JVM Languages Java Scala Clojure Groovy/ JRuby Java8 Strongly
 Typed Loosely
 Typed OO/verbose Functional/Rich )))))))))))))))))))))))) Ceylon
  7. 7. JVM Languages Java Scala Groovy/ JRuby Java8 Strongly
 Typed Loosely
 Typed OO/verbose Functional/Rich Clojure)))))))))))))))))))))))) Ceylon Kotlin
  8. 8. What is Kotlin ? • Strongly typed programming language • For the JVM, Android and the browser (JS) • 100% interoperable with Java™ (well almost) • Developed by JetBrains • Revealed as an open source in July 2011 • v1.0 Release on Feb 2016 • 1.1.51 current stable version (as of 28-Sep-2017) • 1.2 is in EA
  9. 9. Kotlin Design Goals • Concise • Safe • Versatile • Practical • Interoperable
  10. 10. Bottom Line
  11. 11. HugeSuccess
  12. 12. Kotlin Adoption • Android official language • 9 talks in JavaOne 2017 • Community enthusiasm ( hype ?)
  13. 13. We use Kotlin for • Building our backend micro-services over DropWizard (deployed to AWS) • Building serverless endpoints (AWS Lambda) 
 
 
 8 micro services 12 Lambda functions 120K lines of Kotlin code 5K lines of Java code
  14. 14. Kotlin version upgrade • Started at 1.0.2 • Upgraded to every release of Kotlin immediately • Migration to 1.1.0 ( Java8 support ) was smooth • No breaking changes so far (for us) • Now on 1.1.51
  15. 15. Onboarding • Onboarding of new Java developers proved to be smooth • Java developers are capable to developing in Kotlin on the same pace they are able to understand the architecture
  16. 16. Java Ecosystem
  17. 17. Java Ecosystem • Java open source libraries works well with Kotlin. • Just add the dependency to you build file and you are done
  18. 18. Kotlin Primitives • kotlin.Int => int • kotlin.Double => double • kotlin.String => java.lang.String
  19. 19. Collections • kotlin.HashMap = java.util.LinkedHashMap • Underlying Java collections • Maps and lists can be either mutable and immutable • “Immutability” = immutable view (Compromise)
  20. 20. Collections val heros = mapOf("Terion" to "Lannister", "John" to "Snow")
 heros["Terion"] val chars2 = mutableMapOf<String,String>()
 chars2["A girl"] = "has no name" val sigils = [“Direwolf", "Lion", “Three headed Dragon", “Flower"]
 println(sigils[0]) heros[“Aria"] = “Stark"
  21. 21. Dropwizard AWS Lambda (Java) Third Party Libraries KotlinJDK8 log4jJersey RDS (mysql) JettyJackson logback Jackson Jersey client PDF box Flyway Dropwizard
 Swagger Stripe- java XMPBox guava Jersey client JUnit Mockito*JDBI
  22. 22. Dropwizard AWS Lambda (Java) Third Party Libraries KotlinJDK8 log4jJersey RDS (mysql) JettyJackson logback Jackson Jersey client PDF box Flyway Dropwizard
 Swagger Stripe- java XMPBox guava Jersey client JUnit MockitoJDBI Mockito
 Kotlin
 *
  23. 23. Mockito Kotlin • when -> `when` -> whenever • Solve Null safety issues with any() • DSL like syntax using Lambda expressions
  24. 24. Project organization • Build with kotlin-maven plugin • Same source paths as java • src/main/java • src/test/java • Dependency management : • kotlin-stdlib • kotlin-reflect • kotlin-stdlib-jre7 • kotlin-stdlib-jre8

  25. 25. Extension Functions
  26. 26. Extension functions • Add functionality to a class w/o inheritance • Only extend functionality cannot override members • Not part of the class • Static methods with the receiver as first a parameter • (Not like ruby monkey patching )
 
 fun String.paperWrap = “[$this]” “hello”.paperWrap
 -> “[hello]”
  27. 27. ResultSet null values • When querying a java.sql.ResultSet for a value that is nullable • getLong will return 0 when the value is null and you are expected to invoke wasNull afterwards fun ResultSet.getNullableLong(colName: String): Long? { val value = this.getLong(colName) return if (this.wasNull()) null else value }
  28. 28. Measuring endpoint duration • Write endpoint duration to log entries • ES/Kibana (we use logz.io) • When we report our data to we have duration field for every endpoint invocation.
  29. 29. Measuring endpoint duration fun Logger.infoWithDuration(message: String, vararg additionalArgs: Any){ loggerActionWithDuration { if (additionalArgs.isNotEmpty()) info(message,*additionalArgs) else info(message) } }
  30. 30. loggerActionWithDuration inline fun Logger.loggerActionWithDuration(action: () -> Unit){ updateDurationMDCValue() action.invoke() MDC.remove(MDC_DURATION_KEY) }
  31. 31. Calculating endpoint duration • store on MDC the transaction start time • in this method we store the the duration from start on MDC as well
 fun Logger.updateDurationMDCValue() { val startTimestampMDCValue = MDC.get(MDC_TRANSACTION_START_TS_KEY) if(startTimestampMDCValue!=null){ val startTimestamp = startTimestampMDCValue.toLong() val requestDuration = now() - startTimestamp MDC.put(MDC_DURATION_KEY, requestDuration.toString()) } }
  32. 32. Request Filter class DurationStartFilter : ContainerRequestFilter { override fun filter(requestContext: ContainerRequestContext) { val transStartTS = now() MDC.put(MDC_TRANSACTION_START_TS_KEY, transStartTS.toString()) } }
  33. 33. Response Filter class DurationFilter : ContainerResponseFilter { val logger: Logger = LoggerFactory.getLogger(DurationFilter::class.java) override fun filter(containerRequestContext: ContainerRequestContext?, containerResponseContext: ContainerResponseContext?) { logger.infoWithDuration("Request processing finished.") } }
  34. 34. Null Safety
  35. 35. Null Safety • Nullability part of the type of an object • Option[T] Optional<T> • Swift anyone ?
 
 
 
 
 var msg : String = "Welcome"
 msg = null val nullableMsg : String? = null
  36. 36. Safe operator ?. • The safe call operator ?. will result null on null receiver • Elvis operator for default
 
 
 
 
 
 fun funny(funnier: String?): Int? {
 
 println(x?.length ?: "")
 return x?.length
 }
  37. 37. Bang Bang !! • The bang bang !! throws an NPE if object is null
 
 fun funny(funnier: String?): String {
 return funnier!!
 }
  38. 38. Null Pollution • It is really easy to pollute our code with nulls • Java code is not handling nulls properly • map.get() or the [] shortcut possibly return null • map[“key”]!! with throw KotlinNullPointerException
  39. 39. Require • Our own implementation • Extension function • Throws a clearer exception fun <T> Map<String, T>.require(key: String, allowEmpty: Boolean = false): T { val value = this[key] ?: throw IllegalArgumentException("Required aMap["$key"] is missing. aMap.size = ${this.size}") if (!allowEmpty) { if (value is String) { if (value.isEmpty()) { throw IllegalArgumentException("Required aMap["$key"] is empty. aMap.size = ${this.size}") } } } return value }
  40. 40. getValue • Since Kotlin 1.1 • Throws a Descriptive NoSuchElementException which includes key name val value = mappy.getValue("key")
  41. 41. Delegate by map data class Person(val firstName: String, val lastName: String, var props: MutableMap<String, String>) { var businessname: String by props val emailaddress: String by props }
  42. 42. JSON Serialization
  43. 43. Microservices Talk • Over HTTP • JSON serialization
 
 
 
 
 
 
 { “firstName”: “Eddard”, “lastName” : “Stark” } Service
 A Service
 Winterfell setLordOfWinterfell
  44. 44. DTOs • Getter and setters for all fields • Implementation of • Implemented hashcode() equals() • copy() • destructuring (component1 component2 …)
 
 
 data class Lord(val firstName: String, val lastName: String) val starkInWinterfellS1 = Lord(“Eddard”,”Stark”) val starkInWinterfellS2to3 = starkInWinterfell.copy(firstName = “Robb”) val (first,last) = starkInWinterfell
  45. 45. Evolution Season 1 Episode 9 • Adding a field should not be a breaking change • Ability to deserialize • With missing field • With additional field 
 
 
 
 Service
 A Service
 B { “firstName”: “Eddard”, “lastName” : “Stark”, “beheaded” : true } lordOfWinterfell
  46. 46. jackson-module-kotlin • Introduces an introspection which do not need annotations for most cases • Nullable represents optional
 data class Lord( val firstName: String, val lastName: String, val beheaded: Boolean?, ) ObjectMapper() .registerModule(KotlinModule()) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES,true)
  47. 47. Delegate by map data class Person(val firstName: String, val lastName: String, var props: MutableMap<String, String>) { @get:JsonIgnore val businessname: String by props @get:JsonIgnore val emailaddress: String by props } println(person.businessname)
  48. 48. Inline / Reified
  49. 49. execution_statuses Table id name 1 success 2 referral 3 technical_error 4 decline 6 renewal
  50. 50. Enum enum class ExecutionStatuses( override val id: Int, override val dbName: String) : DBEnum { SUCCESS(1, "success"), REFERRAL(2, "referral"), TECHNICAL_ERROR(3, "technical_error"), DECLINE(4, "decline"), RENEWAL(5, "renewal"); }
  51. 51. DBEnum interface DBEnum { val id: Int val dbName: String companion object { inline fun <reified T> fromId(id: Int): T where T : Enum<T>, T : DBEnum { return enumValues<T>().first { it.id == id } } inline fun <reified T> fromName(name: String): T where T : Enum<T>, T : DBEnum { return enumValues<T>().first { it.dbName == name } } } }
  52. 52. Integration Test inline fun <reified T> verifyValuesAreConsistent(dbIdToName: MutableMap<Int, String>) where T : Enum<T>, T : DBEnum { val enumValues = enumValues<T>() expect(dbIdToName.size).toBe(enumValues.size) dbIdToName.forEach { val dbId = it.key val dbName = it.value expect(DBEnum.fromId<T>(dbId).dbName).toBe(dbName) expect(DBEnum.fromName<T>(dbName).id).toBe(dbId) } }
  53. 53. Integration Test DSL
  54. 54. TestStage abstract class TestStage<out T> { lateinit var testIT: UnderwritingCycleTest lateinit var testDataSet: TestDataSet abstract fun construct(testIT: UnderwritingCycleTest, testDataSet: TestDataSet): T }
  55. 55. Test @Ignore @Test fun e2eFlowWithCarrierTennesseeState() { val testDataSet = TestDataSet.build(this, PartnerTestData) { overrideParam("state", "TN") } startFlow(testDataSet) .sendBusinessDetails() .screenRequest() .createQuoteSync() .preSelect() .select() .paySuccessWithoutBind() .bindFailure{ assertEquals(CarrierBindStatuses.MANUAL_STEPS_REQUIRED.dbName, this.carrierBindStatus) } }
  56. 56. Lorem Ipsum Dolor Questions?

×