Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin multiplatform + Domain models = ❤️

Nico Krijnen
January 19, 2023

Kotlin multiplatform + Domain models = ❤️

In most of the applications we write, the domain model with all the crucial business logic only lives in the backend to ensure consistent behavior of a system. But with Kotlin multi-platform, that same domain model can suddenly also be used in your user-facing applications.

In this talk, we will look at what that means for the applications you build. What does your code look like when you share your domain model? How do you ensure that that domain model is re-usable? What kind of trouble can you run into and what techniques can you use to avoid that trouble? And how does the ability to use the full domain model benefit the user experience? And last but not least, how can your organizational team structure make this way of working a huge success or a road towards disaster?!

Nico Krijnen

January 19, 2023
Tweet

More Decks by Nico Krijnen

Other Decks in Business

Transcript

  1. What do we mean with "a domain"? An area of

    knowledge. The thing the software is about.
  2. What do we mean with "a domain"? The problem space

    you are working in. The thing the software is about. An area of knowledge.
  3. What do we mean with "a domain"? The thing the

    software is about. An area of knowledge. The problem space you are working in. A sphere of knowledge, influence, or activity. The subject area 
 to which the user applies a program is the domain of the software. —Eric Evans
  4. What do we mean with "a domain"? The thing the

    software is about. An area of knowledge. The problem space you are working in. The domain is the real-world context in which you're attempting to solve a problem using software. Each domain comes with expertise, vocabulary and tools that are part of that domain. – Robert Harvey, stackexchange " A sphere of knowledge, influence, or activity. The subject area 
 to which the user applies a program is the domain of the software. —Eric Evans
  5. What do we mean with "a domain"? Shipping cargo Airline

    booking Medical research Education Insurance
  6. What is a domain model? Need to look at business

    logic Decisions made by code that are specific to the domain of the app
  7. Where is the business logic? Routes Services Data Access UI

    HTML / CSS Application Layer Data Access Layer Navigation Offline Storage
  8. Where is the business logic? Routes Services Data Access UI

    HTML / CSS Application Layer Data Access Layer Navigation Offline Storage
  9. Where is the business logic? class UserService(private val userPersistence: UserDAO)

    { suspend fun registerNewUser(request: NewUserRequest) { require(request.email.isNotBlank() && value.isValidEmail()) { "Please enter an email address" } require(request.password.isNotBlank() && request.password.length >= 8) { "Password must be at least 8 characters long" } userPersistence.insertUser(request) } }
  10. Where is the business logic? class UserService(private val userPersistence: UserDAO)

    { suspend fun registerNewUser(request: NewUserRequest) { require(request.email.isNotBlank() && value.isValidEmail()) { "Please enter an email address" } require(request.password.isNotBlank() && request.password.length >= 8) { "Password must be at least 8 characters long" } userPersistence.insertUser(request) } }
  11. class UserService(private val userPersistence: UserPersistence) { suspend fun registerNewUser(command: NewUserCommand)

    { userPersistence.insertUser(command.email, command.password) } } @JvmInline value class Email(val value: String) { init { require(value.isNotBlank() && value.isValidEmail()) { "Please enter an email address" } } } @JvmInline value class Password(val value: String) { init { require(value.isNotBlank() && value.length >= 8) { "Password must be at least 8 characters long" } } } Where is the business logic?
  12. Domain model? Routes Services Data Access UI HTML / CSS

    Application Layer Data Access Layer Navigation Offline Storage Code that makes your app unique and deals with your domain
  13. Domain model? Routes Services Data Access UI HTML / CSS

    Application Layer Data Access Layer Navigation Offline Storage Domain model = only 20% of your code
  14. ✅ Pure Kotlin + Stdlib ❌ JVM apis or libraries

    ❌ JS apis or libraries ❌ Native apis or libraries Domain model = Free of dependencies
  15. Hexagonal / Clean architecture ✅ Isolated, pure-code domain model ✅

    No framework code mixed in ✅ Easy to read and understand ✅ Easy to test ✅ Always-valid Immutable
  16. @Serializable data class AddRegistrationCommand(val email: String, val name: String) @Serializable

    data class UpdateRegistrationEmailCommand(val email: String, val newEmail: String) @Serializable data class UpdateRegistrationNameCommand(val email: String, val newName: String) common / model
  17. interface RegistrationService { suspend fun list(): List<Registration> suspend fun handle(command:

    AddRegistrationCommand): Registration suspend fun handle(command: UpdateRegistrationEmailCommand): Registration suspend fun handle(command: UpdateRegistrationNameCommand): Registration } jvm / domain
  18. fun Application.registrationAPIRoutes(service: RegistrationService) { routing { get("/registration/list") { call.respond(RegistrationList(service.list())) }

    post("/registration") { call.receive<AddRegistrationCommand>().let { command !" service.handle(command).let { registration !" call.respond(registration) } } } put("/registration/email") { call.receive<UpdateRegistrationEmailCommand>().let { command !" service.handle(command).let { registration !" call.respond(registration) } } } !!" } } jvm / infra
  19. fun listRegistrations(resultHandler: (RegistrationList) !# Unit) { fetch("/registration/list", resultHandler) } fun

    AddRegistrationCommand.send(resultHandler: (Registration) !# Unit) { fetch( "POST", "/registration", Json.encodeToString(this), resultHandler.asResponseHandler() ) } fun UpdateRegistrationEmailCommand.send(resultHandler: ((Registration) !# Unit)? = null) { fetch( "PUT", "/registration/email", Json.encodeToString(this), resultHandler!$asResponseHandler() ) } !!" js / api
  20. fun main() { addAppToBody() registerGlobalErrorHandler() } private fun addAppToBody() {

    document.addEventListener("DOMContentLoaded", { listRegistrations { registrations !" document.body!$appendChild(AppComponent(registrations.items).fragment) } }) } js / app
  21. class AppComponent(registrations: List<Registration>) { val fragment = document.createDocumentFragment().apply { appendChild(HeaderComponent().element)

    appendChild(RegistrationListComponent(registrations).element.apply { appendChild(AddRegistrationRowComponent { addedRegistration !" insertBefore(RegistrationRowComponent(addedRegistration).element, lastChild) }.element) }) } } js / component
  22. class RegistrationListComponent(registrations: List<Registration>) { val element = document.createElement("div") { className

    = "reg-list" registrations.forEach { appendChild(RegistrationRowComponent(it).element) } } } class RegistrationRowComponent(registration: Registration) { val element = document.createElement("div") { className = "reg-list!%item" appendChild(inputWithValue("email", registration.email) { newValue !" UpdateRegistrationEmailCommand(registration.email, newValue).send() }) appendChild(inputWithValue("name", registration.name) { newValue !" UpdateRegistrationNameCommand(registration.email, newValue).send() }) appendChild(divWithText(Date(registration.registrationTime).toDateString())) } } js / component
  23. as reached Beta! o becoming Stable now! Single codebase for

    the application NativeCode SharedCode Businesslogic andcore View iOS specificAPIs Android specificAPIs View Learn more about beta → Case studies Support Get started Kotlin Multiplatform Mobile is an SDK for iOS and Android app development. It offers all the combined benefits of creating cross-platform and native apps. It is trusted in production by many of the world’s leading companies, including Philips, Netflix, Leroy Merlin, and VMWare. Singl logic Maintain a other logic Implement devices. Busines andcor iOS spec We loved the “shared business, native UI” idea that Kotlin Multiplatform promoted, and it m our teams did not have to give up using their preferred toolchains.” “ Get started Case studies Kotlin Multiplatform Mobile
  24. %

  25. Server-driven UI Domain Model Domain Model Domain Model Domain Model

    Only view logic Return desired UI Only view logic Only view logic
  26. Kotlin Isolated ❤ ❤ ❤ Kotlin multiplatform & Not for

    everyone '( Team organization matters Domain models Key Takeaways