SlideShare a Scribd company logo
© Instil Software 2020
Using Kotlin,
to Create Kotlin,
to Teach Kotlin,
in Space
Amy Crockett
Garth Gilmour
This is a Fusion Talk
We aim to tie together many threads
Kotlin Spring 5 Reactor
Space Automation DSLs
@GarthGilmour / garth.gilmour@instil.co
amy.crockett@instil.co
The Instil Team
The classroom is closed…
This caused us some anxiety…
We had to take our training virtual…
– Multiple Instructors
– Specialized Tools
– Flexible Hours
The Three Key Components
To Make Virtual Training Work
– The instructor works with the group
– By teaching, live coding etc…
– They proceed at the average pace
– The coach responds to queries
– Working with students at the extremes
– They ensure that no one is left behind
Multiple Trainers
Acting as Instructor and Coach
– We partitioned our material into 60 min blocks
– Allowing us to deliver a course to your timeline
– A delivery could take place over:
– A week's worth of mornings
– One day a week for six weeks
– Afternoon and evening sessions
Flexible Hours
Fitting Material Into Your Day
– Distributed teams already build software
– We can take advantage of their tooling
– We already do:
– Video-conferencing
– Messaging and Chats
– Collaborative Content
– Distributed Versioning
Specialized Tools
We Have The Technology
The Feedback Cycle
How do we support students?
The Feedback Cycle
How do we support students?
Enter Space…
We needed a ‘one size fits all’ solution…
Describing Space
A Simple Domain Model
Profiles Teams Projects Repos
Describing Space
A Simple Domain Model
Chats Reviews Issues Checklists
Calendars Meetings Absences To-Dos
The Space Playground
Using the API without security woes
Making a Start
Thank goodness for the Initializr
spring.security.oauth2.client.registration.FOO.aut
horization-grant-type=client_credentials
spring.security.oauth2.client.registration.FOO.cli
ent-id=ID_GOES_HERE
spring.security.oauth2.client.registration.FOO.cli
ent-secret=SECRET_GOES_HERE
spring.security.oauth2.client.registration.FOO.sco
pe=**
spring.security.oauth2.client.provider.FOO
.token-uri=URL_GOES_HERE
application.properties
Configuring OAuth
@Bean(name= ["OAuthWebClient"])
fun oauthWebClient(clientReg: ReactiveClientRegistrationRepository?)
: WebClient? {
val oauth = ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientReg,
UnAuthenticatedServerOAuth2AuthorizedClientRepository())
oauth.setDefaultClientRegistrationId(”FOO”)
return WebClient.builder()
.filter(oauth)
.baseUrl("https://SPACE_URL/api/http")
.build()
}
WebConfig.kt
Accessing Endpoints
@Bean(name= ["TokenWebClient"])
fun tokenWebClient() = WebClient
.builder()
.baseUrl("https://SPACE_URL/api/http")
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer TOKEN")
.build()
WebConfig.kt
Accessing Endpoints
Demo 1
Running the console app
– Create a specific instance for the course
– Add admin accounts for the 3 principal trainers
– Add a welcome blog post with setup instructions
– Create a project for examples / exercises (with repos)
– Create a private project for solutions (with repos)
– Create accounts for students with TODO lists
Making the Code Useful
What we need to do on each delivery…
package com.instil.maurice.dsl
fun instance(title: String = "An Instil Delivery",
action: SpaceInstance.() -> Unit)
= SpaceInstance(title).apply(action)
class SpaceInstance(val title: String) {
override fun toString() = title
}
Building the DSL – Iteration 1
val dsl = instance("Kotlin 101 for Megacorp") {
}
println(dsl)
Kotlin 101 for Megacorp
Building the DSL – Iteration 1
class SpaceInstance(val title: String) {
private lateinit var projects: Projects
private lateinit var profiles: Profiles
private lateinit var blogs: Blogs
override fun toString() = "$titlen$profilesn$projectsn$blogsn"
fun profiles(action: Profiles.() -> Unit)
= Profiles().apply(action).also { this.profiles = it }
fun projects(action: Projects.() -> Unit)
= Projects().apply(action).also { this.projects = it }
fun blogs(action: Blogs.() -> Unit)
= Blogs().apply(action).also { this.blogs = it }
}
Building the DSL – Iteration 2
class Profiles {
private val profiles = mutableListOf<Profile>()
fun profile(action: Profile.() -> Unit)
= Profile().apply(action).also { profiles.add(it) }
override fun toString()
= profiles.fold("Current profiles:") { state, profile ->
"$statent$profile"
}
}
Building the DSL – Iteration 2
class Profile {
lateinit var forename: String
lateinit var surname: String
lateinit var email: String
override fun toString() = "$forename $surname at $email"
}
Building the DSL – Iteration 2
val dsl = instance("Kotlin 101 for Megacorp") {
profiles {
profile {
forename = "Jane"
surname = "Smith"
email = "Jane.Smith@megacorp.com"
}
}
projects { }
blogs { }
}
println(dsl)
Kotlin 101 for Megacorp
Current profiles:
Jane Smith at
Jane.Smith@megacorp.com
com.instil.maurice.dsl.Projects@350b3a17
com.instil.maurice.dsl.Blogs@38600b
Building the DSL – Iteration 2
class Repo(private val location: URI) {
override fun toString() = "t$location"
}
Building the DSL – Iteration 3
class Project(val title: String) {
private val repos = mutableListOf<Repo>()
fun repo(location: URI, action: Repo.() -> Unit)
= Repo(location).apply(action).also { repos.add(it) }
override fun toString()
= repos.fold("Project $title with repos:") { state, repo ->
"$statent$repo"
}
}
Building the DSL – Iteration 3
class Projects {
private val projects = mutableListOf<Project>()
fun project(title: String, action: Project.() -> Unit)
= Project(title).apply(action).also { projects.add(it) }
override fun toString()
= projects.fold("Current projects:") { state, project ->
"$statent$project"
}
}
Building the DSL – Iteration 3
class Blogs {
private val blogs = mutableListOf<Blog>()
fun blog(title: String,
location: URI,
action: Blog.() -> Unit)
= Blog(title, location).apply(action).also { blogs.add(it) }
override fun toString()
= blogs.fold("Current blogs:") { state, blog ->
"$statent$blog"
}
}
Building the DSL – Iteration 3
class Blog(val title: String, val location: URI) {
private val additionalContent = mutableListOf<String>()
operator fun String.unaryPlus() = additionalContent.add(this)
override fun toString()
= additionalContent.fold("$titlentt$location") {
state, text ->
"$statentt$text"
}
}
Building the DSL – Iteration 3
val dsl = instance("Kotlin 101 for Megacorp") {
profiles {
profile {
forename = "Jane"
surname = "Smith"
email = "Jane.Smith@megacorp.com"
}
}
projects {
project("Kotlin Examples") {
repo(URI("http://somewhere.com")) {}
}
}
blogs {
blog("Welcome and Setup", URI("http://elsewhere.com")) {
+"Some additional client-specific content"
}
}
}
println(dsl)
Building the DSL – Iteration 3
Kotlin 101 for Megacorp
Current profiles:
Jane Smith at Jane.Smith@megacorp.com
Current projects:
Project Kotlin Examples with repos:
http://somewhere.com
Current blogs:
Welcome and Setup
http://elsewhere.com
Some additional client-specific content
Building the DSL – Iteration 3
fun <T> foldOverChildren(start: String,
children: List<T>,
indent: String ="t")
= children.fold(start) { state, child -> "$staten$indent$child” }
Building the DSL – Refactoring 1
class Blog(private val title: String, private val location: URI) {
private val additionalContent = mutableListOf<String>()
operator fun String.unaryPlus() = additionalContent.add(this)
override fun toString()
= foldOverChildren("$titlentt$location",
additionalContent,
"tt")
}
Building the DSL – Refactoring 1
class Blogs {
private val blogs = mutableListOf<Blog>()
fun blog(title: String, location: URI, action: Blog.() -> Unit)
= Blog(title, location).apply(action).also { blogs.add(it) }
override fun toString() = foldOverChildren("Current blogs:", blogs)
}
Building the DSL – Refactoring 1
profiles {
profile {
forename = "Jane"
surname = "Smith"
email = "Jane.Smith@megacorp.com"
}
//Whoops!!!
profiles {
}
}
Building the DSL – Refactoring 2
@DslMarker
annotation class SpaceEntityMarker
@SpaceEntityMarker
class SpaceInstance(val title: String) { ... }
@SpaceEntityMarker
class Profiles { ... }
@SpaceEntityMarker
class Profile { ... }
Building the DSL – Refactoring 2
– We have a stable structure describing data
– We do want to add support for many operations
– The operations will have overlapping functionality
– We don’t want to pollute the DSL code with IO
Integrating the DSL with IO
Sounds like a familiar problem...
Applying the Visitor Pattern
interface DslVisitor {
fun visitBlog(blog: Blog)
fun visitRepo(repo: Repo)
fun visitProfile(profile: Profile)
fun visitProject(project: Project)
fun visitInstance(instance:SpaceInstance)
}
interface Visited {
fun accept(visitor: DslVisitor)
}
Applying the Visitor Pattern
@SpaceEntityMarker
class SpaceInstance(val title: String): Visited {
private lateinit var projects: Projects
private lateinit var profiles: Profiles
private lateinit var blogs: Blogs
override fun toString() = "$titlen$profilesn$projectsn$blogsn"
fun profiles(action: Profiles.() -> Unit) = ...
fun projects(action: Projects.() -> Unit) = ...
fun blogs(action: Blogs.() -> Unit) = ...
override fun accept(visitor: DslVisitor) {
visitor.visitInstance(this)
listOf(projects, profiles, blogs).forEach { it.accept(visitor) }
}
}
class PrintVisitor: DslVisitor {
override fun visitBlog(blog: Blog) {
println("tBlog entitled ${blog.title}")
}
override fun visitRepo(repo: Repo) {
println("ttRepo at ${repo.location}")
}
override fun visitProfile(profile: Profile) {
with(profile) {
println("tProfile for $forename $surname at $email")
}
}
override fun visitProject(project: Project) {
println("tProject ${project.name} with key ${project.key}")
}
override fun visitInstance(instance: SpaceInstance) {
println("Visiting instance ${instance.title}")
}
}
Applying the Visitor Pattern
– We can leverage our existing WebClient code
– We put it behind an interface for abstraction
– Our component uses two WebClient objects
– One running as a Service Account for reading
– The other using a token to create entities
Creating the Space Client
Returning to the WebFlux WebClient
interface SpaceClient {
fun findProfiles(): Flux<Profile>
fun findProjects(): Flux<Project>
fun findBlogs(): Flux<Article>
fun createProfile(forename: String,
surname: String,
username: String): Mono<Boolean>
fun createProject(name: String, key: String): Mono<Boolean>
fun createBlog(title: String, content: String): Mono<Boolean>
}
SpaceClient.kt
Creating the Space Client
@Component("WebFluxSpaceClient")
class WebFluxSpaceClient(
@Qualifier("OAuthWebClient") val oauthClient: WebClient,
@Qualifier("TokenWebClient") val tokenClient: WebClient): SpaceClient {
override fun findProfiles(): Flux<Profile> {
val url = "/team-directory/profiles"
return retrieveData<AllProfilesResponse, Profile>(url) {
it.data ?: emptyList()
}
}
Creating the Space Client
– We can now create a Visitor for populating the instance
– Our ‘WebFluxSpaceClient’ will be injected into it
Bringing Everything Together
Using the Visitor Pattern
@Component
class SpaceCreationVisitor(val client: WebFluxSpaceClient): DslVisitor {
override fun visitBlog(blog: Blog) {
println("tCreating blog entitled ${blog.title}")
val content = blog.additionalContent.joinToString()
waitOnMono(client.createBlog(blog.title, content))
}
override fun visitRepo(repo: Repo) {
println("ttRepo at ${repo.location}")
}
SpaceCreationVisitor.kt
Bringing Everything Together
override fun visitProfile(profile: Profile) {
with(profile) {
println("tCreating profile for $forename $surname at $email")
val username = "$forename.$surname"
waitOnMono(client.createProfile(forename, surname, username))
}
}
override fun visitProject(project: Project) {
with(project) {
println("tCreating project ${project.name} with key ${project.key}")
waitOnMono(client.createProject(name, key))
}
}
SpaceCreationVisitor.kt
Bringing Everything Together
override fun visitInstance(instance: SpaceInstance) {
println("Trying to initialise ${instance.title}")
}
fun waitOnMono(mono: Mono<Boolean>) {
val result = mono.block() ?: false
println(if(result) "Success" else "Failure")
}
}
SpaceCreationVisitor.kt
Bringing Everything Together
Demo 2
Running the DSL
– Space is intuitive and works well
– The Space API works well from Spring 5
– Automation saves time and reduces stress 
Conclusions
The Good Things
– Space and its API are still in EAP
– Reactive coding remains tough going
– Bridging the ‘reactive divide’ is ugly
Conclusions
The Bad Things
Thank You!
Please reach out to us with questions...

More Related Content

What's hot

Devon 2011-f-4-improve your-javascript
Devon 2011-f-4-improve your-javascriptDevon 2011-f-4-improve your-javascript
Devon 2011-f-4-improve your-javascriptDaum DNA
 
Kotlin coroutines and spring framework
Kotlin coroutines and spring frameworkKotlin coroutines and spring framework
Kotlin coroutines and spring frameworkSunghyouk Bae
 
First few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesFirst few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesNebojša Vukšić
 
JUnit5 and TestContainers
JUnit5 and TestContainersJUnit5 and TestContainers
JUnit5 and TestContainersSunghyouk Bae
 
Create your DSL with Kotlin
Create your DSL with KotlinCreate your DSL with Kotlin
Create your DSL with KotlinLINE Corporation
 
2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin Coroutines2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin CoroutinesEamonn Boyle
 
Writing Hadoop Jobs in Scala using Scalding
Writing Hadoop Jobs in Scala using ScaldingWriting Hadoop Jobs in Scala using Scalding
Writing Hadoop Jobs in Scala using ScaldingToni Cebrián
 
AMD - Why, What and How
AMD - Why, What and HowAMD - Why, What and How
AMD - Why, What and HowMike Wilcox
 
Scala for Java programmers
Scala for Java programmersScala for Java programmers
Scala for Java programmers輝 子安
 
RubyKaigi2015 making robots-with-mruby
RubyKaigi2015 making robots-with-mrubyRubyKaigi2015 making robots-with-mruby
RubyKaigi2015 making robots-with-mrubyyamanekko
 
Compact and safely: static DSL on Kotlin
Compact and safely: static DSL on KotlinCompact and safely: static DSL on Kotlin
Compact and safely: static DSL on KotlinDmitry Pranchuk
 

What's hot (15)

Devon 2011-f-4-improve your-javascript
Devon 2011-f-4-improve your-javascriptDevon 2011-f-4-improve your-javascript
Devon 2011-f-4-improve your-javascript
 
Kotlin coroutines and spring framework
Kotlin coroutines and spring frameworkKotlin coroutines and spring framework
Kotlin coroutines and spring framework
 
First few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesFirst few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examples
 
Spark workshop
Spark workshopSpark workshop
Spark workshop
 
JUnit5 and TestContainers
JUnit5 and TestContainersJUnit5 and TestContainers
JUnit5 and TestContainers
 
Dynomite Nosql
Dynomite NosqlDynomite Nosql
Dynomite Nosql
 
Spring data requery
Spring data requerySpring data requery
Spring data requery
 
Create your DSL with Kotlin
Create your DSL with KotlinCreate your DSL with Kotlin
Create your DSL with Kotlin
 
Scala+data
Scala+dataScala+data
Scala+data
 
2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin Coroutines2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin Coroutines
 
Writing Hadoop Jobs in Scala using Scalding
Writing Hadoop Jobs in Scala using ScaldingWriting Hadoop Jobs in Scala using Scalding
Writing Hadoop Jobs in Scala using Scalding
 
AMD - Why, What and How
AMD - Why, What and HowAMD - Why, What and How
AMD - Why, What and How
 
Scala for Java programmers
Scala for Java programmersScala for Java programmers
Scala for Java programmers
 
RubyKaigi2015 making robots-with-mruby
RubyKaigi2015 making robots-with-mrubyRubyKaigi2015 making robots-with-mruby
RubyKaigi2015 making robots-with-mruby
 
Compact and safely: static DSL on Kotlin
Compact and safely: static DSL on KotlinCompact and safely: static DSL on Kotlin
Compact and safely: static DSL on Kotlin
 

Similar to Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space

Kotlin boost yourproductivity
Kotlin boost yourproductivityKotlin boost yourproductivity
Kotlin boost yourproductivitynklmish
 
«Продакшн в Kotlin DSL» Сергей Рыбалкин
«Продакшн в Kotlin DSL» Сергей Рыбалкин«Продакшн в Kotlin DSL» Сергей Рыбалкин
«Продакшн в Kotlin DSL» Сергей РыбалкинMail.ru Group
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingSchalk Cronjé
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingSchalk Cronjé
 
Kotlin decoration - February Berlin Kotlin Meetup
Kotlin decoration - February Berlin Kotlin MeetupKotlin decoration - February Berlin Kotlin Meetup
Kotlin decoration - February Berlin Kotlin MeetupSinan KOZAK
 
Entity Framework: Nakov @ BFU Hackhaton 2015
Entity Framework: Nakov @ BFU Hackhaton 2015Entity Framework: Nakov @ BFU Hackhaton 2015
Entity Framework: Nakov @ BFU Hackhaton 2015Svetlin Nakov
 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native CompilationPGConf APAC
 
Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Rajeev Rastogi (KRR)
 
Uncommon Design Patterns
Uncommon Design PatternsUncommon Design Patterns
Uncommon Design PatternsStefano Fago
 
Nosql hands on handout 04
Nosql hands on handout 04Nosql hands on handout 04
Nosql hands on handout 04Krishna Sankar
 
The Ring programming language version 1.6 book - Part 16 of 189
The Ring programming language version 1.6 book - Part 16 of 189The Ring programming language version 1.6 book - Part 16 of 189
The Ring programming language version 1.6 book - Part 16 of 189Mahmoud Samir Fayed
 
Basic Gradle Plugin Writing
Basic Gradle Plugin WritingBasic Gradle Plugin Writing
Basic Gradle Plugin WritingSchalk Cronjé
 
A brief overview of java frameworks
A brief overview of java frameworksA brief overview of java frameworks
A brief overview of java frameworksMD Sayem Ahmed
 
Idiomatic gradle plugin writing
Idiomatic gradle plugin writingIdiomatic gradle plugin writing
Idiomatic gradle plugin writingSchalk Cronjé
 
From Java to Kotlin - The first month in practice
From Java to Kotlin - The first month in practiceFrom Java to Kotlin - The first month in practice
From Java to Kotlin - The first month in practiceStefanTomm
 

Similar to Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space (20)

Kotlin boost yourproductivity
Kotlin boost yourproductivityKotlin boost yourproductivity
Kotlin boost yourproductivity
 
«Продакшн в Kotlin DSL» Сергей Рыбалкин
«Продакшн в Kotlin DSL» Сергей Рыбалкин«Продакшн в Kotlin DSL» Сергей Рыбалкин
«Продакшн в Kotlin DSL» Сергей Рыбалкин
 
Angular Schematics
Angular SchematicsAngular Schematics
Angular Schematics
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 
Kotlin decoration - February Berlin Kotlin Meetup
Kotlin decoration - February Berlin Kotlin MeetupKotlin decoration - February Berlin Kotlin Meetup
Kotlin decoration - February Berlin Kotlin Meetup
 
Entity Framework: Nakov @ BFU Hackhaton 2015
Entity Framework: Nakov @ BFU Hackhaton 2015Entity Framework: Nakov @ BFU Hackhaton 2015
Entity Framework: Nakov @ BFU Hackhaton 2015
 
C++ Programming
C++ ProgrammingC++ Programming
C++ Programming
 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native Compilation
 
Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2
 
Uncommon Design Patterns
Uncommon Design PatternsUncommon Design Patterns
Uncommon Design Patterns
 
C++ Programming
C++ ProgrammingC++ Programming
C++ Programming
 
Scala in Practice
Scala in PracticeScala in Practice
Scala in Practice
 
Nosql hands on handout 04
Nosql hands on handout 04Nosql hands on handout 04
Nosql hands on handout 04
 
The Ring programming language version 1.6 book - Part 16 of 189
The Ring programming language version 1.6 book - Part 16 of 189The Ring programming language version 1.6 book - Part 16 of 189
The Ring programming language version 1.6 book - Part 16 of 189
 
Basic Gradle Plugin Writing
Basic Gradle Plugin WritingBasic Gradle Plugin Writing
Basic Gradle Plugin Writing
 
A brief overview of java frameworks
A brief overview of java frameworksA brief overview of java frameworks
A brief overview of java frameworks
 
Idiomatic gradle plugin writing
Idiomatic gradle plugin writingIdiomatic gradle plugin writing
Idiomatic gradle plugin writing
 
Django Good Practices
Django Good PracticesDjango Good Practices
Django Good Practices
 
From Java to Kotlin - The first month in practice
From Java to Kotlin - The first month in practiceFrom Java to Kotlin - The first month in practice
From Java to Kotlin - The first month in practice
 

More from Garth Gilmour

Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android UpdateGarth Gilmour
 
TypeScript Vs. KotlinJS
TypeScript Vs. KotlinJSTypeScript Vs. KotlinJS
TypeScript Vs. KotlinJSGarth Gilmour
 
Shut Up And Eat Your Veg
Shut Up And Eat Your VegShut Up And Eat Your Veg
Shut Up And Eat Your VegGarth Gilmour
 
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerLies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerGarth Gilmour
 
A TypeScript Fans KotlinJS Adventures
A TypeScript Fans KotlinJS AdventuresA TypeScript Fans KotlinJS Adventures
A TypeScript Fans KotlinJS AdventuresGarth Gilmour
 
The Heat Death Of Enterprise IT
The Heat Death Of Enterprise ITThe Heat Death Of Enterprise IT
The Heat Death Of Enterprise ITGarth Gilmour
 
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerLies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerGarth Gilmour
 
Type Driven Development with TypeScript
Type Driven Development with TypeScriptType Driven Development with TypeScript
Type Driven Development with TypeScriptGarth Gilmour
 
Generics On The JVM (What you don't know will hurt you)
Generics On The JVM (What you don't know will hurt you)Generics On The JVM (What you don't know will hurt you)
Generics On The JVM (What you don't know will hurt you)Garth Gilmour
 
Is Software Engineering A Profession?
Is Software Engineering A Profession?Is Software Engineering A Profession?
Is Software Engineering A Profession?Garth Gilmour
 
Social Distancing is not Behaving Distantly
Social Distancing is not Behaving DistantlySocial Distancing is not Behaving Distantly
Social Distancing is not Behaving DistantlyGarth Gilmour
 
The Great Scala Makeover
The Great Scala MakeoverThe Great Scala Makeover
The Great Scala MakeoverGarth Gilmour
 
Transitioning Android Teams Into Kotlin
Transitioning Android Teams Into KotlinTransitioning Android Teams Into Kotlin
Transitioning Android Teams Into KotlinGarth Gilmour
 
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)Garth Gilmour
 
The Three Horse Race
The Three Horse RaceThe Three Horse Race
The Three Horse RaceGarth Gilmour
 
The Bestiary of Pure Functional Programming
The Bestiary of Pure Functional Programming The Bestiary of Pure Functional Programming
The Bestiary of Pure Functional Programming Garth Gilmour
 
BelTech 2019 Presenters Workshop
BelTech 2019 Presenters WorkshopBelTech 2019 Presenters Workshop
BelTech 2019 Presenters WorkshopGarth Gilmour
 
Kotlin The Whole Damn Family
Kotlin The Whole Damn FamilyKotlin The Whole Damn Family
Kotlin The Whole Damn FamilyGarth Gilmour
 
The Philosophy of DDD
The Philosophy of DDDThe Philosophy of DDD
The Philosophy of DDDGarth Gilmour
 

More from Garth Gilmour (20)

Compose in Theory
Compose in TheoryCompose in Theory
Compose in Theory
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android Update
 
TypeScript Vs. KotlinJS
TypeScript Vs. KotlinJSTypeScript Vs. KotlinJS
TypeScript Vs. KotlinJS
 
Shut Up And Eat Your Veg
Shut Up And Eat Your VegShut Up And Eat Your Veg
Shut Up And Eat Your Veg
 
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerLies Told By The Kotlin Compiler
Lies Told By The Kotlin Compiler
 
A TypeScript Fans KotlinJS Adventures
A TypeScript Fans KotlinJS AdventuresA TypeScript Fans KotlinJS Adventures
A TypeScript Fans KotlinJS Adventures
 
The Heat Death Of Enterprise IT
The Heat Death Of Enterprise ITThe Heat Death Of Enterprise IT
The Heat Death Of Enterprise IT
 
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerLies Told By The Kotlin Compiler
Lies Told By The Kotlin Compiler
 
Type Driven Development with TypeScript
Type Driven Development with TypeScriptType Driven Development with TypeScript
Type Driven Development with TypeScript
 
Generics On The JVM (What you don't know will hurt you)
Generics On The JVM (What you don't know will hurt you)Generics On The JVM (What you don't know will hurt you)
Generics On The JVM (What you don't know will hurt you)
 
Is Software Engineering A Profession?
Is Software Engineering A Profession?Is Software Engineering A Profession?
Is Software Engineering A Profession?
 
Social Distancing is not Behaving Distantly
Social Distancing is not Behaving DistantlySocial Distancing is not Behaving Distantly
Social Distancing is not Behaving Distantly
 
The Great Scala Makeover
The Great Scala MakeoverThe Great Scala Makeover
The Great Scala Makeover
 
Transitioning Android Teams Into Kotlin
Transitioning Android Teams Into KotlinTransitioning Android Teams Into Kotlin
Transitioning Android Teams Into Kotlin
 
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
 
The Three Horse Race
The Three Horse RaceThe Three Horse Race
The Three Horse Race
 
The Bestiary of Pure Functional Programming
The Bestiary of Pure Functional Programming The Bestiary of Pure Functional Programming
The Bestiary of Pure Functional Programming
 
BelTech 2019 Presenters Workshop
BelTech 2019 Presenters WorkshopBelTech 2019 Presenters Workshop
BelTech 2019 Presenters Workshop
 
Kotlin The Whole Damn Family
Kotlin The Whole Damn FamilyKotlin The Whole Damn Family
Kotlin The Whole Damn Family
 
The Philosophy of DDD
The Philosophy of DDDThe Philosophy of DDD
The Philosophy of DDD
 

Recently uploaded

Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Anthony Dahanne
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024Ortus Solutions, Corp
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of ProgrammingMatt Welsh
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowPeter Caitens
 
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume MontevideoVitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume MontevideoVitthal Shirke
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyanic lab
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Globus
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessWSO2
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus
 
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfAMB-Review
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus
 
Strategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptxStrategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptxvarshanayak241
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfkalichargn70th171
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Globus
 
2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptxGeorgi Kodinov
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...Juraj Vysvader
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsGlobus
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfOrtus Solutions, Corp
 

Recently uploaded (20)

Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should Know
 
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume MontevideoVitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume Montevideo
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
 
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
Strategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptxStrategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptx
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
 
2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 

Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space

  • 1. © Instil Software 2020 Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space Amy Crockett Garth Gilmour
  • 2. This is a Fusion Talk We aim to tie together many threads Kotlin Spring 5 Reactor Space Automation DSLs
  • 3.
  • 7.
  • 8.
  • 9. The classroom is closed…
  • 10. This caused us some anxiety…
  • 11. We had to take our training virtual…
  • 12. – Multiple Instructors – Specialized Tools – Flexible Hours The Three Key Components To Make Virtual Training Work
  • 13. – The instructor works with the group – By teaching, live coding etc… – They proceed at the average pace – The coach responds to queries – Working with students at the extremes – They ensure that no one is left behind Multiple Trainers Acting as Instructor and Coach
  • 14. – We partitioned our material into 60 min blocks – Allowing us to deliver a course to your timeline – A delivery could take place over: – A week's worth of mornings – One day a week for six weeks – Afternoon and evening sessions Flexible Hours Fitting Material Into Your Day
  • 15. – Distributed teams already build software – We can take advantage of their tooling – We already do: – Video-conferencing – Messaging and Chats – Collaborative Content – Distributed Versioning Specialized Tools We Have The Technology
  • 16. The Feedback Cycle How do we support students?
  • 17. The Feedback Cycle How do we support students?
  • 18. Enter Space… We needed a ‘one size fits all’ solution…
  • 19. Describing Space A Simple Domain Model Profiles Teams Projects Repos
  • 20. Describing Space A Simple Domain Model Chats Reviews Issues Checklists Calendars Meetings Absences To-Dos
  • 21.
  • 22.
  • 23.
  • 24.
  • 25. The Space Playground Using the API without security woes
  • 26. Making a Start Thank goodness for the Initializr
  • 27.
  • 29. @Bean(name= ["OAuthWebClient"]) fun oauthWebClient(clientReg: ReactiveClientRegistrationRepository?) : WebClient? { val oauth = ServerOAuth2AuthorizedClientExchangeFilterFunction( clientReg, UnAuthenticatedServerOAuth2AuthorizedClientRepository()) oauth.setDefaultClientRegistrationId(”FOO”) return WebClient.builder() .filter(oauth) .baseUrl("https://SPACE_URL/api/http") .build() } WebConfig.kt Accessing Endpoints
  • 30. @Bean(name= ["TokenWebClient"]) fun tokenWebClient() = WebClient .builder() .baseUrl("https://SPACE_URL/api/http") .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer TOKEN") .build() WebConfig.kt Accessing Endpoints
  • 31. Demo 1 Running the console app
  • 32. – Create a specific instance for the course – Add admin accounts for the 3 principal trainers – Add a welcome blog post with setup instructions – Create a project for examples / exercises (with repos) – Create a private project for solutions (with repos) – Create accounts for students with TODO lists Making the Code Useful What we need to do on each delivery…
  • 33.
  • 34. package com.instil.maurice.dsl fun instance(title: String = "An Instil Delivery", action: SpaceInstance.() -> Unit) = SpaceInstance(title).apply(action) class SpaceInstance(val title: String) { override fun toString() = title } Building the DSL – Iteration 1
  • 35. val dsl = instance("Kotlin 101 for Megacorp") { } println(dsl) Kotlin 101 for Megacorp Building the DSL – Iteration 1
  • 36. class SpaceInstance(val title: String) { private lateinit var projects: Projects private lateinit var profiles: Profiles private lateinit var blogs: Blogs override fun toString() = "$titlen$profilesn$projectsn$blogsn" fun profiles(action: Profiles.() -> Unit) = Profiles().apply(action).also { this.profiles = it } fun projects(action: Projects.() -> Unit) = Projects().apply(action).also { this.projects = it } fun blogs(action: Blogs.() -> Unit) = Blogs().apply(action).also { this.blogs = it } } Building the DSL – Iteration 2
  • 37. class Profiles { private val profiles = mutableListOf<Profile>() fun profile(action: Profile.() -> Unit) = Profile().apply(action).also { profiles.add(it) } override fun toString() = profiles.fold("Current profiles:") { state, profile -> "$statent$profile" } } Building the DSL – Iteration 2
  • 38. class Profile { lateinit var forename: String lateinit var surname: String lateinit var email: String override fun toString() = "$forename $surname at $email" } Building the DSL – Iteration 2
  • 39. val dsl = instance("Kotlin 101 for Megacorp") { profiles { profile { forename = "Jane" surname = "Smith" email = "Jane.Smith@megacorp.com" } } projects { } blogs { } } println(dsl) Kotlin 101 for Megacorp Current profiles: Jane Smith at Jane.Smith@megacorp.com com.instil.maurice.dsl.Projects@350b3a17 com.instil.maurice.dsl.Blogs@38600b Building the DSL – Iteration 2
  • 40. class Repo(private val location: URI) { override fun toString() = "t$location" } Building the DSL – Iteration 3
  • 41. class Project(val title: String) { private val repos = mutableListOf<Repo>() fun repo(location: URI, action: Repo.() -> Unit) = Repo(location).apply(action).also { repos.add(it) } override fun toString() = repos.fold("Project $title with repos:") { state, repo -> "$statent$repo" } } Building the DSL – Iteration 3
  • 42. class Projects { private val projects = mutableListOf<Project>() fun project(title: String, action: Project.() -> Unit) = Project(title).apply(action).also { projects.add(it) } override fun toString() = projects.fold("Current projects:") { state, project -> "$statent$project" } } Building the DSL – Iteration 3
  • 43. class Blogs { private val blogs = mutableListOf<Blog>() fun blog(title: String, location: URI, action: Blog.() -> Unit) = Blog(title, location).apply(action).also { blogs.add(it) } override fun toString() = blogs.fold("Current blogs:") { state, blog -> "$statent$blog" } } Building the DSL – Iteration 3
  • 44. class Blog(val title: String, val location: URI) { private val additionalContent = mutableListOf<String>() operator fun String.unaryPlus() = additionalContent.add(this) override fun toString() = additionalContent.fold("$titlentt$location") { state, text -> "$statentt$text" } } Building the DSL – Iteration 3
  • 45. val dsl = instance("Kotlin 101 for Megacorp") { profiles { profile { forename = "Jane" surname = "Smith" email = "Jane.Smith@megacorp.com" } } projects { project("Kotlin Examples") { repo(URI("http://somewhere.com")) {} } } blogs { blog("Welcome and Setup", URI("http://elsewhere.com")) { +"Some additional client-specific content" } } } println(dsl) Building the DSL – Iteration 3
  • 46. Kotlin 101 for Megacorp Current profiles: Jane Smith at Jane.Smith@megacorp.com Current projects: Project Kotlin Examples with repos: http://somewhere.com Current blogs: Welcome and Setup http://elsewhere.com Some additional client-specific content Building the DSL – Iteration 3
  • 47. fun <T> foldOverChildren(start: String, children: List<T>, indent: String ="t") = children.fold(start) { state, child -> "$staten$indent$child” } Building the DSL – Refactoring 1
  • 48. class Blog(private val title: String, private val location: URI) { private val additionalContent = mutableListOf<String>() operator fun String.unaryPlus() = additionalContent.add(this) override fun toString() = foldOverChildren("$titlentt$location", additionalContent, "tt") } Building the DSL – Refactoring 1
  • 49. class Blogs { private val blogs = mutableListOf<Blog>() fun blog(title: String, location: URI, action: Blog.() -> Unit) = Blog(title, location).apply(action).also { blogs.add(it) } override fun toString() = foldOverChildren("Current blogs:", blogs) } Building the DSL – Refactoring 1
  • 50. profiles { profile { forename = "Jane" surname = "Smith" email = "Jane.Smith@megacorp.com" } //Whoops!!! profiles { } } Building the DSL – Refactoring 2
  • 51. @DslMarker annotation class SpaceEntityMarker @SpaceEntityMarker class SpaceInstance(val title: String) { ... } @SpaceEntityMarker class Profiles { ... } @SpaceEntityMarker class Profile { ... } Building the DSL – Refactoring 2
  • 52. – We have a stable structure describing data – We do want to add support for many operations – The operations will have overlapping functionality – We don’t want to pollute the DSL code with IO Integrating the DSL with IO Sounds like a familiar problem...
  • 53.
  • 54. Applying the Visitor Pattern interface DslVisitor { fun visitBlog(blog: Blog) fun visitRepo(repo: Repo) fun visitProfile(profile: Profile) fun visitProject(project: Project) fun visitInstance(instance:SpaceInstance) } interface Visited { fun accept(visitor: DslVisitor) }
  • 55. Applying the Visitor Pattern @SpaceEntityMarker class SpaceInstance(val title: String): Visited { private lateinit var projects: Projects private lateinit var profiles: Profiles private lateinit var blogs: Blogs override fun toString() = "$titlen$profilesn$projectsn$blogsn" fun profiles(action: Profiles.() -> Unit) = ... fun projects(action: Projects.() -> Unit) = ... fun blogs(action: Blogs.() -> Unit) = ... override fun accept(visitor: DslVisitor) { visitor.visitInstance(this) listOf(projects, profiles, blogs).forEach { it.accept(visitor) } } }
  • 56. class PrintVisitor: DslVisitor { override fun visitBlog(blog: Blog) { println("tBlog entitled ${blog.title}") } override fun visitRepo(repo: Repo) { println("ttRepo at ${repo.location}") } override fun visitProfile(profile: Profile) { with(profile) { println("tProfile for $forename $surname at $email") } } override fun visitProject(project: Project) { println("tProject ${project.name} with key ${project.key}") } override fun visitInstance(instance: SpaceInstance) { println("Visiting instance ${instance.title}") } } Applying the Visitor Pattern
  • 57. – We can leverage our existing WebClient code – We put it behind an interface for abstraction – Our component uses two WebClient objects – One running as a Service Account for reading – The other using a token to create entities Creating the Space Client Returning to the WebFlux WebClient
  • 58. interface SpaceClient { fun findProfiles(): Flux<Profile> fun findProjects(): Flux<Project> fun findBlogs(): Flux<Article> fun createProfile(forename: String, surname: String, username: String): Mono<Boolean> fun createProject(name: String, key: String): Mono<Boolean> fun createBlog(title: String, content: String): Mono<Boolean> } SpaceClient.kt Creating the Space Client
  • 59. @Component("WebFluxSpaceClient") class WebFluxSpaceClient( @Qualifier("OAuthWebClient") val oauthClient: WebClient, @Qualifier("TokenWebClient") val tokenClient: WebClient): SpaceClient { override fun findProfiles(): Flux<Profile> { val url = "/team-directory/profiles" return retrieveData<AllProfilesResponse, Profile>(url) { it.data ?: emptyList() } } Creating the Space Client
  • 60. – We can now create a Visitor for populating the instance – Our ‘WebFluxSpaceClient’ will be injected into it Bringing Everything Together Using the Visitor Pattern
  • 61. @Component class SpaceCreationVisitor(val client: WebFluxSpaceClient): DslVisitor { override fun visitBlog(blog: Blog) { println("tCreating blog entitled ${blog.title}") val content = blog.additionalContent.joinToString() waitOnMono(client.createBlog(blog.title, content)) } override fun visitRepo(repo: Repo) { println("ttRepo at ${repo.location}") } SpaceCreationVisitor.kt Bringing Everything Together
  • 62. override fun visitProfile(profile: Profile) { with(profile) { println("tCreating profile for $forename $surname at $email") val username = "$forename.$surname" waitOnMono(client.createProfile(forename, surname, username)) } } override fun visitProject(project: Project) { with(project) { println("tCreating project ${project.name} with key ${project.key}") waitOnMono(client.createProject(name, key)) } } SpaceCreationVisitor.kt Bringing Everything Together
  • 63. override fun visitInstance(instance: SpaceInstance) { println("Trying to initialise ${instance.title}") } fun waitOnMono(mono: Mono<Boolean>) { val result = mono.block() ?: false println(if(result) "Success" else "Failure") } } SpaceCreationVisitor.kt Bringing Everything Together
  • 65. – Space is intuitive and works well – The Space API works well from Spring 5 – Automation saves time and reduces stress  Conclusions The Good Things
  • 66. – Space and its API are still in EAP – Reactive coding remains tough going – Bridging the ‘reactive divide’ is ugly Conclusions The Bad Things
  • 67. Thank You! Please reach out to us with questions...