Hi! I am Armando

Welcome to my website where I will share about software in general, Kotlin and the Indie Web

Hexagonal Feedback

(Last update: )

Recently, Alistair Cockburn has been asking for feedback and making efforts to consolidate talks, documents and the concept of Hexagonal Architecture.

// https://alistaircockburn.com/Articles/Component-Strategy-generalizes-Ports-Adapters#wbb1
I am drafting a new pattern, Component + Strategy, which is the more general form of Ports & Adapters (Hexagonal Architecture).
Just now, I'm looking for comments, corrections, improvements and general feedback.

In the draft on page 16 and 17 there is a code example of a configuration written in Java with Spring.

While Spring is very popular for Java programmers I think it is important to show a configuration written with no libraries (or reflection) and why not in a different language.

I proposed translating the code to Kotlin as it was, but couldn't wrap my head around the Driver interface. I will explain why I think it is problematic and submit it as feedback, along with my alternative configuration.

This is a close translation of what I found on the draft, adding the interfaces and classes explicitly:

// Not my proposal but a close Kotlin translation of what I found on the draft 
interface Driver // (?)
class TestCases(val forDiscounting: ForDiscounting): Driver // Primary Adapter
class Console(val forDiscounting: ForDiscounting): Driver // Primary Adapter
interface ForDiscounting // Primary Port
class DiscounterApp(val rateRepository: ForObtainingRates): ForDiscounting // App
interface ForObtainingRates // Secondary Port
class StubRateRepository: ForObtainingRates // Secondary Adapter
class FileRateRepository: ForObtainingRates // Secondary Adapter

class DiscounterAppConfig(useConsoleDriver: Boolean, useFileRateRepository: Boolean) {
    val rateRepository: ForObtainingRates =
        if(useFileRateRepository) FileRateRepository()
        else StubRateRepository()
    val discounterApp: ForDiscounting = DiscounterApp(rateRepository)
    val driver: Driver =
        if(useConsoleDriver) Console(discounterApp)
        else TestCases(discounterApp)
}

As you can see, no library, just code. Sure this implementation will have to be instantiated manually somewhere else, but it should be a straightforward process. By the way, there is nothing preventing Java to use the same approach for the configuration.

"But I see no functions and Spring wasn't creating fields", I hear you say, and you are right. By default, Spring provides beans as singletons this just means that it will call that method only once and share that instance to the code that needs it. I decided to use the fields for that reason and for simple (or carefully designed) apps this pattern can scale well with few tweaks.

Ok, onto Driver now (I am assuming this interface is not empty and defines functions to be implemented for Primary Adapters):

  1. This interface has no name on Hexagonal Architecture, in clear contrast with all other classes and interfaces. It is effectively used as a Primary Adapter Interface
  2. Primary Adapters are supposed to be technology dependent their API may need to be adjusted to satisfy the libraries, frameworks and protocols they work with
  3. Primary Adapters depend on the application, but shouldn't "wear a uniform" to align with all others. Let the Primary Adapter implement what it wants and name it as it wishes
    • Just think about TestCases, realistically tests have other goals and naming requirements than a Console Primary Adapter
  4. Finally, not all Primary Adapters fit well into the configuration. TestCases in my experience works best depending on the configuration and being instantiated by a framework

With that I would leave the new example configuration as:

// Proposal also found at: https://corlaez.com/hexagonal-proposal.html
class TestCases { // Primary Adapter (instantiated by testing framework)
   val discounterApp: ForDiscounting = DiscounterAppConfig(false).discounterApp
}
class Console(val forDiscounting: ForDiscounting) // Primary Adapter
interface ForDiscounting // Primary Port
class DiscounterApp(val rateRepository: ForObtainingRates): ForDiscounting // App
interface ForObtainingRates // Secondary Port
class StubRateRepository: ForObtainingRates // Secondary Adapter
class FileRateRepository: ForObtainingRates // Secondary Adapter

class DiscounterAppConfig(useFileRateRepository: Boolean) {
    private val rateRepository: ForObtainingRates =
        if(useFileRateRepository) FileRateRepository()
        else StubRateRepository()
    val discounterApp: ForDiscounting = DiscounterApp(rateRepository)
    val discounterConsole: Console = Console(discounterApp)
}

One extra thing I have added is the private for the repository (or Secondary Adapters in General). The idea being that other classes should only use the discounterApp or discounterConsole and not depend on or use the Secondary Adapters, not even tests.

I am happy that Alistair is still working on promoting Hexagonal Architecture and asking feedback from the community. If you are reading this, Alistair, I want to say thank you from the heart because your writings have influenced my growth in this industry.

... now an extra section that I won't include in the proposal, but I find very useful:

I love using mocks on my tests. With a small change our configuration can be used with mocking libraries!

// Not included in proposal. A recommendation that works with mocking libraries
// Adding an App with a Secondary Port meant to be mocked
class DiscounterApp2(val rateRepository: ForObtainingRates, val chaosService: ForChaos): ForDiscounting // App
interface ForChaos // Secondary Port
class RealChaos: ForChaos // Secondary Adapter

class DiscounterAppConfig(useFileRateRepository: Boolean) {
   private val chaosService: ForChaos = RealChaos()
   private val rateRepository: ForObtainingRates =
      if(useFileRateRepository) FileRateRepository()
      else StubRateRepository()
   val discounterApp: ForDiscounting = newDiscounterApp(chaosService)// Same function used here
   val discounterConsole: Console = newDiscounterConsole(discounterApp)// Same function used here

   // Functions used by tests, the parameters allow mocks to be injected.
   fun newDiscounterApp(chaosService: ForChaos) = DiscounterApp2(rateRepository, chaosService)
   fun newDiscounterConsole(discounterApp: ForDiscounting) = Console(discounterApp)
}

First we create functions to will instantiate our test subjects (app and Primary Adapters). This will also be used to instantiate their real counterparts. It is important to use the same function on both cases to avoid wiring the objects with a different logic.

Now the new method may have fewer arguments than the underlying class. Only keep the arguments that are meant to be mocked in tests. The other arguments can be injected directly using the already created instances (such is the case of rateRepository)

And this would be the usage in tests:

class DiscounterAppTest { // Primary Adapter (instantiated by testing framework)
   val chaosService = createMock<ForChaos>()
   val discounterApp: ForDiscounting = DiscounterAppConfig(false).newDiscounterApp(chaosService)
}

And there you go, the main code will work the same and the tests will be able to mock the designated arguments using these functions.

And that's all for now!

PS: If you think that a single expression to instantiate a field is too limiting you can always wrap the code in a run helper function val x = run {...} and use as many lines as you wish




Kotlin-htmx

Today I will talk about why I think Kotlin and htmx mix so well. You can follow along (or skip the article) with the code here (there is also a static generation example in the static branch there). Try the demo here.

Kotlin as you may know is a modern JVM and (more recently) multiplatform language. It has a great type system and interesting advanced features while still being a pragmatic tool meant for engineers.

htmx is a JavaScript library that allows you to write HTML attributes instead of JS code to load content from the server and manipulate the DOM. Your HTML will be more powerful than ever and you will deal less with JS.

Let's start! The main function creates a Javalin HTTP Server (static files config including Webjars which is how we will import the htmx js code avoiding node) and adds the "Friends" module (which is an extension function). Finally, it starts the server. A key config I want to highlight is the webjars setup that will help us serve htmx:

// https://github.com/corlaez/kotlin-htmx/blob/master/src/main/kotlin/javalin.kt
config.addStaticFiles { staticFiles ->
    staticFiles.directory = "META-INF/resources/webjars/"
    staticFiles.location = Location.CLASSPATH
}

It is important to mention that Javalin can be replaced with any HTTP Server you like. In fact your can drop the server altogether, write your HTML Strings to files and make your own static generator (that's how corlaez.com is written)

Then addFriendsModule creates an index route and a route for each friend. ctx.html is the Javalin function to respond with an HTML string. friends.forEach will be inlined into a regular for loop

// https://github.com/corlaez/kotlin-htmx/blob/master/src/main/kotlin/friends/addFriendsModule.kt
fun Javalin.addFriendsModule() {
    val friends = listOf("Joseph", "Nicholas", "Caesar")
    get("/") { ctx ->
        ctx.html(htmlFriendsIndex(friends))
    }
    friends.forEach { friend ->
        get("/$friend") { ctx ->
            val characteristic = listOf("swimmer", "runner", "debater").random()
            ctx.html(htmlFriendProfile(friend, characteristic))
        }
    }
}

Next we have the base html template which is a Kotlin function. The parameter is a lambda with receiver that will populate our HTML body tag and the return is an String. createHTML takes out fancy DSL and outputs a String as well. If you try to define a body tag inside a head or viceversa the editor and compiler will let you know.

// https://github.com/corlaez/kotlin-htmx/blob/master/src/main/kotlin/htmlBaseTemplate.kt
fun htmlBaseTemplate(bodyFn: BODY.() -> Unit): String {
    return "<!DOCTYPE html>" + createHTML().html {
        lang = "en"
        head {
            script { src = "/htmx.org/$htmxVersion/dist/htmx.js" }
            link { href = "/modest-variation.css"; rel="stylesheet" }
        }
        body {
            bodyFn()
        }
    }
}

Let's now focus on htmlFriendProfile and htmlFriendsIndex now:

// https://github.com/corlaez/kotlin-htmx/blob/master/src/main/kotlin/friends/html.kt
fun htmlFriendsIndex(friends: List<String>): String {
    return htmlBaseTemplate {
        h1 { a { href = "/"; +"My Friends" } }// nested `a` inside a `h1`. To insert a text inside any tag we use the + operator
        friends.forEach { friend ->// Regular Kotlin used to loop!
            h2 {
                a {
                    href = "/$friend"// Sets cursor pointer and works without js
                    hxGet("/$friend")
                    hxSwap("outerHTML")
                    hxTarget("closest h2")
                    +friend
                }
            }
        }
    }
}

fun htmlFriendProfile(friend: String, characteristic: String): String {
    return createHTML().article { // createHTML will take all the DSL and produce a String
        h2(classes = "your-css-class") {
            +friend
        }
        p {
            +"My friend $friend is smart and a good $characteristic"
        }
    }
}

htmlFriendsIndex calls htmlBaseTemplate as this is meant to be a full page. This index builds its contents using regular Kotlin loops. htmlFriendProfile, on the other hand, creates the HTML directly as it is just a partial HTML document.

The hx functions are simple HTMLTag extension functions that add HTML attributes.

// https://github.com/corlaez/kotlin-htmx/blob/master/src/main/kotlin/hx.kt
fun HTMLTag.hxGet(value: String) {
    attributes += "hx-get" to value
}
fun HTMLTag.hxSwap(value: String) {
    attributes += "hx-swap" to value
}
fun HTMLTag.hxTarget(value: String) {
    attributes += "hx-target" to value
}

The autocomplete game of HTML DSL gives me the best experience writing HTML I have ever experienced and the htmx integration is seamless. It is hard to articulate how good is it until you try it (Use IntelliJ IDEA if in doubt, there is a free community edition, and they do offer education licences if you have an institutional email)

Cons!

  • The DSL is written with advanced Kotlin features and will force you to use/learn (maybe not that bad) advanced features if you try to break templates into different functions as I did.
  • Kotlin's advanced features are better experienced with IntelliJ IDEA. There is a great free community edition but no other great alternatives that I know of.
  • While the HTML DSL autocomplete is very powerful at preventing mistakes, it does rely on a lot of imports. I recommend isolating the template code from the rest of your code (which is probably a good idea anyway)
  • Regarding HTMX, perhaps the biggest drawback and advantage is that it goes against the norm: it works best if you serve HTML partials from your server, the old school way. This works great for websites meant to be used by humans.

I hope this was interesting, have fun!




More Kotlin, Less JS!

(Last update: )

In the last years, JavaScript had an incredible growth, complex apps, frameworks and languages that compile to JS have been developed to create rich and complex web UIs and experiences. I started to use React at work in 2017 in a webapp that truly required the use of that library. I enjoyed working with React and used it whenever I had a chance. That's how I ended up writing mi personal website in React, in retrospective a terrible idea since my web wouldn't load at all without JavaScript, affecting SEO and reducing load speeds.

Today, I finally rewrote this website adding some big changes I have been planning for a while:

  • The web is generated statically using Kotlin
  • The website no longer requires JavaScript to render
  • The articles are written in Markdown
  • Internalization support for the Kotlin templates and Markdown articles
  • Templates are defined using the Kotlinx HTML DSL. (Similar to JSX but strongly typed)
  • There is a dev server that reloads webpages as code changes (inspired on react-hot-loader)

These projects and ideas have influenced the design of my website:

  • htmx AJAX, CSS Transitions, WebSockets and Server Sent Events directly in HTML, using attributes and reclaim HTML as the Hypermedia to be exchanged between browser and HTTP Server
  • Gemini Protocol: Gemini is a lighter and simpler protocol than HTTP with mandatory Transport Layer Security and privacy focus (JavaScript does not exist)
  • The Small Web: Aral Balkan and Laura Kalbag are building tools to promote independent web avoiding the centralized web and the problems it creates for democracy and society
  • website < 14kb endtime.dev's article on the significant performance improvement that smaller web pages gain.

So there you have it, I think this changes will allow me to experiment and create more easily. We shall see...




Skype Chatbot

(Last update: )

"Daniel en mi piso" (Daniel in my floor) was a Skype bot that I made for my coworkers when I worked at Bellatrix. Daniel came every day selling delicious home-made sandwiches. He stayed a few minutes outside each floor with Bellatrix offices and other companies. However, we would have to step out at the right time to catch him, or we would miss him.

The bot was meant to Announce when Daniel arrives to your floor. You subscribe to a given floor, and when the bot is notified that Daniel is in a given floor, you receive a message and a notification. The simple program relied on trust and accurate reports of its participants to work, but it was a fun experiment to run. The bot is deployed but deactivated

Skype Bot GitHub Repo

Skype Bot Link (deactivated)




Overmind tutorial

(Last update: )

A tutorial on the JavaScript UI library state manager Overmind JS in a React application.

In the video I use React, but it can also be used with Angular, Vue and Svelte.

YouTube tutorial