training@instil.co
June 2019
© Instil Software 2019
The Three Horse Race
Picking a winner between Coroutines,
Reactive Streams and Effects
Develop	
Consult	
Train
Garth Gilmour
garth.gilmour@instil.co
6 years as a developer
15 as a coach / trainer
Eamonn Boyle
eamonn.boyle@instil.co
15 years as a developer
2 as a coach / trainer
About Your Presenters
We’ve bought into Kotlin in a big way
•  Also Android, React and Cloud
About Instil
About Instil
© Instil Software 2018
•  The High Level View
Part 1
Pure Functional Coding
DDD and Event Storming
Distributed Event Queues
Property Based Testing
Serverless Computing
Mob Programming
Welcome to the Future!
Do You Need All The Shiny Things?
Agility is no longer optional
Capability beats maturity
24 capabilities that include:
•  CICD and test automation
•  Loose coupling with small
teams & visible workflows
•  Culture of fast feedback &
learning by experiment
MTTR is the key metric
The Blueprint for the Next Decade
The Reactive Manifesto
The Reactive Manifesto
Evolving Architectures
Stage 1 - Monolith with Overlapping Subsystems
Stage 2 - Subsystems Become Microservices
Why Move to Microservices?
Stage 3 - Microservices Become Bounded Contexts
Order	
Id
Value
Commission
Payment Deadline
Delivery Date
Delivery Address
Volume
Weight
Order	
Id
Value
Commission
Payment Deadline
Order	
Id
Delivery Date
Delivery Address
Volume
Weight
Stage 3 - Microservices Become Bounded Contexts
Stage 3 - Microservices Become Bounded Contexts
Monoliths vs. Microservices
Total Monolith
(all types deployed together)
(one unit, millions of lines of code)
Pure Microservices
(all types deployed separately)
(many units, each less than 100 lines)
Microservice per
Bounded Context
Stage 3 - Microservices Become Micro J
Stage 3 - Microservices Become Micro
Stage 4a - Microservices Become Lambdas
Why Go Serverless?
Stage 4b - Microservices Live Within Lambdas
Stage 5 - The Whole Infrastructure Moves to Cloud
Stage 5 - The Whole Infrastructure Moves to Cloud
Configuration is everything
•  The platform handles scaling
Events are the new objects
•  The core building blocks
Code becomes just glue
•  That sticks together services
Functions are always stateless
•  Making FP the new paradigm
Principles of this Brave New World
Principles of this Brave New World
Events	
Configuration
Stage 5 - Cloud Architecture with ‘Virtual Components’
The Problem This Produces…
© Instil Software 2018
•  The Low Level
Part 2
There’s An Awful Lot to Choose From…
It May Feel Like This…
The TornadoFX Library and DSL
The TornadoFX UI For Our Demo…
Reactive Streams
Reactive Streams are defined as observable sequences
•  Components act as publishers and/or subscribers
Observables share traits with both Iterators and Promises
•  Iterators pull values synchronously (via ‘next’)
•  Promises are pushed a single value (via ‘then’)
•  Observables are pushed many items (via ‘subscribe’)
Introducing Observables
Single	Invocation	 Multiple	Invocations	
Pulling	Value(s)	
(Synchronous)	
Option	(aka	Maybe	)	
Try	in	Scala	etc…	
Iterator	
Pushing	Value(s)	
(Usually	Asynchronous)	
Promise	
(aka	Future	&	IOU)	
Observable
The Reactive Streams Specification
Marble diagrams are used to describe observable sequences
•  Horizontal arrows denote streams over time
•  Marbles denote data flowing through the stream
•  Applying an operator produces a new stream
Introducing Marble Diagrams
6 1 6 54
6 64
3 32
.filter(x -> x % 2 == 0)
.map(x -> x / 2)
Introducing Marble Diagrams
Introducing Project Reactor
The methods for building streams can be divided into:
•  Methods for building streams from existing data
•  Such as ‘just’, ‘fromArray’ and ‘fromIterable’
•  Methods for building streams programmatically
•  Such as ‘generate’ and ‘create’
The implementation is concurrency agnostic
•  It does not force you to use a particular threading model
•  Both producers and consumers can be single or multi threaded
A ‘Scheduler’ controls the threading models in use
•  The ‘publishOn’ and ‘subscribeOn’ methods determine the
threading models used at either end of the stream
Way to Build Reactive Streams
Method	Name	 Description	
empty	 Creates	a	stream	that	completes	without	emitting	any	items	
just	 Creates	a	stream	that	emits	one	or	more	items	
			NB	If	you	pass	in	an	array	then	it	is	emitted	as	the	single	item	
fromIterable	 Creates	a	stream	that	emits	the	items	from	a	‘java.lang.Iterable’	
fromArray	 Creates	a	stream	that	emits	the	items	from	a	Java	array	
				NB	You	may	need	to	convert	a	Kotlin	/	Scala	Array	to	Java	
generate	 Creates	a	stream	via	a	call-back	function	and	some	state	
create	 Creates	a	stream	via	a	call-back	function	
repeat	 Creates	a	new	stream	by	repeatedly	subscribing	to	an	existing	one	
mergeWith	 Interleaves	the	current	stream	with	another	one	
concatWith	 Concatenates	the	output	of	another	stream	with	the	current	one	
Some Different Ways to Build Reactive Streams
fun	main(args:	Array<String>)	{	
				val	loremIpsum	=	"""Lorem	ipsum	dolor	sit	amet,	consectetur	adipiscing	
																								elit,	sed	do	eiusmod	tempor	incididunt	ut	labore	et	
																								dolore	magna	aliqua.	Ut	enim	ad	minim	veniam,	quis	
																								nostrud	exercitation	ullamco	laboris	nisi	ut	aliquip	
																								ex	ea	commodo	consequat.	Duis	aute	irure	dolor	in	
																								reprehenderit	in	voluptate	velit	esse	cillum	dolore	
																								eu	fugiat	nulla	pariatur.	Excepteur	sint	occaecat	
																								cupidatat	non	proident,	sunt	in	culpa	qui	officia	
																								deserunt	mollit	anim	id	est	laborum."""	
	
				val	flux	=	Flux.fromIterable(loremIpsum.split("	"))	
				flux.map	{	it.toLowerCase()	}	
								.flatMap	{	word	->	Flux.fromArray(word.toCharArray()	
	.toTypedArray())	}	
								.filter	{	theChar	->	Character.isLetter(theChar)	}	
								.collectMultimap	{	it	}	
								.map	{	table	->	table.mapValues	{	entry	->	entry.value.size	}	}	
								.subscribe(::printTable)	
}	
Program.kt
Using Reactor To Process In-Memory Data
fun	printTable(input:	Map<Char,	Int>)	{	
				println("The	frequency	count	of	letters	in	'lorem	ipsum'	is:")	
				input.forEach	{	entry	->	
								val	msgWord	=	"instance"	+	if	(entry.value	>	1)	"s"	else	""	
								println("${entry.value}	$msgWord	of	${entry.key}")	
				}	
}	
The	frequency	count	of	letters	in	'lorem	ipsum'	is:	
29	instances	of	a	
3	instances	of	b	
16	instances	of	c	
19	instances	of	d	
38	instances	of	e	
3	instances	of	f	
3	instances	of	g	
1	instance	of	h	
42	instances	of	i	
22	instances	of	l	
17	instances	of	m	
24	instances	of	n	
29	instances	of	o	
11	instances	of	p	
...	
Using Reactor To Process In-Memory Data
@GetMapping(produces	=	["application/json"])	
fun	allCourses():	ResponseEntity<Collection<Course>>	{	
				return	if	(portfolio.isEmpty())	{	
								notFound().build()	
				}	else	{	
								ok(portfolio.values)	
				}	
}	
	
	
	
@GetMapping(produces	=	[MediaType.TEXT_EVENT_STREAM_VALUE])	
fun	allCourses():	ResponseEntity<Flux<Course>>		{	
				return	if	(portfolio.isEmpty())	{	
								notFound().build()	
				}	else	{	
								val	coursesFlux	=	Flux	
																.fromIterable(portfolio.values)	
																.delayElements(Duration.ofSeconds(1))	
								ok(coursesFlux)	
				}	
}	
CourseController.kt
Project Reactor in Our Demo (Server Side)
private	fun	buildEvent(course:	Course):	ServerSentEvent<Course>	{	
				return	ServerSentEvent.builder<Course>()	
												.id(course.id)	
												.event("an-course")	
												.data(course)	
												.build()	
}	
	
@GetMapping	
fun	allCourses():	ResponseEntity<Flux<ServerSentEvent<Course>>>	{	
				return	if	(portfolio.isEmpty())	{	
								notFound().build()	
				}	else	{	
								val	coursesFlux	=	Flux	
																.fromIterable(portfolio.values)	
																.map(::buildEvent)	
																.delayElements(Duration.ofSeconds(1))	
								ResponseEntity(coursesFlux,	OK)	
				}	
}	
	
CourseController.kt
Project Reactor in Our Demo (Server Side)
private	fun	loadAllCoursesAsyncReactor()	{	
				courses.clear()	
				reactiveController.loadAllCourses	{	course	->	
								Platform.runLater	{	
												courses.add(course)	
								}	
				}	
				showSelectedCourse.value	=	false	
}	
	
//from	ReactiveCoursesController	
fun	loadAllCourses(action:	(Course)	->	Unit)	{	
				webClient.get()	
								.exchange()	
								.subscribe	{	response	->	
												response.bodyToFlux(Course::class.java)	
																.subscribe(action)	
								}	
}	
CourseBookingView.kt
Project Reactor in Our Demo (Client Side)
Reactive is the right choice
•  When processing huge
volumes of information
•  When you have to manage
1000s of connections
But is requires you have
•  Enough technical expertise
•  A genuine business need
The dangers are
•  Needlessly complex code
•  Fragmented business logic
•  Obscured problem domain
The Verdict…
A Great Overview of Issues
Coroutines
“Coroutines are computer-program
components that generalize subroutines for
non-preemptive multitasking, by allowing
multiple entry points for suspending and
resuming execution at certain locations.”
Wikipedia
Coroutine
Lets assume we need to read and process multiple values
•  We may need to interleave reading and processing
•  Coroutines can perform this interleaving for us
The functionality is mostly provided by a library
•  The only exception is the new suspend keyword
Understanding Coroutines
1 2 3 4 5 6 7 1 2 3 4 5 6 7
Reading Function
Processing Function
1 1 2 2 3 3 4 4 5 5 6 6 7 7
button("Load	Async	Via	Coroutines")	{	
				action	{	
								GlobalScope.launch(Dispatchers.Main)	{	
												loadAllCoursesAsyncCoroutines()	
								}	
				}	
}	
	
private	suspend	fun	loadAllCoursesAsyncCoroutines()	{	
				courses.clear()	
				coroutineController.loadAllCourses(courses)	
				showSelectedCourse.value	=	false	
}	
CourseBookingView.kt
Coroutines in Our Demo (Client Side)
What	
happens	
here?
private	suspend	fun	addCourse(courses:	ObservableList<Course>,	
																							 	event:	InboundSseEvent)	{	
				withContext(Dispatchers.Main)	{	
								val	course	=	event.readData(Course::class.java,		
	 	APPLICATION_JSON_TYPE)	
								courses.add(course)	
				}	
}	
	
suspend	fun	loadAllCourses(courses:	ObservableList<Course>)	{	
	
				withContext(Dispatchers.IO)	{	
								val	target	=	client.target(baseURL)	
								val	input	=	target.request().get(EventInput::class.java)	
								while(!input.isClosed)	{	
												val	sseEvent	=	input.read()	
												if(sseEvent	!=	null)	{	
																addCourse(courses,	sseEvent)	
												}	
								}	
				}	
}	
	
CoroutineCoursesController.kt
Coroutines in Our Demo (Client Side)
Kotlin Flows
Combining Coroutines and WebFlux
@GetMapping(value	=	["/{id}"],	produces	=	["application/json"])	
fun	singleCourse(@PathVariable("id")	id:	String):		
	ResponseEntity<Mono<Course>>	{	
				val	course	=	portfolio[id]	
				return	if	(course	!=	null)	{	
								ok(Mono.just(course))	
				}	else	{	
								notFound().build()	
				}	
}	
	
@GetMapping(value	=	["/{id}"],	produces	=	["application/json"])	
suspend	fun	singleCourse(@PathVariable("id")	id:	String):		
	ResponseEntity<Course>	{	
				val	course	=	portfolio[id]	
				return	if	(course	!=	null)	{	
								ok(course)	
				}	else	{	
								notFound().build()	
				}	
}	
CourseController.kt
Coroutines in Our Demo (Server Side)
@GetMapping(produces	=	[MediaType.TEXT_EVENT_STREAM_VALUE])	
fun	allCourses():	ResponseEntity<Flux<Course>>		{	
				return	if	(portfolio.isEmpty())	{	
								notFound().build()	
				}	else	{	
								val	coursesFlux	=	Flux	
																.fromIterable(portfolio.values)	
																.delayElements(Duration.ofSeconds(1))	
								ok(coursesFlux)	
				}	
}	
CourseController.kt
Coroutines in Our Demo (Server Side)
@GetMapping(produces	=	[MediaType.TEXT_EVENT_STREAM_VALUE])	
fun	allCourses():	ResponseEntity<Flow<Course>>	{	
				return	if	(portfolio.isEmpty())	{	
								notFound().build()	
				}	else	{	
								val	coursesFlow	=	flow	{	
												portfolio.values.forEach	{	course	->	
																delay(1)	
																emit(course)	
												}	
								}	
								ok(coursesFlow)	
				}	
}	
CourseController.kt
Coroutines in Our Demo (Server Side)
Java and Project Loom
Coroutines are
•  A well proven technology
•  Soon to become ubiquitous
•  The simplest possible
solution for juggling calls
The coding model is good
•  It adds the least possible
cognitive burden to code
•  IDEs can provide a lot of
help to mitigate this
Not always the right choice
•  Reactive streams are a
better option for parallelism
The Verdict…
Effects
FP contains a contradiction
•  You cannot be both pure and useful
We want to write functions which are:
•  Total (work for every input)
•  Pure (have no side-effects)
•  Deterministic (will always return the
same output for the same inputs)
But then a program can’t do anything
•  Since any form of IO is ruled out
A solution is to move IO ‘to the edges’
•  Using the IO Monad and Effects
•  Effects work as ‘lazy coroutines’
Introducing Effects
Effects and Arrow Fx
fun	putStrLn(s:	String):	IO<Unit>	=	IO	{	println(s)	}	
	
fun	getStrLn():	IO<String>	=	IO	{	readLine()	?:	""	}	
	
fun	nextInt(upper:	Int):	IO<Int>	=	IO	{		
				utilRandom().nextInt(upper)		
}	
	
fun	commandLoop(state:	List<String>):	IO<Unit>	=	fx	{	
		!printMenu()	
	
		val	choice	=	!getStrLn()	
		val	command	=	Command(choice)	
		val	newState	=	!processCommand(command,	state)	
	
		if	(command	is	Quit)	Unit	
		else	!commandLoop(newState)	
	
}.handleErrorWith	{	t	->	
		fx	{	
				!putStrLn(t.message	?:	"unknown	error")	
				!commandLoop(state)	
		}	
}	
Program.kt
Using Arrow FX
The Cats and Scalaz Libraries
A Great Introduction
Effects are innovative
•  They require that we
change the way we think
They have clear benefits
•  The Pure FP style solves
many issues En Passant
•  You can run effects on top
of any parallel environment
But the risks are great
•  Its unproved technology
•  Will it prove viable for the
majority of coding shops?
The Verdict…
© Instil Software 2018
•  What Are Your Options?
Conclusions
Reactive	 Coroutines	 Effects	 Spring	Boot	 Ktor	
Reactive	
	
	
Coroutines	
	
	
Effects	
	
	
Spring	Boot	
	
	
Ktor	
	
	
What Goes With What?
Any Questions?
Thank You and Farewell!

The Three Horse Race