Reactive Microservices in Kotlin

With Spring Framework 5 and Spring Boot 2.0

Juan Antonio Medina Iglesias

Hello, I'm Juan Medina

a software engineer that just released a book about creating Microservices in Kotlin

I've been coding since I was 10

when I learned BASIC and Z80 Assembler

Three years ago I was a manager

that was only coding on my own personal time

I was disconnected from technology

except Excel, PowerPoint and Word

Transformation was happening

and I was not ready

Research time

Forums, Github, twitter, Stackoverflow, YouTube

Conversations

Yammer, Slack, Tech talks, Conferences & a lot of coffee

Opportunity

solutioning and innovation

Building

a cloud native application

Upgrading coding skills

refreshing and learning technologies

Learning by Example

https://github.com/LearningByExample

Blog and Articles

https://juan-medina.com

Kotlin mainstream language

  • Google's support for Kotlin in Android
  • Spring Framework 5 Kotlin extensions
  • Reactor Kotlin extensions
  • Spark Kotlin support

Learning Kotlin

Microservices, Reactive, Native, Serverless

Packt Publishing want a book

about Microservices in Kotlin

Writing a book

is a life changing experience

There is never enough feedback

at least until you get more feedback

Finally the book is done done

or did I mean done done done?

https://www.packtpub.com/web-development/microservices-kotlin

What I have learned

If you really want it, you can do it.

Why a book about Kotlin?

What is Kotlin

  • A programming language
  • Created by JetBrains
  • Strong Typed
  • C++/Java looks-like
  • Concise
  • Not a paradigm shift
  • Modern constructs
  • LLVM compiler

Can produce code for

  • JVM
  • JavaScript
  • Native
    • applications
    • imports/export C libraries
    • WebAssembly
  • Cross platform modules

What it looks like

fun main(args : Array<String>) {
  println("Hello, world!")
}

Kotlin provides several features

let's review some of them

Null Safety

var a: String = "abc"
a = null // compilation error

var b: String? = "abc"
b = null // ok

val l = b?.length ?: -1

Object Oriented

class Greeter(val name: String) {
   fun greet() {
      println("Hello, $name")
   }
}

fun main(args: Array<String>) {
   Greeter(args[0]).greet()
}

Type inference

val a = "abc"
val b = 1

fun getData() : String {
	return "hello world"
}

val c = getData()
print(c) // will print "hello world"

fun getData() : Customer {
	return Customer(1, "super customer") //a class that have id, name
}
print(c) // will print "Customer(id=1, name=super customer)"

Single expression functions

fun sum(a : Int, b : Int) : Int = a + b

fun sum2(a : Int, b : Int) = a + b

fun bigger(a : Int, b : Int) = if (a>b) a else b

val value = if (bigger(x, y)==x) z else 1-z

val other = when(getValue(x, y)){
	0, 1 -> 0
	-1 -> y
	else -> x
}

Default and named arguments

fun displayBorder(character: Char = '=', length: Int = 15) {
  for (i in 1..length) {
    print(character)
  }
  println("")
}

fun main(args : Array<String>) {
  displayBorder()           //print: ===============
  displayBorder('*')        //print: ***************
  displayBorder('*', 5)     //print: *****
  displayBorder(length = 2) //print: ==
}

Data classes

//  - equals() / hashCode()
//  - toString() of the form "User(name=John, age=42)"
//  - copy()
//  - componentN() : component1() = name, component2() = age
data class User(val name: String = "", val age: Int = 0)

val user = User("John", "42")
val olderUser = user.copy(age=50);

val name, age = user;

fun getUser() = User("John", "42")

val userName, userAge = getUser()

Extensions functions

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}

val l = mutableListOf(1, 2, 3)
l.swap(0, 2) // the list will be (3, 2, 1)

Lambdas

val strings = listOf("hello", "I'm", "a list", "of", "strings")

strings.filter {
	value : String -> value.length > 3
}.forEach{ value : String -> println(value) }

strings.filter{
	value -> value.length > 3
}.forEach{ value -> println(value) }

strings.filter { it.length > 3 }.forEach(::println)

Type-Safe builders

fun result(args: Array<String>) =
	house {
		rooms {
			room {
				person {+"Lonley"}
			}
			room  {
				person {
					for (arg in args)
						+arg
				}
		}
	}

They are dozen more features

for more details visit: https://kotlinlang.org/

Kotlin vs Java

https://juan-medina.com/2017/06/04/reactive-kotlin-vs-java/

Comparing two identical projects:
Lines of Code Source Tests
Java 1004 1172
Kotlin 721 1017
Complexity Max
Java 45
Kotlin 8
reported by https://codebeat.co
createResult() Java vs Kotlin
  Mono<SunriseSunset> createResult(final Mono<GeoTimesResponse> geoTimesResponseMono) {
      return geoTimesResponseMono.flatMap(geoTimesResponse -> {
          if ((geoTimesResponse.getStatus() != null) && (geoTimesResponse.getStatus()
              .equals(STATUS_OK))) {
              return Mono.just(new SunriseSunset(geoTimesResponse.getResults().getSunrise(),
                      geoTimesResponse.getResults().getSunset()));
          } else {
              return Mono.error(new GetSunriseSunsetException(SUNRISE_RESULT_NOT_OK));
          }
      });
  }
  open internal fun createResult(geoTimesResponseMono: Mono<GeoTimesResponse>) =
    geoTimesResponseMono.flatMap {
        with(it){
            if (status == STATUS_OK) with(results) { SunriseSunset(sunrise, sunset).toMono() }
            else GetSunriseSunsetException(SUNRISE_RESULT_NOT_OK).toMono()
        }
    }
Kotlin is not only about shortening our code, is about reducing the boilerplate, making our code more comprehensible and easier to maintain

And as a bonus we can take our code to other platforms

Reactive Revolution

Everyone wants a reactive Framework



And these are just the most populars

Reactive Manifesto

We believe that a coherent approach to systems architecture is needed, and we believe that all necessary aspects are already recognised individually: we want systems that are Responsive, Resilient, Elastic and Message Driven. We call these Reactive Systems.
https://www.reactivemanifesto.org/

What is a reactive system

A system that process asynchronously a stream of data with non-blocking back pressure.

non-reactive system


CLIENT SERVER DATABASE

  • The client waits until everything is completed
  • No more requests can be handle in this thread
  • This is a blocking operation

reactive system


CLIENT SERVER DATABASE

  • The client get data as soon as is available
  • We could process far more requests
  • Client and server are free to other tasks
  • This is a non-blocking operation
Raw performance Spring Boot 1 vs 2
https://dzone.com/articles/raw-performance-numbers-spring-boot-2-webflux-vs-s

If software is eating the world

thinking reactively: it will not be eaten in a single bite

Creating a Reactive Microservice

Prerequisites

  • JDK 1.8+
  • MongoDB 3.4+ (running on localhost:27017)
  • Any IDE such: Intellij IDEA Community Edition

Initialize some data

customers.json
{ "_id": 1, "name": "Kotlin"}
{ "_id": 2, "name": "Reactive"}
{ "_id": 3, "name": "Microservices" }
run from command line
$ mongoimport --collection customers --drop --file customers.json
Spring Initializr https://start.spring.io/
Run it
$ mvnw spring-boot:run
INFO 1792 --- [localhost:27017] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:1, serverValue:1}] to localhost:27017
INFO 1792 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
INFO 1792 --- [           main] c.j.m.R.ReactiveKotlinApplicationKt      : Started ReactiveKotlinApplicationKt in 3.351 seconds (JVM running for 3.721)
Customer Class
package com.juan.medina.ReactiveKotlin

data class Customer(var id : Int = 0, var name : String = "")
Creating a repository
@Repository
class CustomerRepository(private val template: ReactiveMongoTemplate) {
  fun findById(id: Int) = template.findById<Customer>(id)
  fun getAll() = template.findAll<Customer>()
}
Mono vs Flux
fun findById(id: Int) = template.findById<Customer>(id)
fun getAll() = template.findAll<Customer>()
template.findbyId returns a Mono<Customer>
template.findAll returns a Flux<Customer>

Mono is a promise of a value, that when is ready will be published to who is subscribe to that Mono. Flux is a promise of multiple values
Creating a Handler
@Component
class CustomerHandler(val customerRepository: CustomerRepository) {
  fun getCustomer(serverRequest: ServerRequest) = ServerResponse.ok()
      .body<Customer>(customerRepository.findById(serverRequest.pathVariable("id").toInt()))

  fun getAllCustomers(serverRequest: ServerRequest) = ServerResponse.ok()
      .body<Customer>(customerRepository.getAll())
}
Everything is reactive
ServerResponse.ok().body<Customer>(Mono<Customer>)
ServerResponse.ok().body<Customer>(Flux<Customer>)
ServerResponse.ok().body returns a Mono<ServerResponse>
that Mono<ServerResponse> is subscribed to a Mono<Customer> or Flux<Customer>

WebFlux will be subscribed to the Mono<ServerResponse>, a promise of a response that is subscribed to a promise of results of the database
Creating a Router
@Component
class CustomerRouter(val customerHandler: CustomerHandler) {
  @Bean
  fun customerRoutes() = router {
    "/customer".nest {
      GET("/{id}", customerHandler::getCustomer)
      GET("/", customerHandler::getAllCustomers)
    }
  }
}
Navigating to our server http://localhost:8080/customer/1
{
	"id" : 1,
	"name" : "Kotlin"
}
http://localhost:8080/customer
[
	{"id": 1, "name" : "Kotlin"},
	{"id": 2, "name" : "Reactive"},
	{"id": 3, "name" : "Microservice"}
]

Now we have a reactive REST API

that uses MongoDB reactively

This complete example and the presentation is available at
https://github.com/juan-medina/ReactiveKotlin

Q & A


 @JuanMedinaCode
 jamedina@gmail.com
 https://juan-medina.com
 https://github.com/juan-medina

This quote will be the only part of this presentation you remember
xxcd