SlideShare une entreprise Scribd logo
1  sur  67
© 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...

Contenu connexe

Tendances

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
 

Tendances (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
 

Similaire à 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
 

Similaire à 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
 

Plus de 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
 

Plus de 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
 

Dernier

The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
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
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
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
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
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
 
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
 
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
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
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
 
+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
 
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
 
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
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
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
 
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.
 
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
 

Dernier (20)

The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
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...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
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
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
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
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
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
 
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
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
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 ☂️
 
+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...
 
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
 
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
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
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
 
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 ...
 
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 ...
 

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...