<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Byte for your thoughts</title>
    <link>https://qua.name/antolius/</link>
    <description>Some thoughts on programing. Mostly subjective, potentially helpful.</description>
    <pubDate>Sat, 30 May 2026 21:23:07 +0200</pubDate>
    <item>
      <title>What makes Clojure REPL great</title>
      <link>https://qua.name/antolius/what-makes-clojure-repl-great</link>
      <description>&lt;![CDATA[I&#39;ve been learning Clojure lately. It&#39;s my first experience with a Lisp dialect and I&#39;m enjoying it. So far my favorite surprise is REPL! I&#39;ve heard the promise of &#34;interactive coding&#34; or &#34;live updates&#34; before from other languages, but this is the first time such a promise has actually payed off for me. REPL has had a real impact on my, fairly limited, Clojure programming experience. In this post I&#39;ll explore why it works so well for me, while some seemingly similar technologies haven&#39;s had nearly as much of an impact. !--more--&#xA;&#xA;How others fail&#xA;&#xA;I&#39;ll start by exploring languages I&#39;ve used in the past and how their interactive shells have failed to be as transformative as Clojure&#39;s REPL.&#xA;&#xA;JavaScript&#xA;&#xA;JavaScript may be the most widely used language which touts instant feedback. I can open the console in my browser and start playing around with the language. For my server-side needs I have Node.js which comes with a REPL. While all this is undeniably true, I&#39;ve never felt it integral to my JS coding experience. I think there are a couple of reasons for this:&#xA;&#xA;Web apps these days are far removed from basic console interactions. We use build tools such as Webpack to bundle and transpile our code, and frameworks like React to render the app. Not to mention using language features not yet supported by the browser, or coding in TypeScript.&#xA;Even if I try to write a snippet of code in my console, I&#39;m fighting against the language&#39;s imperative syntax. As soon as my snippet surpasses a few lines of code it&#39;s easier to put it in a script and runt it from there. JavaScript shares this with languages from the C family.&#xA;Web apps are heavily intertwined with DOM, or some equivalent internal state. This makes poking at my code from browser console more difficult as it is often tied to DOM events or depends on a complex state.&#xA;&#xA;This is not to say that JavaScript coding experience is objectively bad, just that I prefer to interact with my web apps through their UI instead of interactive console.&#xA;&#xA;Java&#xA;&#xA;Back with Java 9 in 2017 Oracle introduced JShell:&#xA;&#xA;  The Java Shell tool (JShell) is an interactive tool for learning the Java programming language and prototyping Java code.  JShell is a Read-Evaluate-Print Loop (REPL) ...&#xA;    Oracle docs&#xA;&#xA;Is it cool that Java has an official REPL? Yeah, I guess. Has it in any way changed my approach to writing Java code? No. It&#39;s notable that I felt the need to link to the docs, as if to prove this thing actually exists. I use Java daily and most of the time I simply forget about JShell. &#xA;&#xA;The greatest impediment to good REPL experience in Java is its object orientation along with all design patterns used with that paradigm. For example, I rely on Spring&#39;s dependency injection to bootstrap my Java apps. In unit tests I need Mockito library to help me mock all dependencies of a class before I can start working with it. This makes it near impossible to interact with my code from REPL. Imperative code structure and verbosity don&#39;t help either.&#xA;&#xA;Go&#xA;&#xA;Other languages I&#39;ve used in the past usually have some combination of these flaws. For example Go has a fast compiler. In fact people go as far as using it as &#34;scripting language&#34; in place of shell scripting. However, the speed of compiler itself is not enough. Being highly imperative Go would make for an unpractical REPL experience.&#xA;&#xA;How Clojure succeeds&#xA;&#xA;Previous examples illustrate a few key points. For a good experience it&#39;s not enough that a REPL, or a similar interactive shell, simply exists. It&#39;s also not a necessity for the language to be interpreted (Clojure is not, mind you). It might be a good idea to have a relatively fast compiler, but that in itself is not enough.&#xA;&#xA;So, why is Clojure REPL so transformative? Here are a few language characteristics that I found critical to my usage:&#xA;&#xA;Expression based syntax&#xA;Functional paradigm&#xA;Dynamically typed&#xA;Simple at scale&#xA;&#xA;Expression based syntax&#xA;&#xA;This is where imperative languages fall short. In Clojure the code is structured as a series of expressions. This lends itself extremely well to REPL interaction, which is essentially a loop of reading and evaluating expressions. My &#34;normal&#34; Clojure code, which I store in files, doesn&#39;t differ too much from a series of expressions I input into a REPL session. This makes interacting with REPL feel as natural as coding. There&#39;s no urge so quit REPL and just dump it all in a script file.&#xA;&#xA;Functional paradigm&#xA;&#xA;Being functional helps the language be expression based. Beyond that it favors composition. In Clojure complex behaviors are implemented by combining simpler functions. This is in contrast with Object Oriented languages where primary tool is inheritance. With OO complex features are implemented by building type hierarchies, which breaks the REPL experience. If I want to poke around at different segments of a composed function I invoke its component functions. With type hierarchy on the other hand I&#39;d probably need to implement  abstract classes to try to isolate and invoke some of their methods.&#xA;&#xA;In addition to composition, another benefit is working with mostly pure functions. The fact that things I&#39;m playing with in REPL don&#39;t have side-effects is hugely helpful. REPL shines in exploratory interactions and being able to repeat function calls without messing up some internal state is critical.&#xA;&#xA;Dynamically typed&#xA;&#xA;One benefit of dynamic typing is capability of functions to care less about their parameters. As long as parameters contain particular data that function needs it doesn&#39;t matter what else is in there. In Clojure there might be some state carried over between functions, but they themselves don&#39;t care about entirety of it. All that&#39;s needed to invoke a function in REPL is it&#39;s own minimal set of data.&#xA;&#xA;Of course, extra benefit is not having to write a class for every single piece of data.&#xA;&#xA;Simple at scale&#xA;&#xA;In some of the other languages REPL starts promising, but there&#39;s a breaking point which production applications cross and it becomes useless. Think of Java hello world example vs. a minimum Spring Boot app. Amount of code might not be all that different, but effectiveness of JShell tanks.&#xA;&#xA;I lack personal experience to speak on this point. As I mentioned I&#39;m just starting with Clojure, and I haven&#39;t worked on any production Clojure apps. However, simplicity is famously one of the core objectives of Clojure language. There&#39;s plenty of testimony from experience Clojurians to attest to this. So I&#39;m optimistic about my REPL being able to keep up with me as my programs grow in scale.&#xA;&#xA;The end&#xA;&#xA;In the end it took a particular language built around a set of conscious design decisions to ignite my love for REPL. In hindsight it seems obvious that design of a language would influence programming techniques that work well with it. However, that gets increasingly overlooked in current programming landscape where more and more languages strive for feature parity.&#xA;&#xA;If you&#39;d like to get in touch with me, either to share in my enthusiasm for Clojure, or to tell me that I should have learned Python and saved myself all this overthinking, you can find me on Mastodon @antolius.&#xA;&#xA;If you liked the post and are interested in more similar content you can subscribe to this blog&#39;s RSS feed or follow @antolius@qua.name in fediverse. &#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>I&#39;ve been learning Clojure lately. It&#39;s my first experience with a Lisp dialect and I&#39;m enjoying it. So far my favorite surprise is REPL! I&#39;ve heard the promise of “interactive coding” or “live updates” before from other languages, but this is the first time such a promise has actually payed off for me. REPL has had a real impact on my, fairly limited, Clojure programming experience. In this post I&#39;ll explore why it works so well for me, while some seemingly similar technologies haven&#39;s had nearly as much of an impact. </p>

<h2 id="how-others-fail" id="how-others-fail">How others fail</h2>

<p>I&#39;ll start by exploring languages I&#39;ve used in the past and how their interactive shells have failed to be as transformative as Clojure&#39;s REPL.</p>

<h3 id="javascript" id="javascript">JavaScript</h3>

<p>JavaScript may be the most widely used language which touts instant feedback. I can open the console in my browser and start playing around with the language. For my server-side needs I have Node.js which comes with a REPL. While all this is undeniably true, I&#39;ve never felt it integral to my JS coding experience. I think there are a couple of reasons for this:</p>
<ol><li>Web apps these days are far removed from basic console interactions. We use build tools such as Webpack to bundle and transpile our code, and frameworks like React to render the app. Not to mention using language features not yet supported by the browser, or coding in TypeScript.</li>
<li>Even if I try to write a snippet of code in my console, I&#39;m fighting against the language&#39;s imperative syntax. As soon as my snippet surpasses a few lines of code it&#39;s easier to put it in a script and runt it from there. JavaScript shares this with languages from the C family.</li>
<li>Web apps are heavily intertwined with DOM, or some equivalent internal state. This makes poking at my code from browser console more difficult as it is often tied to DOM events or depends on a complex state.</li></ol>

<p>This is not to say that JavaScript coding experience is objectively bad, just that I prefer to interact with my web apps through their UI instead of interactive console.</p>

<h3 id="java" id="java">Java</h3>

<p>Back with Java 9 in 2017 Oracle introduced JShell:</p>

<blockquote><p>The Java Shell tool (JShell) is an interactive tool for learning the Java programming language and prototyping Java code.  JShell is a Read-Evaluate-Print Loop (REPL) ...</p>

<p><a href="https://docs.oracle.com/javase/9/jshell/introduction-jshell.htm#JSHEL-GUID-630F27C8-1195-4989-9F6B-2C51D46F52C8" rel="nofollow"><em>Oracle docs</em></a></p></blockquote>

<p>Is it cool that Java has an official REPL? Yeah, I guess. Has it in any way changed my approach to writing Java code? No. It&#39;s notable that I felt the need to link to the docs, as if to prove this thing actually exists. I use Java daily and most of the time I simply forget about JShell.</p>

<p>The greatest impediment to good REPL experience in Java is its object orientation along with all design patterns used with that paradigm. For example, I rely on Spring&#39;s dependency injection to bootstrap my Java apps. In unit tests I need Mockito library to help me mock all dependencies of a class before I can start working with it. This makes it near impossible to interact with my code from REPL. Imperative code structure and verbosity don&#39;t help either.</p>

<h3 id="go" id="go">Go</h3>

<p>Other languages I&#39;ve used in the past usually have some combination of these flaws. For example Go has a fast compiler. In fact people go as far as using it as “scripting language” in place of shell scripting. However, the speed of compiler itself is not enough. Being highly imperative Go would make for an unpractical REPL experience.</p>

<h2 id="how-clojure-succeeds" id="how-clojure-succeeds">How Clojure succeeds</h2>

<p>Previous examples illustrate a few key points. For a good experience it&#39;s not enough that a REPL, or a similar interactive shell, simply exists. It&#39;s also not a necessity for the language to be interpreted (Clojure is not, mind you). It might be a good idea to have a relatively fast compiler, but that in itself is not enough.</p>

<p>So, why is Clojure REPL so transformative? Here are a few language characteristics that I found critical to my usage:</p>
<ol><li>Expression based syntax</li>
<li>Functional paradigm</li>
<li>Dynamically typed</li>
<li>Simple at scale</li></ol>

<h3 id="expression-based-syntax" id="expression-based-syntax">Expression based syntax</h3>

<p>This is where imperative languages fall short. In Clojure the code is structured as a series of expressions. This lends itself extremely well to REPL interaction, which is essentially a loop of reading and evaluating expressions. My “normal” Clojure code, which I store in files, doesn&#39;t differ too much from a series of expressions I input into a REPL session. This makes interacting with REPL feel as natural as coding. There&#39;s no urge so quit REPL and just dump it all in a script file.</p>

<h3 id="functional-paradigm" id="functional-paradigm">Functional paradigm</h3>

<p>Being functional helps the language be expression based. Beyond that it favors composition. In Clojure complex behaviors are implemented by combining simpler functions. This is in contrast with Object Oriented languages where primary tool is inheritance. With OO complex features are implemented by building type hierarchies, which breaks the REPL experience. If I want to poke around at different segments of a composed function I invoke its component functions. With type hierarchy on the other hand I&#39;d probably need to implement  abstract classes to try to isolate and invoke some of their methods.</p>

<p>In addition to composition, another benefit is working with mostly pure functions. The fact that things I&#39;m playing with in REPL don&#39;t have side-effects is hugely helpful. REPL shines in exploratory interactions and being able to repeat function calls without messing up some internal state is critical.</p>

<h3 id="dynamically-typed" id="dynamically-typed">Dynamically typed</h3>

<p>One benefit of dynamic typing is capability of functions to care less about their parameters. As long as parameters contain particular data that function needs it doesn&#39;t matter what else is in there. In Clojure there might be some state carried over between functions, but they themselves don&#39;t care about entirety of it. All that&#39;s needed to invoke a function in REPL is it&#39;s own minimal set of data.</p>

<p>Of course, extra benefit is not having to write a class for every single piece of data.</p>

<h3 id="simple-at-scale" id="simple-at-scale">Simple at scale</h3>

<p>In some of the other languages REPL starts promising, but there&#39;s a breaking point which production applications cross and it becomes useless. Think of Java hello world example vs. a minimum Spring Boot app. Amount of code might not be all that different, but effectiveness of JShell tanks.</p>

<p>I lack personal experience to speak on this point. As I mentioned I&#39;m just starting with Clojure, and I haven&#39;t worked on any production Clojure apps. However, simplicity is famously one of the core objectives of Clojure language. There&#39;s plenty of testimony from experience Clojurians to attest to this. So I&#39;m optimistic about my REPL being able to keep up with me as my programs grow in scale.</p>

<h2 id="the-end" id="the-end">The end</h2>

<p>In the end it took a particular language built around a set of conscious design decisions to ignite my love for REPL. In hindsight it seems obvious that design of a language would influence programming techniques that work well with it. However, that gets increasingly overlooked in current programming landscape where more and more languages strive for feature parity.</p>

<p>If you&#39;d like to get in touch with me, either to share in my enthusiasm for Clojure, or to tell me that I should have learned Python and saved myself all this overthinking, you can find me on <a href="https://mastodon.social" rel="nofollow">Mastodon</a> <a href="https://mastodon.social/@antolius" rel="nofollow">@antolius</a>.</p>

<p>If you liked the post and are interested in more similar content you can subscribe to this blog&#39;s <a href="https://qua.name/antolius/feed" rel="nofollow">RSS feed</a> or follow <code><a href="https://qua.name/@/antolius@qua.name" class="u-url mention" rel="nofollow">@<span>antolius@qua.name</span></a></code> in <a href="https://en.wikipedia.org/wiki/Fediverse" rel="nofollow">fediverse</a>.</p>
]]></content:encoded>
      <guid>https://qua.name/antolius/what-makes-clojure-repl-great</guid>
      <pubDate>Sun, 07 Feb 2021 01:06:33 +0100</pubDate>
    </item>
    <item>
      <title>Smarter routing in Spring Cloud Gateway</title>
      <link>https://qua.name/antolius/smarter-routing-in-spring-cloud-gateway</link>
      <description>&lt;![CDATA[Another day, another Spring Cloud Gateway story. I&#39;ve previously written about customizing its underlying Netty server and how the framework handles downstream HTTP requests. This time around I&#39;ll be taking a look at the heart of Spring Cloud Gateway: its routing system.!--more--&#xA;&#xA;Use-case&#xA;&#xA;At work I&#39;ve been running a Spring Cloud Gateway app in production for over a year and a half. By now we are exposing most of our 500+ API endpoints through it. With so many endpoints we encountered some tricky situations. One of them is overlapping path definitions. Here&#39;s an example:&#xA;&#xA;Imagine a Foo product implemented by a foo-service application. Since all foo related endpoints are handled by the same app all it needs is a single Cloud Gateway route:&#xA;&#xA;builder.routes()&#xA;  .route(r -  r.path(&#34;/foo/&#34;).uri(fooServiceUri))&#xA;  .build();&#xA;&#xA;  Spring Cloud Gateway uses Ant-style matching here, so `` matches zero or more path segments.&#xA;&#xA;As time goes by a new version of the product is designed. new-foo-serice app is built to implement it. The new app exposes /foo/2/ endpoints. Finally, in order to enable independent scaling, /foo/2/bars endpoint is extracted into a separate bars-service app.&#xA;&#xA;| Downstream app  | Path pattern   |&#xA;|------------------|--------------|&#xA;| foo-service         | /foo/         |&#xA;| new-foo-service | /foo/2/    |&#xA;| bars-service        | /foo/2/bars |&#xA;&#xA;In this case a request to GET /foo/2/bars matches all 3 routes.  &#xA;&#xA;The problem&#xA;&#xA;This by itself is not a problem, as Cloud Gateway has a mechanism for handling such situations. The Route class implements the Ordered interface. Gateway picks a route with the highest precedence to handle an incoming request. This seems flexible and is easy to configure using the route builder. However, it does not solve my problem.&#xA;&#xA;In my production application I don&#39;t know all the routes in advance. They are discovered and updated at runtime, one downstream app at a time. This means that my gateway loads routes in batches and only updates the ones that have actually changed. This is a problem, because order of each individual route needs to be defined at load time and depends on all the other routes.&#xA;&#xA;Imagine routes loading happens like this:&#xA;&#xA;foo-service routes load first, and /foo/ route is given order 0.&#xA;bars-service loads next. Since its path /foo/2/bars is more exact its route is given order -1, which has higher precedence.&#xA;new-foo-service loads last. At this point there&#39;s no order that could be given to its /foo/2/* route that would correctly position it between the two previously loaded routes.&#xA;&#xA;In this case a &#34;solution&#34; might be to load downstream apps in a particular order. However, it&#39;s easy to construct a counter example in which an app could have both more exact route in one hierarchy and a more general one in another. This makes the app ordering solution insufficient. &#xA;&#xA;How Cloud Gateway works&#xA;&#xA;Cloud Gateway itself is built on top of Spring WebFlux. As such, there are two key classes that implement handing of all incoming HTTP requests:&#xA;&#xA;RoutePredicateHandlerMapping which implements WebFlux&#39;s HandlerMapping. This is the class that assigns a route to an incoming request.&#xA;FilteringWebHandler which implements WebHandler by delegating request processing to the chain of Cloud Gateway filters defined by the route.&#xA;&#xA;RoutePredicateHandlerMapping is of interest here. More specifically, its lookupRoute method. Here&#39;s what the method looks like with logging, error and empty state handling removed:&#xA;&#xA;protected MonoRoute lookupRoute(ServerWebExchange exchange) {&#xA;    // start with an ordered list of all registered routes:&#xA;    return this.routeLocator.getRoutes()&#xA;        .concatMap(route -  Mono.just(route)&#xA;                // check if a route matches the request:&#xA;                .filterWhen(r -  r.getPredicate().apply(exchange))&#xA;        )&#xA;        // take the first route that matches:&#xA;        .next()&#xA;        .map(route -  {&#xA;            // by default all routes are valid&#xA;            validateRoute(route, exchange);&#xA;            return route;&#xA;        });&#xA;}&#xA;&#xA;The trick here is in the .next() operator. Because of it Cloud Gateway always picks the first route that matches the request. Also of note is that the lookupRoute method is protected!&#xA;&#xA;Solution&#xA;&#xA;This allowed me to implement my own handler mapping class by extending the RoutePredicateHandlerMapping and overriding the lookupRoute method. The change was simple: I sorted the matching routes so that &#34;more exact&#34; ones come first. The rest of the implementation is the same:&#xA;&#xA; protected MonoRoute lookupRoute(ServerWebExchange exchange) {&#xA;    return this.routeLocator.getRoutes()&#xA;        .concatMap(/ filter routes /)&#xA;        // sort routes so that more exact ones come first:&#xA;        .sort(pathBasedRouteComparator)&#xA;        .next() // pick the first route, like before&#xA;        .map(/ validate picked route */);&#xA;}&#xA;&#xA;What&#39;s left to determine is what precisely &#34;more exact&#34; route means. For routes R1 with path /foo/ and R2 with path /foo/2/ I defined R2 to be more exact because pattern /foo/ matches the literal path /foo/2/ , while the opposite is not true. This is how I implemented it in a comparator:&#xA;&#xA;@Component&#xA;public class PathBasedRouteComparator implements ComparatorRoute {&#xA;    @Override&#xA;    public int compare(Route r1, Route r2) {&#xA;        var info1 = (PathInfo) r1.getMetadata().get(PathInfo.KEY);&#xA;        var info2 = (PathInfo) r2.getMetadata().get(PathInfo.KEY);&#xA;        if (info1 == null || info2 == null) {&#xA;            // fall back to native route ordering:&#xA;            return compareOrders(r1, r2);&#xA;        }&#xA;        var r1MatchesR2 = info1.getPattern().matches(info2.getPath());&#xA;        var r2MatchesR1 = info2.getPattern().matches(info1.getPath());&#xA;        if (r1MatchesR2 &amp;&amp; !r2MatchesR1) {&#xA;            return 1;&#xA;        }&#xA;        if (r2MatchesR1 &amp;&amp; !r1MatchesR2) {&#xA;            return -1;&#xA;        }&#xA;        // fall back to native route ordering:&#xA;        return compareOrders(r1, r2);&#xA;    }&#xA;    private int compareOrders(Route r1, Route r2) {&#xA;        return Integer.compare(r1.getOrder(), r2.getOrder());&#xA;    }&#xA;}&#xA;&#xA;For this comparator to work routes need to have a PathInfo added to their metadata. This can be done at route loading time because, unlike the order, path info depends only on the individual route that&#39;s currently loading.&#xA;&#xA;Alternative solution&#xA;&#xA;This customization allowed Cloud Gateway application to handle any convoluted path overriding that API developers could came up with. It did, however, come with a runtime performance cost. With the new routing logic all loaded routs are matched against each incoming request. As expected, the lower latency percentiles were impacted by this. They represent situations in which request matched one of the high precedence routes, so a lot of matching was skipped in the original implementation.&#xA;&#xA;For use-cases where routes are either known in advanced or are updated all at once I&#39;d recommend using the original, order based, routing logic. In this case route order can be determined upfront at route loading time. The comparator logic can be reused to calculate the route order. This solution would have no impact on the runtime performance.&#xA;&#xA;Example&#xA;&#xA;I&#39;ve created a demo project on GitHub that illustrates the solution using the custom handler mapping. Feel free to check out the project and play around with it. If you find a better solution, please let me know about it! You can reach me at:&#xA;&#xA;josip.antolis@protonmail.com&#xA;@antolius on Mastodon&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>Another day, another <a href="https://spring.io/projects/spring-cloud-gateway" rel="nofollow">Spring Cloud Gateway</a> story. I&#39;ve previously written about <a href="https://qua.name/antolius/spring-cloud-gateway-max-http-header-size" rel="nofollow">customizing its underlying Netty server</a> and how the framework <a href="https://qua.name/antolius/spring-cloud-gateway-connection-header" rel="nofollow">handles downstream HTTP requests</a>. This time around I&#39;ll be taking a look at the heart of Spring Cloud Gateway: its routing system.</p>

<h2 id="use-case" id="use-case">Use-case</h2>

<p>At work I&#39;ve been running a Spring Cloud Gateway app in production for over a year and a half. By now we are exposing most of our 500+ API endpoints through it. With so many endpoints we encountered some tricky situations. One of them is overlapping path definitions. Here&#39;s an example:</p>

<p>Imagine a <em>Foo</em> product implemented by a <code>foo-service</code> application. Since all foo related endpoints are handled by the same app all it needs is a single Cloud Gateway route:</p>

<pre><code class="language-java">builder.routes()
  .route(r -&gt; r.path(&#34;/foo/**&#34;).uri(fooServiceUri))
  .build();
</code></pre>

<blockquote><p>Spring Cloud Gateway uses <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html" rel="nofollow">Ant-style matching</a> here, so <code>**</code> matches zero or more path segments.</p></blockquote>

<p>As time goes by a new version of the product is designed. <code>new-foo-serice</code> app is built to implement it. The new app exposes <code>/foo/2/**</code> endpoints. Finally, in order to enable independent scaling, <code>/foo/2/bars</code> endpoint is extracted into a separate <code>bars-service</code> app.</p>

<table>
<thead>
<tr>
<th>Downstream app</th>
<th>Path pattern</th>
</tr>
</thead>

<tbody>
<tr>
<td><code>foo-service</code></td>
<td><code>/foo/**</code></td>
</tr>

<tr>
<td><code>new-foo-service</code></td>
<td><code>/foo/2/**</code></td>
</tr>

<tr>
<td><code>bars-service</code></td>
<td><code>/foo/2/bars</code></td>
</tr>
</tbody>
</table>

<p>In this case a request to <code>GET /foo/2/bars</code> matches all 3 routes.</p>

<h3 id="the-problem" id="the-problem">The problem</h3>

<p>This by itself is not a problem, as Cloud Gateway has a mechanism for handling such situations. The <a href="https://github.com/spring-cloud/spring-cloud-gateway/blob/v3.0.0-M6/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/Route.java#L44" rel="nofollow"><code>Route</code> class</a> implements the <code>Ordered</code> interface. Gateway picks a route with the highest precedence to handle an incoming request. This seems flexible and is easy to configure using the route builder. However, it does not solve my problem.</p>

<p>In my production application I don&#39;t know all the routes in advance. They are discovered and updated at runtime, one downstream app at a time. This means that my gateway loads routes in batches and only updates the ones that have actually changed. This is a problem, because order of each individual route needs to be defined at load time and depends on all the other routes.</p>

<p>Imagine routes loading happens like this:</p>
<ol><li><code>foo-service</code> routes load first, and <code>/foo/**</code> route is given order 0.</li>
<li><code>bars-service</code> loads next. Since its path <code>/foo/2/bars</code> is more exact its route is given order -1, which has higher precedence.</li>
<li><code>new-foo-service</code> loads last. At this point there&#39;s no order that could be given to its <code>/foo/2/**</code> route that would correctly position it between the two previously loaded routes.</li></ol>

<p>In this case a “solution” might be to load downstream apps in a particular order. However, it&#39;s easy to construct a counter example in which an app could have both more exact route in one hierarchy and a more general one in another. This makes the app ordering solution insufficient.</p>

<h2 id="how-cloud-gateway-works" id="how-cloud-gateway-works">How Cloud Gateway works</h2>

<p>Cloud Gateway itself is built on top of <a href="https://docs.spring.io/spring-framework/docs/5.3.1/reference/html/web-reactive.html" rel="nofollow">Spring WebFlux</a>. As such, there are two key classes that implement handing of all incoming HTTP requests:</p>
<ul><li><a href="https://github.com/spring-cloud/spring-cloud-gateway/blob/v3.0.0-M6/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java" rel="nofollow"><code>RoutePredicateHandlerMapping</code></a> which implements WebFlux&#39;s <a href="https://docs.spring.io/spring-framework/docs/5.3.1/reference/html/web-reactive.html#webflux-special-bean-types" rel="nofollow">HandlerMapping</a>. This is the class that assigns a route to an incoming request.</li>
<li><a href="https://github.com/spring-cloud/spring-cloud-gateway/blob/v3.0.0-M6/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/FilteringWebHandler.java" rel="nofollow"><code>FilteringWebHandler</code></a> which implements <a href="https://docs.spring.io/spring-framework/docs/5.3.1/reference/html/web-reactive.html#webflux-web-handler-api" rel="nofollow">WebHandler</a> by delegating request processing to the chain of Cloud Gateway filters defined by the route.</li></ul>

<p><code>RoutePredicateHandlerMapping</code> is of interest here. More specifically, its <code>lookupRoute</code> method. Here&#39;s what the method looks like with logging, error and empty state handling removed:</p>

<pre><code class="language-java">protected Mono&lt;Route&gt; lookupRoute(ServerWebExchange exchange) {
    // start with an ordered list of all registered routes:
    return this.routeLocator.getRoutes()
        .concatMap(route -&gt; Mono.just(route)
                // check if a route matches the request:
                .filterWhen(r -&gt; r.getPredicate().apply(exchange))
        )
        // take the first route that matches:
        .next()
        .map(route -&gt; {
            // by default all routes are valid
            validateRoute(route, exchange);
            return route;
        });
}
</code></pre>

<p>The trick here is in the <code>.next()</code> operator. Because of it Cloud Gateway always picks the first route that matches the request. Also of note is that the <code>lookupRoute</code> method is protected!</p>

<h2 id="solution" id="solution">Solution</h2>

<p>This allowed me to implement my own handler mapping class by extending the <code>RoutePredicateHandlerMapping</code> and overriding the <code>lookupRoute</code> method. The change was simple: I sorted the matching routes so that “more exact” ones come first. The rest of the implementation is the same:</p>

<pre><code class="language-java">protected Mono&lt;Route&gt; lookupRoute(ServerWebExchange exchange) {
    return this.routeLocator.getRoutes()
        .concatMap(/* filter routes */)
        // sort routes so that more exact ones come first:
        .sort(pathBasedRouteComparator)
        .next() // pick the first route, like before
        .map(/* validate picked route */);
}
</code></pre>

<p>What&#39;s left to determine is what precisely “more exact” route means. For routes <code>R1</code> with path <code>/foo/**</code> and <code>R2</code> with path <code>/foo/2/**</code> I defined <code>R2</code> to be more exact because pattern <code>/foo/**</code> matches the literal path <code>/foo/2/**</code> , while the opposite is not true. This is how I implemented it in a comparator:</p>

<pre><code class="language-java">@Component
public class PathBasedRouteComparator implements Comparator&lt;Route&gt; {
    @Override
    public int compare(Route r1, Route r2) {
        var info1 = (PathInfo) r1.getMetadata().get(PathInfo.KEY);
        var info2 = (PathInfo) r2.getMetadata().get(PathInfo.KEY);
        if (info1 == null || info2 == null) {
            // fall back to native route ordering:
            return compareOrders(r1, r2);
        }
        var r1MatchesR2 = info1.getPattern().matches(info2.getPath());
        var r2MatchesR1 = info2.getPattern().matches(info1.getPath());
        if (r1MatchesR2 &amp;&amp; !r2MatchesR1) {
            return 1;
        }
        if (r2MatchesR1 &amp;&amp; !r1MatchesR2) {
            return -1;
        }
        // fall back to native route ordering:
        return compareOrders(r1, r2);
    }
    private int compareOrders(Route r1, Route r2) {
        return Integer.compare(r1.getOrder(), r2.getOrder());
    }
}
</code></pre>

<p>For this comparator to work routes need to have a <code>PathInfo</code> added to their metadata. This can be done at route loading time because, unlike the order, path info depends only on the individual route that&#39;s currently loading.</p>

<h3 id="alternative-solution" id="alternative-solution">Alternative solution</h3>

<p>This customization allowed Cloud Gateway application to handle any convoluted path overriding that API developers could came up with. It did, however, come with a runtime performance cost. With the new routing logic all loaded routs are matched against each incoming request. As expected, the lower latency percentiles were impacted by this. They represent situations in which request matched one of the high precedence routes, so a lot of matching was skipped in the original implementation.</p>

<p>For use-cases where routes are either known in advanced or are updated all at once I&#39;d recommend using the original, order based, routing logic. In this case route order can be determined upfront at route loading time. The comparator logic can be reused to calculate the route order. This solution would have no impact on the runtime performance.</p>

<h2 id="example" id="example">Example</h2>

<p>I&#39;ve created a <a href="https://github.com/Antolius/spring-cloud-gateway-examples-routing" rel="nofollow">demo project</a> on GitHub that illustrates the solution using the custom handler mapping. Feel free to check out the project and play around with it. If you find a better solution, please let me know about it! You can reach me at:</p>
<ul><li><a href="mailto:josip.antolis@protonmail.com" rel="nofollow">josip.antolis@protonmail.com</a></li>
<li><a href="https://mastodon.social/@antolius" rel="nofollow">@antolius</a> on <a href="https://mastodon.social" rel="nofollow">Mastodon</a></li></ul>
]]></content:encoded>
      <guid>https://qua.name/antolius/smarter-routing-in-spring-cloud-gateway</guid>
      <pubDate>Mon, 28 Dec 2020 01:08:23 +0100</pubDate>
    </item>
    <item>
      <title>Liskov substitution principle</title>
      <link>https://qua.name/antolius/liskov-substitution-principle</link>
      <description>&lt;![CDATA[An unsung hero of the SOLID principles.&#xA;&#xA;  Derived classes must be substitutable for their base classes.&#xA;    Liskov substitution principle&#xA;!--more--&#xA;&#xA;Considering each of the SOLID princpiles Liskov substitution principle (LSP) often gets least attention in both theoretical analysis and practical application. Single responsibility invites discussion with its definition of The One reason to change. As a result it has been extensively talked and blogged about. Open-closed principle is well covered by the object-oriented design patterns as many of them are essentially clever tricks for applying the principle. Similarly, there are many popular dependency injection frameworks that implement the dependency inversion. This empowers developers to more easily adhere to those two principles.&#xA;&#xA;That leaves interface segregation and Liskov substitution principle. Of those two I find the former to be easier to abide by. In its definition interface segregation invites the code author to make their interfaces more concise. It&#39;s easier to follow because it relates directly to the activity that I, as a code author, am involved in; i.e. writing my interface.&#xA;&#xA;In contrast, Liskov substitution asks me as author of the derived class to make sure it behaves same as the base class (written by someone else) from the perspective of the user code (written by yet another author). It&#39;s no just about me and my code, I need to consider two more perspectives. It requires a sort of developer empathy.&#xA;&#xA;This isn&#39;t helped by examples that are often used to illustrate the violation of the principle. Classic example is the problem of modeling a square class as a derivative of a more generalized rectangle class. It&#39;s a valid example in theory, but is obviously contrived and as such fails to resonate. That&#39;s why I was excited when one of my real world bugs boiled down to a violation of Liskov substitution principle.&#xA;&#xA;The bug&#xA;&#xA;I&#39;ve recently been learning Vala programming language and GTK framework. Vala is a higher-order language, with syntax similar to C# and Java, that compiles down to C. It promises to make targeting the GNOME stack simple. Vala is strongly typed and object-oriented, however this example does not rely on the language itself and can be reproduced in C code as well. GTK is a feature-packed UI toolkit with a rich hierarchy of widgets. It is in the thick of its widgets&#39; inheritance tree that the root of my problem lies.&#xA;&#xA;In my app I needed a container widget that could expand dynamically row by row as I added more child elements to it. Luckily GTK covers just such use-case with its FlowBox component. The FlowBox extends the abstract Container widget which defines the interface for adding and removing child widgets:&#xA;&#xA;Container defines add and remove methods, FlowBox extends from it&#xA;&#xA;This was convenient as I needed to occasionally remove child widgets from the container. Here&#39;s a simplified example of what I wanted to achieve:&#xA;&#xA;public class ExampleApp : Gtk.Application {&#xA;&#x9;protected override void activate () {&#xA;&#x9;&#x9;var window = new Gtk.ApplicationWindow (this);&#xA;&#x9;&#x9;window.setdefaultsize (300, 200);&#xA;&#xA;&#x9;&#x9;var helloworld = new Gtk.Label (&#34;Hello, World!&#34;);&#xA;&#xA;&#x9;&#x9;var box = new Gtk.FlowBox ();&#xA;&#x9;&#x9;box.add (helloworld);&#xA;&#x9;&#x9;// removing the child immediately to simplify the example&#xA;&#x9;&#x9;box.remove (helloworld);&#xA;&#xA;&#x9;&#x9;window.add (box);&#xA;&#x9;&#x9;window.showall ();&#xA;&#x9;}&#xA;&#xA;&#x9;public static int main (string[] args) {&#xA;&#x9;&#x9;var app = new ExampleApp ();&#xA;&#x9;&#x9;return app.run (args);&#xA;&#x9;}&#xA;}&#xA;&#xA;Try guessing what this program does:&#xA;&#xA;It opens an empty window.&#xA;It opens a window with &#34;Hello, World!&#34; text.&#xA;It segfaults.&#xA;&#xA;Spoiler alert: it&#39;s option 3:&#xA;&#xA;$ valac --pkg gtk+-3.0 app.vala &amp;&amp; ./app&#xA;(app:9912): GLib-CRITICAL : 23:54:22.670: gsequenceremove: assertion &#39;iter != NULL&#39; failed&#xA;(app:9912): Gtk-CRITICAL : 23:54:22.670: gtkwidgetshowall: assertion &#39;GTKISWIDGET (widget)&#39; failed&#xA;(app:9912): Gtk-CRITICAL : 23:54:22.697: gtkwidgetgetvisible: assertion &#39;GTKISWIDGET (widget)&#39; failed&#xA;(app:9912): Gtk-CRITICAL : 23:54:22.701: gtkwidgetgetvisible: assertion &#39;GTKISWIDGET (widget)&#39; failed&#xA;(app:9912): Gtk-CRITICAL : 23:54:22.701: gtkwidgetgetvisible: assertion &#39;GTKISWIDGET (widget)&#39; failed&#xA;(app:9912): Gtk-CRITICAL : 23:54:22.701: gtkwidgetgetvisible: assertion &#39;GTKISWIDGET (widget)&#39; failed&#xA;(app:9912): Gtk-CRITICAL : 23:54:22.701: gtkwidgetgetvisible: assertion &#39;GTKISWIDGET (widget)&#39; failed&#xA;(app:9912): Gtk-CRITICAL : 23:54:22.701: gtkwidgetisvisible: assertion &#39;GTKISWIDGET (widget)&#39; failed&#xA;[1]    9912 segmentation fault  ./app&#xA;&#xA;Flawed box&#xA;&#xA;What went wrong? The first thing I checked was documentation of add and remove methods on the Container class. The latter one was more interesting (full doc available here):&#xA;&#xA;  Removes widget from this.&#xA;  widget must be inside this...&#xA;&#xA;This seemed like a reasonable constraint; I can&#39;t remove what&#39;s not there. But I just put my helloworld label into the box, how could it not be inside? On to the FlowBox docs (available in full here):&#xA;&#xA;  A GtkFlowBox positions child widgets in sequence according to its orientation.&#xA;  ...&#xA;  Although a GtkFlowBox must have only FlowBoxChild children, you can add any kind of widget to it via add, and a GtkFlowBoxChild widget will automatically be inserted between the box and the widget.&#xA;&#xA;There it was: FlowBox wrapped my Label, and so it really wasn&#39;t helloworld inside the box, although I thought I had added it. That&#39;s why program segfaulted when I tried to remove the label. &#xA;&#xA;Liskov principle violation&#xA;&#xA;In this case it&#39;s the FlowBox that breaks the substitution principle. Instance of FlowBox cannot be treated as a Container by the user. This one was easy to spot as I was instantiating the box myself so I knew its exact type. The problem would have been worse had add and remove methods been invoked farther away from the instantiation code. It might have been written by another developer who doesn&#39;t even know of the FlowBox class at all.&#xA;&#xA;Understanding what caused the issue was satisfying, but I wasn&#39;t ready to let go of it just yet. I wanted to understand what the fundamental issue here was. Container in this case could be considered as a generic container, and FlowBox a derived class with a narrower element type. In this case the GTK classes themselves are not parametrized, but my Java trained brain was happy to recognize a familiar pattern!&#xA;&#xA;Java type system is infamous for having invariant generics, meaning ListString is not a subtype of ListObject, even thought String is a subtype of Object. This restriction limits developer&#39;s options when writing code but it provides greater compile time safety. (Just as a sidenote; Vala is more loose in this case, allowing more assignments at compile time and failing at runtime.) Kotlin language offers more fine-tuned control while maintaining strict compile time checks. It does this at the expanse of language complexity.&#xA;&#xA;Thinking of Kotlin in this context made me suspect that I was still missing something crucial. I generally find Kotlin interesting but overly complex at times. Its handling of generics is one example of that complexity. So perhaps I was too focused on the type system and compiler in this case? And in GTK widgets hierarchy there was no generic type information to begin with.&#xA;&#xA;Reframing the problem&#xA;&#xA;The issue with FlowBox and Container wasn&#39;t that type system was too weak to properly define relationship between them. It&#39;s simpler than that. The Container defined a special relationship between its add and remove methods. This contract is described in the documentation. It&#39;s easily understandable by a human reader, in fact that&#39;s how I managed to find the issue. However, it&#39;s completely transparent to the type system and the compiler.&#xA;&#xA;Liskov substitution principle is helpful with precisely this type of problems. When working with strongly typed languages it&#39;s easy to forget how many expectations and rules for using a piece of code there are. This is to be expected since the compiler tries to check those rules for us. In a perfect world compiled would stop us from creating invalid derived classes in the first place. However, we are not there yet, and perhaps never will be.&#xA;&#xA;There are a lot of situations when contracts are not enforceable by the compiler. Kotlin&#39;s experimental contracts feature is an interesting attempt to expand the scope of the compile time checks. But even that covers only a simple form of contract that is related to a single method. It&#39;s hard to declaratively express arbitrary contracts involving multiple methods. The Container&#39;s add / remove is one example of such contract. Another popular one is a relationship between equals and hashcode methods.&#xA;&#xA;With this in mind the Liskov substitution principle could be reworded as:&#xA;&#xA;  Derived class must not break contracts of its base class.&#xA;&#xA;I find this to be an interesting wording from the perspective of an author of a derived class. Specifically:&#xA;&#xA;It drops the user of the code from my consideration. I no longer have to think about how someone else might attempt to use my derived class. There&#39;s no more thinking about substitutions.&#xA;It points me directly at what I need to pay attention to: it&#39;s the contracts defined by the base class. Those contracts might be expressible in the type system, in which case I can rely on the compiler. Or they might be implicit, in which case I need to pay more attention. In this way it&#39;s more actionable that the original wording.&#xA;&#xA;Admittedly, this new wording has a problem of defining a contract. In this aspect the original form is far more elegant and precise. It&#39;s easier to define what a substitution_ is.&#xA;&#xA;Another problem is that there&#39;s no clear standard for expressing contracts outside a type system. Putting them into code comments or documentation is one way to go about it. Comments are cheap to add initially and human readers can usually understand them relatively easily. On the other hand they are hard to maintain and reading them requires context switching. There are also annotations that can be used for expressing contracts. For example Java&#39;s @Nullable and @NotNull placed on methods to describe return values and parameters. Some times the code of a base class is available so contracts might be inferred from reading the source itself.&#xA;&#xA;Wrap up&#xA;&#xA;Having written all of this down I was finally happy with my conclusions. Of course, none of this helped me fix my code. For that I found that if I manually wrapped my child widget into FlowBoxChild then add method will add it as-is, making the remove work.&#xA;&#xA;On the GTK side of things, the next major framework version will no longer include the Container class with add and remove methods. The migration guide suggests using specialized methods on the derived classes to add child widgets.&#xA;&#xA;Latest Kotlin version 1.4 does not include any improvements to the experimental contracts feature introduced in 1.3. And speaking of programing languages, I&#39;ve intentionally refrained from bringing up the Go contracts proposal in this discussion. It had only dealt with generics and was abandoned in favor of reusing existing language concepts.&#xA;&#xA;Lastly, I&#39;ve created a git repository with the example app from above. I&#39;ve also included versions in C and Python. Unsurprisingly, all three versions behave the same. You can find them on GitHub.&#xA;&#xA;If you liked this post and are interested in more similar content you can subscribe to this blog&#39;s RSS feed or follow @antolius@qua.name in fediverse. Alternatively, you can tell me all the things I&#39;m wrong about over at @antolius on Mastodon.&#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>An unsung hero of the SOLID principles.</p>

<blockquote><p>Derived classes must be substitutable for their base classes.</p>

<p><em>Liskov substitution principle</em>
</p></blockquote>

<p>Considering each of the <a href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod" rel="nofollow">SOLID princpiles</a> Liskov substitution principle (LSP) often gets least attention in both theoretical analysis and practical application. Single responsibility invites discussion with its definition of <em>The One</em> reason to change. As a result it has been extensively talked and blogged about. Open-closed principle is well covered by the object-oriented design patterns as many of them are essentially clever tricks for applying the principle. Similarly, there are many popular dependency injection frameworks that implement the dependency inversion. This empowers developers to more easily adhere to those two principles.</p>

<p>That leaves interface segregation and Liskov substitution principle. Of those two I find the former to be easier to abide by. In its definition interface segregation invites the code author to make their interfaces more concise. It&#39;s easier to follow because it relates directly to the activity that I, as a code author, am involved in; i.e. writing my interface.</p>

<p>In contrast, Liskov substitution asks me as author of the derived class to make sure it behaves same as the base class (written by someone else) from the perspective of the user code (written by yet another author). It&#39;s no just about me and my code, I need to consider two more perspectives. It requires a sort of developer empathy.</p>

<p>This isn&#39;t helped by examples that are often used to illustrate the violation of the principle. Classic example is the problem of modeling a square class as a derivative of a more generalized rectangle class. It&#39;s a valid example in theory, but is obviously contrived and as such fails to resonate. That&#39;s why I was excited when one of my real world bugs boiled down to a violation of Liskov substitution principle.</p>

<h2 id="the-bug" id="the-bug">The bug</h2>

<p>I&#39;ve recently been learning <a href="https://wiki.gnome.org/Projects/Vala" rel="nofollow">Vala</a> programming language and <a href="https://www.gtk.org/" rel="nofollow">GTK</a> framework. Vala is a higher-order language, with syntax similar to C# and Java, that compiles down to C. It promises to <em>make targeting the GNOME stack simple</em>. Vala is strongly typed and object-oriented, however this example does not rely on the language itself and can be reproduced in C code as well. GTK is a feature-packed UI toolkit with a rich hierarchy of widgets. It is in the thick of its widgets&#39; inheritance tree that the root of my problem lies.</p>

<p>In my app I needed a container widget that could expand dynamically row by row as I added more child elements to it. Luckily GTK covers just such use-case with its <a href="https://valadoc.org/gtk+-3.0/Gtk.FlowBox.html" rel="nofollow"><code>FlowBox</code></a> component. The <code>FlowBox</code> extends the abstract <a href="https://valadoc.org/gtk+-3.0/Gtk.Container.html" rel="nofollow"><code>Container</code></a> widget which defines the interface for adding and removing child widgets:</p>

<p><img src="https://i.postimg.cc/R0t83Thv/flowbox-container.png" alt="Container defines add and remove methods, FlowBox extends from it"></p>

<p>This was convenient as I needed to occasionally remove child widgets from the container. Here&#39;s a simplified example of what I wanted to achieve:</p>

<pre><code class="language-vala">public class ExampleApp : Gtk.Application {
	protected override void activate () {
		var window = new Gtk.ApplicationWindow (this);
		window.set_default_size (300, 200);

		var hello_world = new Gtk.Label (&#34;Hello, World!&#34;);

		var box = new Gtk.FlowBox ();
		box.add (hello_world);
		// removing the child immediately to simplify the example
		box.remove (hello_world);

		window.add (box);
		window.show_all ();
	}

	public static int main (string[] args) {
		var app = new ExampleApp ();
		return app.run (args);
	}
}
</code></pre>

<p>Try guessing what this program does:</p>
<ol><li>It opens an empty window.</li>
<li>It opens a window with <em>“Hello, World!”</em> text.</li>
<li>It segfaults.</li></ol>

<p>Spoiler alert: it&#39;s option 3:</p>

<pre><code class="language-shell">$ valac --pkg gtk+-3.0 app.vala &amp;&amp; ./app
(app:9912): GLib-CRITICAL **: 23:54:22.670: g_sequence_remove: assertion &#39;iter != NULL&#39; failed
(app:9912): Gtk-CRITICAL **: 23:54:22.670: gtk_widget_show_all: assertion &#39;GTK_IS_WIDGET (widget)&#39; failed
(app:9912): Gtk-CRITICAL **: 23:54:22.697: gtk_widget_get_visible: assertion &#39;GTK_IS_WIDGET (widget)&#39; failed
(app:9912): Gtk-CRITICAL **: 23:54:22.701: gtk_widget_get_visible: assertion &#39;GTK_IS_WIDGET (widget)&#39; failed
(app:9912): Gtk-CRITICAL **: 23:54:22.701: gtk_widget_get_visible: assertion &#39;GTK_IS_WIDGET (widget)&#39; failed
(app:9912): Gtk-CRITICAL **: 23:54:22.701: gtk_widget_get_visible: assertion &#39;GTK_IS_WIDGET (widget)&#39; failed
(app:9912): Gtk-CRITICAL **: 23:54:22.701: gtk_widget_get_visible: assertion &#39;GTK_IS_WIDGET (widget)&#39; failed
(app:9912): Gtk-CRITICAL **: 23:54:22.701: gtk_widget_is_visible: assertion &#39;GTK_IS_WIDGET (widget)&#39; failed
[1]    9912 segmentation fault  ./app
</code></pre>

<h2 id="flawed-box" id="flawed-box">Flawed box</h2>

<p>What went wrong? The first thing I checked was documentation of <code>add</code> and <code>remove</code> methods on the <code>Container</code> class. The latter one was more interesting (full doc available <a href="https://valadoc.org/gtk+-3.0/Gtk.Container.remove.html" rel="nofollow">here</a>):</p>

<blockquote><p>Removes widget from this.
widget must be inside this...</p></blockquote>

<p>This seemed like a reasonable constraint; I can&#39;t remove what&#39;s not there. But I just put my <code>hello_world</code> label into the <code>box</code>, how could it not be inside? On to the <code>FlowBox</code> docs (available in full <a href="https://valadoc.org/gtk+-3.0/Gtk.FlowBox.html" rel="nofollow">here</a>):</p>

<blockquote><p>A GtkFlowBox positions child widgets in sequence according to its orientation.
...
Although a GtkFlowBox must have only FlowBoxChild children, you can add any kind of widget to it via add, and a GtkFlowBoxChild widget will automatically be inserted between the box and the widget.</p></blockquote>

<p>There it was: <code>FlowBox</code> wrapped my <code>Label</code>, and so it really wasn&#39;t <code>hello_world</code> inside the <code>box</code>, although I thought I had added it. That&#39;s why program segfaulted when I tried to remove the label.</p>

<h2 id="liskov-principle-violation" id="liskov-principle-violation">Liskov principle violation</h2>

<p>In this case it&#39;s the <code>FlowBox</code> that breaks the substitution principle. Instance of <code>FlowBox</code> cannot be treated as a <code>Container</code> by the user. This one was easy to spot as I was instantiating the <code>box</code> myself so I knew its exact type. The problem would have been worse had <code>add</code> and <code>remove</code> methods been invoked farther away from the instantiation code. It might have been written by another developer who doesn&#39;t even know of the <code>FlowBox</code> class at all.</p>

<p>Understanding what caused the issue was satisfying, but I wasn&#39;t ready to let go of it just yet. I wanted to understand what the fundamental issue here was. <code>Container</code> in this case could be considered as a generic container, and <code>FlowBox</code> a derived class with a narrower element type. In this case the GTK classes themselves are not parametrized, but my Java trained brain was happy to recognize a familiar pattern!</p>

<p>Java type system is infamous for having invariant generics, meaning <code>List&lt;String&gt;</code> is not a subtype of <code>List&lt;Object&gt;</code>, even thought <code>String</code> is a subtype of <code>Object</code>. This restriction limits developer&#39;s options when writing code but it provides greater compile time safety. (Just as a sidenote; Vala is more loose in this case, allowing more assignments at compile time and failing at runtime.) <a href="https://kotlinlang.org/docs/reference/generics.html" rel="nofollow">Kotlin language offers</a> more fine-tuned control while maintaining strict compile time checks. It does this at the expanse of language complexity.</p>

<p>Thinking of Kotlin in this context made me suspect that I was still missing something crucial. I generally find Kotlin interesting but overly complex at times. Its handling of generics is one example of that complexity. So perhaps I was too focused on the type system and compiler in this case? And in GTK widgets hierarchy there was no generic type information to begin with.</p>

<h2 id="reframing-the-problem" id="reframing-the-problem">Reframing the problem</h2>

<p>The issue with <code>FlowBox</code> and <code>Container</code> wasn&#39;t that type system was too weak to properly define relationship between them. It&#39;s simpler than that. The <code>Container</code> defined a special relationship between its <code>add</code> and <code>remove</code> methods. This contract is described in the documentation. It&#39;s easily understandable by a human reader, in fact that&#39;s how I managed to find the issue. However, it&#39;s completely transparent to the type system and the compiler.</p>

<p>Liskov substitution principle is helpful with precisely this type of problems. When working with strongly typed languages it&#39;s easy to forget how many expectations and rules for using a piece of code there are. This is to be expected since the compiler tries to check those rules for us. In a perfect world compiled would stop us from creating invalid derived classes in the first place. However, we are not there yet, and perhaps never will be.</p>

<p>There are a lot of situations when contracts are not enforceable by the compiler. Kotlin&#39;s experimental <a href="https://kotlinlang.org/docs/reference/whatsnew13.html#contracts" rel="nofollow">contracts feature</a> is an interesting attempt to expand the scope of the compile time checks. But even that covers only a simple form of contract that is related to a single method. It&#39;s hard to declaratively express arbitrary contracts involving multiple methods. The <code>Container</code>&#39;s <code>add</code> / <code>remove</code> is one example of such contract. Another popular one is a relationship between equals and hashcode methods.</p>

<p>With this in mind the Liskov substitution principle could be reworded as:</p>

<blockquote><p>Derived class must not break contracts of its base class.</p></blockquote>

<p>I find this to be an interesting wording from the perspective of an author of a derived class. Specifically:</p>
<ol><li>It drops the user of the code from my consideration. I no longer have to think about how someone else might attempt to use my derived class. There&#39;s no more thinking about substitutions.</li>
<li>It points me directly at what I need to pay attention to: it&#39;s the contracts defined by the base class. Those contracts might be expressible in the type system, in which case I can rely on the compiler. Or they might be implicit, in which case I need to pay more attention. In this way it&#39;s more actionable that the original wording.</li></ol>

<p>Admittedly, this new wording has a problem of defining a <em>contract</em>. In this aspect the original form is far more elegant and precise. It&#39;s easier to define what a <em>substitution</em> is.</p>

<p>Another problem is that there&#39;s no clear standard for expressing contracts outside a type system. Putting them into code comments or documentation is one way to go about it. Comments are cheap to add initially and human readers can usually understand them relatively easily. On the other hand they are hard to maintain and reading them requires context switching. There are also annotations that can be used for expressing contracts. For example Java&#39;s <code>@Nullable</code> and <code>@NotNull</code> placed on methods to describe return values and parameters. Some times the code of a base class is available so contracts might be inferred from reading the source itself.</p>

<h2 id="wrap-up" id="wrap-up">Wrap up</h2>

<p>Having written all of this down I was finally happy with my conclusions. Of course, none of this helped me fix my code. For that I found that if I manually wrapped my child widget into <a href="https://valadoc.org/gtk+-3.0/Gtk.FlowBoxChild.html" rel="nofollow"><code>FlowBoxChild</code></a> then <code>add</code> method will add it as-is, making the <code>remove</code> work.</p>

<p>On the GTK side of things, the next major framework version will no longer include the <code>Container</code> class with <code>add</code> and <code>remove</code> methods. The <a href="https://developer.gnome.org/gtk4/stable/gtk-migrating-3-to-4.html#id-1.7.4.3.17" rel="nofollow">migration guide</a> suggests using specialized methods on the derived classes to add child widgets.</p>

<p>Latest Kotlin version 1.4 does not include any improvements to the experimental contracts feature introduced in 1.3. And speaking of programing languages, I&#39;ve intentionally refrained from bringing up the <a href="https://go.googlesource.com/proposal/+/master/design/go2draft-contracts.md" rel="nofollow">Go contracts proposal</a> in this discussion. It had only dealt with generics and was abandoned in favor of reusing existing language concepts.</p>

<p>Lastly, I&#39;ve created a git repository with the example app from above. I&#39;ve also included versions in C and Python. Unsurprisingly, all three versions behave the same. You can find them on <a href="https://github.com/Antolius/liskov-principal-violation-example" rel="nofollow">GitHub</a>.</p>

<p>If you liked this post and are interested in more similar content you can subscribe to this blog&#39;s <a href="https://qua.name/antolius/feed" rel="nofollow">RSS feed</a> or follow <code><a href="https://qua.name/@/antolius@qua.name" class="u-url mention" rel="nofollow">@<span>antolius@qua.name</span></a></code> in <a href="https://en.wikipedia.org/wiki/Fediverse" rel="nofollow">fediverse</a>. Alternatively, you can tell me all the things I&#39;m wrong about over at <a href="https://mastodon.social/@antolius" rel="nofollow">@antolius</a> on <a href="https://mastodon.social" rel="nofollow">Mastodon</a>.</p>
]]></content:encoded>
      <guid>https://qua.name/antolius/liskov-substitution-principle</guid>
      <pubDate>Mon, 31 Aug 2020 21:17:35 +0200</pubDate>
    </item>
    <item>
      <title>Making a testable Cobra CLI app</title>
      <link>https://qua.name/antolius/making-a-testable-cobra-cli-app</link>
      <description>&lt;![CDATA[I like Go programing language, and I like writing command line tools with it. I feel it strikes the perfect balance of convenience without magic, access to OS and portability. I also like using Cobra library for writing my CLIs. It helps me break my app into sub-commands and build consistent and feature rich command line experiences.&#xA;&#xA;However, I&#39;ve found that Cobra&#39;s documentation and its generation tool for scaffolding CLI projects encourage writing code with coupled responsibilities that&#39;s hard to test. In this post I&#39;ll explore an alternative approach to structuring Cobra based CLI apps. My goal is to decouple business logic from the command line interface, and to cover it with unit tests. I&#39;ve put together a simple project to showcase the idea: Passgen.!--more--&#xA;&#xA;Exploring the problem&#xA;&#xA;Let&#39;s start by creating a new project using Cobra Generator:&#xA;&#xA;$ cobra init passgen --pkg-name github.com/antolis/passgen&#xA;Your Cobra applicaton is ready at ~/passgen&#xA;$ tree passgen&#xA;passgen&#xA;├── cmd&#xA;│   └── root.go&#xA;├── LICENSE&#xA;└── main.go&#xA;&#xA;There&#39;s nothing wrong with this file structure per se, but I&#39;d prefer my main.go placed into a properly named subdirectory under cmd/. This will allow me to add other executables in the future, and it works nicely with the go tool. In fact, if you&#39;re a fan of meta references, you can check the source of Go tools themselves and see how they implements this pattern.&#xA;&#xA;If we take a look inside the generated main.go file, it looks innocent enough:&#xA;&#xA;// cmd/main.go&#xA;func main() {&#xA;&#x9;cmd.Execute()&#xA;}&#xA;&#xA;The cmd.Execute() function call hints at trouble. And here&#39;s what the generated root.go file looks like:&#xA;&#xA;// cmd/root.go&#xA;var cfgFile string // global state! 😧️&#xA;&#xA;var rootCmd = &amp;cobra.Command{&#xA;&#x9;/ command initialization /&#xA;} // more global state! 😖️&#xA;&#xA;func Execute() {&#xA;&#x9;if err := rootCmd.Execute(); err != nil {&#xA;&#x9;&#x9;fmt.Println(err)&#xA;&#x9;&#x9;os.Exit(1) // I&#39;d like main func to define exit code&#xA;&#x9;}&#xA;} // &#34;static&#34; func, uses all that global state 😓️&#xA;&#xA;func init() {&#xA;&#x9;cobra.OnInitialize(initConfig)&#xA;&#xA;&#x9;rootCmd.PersistentFlags().StringVar(&amp;cfgFile, &#34;config&#34;, &#34;&#34;, &#34;config file (default is $HOME/.passgen.yaml)&#34;)&#xA;&#x9;rootCmd.Flags().BoolP(&#34;toggle&#34;, &#34;t&#34;, false, &#34;Help message for toggle&#34;)&#xA;} // global state manipulation 😭️&#xA;&#xA;func initConfig() { / handling of the config file / }&#xA;&#xA;As you may have noticed, I don&#39;t like global state. Here are a few blogs that helped influence my opinions and explain the issue better than I could: &#xA;&#xA;A theory of modern Go, by Peter Bourgon&#xA;Go, without package scoped variables, by Dave Cheney&#xA;&#xA;In addition to objections to global state in general, there&#39;s one issue I&#39;d like to emphasize here: readability. This code implements the registration pattern based on the init func. That makes it hard to unravel the entire CLI app&#39;s command structure by starting from the main function.&#xA;&#xA;When adding new sub-commands using the Generator:&#xA;&#xA;$ cobra add generate&#xA;&#xA;newly generated sub-commands use the init func to register themselves with the root command. This is convenient as it allows the Generator to add new sub-commands without having to update any of the preexisting code. However it obscures the sub-command structure, as there&#39;s no single place where this strucutre is encoded in the source code.&#xA;&#xA;Cobra&#39;s documentation offers an example of an alternative approach. In it all sub-commands are instantiated within programs main function. This is convenient for the documentation example that needs to fit on one page, but doesn&#39;t scale well for a larger app.&#xA;&#xA;Better project structure&#xA;&#xA;I structured the Passgen project a bit differently:&#xA;&#xA;passgen&#xA;├── cmd&#xA;│   ├── passgen&#xA;│   │   └── main.go         # package main&#xA;│   ├── generate.go         # package cmd&#xA;│   ├── params.go           # package cmd&#xA;│   └── root.go             # package cmd&#xA;└── internal&#xA;    └── app&#xA;        ├── app.go          # package app&#xA;        ├── apptest.go     # package apptest&#xA;        └── words.go        # package app&#xA;&#xA;With package dependencies:&#xA;&#xA;+------+   +-----+   +-----+   +----------+&#xA;| main +--  + cmd +--  + app +&lt;--+ apptest |&#xA;+------+   +-+-+-+   +-----+   +----------+&#xA;             | |&#xA;        +----+ +----+&#xA;        |           |&#xA;        v           v&#xA;    +-------+   +-------+&#xA;    | Cobra |   | Viper |&#xA;    +-------+   +-------+&#xA;&#xA;This approach matches the hexagonal architecture). As such it&#39;s nothing fundamentally new. What I try to do here is apply those tried and true ideas to the particulars of the Cobra library and CLI app development in Go.&#xA;&#xA;Package main&#xA;&#xA;My main func is simple, but introduces a slight variation on the generated one:&#xA;&#xA;// cmd/passgen/main.go&#xA;func main() {&#xA;&#x9;root := cmd.RootCmd() // creating new instance of command&#xA;&#x9;if err := root.Execute(); err != nil { // Execute is a method&#xA;&#x9;&#x9;log.Fatal(err) // exit code is defined here in main&#xA;&#x9;}&#xA;}&#xA;&#xA;This enables me to define the root command with:&#xA;&#xA;// cmd/root.go&#xA;func RootCmd() cobra.Command {&#xA;&#x9;cmd := &amp;cobra.Command{ / command initialization / }&#xA;&#x9;cmd.AddCommand(&#xA;&#x9;&#x9;generateCmd(), // sub-commands are listed explicitly&#xA;&#x9;)&#xA;&#x9;return cmd&#xA;}&#xA;&#xA;I admit that listing sub-commands explicitly violates the open-closed principle because I have to update my root command whenever I add another top level sub-command. However, I find the simplicity of directly invoking methods preferable to the opaque self-registration based on the init function. This way you can follow method calls from the main func right down to the business logic.&#xA;&#xA;Business logic&#xA;&#xA;Speaking of the business logic, it&#39;s the interface between that logic housed in the app package and the cli package that&#39;s more interesting. Here I have two goals:&#xA;&#xA;Keep Cobra and Viper dependencies confined to the cli package.&#xA;Inject other dependencies into the app package to enable easy testing.&#xA;&#xA;With that in mind, here&#39;s what the app itself looks like:&#xA;&#xA;// internal/app/app.go&#xA;type App struct {&#xA;&#x9;Params Params&#xA;&#x9;Out io.Writer&#xA;&#x9;Random io.Reader&#xA;}&#xA;&#xA;type Params struct {&#xA;&#x9;Min      int&#xA;&#x9;// other externally configurable parameters&#xA;}&#xA;&#xA;func New() App {&#xA;&#x9;return &amp;App{ &amp;Params{}, os.Stdout, rand.Reader }&#xA;}&#xA;&#xA;func (a App) Generate() error {&#xA;&#x9;// implementation that first validates a.Params&#xA;&#x9;// then it uses them and the provided a.Random&#xA;&#x9;// to generate a password that it writes to a.Out&#xA;}&#xA;&#xA;The App struct encapsulates all application dependencies.&#xA;&#xA;The custom Params struct defines all user-configurable input parameters. Note that the App neither knows nor cares how user provided those parameters. App does, however, handle parameter validation, making that part of the testable business logic.&#xA;&#xA;App sends all its output to the provided io.Writer. This makes writing unit tests easier because they don&#39;t need to sniff out the standard output, and they can still check the output formatting. This makes output formatting another part of the business logic.&#xA;&#xA;Lastly, the injected Random io.Reader is used as a source of randomness. The crypto/rand package from the standard library dictates this type. This is just one example of a dependency; in other applications you might want to inject HTTP client, database connection, etc.&#xA;&#xA;With all this in place I can write classic table driven unit tests for all my business logic. It also means that I can write a CLI command like this:&#xA;&#xA;// cmd/generate.go&#xA;func generateCmd() cobra.Command {&#xA;&#x9;a := app.New() // App instance with production grade dependencies&#xA;&#x9;cmd := &amp;cobra.Command{&#xA;&#x9;&#x9;Use:     &#34;generate&#34;,&#xA;&#x9;&#x9;// documentation related fields...&#xA;&#x9;&#x9;PreRunE: func(cmd cobra.Command, args []string) error {&#xA;&#x9;&#x9;&#x9;// this reads parameters from command line&#xA;&#x9;&#x9;&#x9;// arguments, flags and config files:&#xA;&#x9;&#x9;&#x9;return initParams(cmd, a.Params)&#xA;&#x9;&#x9;},&#xA;&#x9;&#x9;RunE: func(cmd *cobra.Command, args []string) error {&#xA;&#x9;&#x9;&#x9;return a.Generate()&#xA;&#x9;&#x9;},&#xA;&#x9;}&#xA;&#x9;cmd.Flags().IntVarP(&amp;a.Params.Min, &#34;min&#34;, &#34;m&#34;, 16, &#34;Min length&#34;)&#xA;&#x9;// the rest of the mapping from app.Props to flags&#xA;&#x9;return cmd&#xA;}&#xA;&#xA;One good thing about this approach is that no matter how complex the app logic gets its Cobra command will always be more-less the same. The only code that I allow in the cmd package is used to set up the Cobra command.&#xA;&#xA;Some extra benefits&#xA;&#xA;In addition to easy testing, there are a few nice consequences of this design. Not all of them are immediately useful, and some of them may indeed never be used. I still find them interesting!&#xA;&#xA;First of all, since I removed all the static init functions from the cli package, and since all commands are explicitly registered with their parent commands, it&#39;s now easy to create separate executables for a subset of those commands. All that&#39;s needed is to define a separate main function that executes not the root command, but one of the other higher level sub-commands.&#xA;&#xA;Second, I use the same app.Props struct for all sub-commands. This helps me keep various input parameters consistent and unique on the application level. I can then read them from a config file, where a user can define defaults for any flag without specifying the individual command that the flag is used with.&#xA;&#xA;Lastly, the App and it&#39;s logic is completely decoupled from the command line. That means it can easily be exposed behind other interfaces, like an HTTP server, or wrapped into a long running daemon process. This is usually not the first consideration when building CLI apps, but can become a handy benefit as project grows and evolves.&#xA;&#xA;Conclusion&#xA;&#xA;In conclusion, I find this project architecture allows me to test and scale my CLI apps and to get most out of libraries like Cobra and Viper. As previously mentioned, you can find the complete Passgen project on GitHub.&#xA;&#xA;If all this command line talk has piqued your interest, I invite you to check my more general blog series on designing a CLI application:&#xA;&#xA;CLI Development; Part 1 - Tower of Babel&#xA;CLI Development; Part 2 - Command line citizen&#xA;CLI Development; Part 3- Advanced use cases&#xA;&#xA;And in case you are interested in seeing this kind of content from me in the future, you can:&#xA;&#xA;Subscribe to this blog&#39;s RSS feed.&#xA;Follow @antolius@qua.name in fediverse.&#xA;&#xA;Or just come chat with me @antolius on Mastodon&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>I like <a href="https://golang.org/" rel="nofollow">Go</a> programing language, and I like writing command line tools with it. I feel it strikes the perfect balance of convenience without <em>magic</em>, access to OS and portability. I also like using <a href="https://github.com/spf13/cobra" rel="nofollow">Cobra</a> library for writing my CLIs. It helps me break my app into sub-commands and build consistent and feature rich command line experiences.</p>

<p>However, I&#39;ve found that Cobra&#39;s documentation and its generation tool for scaffolding CLI projects encourage writing code with coupled responsibilities that&#39;s hard to test. In this post I&#39;ll explore an alternative approach to structuring Cobra based CLI apps. My goal is to decouple business logic from the command line interface, and to cover it with unit tests. I&#39;ve put together a simple project to showcase the idea: <a href="https://github.com/Antolius/passgen" rel="nofollow">Passgen</a>.</p>

<h2 id="exploring-the-problem" id="exploring-the-problem">Exploring the problem</h2>

<p>Let&#39;s start by creating a new project using <a href="https://github.com/spf13/cobra/blob/master/cobra/README.md" rel="nofollow">Cobra Generator</a>:</p>

<pre><code class="language-sh">$ cobra init passgen --pkg-name github.com/antolis/passgen
Your Cobra applicaton is ready at ~/passgen
$ tree passgen
passgen
├── cmd
│   └── root.go
├── LICENSE
└── main.go
</code></pre>

<p>There&#39;s nothing wrong with this file structure per se, but I&#39;d prefer my <code>main.go</code> placed into a properly named subdirectory under <code>cmd/</code>. This will allow me to add other executables in the future, and it works nicely with the <code>go</code> tool. In fact, if you&#39;re a fan of <a href="https://xkcd.com/917/" rel="nofollow">meta references</a>, you can check the source of Go tools themselves and see how they <a href="https://github.com/golang/tools/tree/master/cmd" rel="nofollow">implements this pattern</a>.</p>

<p>If we take a look inside the generated <code>main.go</code> file, it looks innocent enough:</p>

<pre><code class="language-go">// cmd/main.go
func main() {
	cmd.Execute()
}
</code></pre>

<p>The <code>cmd.Execute()</code> function call hints at trouble. And here&#39;s what the generated <code>root.go</code> file looks like:</p>

<pre><code class="language-go">// cmd/root.go
var cfgFile string // global state! 😧️

var rootCmd = &amp;cobra.Command{
	/* command initialization */
} // more global state! 😖️

func Execute() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1) // I&#39;d like main func to define exit code
	}
} // &#34;static&#34; func, uses all that global state 😓️

func init() {
	cobra.OnInitialize(initConfig)

	rootCmd.PersistentFlags().StringVar(&amp;cfgFile, &#34;config&#34;, &#34;&#34;, &#34;config file (default is $HOME/.passgen.yaml)&#34;)
	rootCmd.Flags().BoolP(&#34;toggle&#34;, &#34;t&#34;, false, &#34;Help message for toggle&#34;)
} // global state manipulation 😭️

func initConfig() { /* handling of the config file */ }
</code></pre>

<p>As you may have noticed, I don&#39;t like global state. Here are a few blogs that helped influence my opinions and explain the issue better than I could:</p>
<ul><li><a href="https://peter.bourgon.org/blog/2017/06/09/theory-of-modern-go.html" rel="nofollow">A theory of modern Go</a>, by <a href="https://peter.bourgon.org/about/" rel="nofollow">Peter Bourgon</a></li>
<li><a href="https://dave.cheney.net/2017/06/11/go-without-package-scoped-variables" rel="nofollow">Go, without package scoped variables</a>, by <a href="https://dave.cheney.net/about" rel="nofollow">Dave Cheney</a></li></ul>

<p>In addition to objections to global state in general, there&#39;s one issue I&#39;d like to emphasize here: readability. This code implements the registration pattern based on the <code>init</code> func. That makes it hard to unravel the entire CLI app&#39;s command structure by starting from the <code>main</code> function.</p>

<p>When adding new sub-commands using the Generator:</p>

<pre><code class="language-sh">$ cobra add generate
</code></pre>

<p>newly generated sub-commands use the <code>init</code> func to register themselves with the root command. This is convenient as it allows the Generator to add new sub-commands without having to update any of the preexisting code. However it obscures the sub-command structure, as there&#39;s no single place where this strucutre is encoded in the source code.</p>

<p>Cobra&#39;s documentation offers an <a href="https://github.com/spf13/cobra#example" rel="nofollow">example</a> of an alternative approach. In it all sub-commands are instantiated within programs <code>main</code> function. This is convenient for the documentation example that needs to fit on one page, but doesn&#39;t scale well for a larger app.</p>

<h2 id="better-project-structure" id="better-project-structure">Better project structure</h2>

<p>I structured the Passgen project a bit differently:</p>

<pre><code class="language-sh">passgen
├── cmd
│   ├── passgen
│   │   └── main.go         # package main
│   ├── generate.go         # package cmd
│   ├── params.go           # package cmd
│   └── root.go             # package cmd
└── internal
    └── app
        ├── app.go          # package app
        ├── app_test.go     # package app_test
        └── words.go        # package app
</code></pre>

<p>With package dependencies:</p>

<pre><code>+------+   +-----+   +-----+   +----------+
| main +--&gt;+ cmd +--&gt;+ app +&lt;--+ app_test |
+------+   +-+-+-+   +-----+   +----------+
             | |
        +----+ +----+
        |           |
        v           v
    +-------+   +-------+
    | Cobra |   | Viper |
    +-------+   +-------+
</code></pre>

<p>This approach matches the <a href="https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)" rel="nofollow">hexagonal architecture</a>. As such it&#39;s nothing fundamentally new. What I try to do here is apply those tried and true ideas to the particulars of the Cobra library and CLI app development in Go.</p>

<h2 id="package-main" id="package-main">Package main</h2>

<p>My <code>main</code> func is simple, but introduces a slight variation on the generated one:</p>

<pre><code class="language-go">// cmd/passgen/main.go
func main() {
	root := cmd.RootCmd() // creating new instance of command
	if err := root.Execute(); err != nil { // Execute is a method
		log.Fatal(err) // exit code is defined here in main
	}
}
</code></pre>

<p>This enables me to define the root command with:</p>

<pre><code class="language-go">// cmd/root.go
func RootCmd() *cobra.Command {
	cmd := &amp;cobra.Command{ /* command initialization */ }
	cmd.AddCommand(
		generateCmd(), // sub-commands are listed explicitly
	)
	return cmd
}
</code></pre>

<p>I admit that listing sub-commands explicitly violates the <a href="https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle" rel="nofollow">open-closed principle</a> because I have to update my root command whenever I add another top level sub-command. However, I find the simplicity of directly invoking methods preferable to the opaque self-registration based on the <code>init</code> function. This way you can follow method calls from the <code>main</code> func right down to the business logic.</p>

<h2 id="business-logic" id="business-logic">Business logic</h2>

<p>Speaking of the business logic, it&#39;s the interface between that logic housed in the <code>app</code> package and the <code>cli</code> package that&#39;s more interesting. Here I have two goals:</p>
<ol><li>Keep Cobra and <a href="https://github.com/spf13/viper" rel="nofollow">Viper</a> dependencies confined to the <code>cli</code> package.</li>
<li>Inject other dependencies into the <code>app</code> package to enable easy testing.</li></ol>

<p>With that in mind, here&#39;s what the app itself looks like:</p>

<pre><code class="language-go">// internal/app/app.go
type App struct {
	Params *Params
	Out io.Writer
	Random io.Reader
}

type Params struct {
	Min      int
	// other externally configurable parameters
}

func New() *App {
	return &amp;App{ &amp;Params{}, os.Stdout, rand.Reader }
}

func (a *App) Generate() error {
	// implementation that first validates a.Params
	// then it uses them and the provided a.Random
	// to generate a password that it writes to a.Out
}
</code></pre>

<p>The <code>App</code> struct encapsulates all application dependencies.</p>

<p>The custom <code>Params</code> struct defines all user-configurable input parameters. Note that the <code>App</code> neither knows nor cares how user provided those parameters. <code>App</code> does, however, handle parameter validation, making that part of the testable business logic.</p>

<p><code>App</code> sends all its output to the provided <code>io.Writer</code>. This makes writing unit tests easier because they don&#39;t need to sniff out the standard output, and they can still check the output formatting. This makes output formatting another part of the business logic.</p>

<p>Lastly, the injected <code>Random io.Reader</code> is used as a source of randomness. The <code>crypto/rand</code> package from the standard library dictates this type. This is just one example of a dependency; in other applications you might want to inject HTTP client, database connection, etc.</p>

<p>With all this in place I can write classic <a href="https://dave.cheney.net/2019/05/07/prefer-table-driven-tests" rel="nofollow">table driven unit tests</a> for all my business logic. It also means that I can write a CLI command like this:</p>

<pre><code class="language-go">// cmd/generate.go
func generateCmd() *cobra.Command {
	a := app.New() // App instance with production grade dependencies
	cmd := &amp;cobra.Command{
		Use:     &#34;generate&#34;,
		// documentation related fields...
		PreRunE: func(cmd *cobra.Command, args []string) error {
			// this reads parameters from command line
			// arguments, flags and config files:
			return initParams(cmd, a.Params)
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			return a.Generate()
		},
	}
	cmd.Flags().IntVarP(&amp;a.Params.Min, &#34;min&#34;, &#34;m&#34;, 16, &#34;Min length&#34;)
	// the rest of the mapping from app.Props to flags
	return cmd
}
</code></pre>

<p>One good thing about this approach is that no matter how complex the app logic gets its Cobra command will always be more-less the same. The only code that I allow in the <code>cmd</code> package is used to set up the Cobra command.</p>

<h2 id="some-extra-benefits" id="some-extra-benefits">Some extra benefits</h2>

<p>In addition to easy testing, there are a few nice consequences of this design. Not all of them are immediately useful, and some of them may indeed never be used. I still find them interesting!</p>

<p>First of all, since I removed all the static <code>init</code> functions from the <code>cli</code> package, and since all commands are explicitly registered with their parent commands, it&#39;s now easy to create separate executables for a subset of those commands. All that&#39;s needed is to define a separate main function that executes not the root command, but one of the other higher level sub-commands.</p>

<p>Second, I use the same <code>app.Props</code> struct for all sub-commands. This helps me keep various input parameters consistent and unique on the application level. I can then read them from a config file, where a user can define defaults for any flag without specifying the individual command that the flag is used with.</p>

<p>Lastly, the <code>App</code> and it&#39;s logic is completely decoupled from the command line. That means it can easily be exposed behind other interfaces, like an HTTP server, or wrapped into a long running daemon process. This is usually not the first consideration when building CLI apps, but can become a handy benefit as project grows and evolves.</p>

<h2 id="conclusion" id="conclusion">Conclusion</h2>

<p>In conclusion, I find this project architecture allows me to test and scale my CLI apps and to get most out of libraries like Cobra and Viper. As previously mentioned, you can find the complete <a href="https://github.com/Antolius/passgen" rel="nofollow">Passgen</a> project on GitHub.</p>

<p>If all this command line talk has piqued your interest, I invite you to check my more general blog series on designing a CLI application:</p>
<ol><li><a href="https://qua.name/antolius/cli-development-part-1" rel="nofollow">CLI Development; Part 1 – Tower of Babel</a></li>
<li><a href="https://qua.name/antolius/cli-development-part-2" rel="nofollow">CLI Development; Part 2 – Command line citizen</a></li>
<li><a href="https://qua.name/antolius/cli-development-part-3" rel="nofollow">CLI Development; Part 3- Advanced use cases</a></li></ol>

<p>And in case you are interested in seeing this kind of content from me in the future, you can:</p>
<ul><li>Subscribe to this blog&#39;s <a href="https://qua.name/antolius/feed" rel="nofollow">RSS feed</a>.</li>
<li>Follow <code><a href="https://qua.name/@/antolius@qua.name" class="u-url mention" rel="nofollow">@<span>antolius@qua.name</span></a></code> in <a href="https://en.wikipedia.org/wiki/Fediverse" rel="nofollow">fediverse</a>.</li></ul>

<p>Or just come chat with me <a href="https://mastodon.social/@antolius" rel="nofollow">@antolius</a> on <a href="https://mastodon.social" rel="nofollow">Mastodon</a></p>
]]></content:encoded>
      <guid>https://qua.name/antolius/making-a-testable-cobra-cli-app</guid>
      <pubDate>Wed, 29 Jul 2020 00:49:30 +0200</pubDate>
    </item>
    <item>
      <title>Spring Cloud Gateway max HTTP header size</title>
      <link>https://qua.name/antolius/spring-cloud-gateway-max-http-header-size</link>
      <description>&lt;![CDATA[I&#39;ve already written about my experiences using Spring Cloud Gateway. While the framework continues to provide a great set of features, it does have its quirks. This is a story about one of them.!--more--&#xA;&#xA;Use-case&#xA; &#xA;Like a lot of stories, this one begins with a feature request. A few days ago I received a request from a client who wished to send large amounts of data through query parameters. Servers generally have a default limit on the maximum HTTP request size and will reject offending requests with HTTP status code 413 or 414. This behavior is configurable, and Spring Boot, which Cloud Gateway builds upon, provides a nice configuration abstraction that works with different servers.&#xA;&#xA;  This should be easy; 1 story point.&#xA;    famous last words&#xA;&#xA;1st attempt&#xA;&#xA;Spring Boot&#39;s common application properties include a property for just this situation: server.max-http-header-size. At first, I thought I&#39;d solve the tasks with a single config line in my app&#39;s application.yaml. Luckily I also added a test to cover this case. In my tests I use WireMock to simulate the backend service and then send requests through the gateway application. Test was rather straightforward:&#xA;&#xA;@Test&#xA;void shouldSupportLongQueryParameters() {&#xA;    // given&#xA;    var givenQueryParamLength = 10000;&#xA;    var givenQueryParam = new String(new char[givenQueryParamLength]).replaceAll(&#34;\0&#34;, &#34;a&#34;);&#xA;    stubFor(get(urlEqualTo(&#34;/foo/bars?q=&#34; + givenQueryParam))&#xA;            .willReturn(aResponse().withStatus(200))&#xA;    );&#xA;&#xA;    // when&#xA;    var actual = client.get().uri(&#34;/foo/bars?q=&#34; + givenQueryParam).exchange();&#xA;&#xA;    // then&#xA;    actual.expectStatus().isOk();&#xA;}&#xA;&#xA;To my surprise, running it resulted in an assertion failure:&#xA;&#xA;Status expected:200 OK but was:413 PAYLOADTOOLARGE&#xA;&#xA;2nd attempt&#xA;&#xA;Ok, I guess the common application property doesn&#39;t work. No problem. Spring Cloud Gateway is using Reactor Netty web server under the hood. So the next thing I looked at was that project&#39;s documentation. And indeed, as per documentation, Netty has 2 configuration parameters of note:&#xA;&#xA;The maximum length of the initial HTTP request line&#xA;The maximum length of all headers&#xA;&#xA;That explained why setting the max-http-header-size config property did not solve the issue: Netty requires a separate parameter for the initial line length, which query parameters are a part of. At this point I registered a slightly customized instance of NettyReactiveWebServerFactory as a bean in my context. In it I set both max header size and max initial line length:&#xA;&#xA;@Bean&#xA;public NettyReactiveWebServerFactory nettyFactory(ServerProperties serverProperties) {&#xA;    var maxInBytes = (int) serverProperties.getMaxHttpHeaderSize().toBytes();&#xA;    var factory = new NettyReactiveWebServerFactory();&#xA;    factory.addServerCustomizers(&#xA;            server -  server.httpRequestDecoder(&#xA;                    reqDecoder -  reqDecoder&#xA;                            .maxInitialLineLength(maxInBytes)&#xA;                            .maxHeaderSize(maxInBytes)&#xA;            )&#xA;    );&#xA;    return factory;&#xA;}&#xA;&#xA;That got me absolutely nowhere:&#xA;&#xA;Status expected:200 OK but was:413 PAYLOADTOOLARGE&#xA;&#xA;3rd attempt&#xA;&#xA;From this failure I realized I&#39;m still missing something crucial about the way in which Spring Boot sets up the Netty server. So I sprinkled a few breakpoints around the code and started debugging. The first thing I noticed was that my server factory&#39;s addServerCustomizers method was getting invoked a second time from within Spring code, specifically from NettyWebServerFactoryCustomizer.&#xA;&#xA;Turns out I didn&#39;t have to instantiate the entire server factory bean. There&#39;s a factory customization mechanism and all I needed to do was provide my own implementation of the customizer interface. The one implementation that Spring provides sets the Netty&#39;s max header size to the value of max-http-header-size application property. However, this did not explain why the value of max initial line length I was setting in my factory bean was getting ignored.&#xA;&#xA;To understand this I had to look into Reactor&#39;s HttpServer, specifically the code that factory customizers use to set max header and initial line values. According to the implementation of the HttpServer::httpRequestDecoder method each attempt to customize those values causes server to create a brand new spec object. This explained how Spring&#39;s factory customizer, which only sets max header size, managed to override my initial line config. What I needed to do was provide a factory customizer with lower order of execution, so that my values don&#39;t get overridden. I created my own WebServerFactoryCustomizer, and set its order to Ordered.LOWESTPRECEDENCE. Implementation was the same as before: I set both max header size and initial line length to the same value.&#xA;&#xA;I rerun the test and got:&#xA;&#xA;Status expected:200 OK but was:414 URITOOLONG&#xA;&#xA;That was... different?&#xA;&#xA;4th attempt&#xA;&#xA;I&#39;ve already established that Netty will return status code 413 if incoming request goes over max initial line setting. So this latest issue must have been somewhere else. Going through my test output log I found this mystery line:&#xA;&#xA;w.org.eclipse.jetty.http.HttpParser      : URI is too large   8192&#xA;&#xA;Where did Jetty come from? Well, there were actually 2 servers in the test: Spring Cloud Gateway app running on Netty and WireMock running on Jetty. Which meant my last attempt worked, I just needed to fix the test! Up until then I relied on Spring to auto-configure WireMock for me. However, I now needed to customize the max URL size for it. Luckily, this can be done easily by providing an instance of an Options bean:&#xA;&#xA;@Bean&#xA;public Options wireMockOptions(@Value(&#34;${wiremock.server.port}&#34;) int port) {&#xA;    return WireMockConfiguration.options()&#xA;            .port(port)&#xA;            .jettyHeaderBufferSize(16384);&#xA;}&#xA;&#xA;Jetty header buffer size was the only property that WireMock needed in order to configure larger max URL size. With this change the test finally passed, and the feature was complete!&#xA;&#xA;Example&#xA;&#xA;I&#39;ve created a demo project on GitHub that illustrates this implementation. I marked each of my attempts with a git tag, so you can follow them step by step. Feel free to check out the project and play around with it. If you find a better solution, please let me know about it! You can reach me at:&#xA;&#xA;josip.antolis@protonmail.com&#xA;@antolius on Mastodon&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>I&#39;ve <a href="https://qua.name/antolius/spring-cloud-gateway-connection-header" rel="nofollow">already written</a> about my experiences using <a href="https://spring.io/projects/spring-cloud-gateway" rel="nofollow">Spring Cloud Gateway</a>. While the framework continues to provide a great set of features, it does have its quirks. This is a story about one of them.</p>

<h2 id="use-case" id="use-case">Use-case</h2>

<p>Like a lot of stories, this one begins with a feature request. A few days ago I received a request from a client who wished to send large amounts of data through query parameters. Servers generally have a default limit on the maximum HTTP request size and will reject offending requests with HTTP status code <code>413</code> or <code>414</code>. This behavior is configurable, and Spring Boot, which Cloud Gateway builds upon, provides a nice configuration abstraction that works with different servers.</p>

<blockquote><p>This should be easy; 1 story point.</p>

<p><em>famous last words</em></p></blockquote>

<h2 id="1st-attempt" id="1st-attempt">1st attempt</h2>

<p>Spring Boot&#39;s <a href="https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/html/appendix-application-properties.html#server-properties" rel="nofollow">common application properties</a> include a property for just this situation: <code>server.max-http-header-size</code>. At first, I thought I&#39;d solve the tasks with a single config line in my app&#39;s <code>application.yaml</code>. Luckily I also added a test to cover this case. In my tests I use <a href="http://wiremock.org/" rel="nofollow">WireMock</a> to simulate the backend service and then send requests through the gateway application. Test was rather straightforward:</p>

<pre><code class="language-java">@Test
void shouldSupportLongQueryParameters() {
    // given
    var givenQueryParamLength = 10_000;
    var givenQueryParam = new String(new char[givenQueryParamLength]).replaceAll(&#34;\0&#34;, &#34;a&#34;);
    stubFor(get(urlEqualTo(&#34;/foo/bars?q=&#34; + givenQueryParam))
            .willReturn(aResponse().withStatus(200))
    );

    // when
    var actual = client.get().uri(&#34;/foo/bars?q=&#34; + givenQueryParam).exchange();

    // then
    actual.expectStatus().isOk();
}
</code></pre>

<p>To my surprise, running it resulted in an assertion failure:</p>

<pre><code>Status expected:&lt;200 OK&gt; but was:&lt;413 PAYLOAD_TOO_LARGE&gt;
</code></pre>

<h2 id="2nd-attempt" id="2nd-attempt">2nd attempt</h2>

<p>Ok, I guess the common application property doesn&#39;t work. No problem. Spring Cloud Gateway is using Reactor Netty web server under the hood. So the next thing I looked at was that project&#39;s documentation. And indeed, <a href="https://projectreactor.io/docs/netty/0.9.8.RELEASE/reference/index.html#_http_request_decoder" rel="nofollow">as per documentation</a>, Netty has 2 configuration parameters of note:</p>
<ol><li>The maximum length of the initial HTTP request line</li>
<li>The maximum length of all headers</li></ol>

<p>That explained why setting the <code>max-http-header-size</code> config property did not solve the issue: Netty requires a separate parameter for the initial line length, which query parameters are a part of. At this point I registered a slightly customized instance of <a href="https://github.com/spring-projects/spring-boot/blob/v2.3.1.RELEASE/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java" rel="nofollow"><code>NettyReactiveWebServerFactory</code></a> as a bean in my context. In it I set both max header size and max initial line length:</p>

<pre><code class="language-java">@Bean
public NettyReactiveWebServerFactory nettyFactory(ServerProperties serverProperties) {
    var maxInBytes = (int) serverProperties.getMaxHttpHeaderSize().toBytes();
    var factory = new NettyReactiveWebServerFactory();
    factory.addServerCustomizers(
            server -&gt; server.httpRequestDecoder(
                    reqDecoder -&gt; reqDecoder
                            .maxInitialLineLength(maxInBytes)
                            .maxHeaderSize(maxInBytes)
            )
    );
    return factory;
}
</code></pre>

<p>That got me absolutely nowhere:</p>

<pre><code>Status expected:&lt;200 OK&gt; but was:&lt;413 PAYLOAD_TOO_LARGE&gt;
</code></pre>

<h2 id="3rd-attempt" id="3rd-attempt">3rd attempt</h2>

<p>From this failure I realized I&#39;m still missing something crucial about the way in which Spring Boot sets up the Netty server. So I sprinkled a few breakpoints around the code and started debugging. The first thing I noticed was that my server factory&#39;s <code>addServerCustomizers</code> method was getting invoked a second time from within Spring code, specifically from <a href="https://github.com/spring-projects/spring-boot/blob/v2.3.1.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java" rel="nofollow"><code>NettyWebServerFactoryCustomizer</code></a>.</p>

<p>Turns out I didn&#39;t have to instantiate the entire server factory bean. There&#39;s a factory customization mechanism and all I needed to do was provide my own implementation of the customizer interface. The one implementation that Spring provides sets the Netty&#39;s max header size to the value of <code>max-http-header-size</code> application property. However, this did not explain why the value of max initial line length I was setting in my factory bean was getting ignored.</p>

<p>To understand this I had to look into Reactor&#39;s <a href="https://github.com/reactor/reactor-netty/blob/v0.9.8.RELEASE/src/main/java/reactor/netty/http/server/HttpServer.java#L458-L462" rel="nofollow"><code>HttpServer</code></a>, specifically the code that factory customizers use to set max header and initial line values. According to the implementation of the <code>HttpServer::httpRequestDecoder</code> method each attempt to customize those values causes server to create a brand new spec object. This explained how Spring&#39;s factory customizer, which only sets max header size, managed to override my initial line config. What I needed to do was provide a factory customizer with lower order of execution, so that my values don&#39;t get overridden. I created my own <code>WebServerFactoryCustomizer</code>, and set its order to <code>Ordered.LOWEST_PRECEDENCE</code>. Implementation was the same as before: I set both max header size and initial line length to the same value.</p>

<p>I rerun the test and got:</p>

<pre><code>Status expected:&lt;200 OK&gt; but was:&lt;414 URI_TOO_LONG&gt;
</code></pre>

<p>That was... different?</p>

<h2 id="4th-attempt" id="4th-attempt">4th attempt</h2>

<p>I&#39;ve already established that Netty will return status code <code>413</code> if incoming request goes over max initial line setting. So this latest issue must have been somewhere else. Going through my test output log I found this mystery line:</p>

<pre><code>w.org.eclipse.jetty.http.HttpParser      : URI is too large &gt;8192
</code></pre>

<p>Where did Jetty come from? Well, there were actually 2 servers in the test: Spring Cloud Gateway app running on Netty and WireMock running on Jetty. Which meant my last attempt worked, I just needed to fix the test! Up until then I relied on Spring to auto-configure WireMock for me. However, I now needed to customize the max URL size for it. Luckily, this can be done easily by providing an instance of an <code>Options</code> bean:</p>

<pre><code class="language-java">@Bean
public Options wireMockOptions(@Value(&#34;${wiremock.server.port}&#34;) int port) {
    return WireMockConfiguration.options()
            .port(port)
            .jettyHeaderBufferSize(16_384);
}
</code></pre>

<p>Jetty header buffer size was the only property that WireMock needed in order to configure larger max URL size. With this change the test finally passed, and the feature was complete!</p>

<h2 id="example" id="example">Example</h2>

<p>I&#39;ve created a <a href="https://github.com/Antolius/spring-cloud-gateway-examples-query-length" rel="nofollow">demo project</a> on GitHub that illustrates this implementation. I marked each of my attempts with a git tag, so you can follow them step by step. Feel free to check out the project and play around with it. If you find a better solution, please let me know about it! You can reach me at:</p>
<ul><li><a href="mailto:josip.antolis@protonmail.com" rel="nofollow">josip.antolis@protonmail.com</a></li>
<li><a href="https://mastodon.social/@antolius" rel="nofollow">@antolius</a> on <a href="https://mastodon.social" rel="nofollow">Mastodon</a></li></ul>
]]></content:encoded>
      <guid>https://qua.name/antolius/spring-cloud-gateway-max-http-header-size</guid>
      <pubDate>Thu, 16 Jul 2020 00:12:35 +0200</pubDate>
    </item>
    <item>
      <title>The joy of code review</title>
      <link>https://qua.name/antolius/the-joy-of-code-review</link>
      <description>&lt;![CDATA[I love code reviews. I love sharing my solutions with others and receiving their feedback. I love seeing what others have developed and finding ways to improve it. I love thinking about code quality and debating it with others. In this blog post, I hope to pass a little bit of that love on to you.!--more--&#xA;&#xA;I will examine some coding best practices and see how they can be applied to code review itself. I&#39;ll borrow inspiration from Uncle Bob Martin. I agree with many of his ideas and they make for some good quotes. I have experience working in a product oriented, mid-sized development team. Ideas I&#39;ll be discussing relate to a 5 - 10 person team reviewing each others code that&#39;s mostly constrained to a handful of products they own.&#xA;&#xA;It&#39;s not about catching bugs&#xA;&#xA;  The secondary value of software is its behavior. ... The ability of software to tolerate and facilitate such ongoing change is the primary value of software.&#xA;    Uncle Bob&#xA;&#xA;I really like this idea of Uncle Bob&#39;s: that fulfilling immediate requirements is secondary to facilitating the future changes. I believe similar can be said of code reviews. The secondary value of code review is to improve the quality of a given code update. Its primary value is to improve all the future code updates!&#xA;&#xA;This commitment to long term improvement means that code reviews should be a learning opportunity for everyone involved. The goal is no longer just to identify bugs, but to teach each other how to produce better code.&#xA;&#xA;In order to achieve this, reviewer should use their comments to educate. It&#39;s not enough just to point out deficiencies. They should propose improvements along with the reasoning for them. The reviewer can be helped in this by a shared set of team values and a common language.&#xA;&#xA;The set of shared values can be as simple as everyone on a team agreeing that they should write clean code. This is where common language kicks in by insuring everyone&#39;s idea of clean code is the same. Common team language is also valuable outside code reviews and there are techniques for building it. One technique I like is a book club in which team members read the same technical book and meet every few weeks to discuss the latest set of chapters. Another technique is the architecture drawing exercise I wrote about before. All this allows reviewer to, for example, simply reference one of the SOLID principles as a motivation for their comment.&#xA;&#xA;Education goes both ways! One way for code author to educate the reviewer is by following good coding practices. They can, however, do more. While comments in code itself are undesirable, I find them useful in a code review. Author of the code can leave comments in the pull request that can be educational for the reviewer.&#xA;&#xA;I find this a good method for teaching design patterns. They can often be hard for  junior developers to grasp. While books on the subject do contain examples, those can be hard to relate to. When a code author introduces a particular design pattern in a pull request they can leave a comment with a link to a theoretical explanation of the pattern. This way a junior reviewer can learn the pattern by seeing it applied to a code base they&#39;re familiar with, and solving a domain problem they understand.&#xA;&#xA;Encourage good behavior&#xA;&#xA;  Leave the campground cleaner than the way you found it.&#xA;    Uncle Bob&#xA;&#xA;There are some good behaviors you may wish to encourage in your team. For me a good example of that is the famous boy scout rule: always leave the code just a little bit better than it was when you found it. This rule is easy to express and can be easily recognized by a human. Yet, it&#39;s somewhat hard for automatic checks such as liters to detect and enforce it.&#xA;&#xA;This makes it a perfect consideration during code review. Reviewer can call for boy scouting where author may have missed it. However, they have an even greater opportunity: to praise the improvements already submitted by the author! This is a handy way to give immediate positive feedback on a desired behavior. And it&#39;s a damn effective one. If you&#39;ve ever received a comment praising your pull request you&#39;ll know how good it can feel when someone else recognizes your hard work and commitment to good practices.&#xA;&#xA;Review for readability&#xA;&#xA;  The ratio of time spent reading (code) versus writing is well over 10 to 1 ... (therefore) making it easy to read makes it easier to write.&#xA;    Uncle Bob&#xA;&#xA;Code review is often the first time someone besides the author reads the code. Simultaneously, this is also the time when it&#39;s easiest to change the code. It&#39;s still fresh in author&#39;s mind, it&#39;s not even in the master branch yet, no one is using it. This combination can be a powerful one.&#xA;&#xA;Junior reviewers can have an advantage here. Intermediate level developers can have a tendency to over-complicate their code. This is a simple byproduct of their expanding skill set. Having a junior reviewer on a such pull request can be helpful as they can call it out. Sometimes a complex chain of callbacks can be rewritten as a simple for loop that will be easier to understand for everyone.&#xA;&#xA;Code review is also a good opportunity to get buy in from another member of the team. If maintenance and future development is shared between all team members it&#39;s important that everyone accept and understand the author&#39;s code as if it was their own. Code review is the first time this happens. We should encourage reviewers to express their confusion with the code. If they don&#39;t understand the code today, when they are seeing it in isolated pull request and they have time to examine it, then they won&#39;t be able to troubleshoot it tomorrow, when it&#39;s integrated with the code base and they are under pressure to fix an issue.&#xA;&#xA;Don&#39;t automate away the humanity&#xA;&#xA;  Programming is a social activity.&#xA;    Uncle Bob&#xA;&#xA;There are aspects of code review that can and should be automated. Things like code formatting, compiling and linting. By all means add git hooks to ensure uniform code style. Hook up CI pipeline to build the project and run tests on each commit. In my team we agree to start the review only after Jenkins job has passed.&#xA;&#xA;All these tools help automate repetitive steps and make reviewer&#39;s life easier. However, I&#39;d caution against relying on them exclusively. I still need a fellow developer to check the readability of my code. Static code analysis can gamify development, but it can&#39;t replace the recognition and encouragement of my peers. There&#39;s no substitute for discussion of coding practices and learning how to apply them that might happen during a review.&#xA;&#xA;Quality code review requires time, commitment and skill. Reviewer needs to approach it with dedication and seriousness. Code author should take the feedback in with an open mind. It&#39;s hard to receive critique of ones own code. It&#39;s hard to distinguish personal preference from best practice. This can be solved with mutual respect, trust and good intentions from both parties. With that, benefits of a quality code review span far beyond a single pull request.&#xA;&#xA;If you have any feedback on the subject of code reviews, you can reach me:&#xA;&#xA;via email: josip.antolis@protonmail.com&#xA;or on Mastodon @antolius ]]&gt;</description>
      <content:encoded><![CDATA[<p>I love code reviews. I love sharing my solutions with others and receiving their feedback. I love seeing what others have developed and finding ways to improve it. I love thinking about code quality and debating it with others. In this blog post, I hope to pass a little bit of that love on to you.</p>

<p>I will examine some coding best practices and see how they can be applied to code review itself. I&#39;ll borrow inspiration from Uncle Bob Martin. I agree with many of his ideas and they make for some good quotes. I have experience working in a product oriented, mid-sized development team. Ideas I&#39;ll be discussing relate to a 5 – 10 person team reviewing each others code that&#39;s mostly constrained to a handful of products they own.</p>

<h2 id="it-s-not-about-catching-bugs" id="it-s-not-about-catching-bugs">It&#39;s not about catching bugs</h2>

<blockquote><p>The secondary value of software is its behavior. ... The ability of software to tolerate and facilitate such ongoing change is the primary value of software.</p>

<p><em>Uncle Bob</em></p></blockquote>

<p>I really like this idea of Uncle Bob&#39;s: that fulfilling immediate requirements is secondary to facilitating the future changes. I believe similar can be said of code reviews. The secondary value of code review is to improve the quality of a given code update. Its primary value is to improve all the future code updates!</p>

<p>This commitment to long term improvement means that code reviews should be a learning opportunity for everyone involved. The goal is no longer just to identify bugs, but to teach each other how to produce better code.</p>

<p>In order to achieve this, reviewer should use their comments to educate. It&#39;s not enough just to point out deficiencies. They should propose improvements along with the reasoning for them. The reviewer can be helped in this by a shared set of team values and a common language.</p>

<p>The set of shared values can be as simple as everyone on a team agreeing that they should write clean code. This is where common language kicks in by insuring everyone&#39;s idea of <em>clean code</em> is the same. Common team language is also valuable outside code reviews and there are techniques for building it. One technique I like is a book club in which team members read the same technical book and meet every few weeks to discuss the latest set of chapters. Another technique is the <a href="https://qua.name/antolius/architecture-drawing-exercise" rel="nofollow">architecture drawing exercise</a> I wrote about before. All this allows reviewer to, for example, simply reference one of the SOLID principles as a motivation for their comment.</p>

<p>Education goes both ways! One way for code author to educate the reviewer is by following good coding practices. They can, however, do more. While comments in code itself are undesirable, I find them useful in a code review. Author of the code can leave comments in the pull request that can be educational for the reviewer.</p>

<p>I find this a good method for teaching design patterns. They can often be hard for  junior developers to grasp. While books on the subject do contain examples, those can be hard to relate to. When a code author introduces a particular design pattern in a pull request they can leave a comment with a link to a theoretical explanation of the pattern. This way a junior reviewer can learn the pattern by seeing it applied to a code base they&#39;re familiar with, and solving a domain problem they understand.</p>

<h2 id="encourage-good-behavior" id="encourage-good-behavior">Encourage good behavior</h2>

<blockquote><p>Leave the campground cleaner than the way you found it.</p>

<p><em>Uncle Bob</em></p></blockquote>

<p>There are some good behaviors you may wish to encourage in your team. For me a good example of that is the famous boy scout rule: always leave the code just a little bit better than it was when you found it. This rule is easy to express and can be easily recognized by a human. Yet, it&#39;s somewhat hard for automatic checks such as liters to detect and enforce it.</p>

<p>This makes it a perfect consideration during code review. Reviewer can call for boy scouting where author may have missed it. However, they have an even greater opportunity: to praise the improvements already submitted by the author! This is a handy way to give immediate positive feedback on a desired behavior. And it&#39;s a damn effective one. If you&#39;ve ever received a comment praising your pull request you&#39;ll know how good it can feel when someone else recognizes your hard work and commitment to good practices.</p>

<h2 id="review-for-readability" id="review-for-readability">Review for readability</h2>

<blockquote><p>The ratio of time spent reading (code) versus writing is well over 10 to 1 ... (therefore) making it easy to read makes it easier to write.</p>

<p><em>Uncle Bob</em></p></blockquote>

<p>Code review is often the first time someone besides the author reads the code. Simultaneously, this is also the time when it&#39;s easiest to change the code. It&#39;s still fresh in author&#39;s mind, it&#39;s not even in the master branch yet, no one is using it. This combination can be a powerful one.</p>

<p>Junior reviewers can have an advantage here. Intermediate level developers can have a tendency to over-complicate their code. This is a simple byproduct of their expanding skill set. Having a junior reviewer on a such pull request can be helpful as they can call it out. Sometimes a complex chain of callbacks can be rewritten as a simple for loop that will be easier to understand for everyone.</p>

<p>Code review is also a good opportunity to get buy in from another member of the team. If maintenance and future development is shared between all team members it&#39;s important that everyone accept and understand the author&#39;s code as if it was their own. Code review is the first time this happens. We should encourage reviewers to express their confusion with the code. If they don&#39;t understand the code today, when they are seeing it in isolated pull request and they have time to examine it, then they won&#39;t be able to troubleshoot it tomorrow, when it&#39;s integrated with the code base and they are under pressure to fix an issue.</p>

<h2 id="don-t-automate-away-the-humanity" id="don-t-automate-away-the-humanity">Don&#39;t automate away the humanity</h2>

<blockquote><p>Programming is a social activity.</p>

<p><em>Uncle Bob</em></p></blockquote>

<p>There are aspects of code review that can and should be automated. Things like code formatting, compiling and linting. By all means add git hooks to ensure uniform code style. Hook up CI pipeline to build the project and run tests on each commit. In my team we agree to start the review only after Jenkins job has passed.</p>

<p>All these tools help automate repetitive steps and make reviewer&#39;s life easier. However, I&#39;d caution against relying on them exclusively. I still need a fellow developer to check the readability of my code. Static code analysis can gamify development, but it can&#39;t replace the recognition and encouragement of my peers. There&#39;s no substitute for discussion of coding practices and learning how to apply them that might happen during a review.</p>

<p>Quality code review requires time, commitment and skill. Reviewer needs to approach it with dedication and seriousness. Code author should take the feedback in with an open mind. It&#39;s hard to receive critique of ones own code. It&#39;s hard to distinguish personal preference from best practice. This can be solved with mutual respect, trust and good intentions from both parties. With that, benefits of a quality code review span far beyond a single pull request.</p>

<p>If you have any feedback on the subject of code reviews, you can reach me:</p>
<ul><li>via email: <a href="mailto:josip.antolis@protonmail.com" rel="nofollow">josip.antolis@protonmail.com</a></li>
<li>or on <a href="https://mastodon.social" rel="nofollow">Mastodon</a> <a href="https://mastodon.social/@antolius" rel="nofollow">@antolius</a></li></ul>
]]></content:encoded>
      <guid>https://qua.name/antolius/the-joy-of-code-review</guid>
      <pubDate>Fri, 08 May 2020 00:14:01 +0200</pubDate>
    </item>
    <item>
      <title>Kotlin script running experiment</title>
      <link>https://qua.name/antolius/kotlin-script-running-experiment</link>
      <description>&lt;![CDATA[In this blog post I&#39;ll go over building a prototype of Java application that can load and run Kotlin scripts at runtime. Extra requirement is to support scripts written in various mutually incompatible Kotlin language versions. This experiment is an isolated, self-contained project, but it does explore a real-world use-case that I&#39;ve encountered.!--more--&#xA;&#xA;Use-case&#xA;&#xA;Kotlin has language features that make it well suited for scripting and using DSLs. As such it is a good candidate for writing more involved configuration files. A good example of this is Gradle&#39;s Kotlin DSL. The configuration file use-case can be generalized into a plugin system. In this case the base application can be extended at runtime with any number of Kotlin scripts.&#xA;&#xA;Such plug-able application can be paired with an HTTP server. In this case the server can execute a plugin script in response to an HTTP request, and use its output as an HTTP response. At this point the application is begging to resemble a simplified Function as a service system. It can read plugin scripts from a public source (e.g. a git repository) and have users submit their own scripts.&#xA;&#xA;With time, as the service grows in popularity, users submit many different scripts. On the other hand development of Kotlin progresses and there are new language version releases. Script developers, enticed by new language features, start requesting support for newer Kotlin versions.&#xA;&#xA;Unfortunately, some of the code in existing scripts is using experimental Kotlin 1.1 features that have suffered breaking changes in subsequent 1.2 and 1.3 releases. This makes upgrading the Kotlin version in the base application problematic. Migrating to 1.3 would make enthusiastic script developers happy, but would also break some existing scripts. On the other hand, scripts cannot be upgraded to newer Kotlin versions and still run on the existing 1.1 version used by the server application. This chicken and the egg problem causes a stand still and Kotlin version is locked to 1.1.&#xA;&#xA;The solution&#xA;&#xA;In this experiment I&#39;ve built a simplified plugin engine that can be used to load and execute Kotlin scripts with various language versions. I&#39;ve skipped fetching scripts form public git repositories, running HTTP server and matching requests to scripts. The solution is lacking in security and performance as well.&#xA;&#xA;What it does achieve is illustrate a solution of the stated use-case in an isolated, self contained project. Complete source code can be found on GitHub.&#xA;&#xA;Running scripts&#xA;&#xA;My first step was to build Java app that can load and run a Kotlin script at runtime. Java itself provides a scripting API (defined by JSR 223) for abstracting the mechanics of running scripts in compatible languages. Form its version 1.1 Kotlin provides an implementation of this Java API.&#xA;&#xA;API documentation suggests registering scripting engine implementations in a special file inside META-INF directory and using dedicated manager to obtain engine instances. However, since I was planning on doing some jar juggling later on, I decided to instantiate Kotlin script engine programmatically and keep all of it in my source code.&#xA;&#xA;At this stage the application was a straightforward maven project with few lines of Java code.&#xA;&#xA;project&#xA;    modelVersion4.0.0/modelVersion&#xA;    groupIdio.github.antolius/groupId&#xA;    artifactIdkotlin-engine-experiment/artifactId&#xA;    version0.1.0-SNAPSHOT/version&#xA;    packagingjar/packaging&#xA;    properties&#xA;        java.version8/java.version&#xA;        kotlin.version1.1.61/kotlin.version&#xA;    /properties&#xA;    dependencies&#xA;        dependency&#xA;            groupIdorg.jetbrains.kotlin/groupId&#xA;            artifactIdkotlin-script-util/artifactId&#xA;            version${kotlin.version}/version&#xA;        /dependency&#xA;        dependency&#xA;            groupIdorg.jetbrains.kotlin/groupId&#xA;            artifactIdkotlin-script-runtime/artifactId&#xA;            version${kotlin.version}/version&#xA;        /dependency&#xA;        dependency&#xA;            groupIdorg.jetbrains.kotlin/groupId&#xA;            artifactIdkotlin-compiler-embeddable/artifactId&#xA;            version${kotlin.version}/version&#xA;        /dependency&#xA;        dependency&#xA;            groupIdorg.jetbrains.kotlin/groupId&#xA;            artifactIdkotlin-reflect/artifactId&#xA;            version${kotlin.version}/version&#xA;        /dependency&#xA;    /dependencies&#xA;    build&#xA;        plugins&#xA;            plugin&#xA;                groupIdorg.apache.maven.plugins/groupId&#xA;                artifactIdmaven-compiler-plugin/artifactId&#xA;                configuration&#xA;                    source${java.version}/source&#xA;                    target${java.version}/target&#xA;                /configuration&#xA;            /plugin&#xA;        /plugins&#xA;    /build&#xA;/project&#xA;&#xA;public class Main {&#xA;    public static void main(String[] args) throws Exception {&#xA;        String kotlinScript = &#34;\&#34;Using Kotlin version: &#34;&#xA;            &#34;${KotlinVersion.CURRENT}\&#34;&#34;;&#xA;        ScriptEngine engine = new KotlinJsr223JvmLocalScriptEngineFactory()&#xA;            .getScriptEngine();&#xA;        Object result = engine.eval(kotlinScript);&#xA;        System.out.println(result); // Using Kotlin version: 1.1.60&#xA;    }&#xA;}&#xA;&#xA;ScriptEngine provides a method for evaluating source code from a java.io.Reader, so executing a script from a file was easy too.&#xA;&#xA;Multi module&#xA;&#xA;Now that the app could load and run Kotlin scripts it was time to support multiple language versions. The maven project described in the previous section declares a compile-time dependency on a specific Kotlin version. Since I needed to support multiple versions I decided to load Kotlin dependencies into separate class loaders at runtime. That way I could work with different versions of Kotlin libraries at the same time. &#xA;&#xA;Next step was to turn the application into a multi module maven project. That way each module could declare a dependency on a distinct Kotlin version. I created 4 modules:&#xA;&#xA;Three Kotlin modules, each with a dependency on a different Kotlin version and code for instantiating the Kotlin JSR 223 script engine.&#xA;Engine module, that contained script loading logic, and didn&#39;t have any Kotlin dependency. Instead it loaded the three Kotlin modules&#39; jars in runtime.&#xA;&#xA;Each of the three Kotlin modules included a single class:&#xA;&#xA;package io.github.antolius.engine.kotlin1;&#xA;// imports...&#xA; &#xA;public class ScriptEngineSupplier implements SupplierScriptEngine {&#xA;    @Override&#xA;    public ScriptEngine get() {&#xA;        return new KotlinJsr223JvmLocalScriptEngineFactory().getScriptEngine();&#xA;    }&#xA;}&#xA;&#xA;The only difference was the package name. Module with 1.1 Kotlin dependency had package kotlin1, module with 1.2 package kotlin2 etc.&#xA;&#xA;The engine module created a dedicated class loader for each language version and loaded individual Kotlin module jar in runtime. It instantiated the Supplier from that jar:&#xA;&#xA;public class ScriptEngineFactory {&#xA;    public ScriptEngine newEngine(&#xA;        URL kotlinModuleJar,&#xA;        String fullyQuelifiedSupplierClassName&#xA;    ) {&#xA;        ClassLoader classLoader = newClassLoaderWith(kotlinModuleJar);&#xA;        SupplierScriptEngine supplier = instantiateSupplierFrom(&#xA;            fullyQuelifiedSupplierClassName,&#xA;            classLoader&#xA;        );&#xA;        return supplier.get();&#xA;    }&#xA;&#xA;    private ClassLoader newClassLoaderWith(URL kotlinModuleJar) {&#xA;        try {&#xA;            return URLClassLoader.newInstance(&#xA;                new URL[] {kotlinModuleJar},&#xA;                getClass().getClassLoader()&#xA;            );&#xA;        } catch (Exception e) {&#xA;            throw new RuntimeException(&#34;Couldn&#39;t create class loader&#34;, e);&#xA;        }&#xA;    }&#xA;&#xA;    private SupplierScriptEngine instantiateSupplierFrom(&#xA;        String className,&#xA;        ClassLoader classLoader&#xA;    ) {&#xA;        try {&#xA;            Class? loadedClass = Class&#xA;                .forName(className, true, classLoader);&#xA;            ClassSupplier&lt;ScriptEngine  supplierClass = cast(loadedClass);&#xA;            ConstructorSupplier&lt;ScriptEngine  constructor = supplierClass&#xA;                .getConstructor();&#xA;            return constructor.newInstance();&#xA;        } catch (Exception e) {&#xA;            throw new RuntimeException(&#34;Couldn&#39;t load &#34; + className, e);&#xA;        }&#xA;    }&#xA;&#xA;    @SuppressWarnings(&#34;unchecked&#34;)&#xA;    private ClassSupplier&lt;ScriptEngine  cast(Class? loadedClass) {&#xA;        return (ClassSupplier&lt;ScriptEngine  ) loadedClass;&#xA;    }&#xA;}&#xA;&#xA;This ScriptEngineFactory could be used to obtain an instance of  JSR 223 script engine capable of running Kotlin scripts with different versions. The problem was in knowing where to find those Kotlin module jars.&#xA;&#xA;The application technically worked, however it was difficult to build manually. At this point I had to compile each Kotlin module into a fat jar that contains both the Supplier implementation and its Kotlin dependencies. Then I had to somehow provide paths to those fat jars to the engine application at runtime.&#xA;&#xA;Maven tricks&#xA;&#xA;Building jars&#xA;&#xA;First thing that maven could help with was building fat jars for the three Kotlin modules. For this I used maven assembly plugin. Specifically I configured the plugin for Kotlin 1 module with:&#xA;&#xA;plugin&#xA;    groupIdorg.apache.maven.plugins/groupId&#xA;    artifactIdmaven-assembly-plugin/artifactId&#xA;    version3.1.1/version&#xA;    configuration&#xA;        descriptorRefs&#xA;            descriptorRefjar-with-dependencies/descriptorRef&#xA;        /descriptorRefs&#xA;        finalNamekotlin-1-module/finalName&#xA;        appendAssemblyIdfalse/appendAssemblyId&#xA;    /configuration&#xA;    executions&#xA;        execution&#xA;            idassemble-all/id&#xA;            phasepackage/phase&#xA;            goals&#xA;                goalsingle/goal&#xA;            /goals&#xA;        /execution&#xA;    /executions&#xA;/plugin&#xA;&#xA;I defined the final jar&#39;s name as kotlin-1-moule. This is important, since by default maven would have included the project version in the name and that would have complicated things for me later on. Config for other modules was nearly identical, just with different jar names.&#xA;&#xA;Packaging jars&#xA;&#xA;The next problem was finding those jars from within the engine module&#39;s code. I solved this by packaging fat jars as resources of the engine module. For this I used maven resources plugin configured in engine module&#39;s pom with:&#xA;&#xA;plugin&#xA;    artifactIdmaven-resources-plugin/artifactId&#xA;    version3.1.0/version&#xA;    executions&#xA;        execution&#xA;            idcopy-resources/id&#xA;            phasevalidate/phase&#xA;            goals&#xA;                goalcopy-resources/goal&#xA;            /goals&#xA;            configuration&#xA;                outputDirectory&#xA;                    ${project.build.outputDirectory}/kotlin-jars&#xA;                /outputDirectory&#xA;                resources&#xA;                    resource&#xA;                        directory&#xA;                            ${rootdir}/kotlin-1-module/target&#xA;                        /directory&#xA;                        filteringfalse/filtering&#xA;                        includes&#xA;                            includekotlin-1-module.jar/include&#xA;                        /includes&#xA;                    /resource&#xA;                    resource&#xA;                        directory&#xA;                            ${rootdir}/kotlin-2-module/target&#xA;                        /directory&#xA;                        filteringfalse/filtering&#xA;                        includes&#xA;                            includekotlin-2-module.jar/include&#xA;                        /includes&#xA;                    /resource&#xA;                    resource&#xA;                        directory&#xA;                            ${rootdir}/kotlin-3-module/target&#xA;                        /directory&#xA;                        filteringfalse/filtering&#xA;                        includes&#xA;                            includekotlin-3-module.jar/include&#xA;                        /includes&#xA;                    /resource&#xA;                /resources&#xA;            /configuration&#xA;        /execution&#xA;    /executions&#xA;/plugin&#xA;&#xA;where ${rootdir} was defined as:&#xA;&#xA;properties&#xA;    rootdir${project.parent.basedir}/rootdir&#xA;/properties&#xA;&#xA;For this to work properly I needed maven to build Kotlin modules first. This would generate the fat jars in their individual target directories. Then maven could build the engine module, and include fat jars as resources. Since engine module didn&#39;t declare direct dependencies on Kotlin modules, maven built modules in the order they appeared in the parent&#39;s pom:&#xA;&#xA;modules&#xA;    modulekotlin-1-module/module&#xA;    modulekotlin-2-module/module&#xA;    modulekotlin-3-module/module&#xA;    moduleengine/module&#xA;/modules&#xA;&#xA;Cleanup&#xA;&#xA;With this setup engine module was packaged with all of its runtime dependencies. Since individual jars didn&#39;t include project version in their names, the jar resource names were constant. This allowed me to define the jar URL and the fully qualified name of the Supplier implementation in an enum:&#xA;&#xA;public enum Language {&#xA;&#xA;    KOTLIN11(&#xA;            &#34;io.github.antolius.engine.kotlin1.ScriptEngineSupplier&#34;,&#xA;            &#34;/kotlin-jars/kotlin-1-module.jar&#34;&#xA;    ),&#xA;    KOTLIN12(&#xA;            &#34;io.github.antolius.engine.kotlin2.ScriptEngineSupplier&#34;,&#xA;            &#34;/kotlin-jars/kotlin-2-module.jar&#34;&#xA;    ),&#xA;    KOTLIN13(&#xA;            &#34;io.github.antolius.engine.kotlin3.ScriptEngineSupplier&#34;,&#xA;            &#34;/kotlin-jars/kotlin-3-module.jar&#34;&#xA;    );&#xA;&#xA;    private final String supplierClass;&#xA;    private final String resourceName;&#xA;&#xA;    Language(String supplierClass, String resourceName) {&#xA;        this.supplierClass = supplierClass;&#xA;        this.resourceName = resourceName;&#xA;    }&#xA;&#xA;    public String getSupplierClass() {&#xA;        return supplierClass;&#xA;    }&#xA;&#xA;    public URL getJarURL() {&#xA;        return this.getClass().getResource(resourceName);&#xA;    }&#xA;}&#xA;&#xA;The ScriptEngineFactory#newEngine method could now be simplified into:&#xA;&#xA;public class ScriptEngineFactory {&#xA;    public ScriptEngine newEngine(Language version) {&#xA;        // rest of the code is more-less the same...&#xA;    }&#xA;}&#xA;&#xA;Plugin API&#xA;&#xA;At this point maven could build the project automatically, and the ScriptEngineFactory could be used to obtain JSR 223 script engine for any Kotlin version. The last usability problem left was defining an interface between scripts and the engine.&#xA;&#xA;For this purpose I introduced a dedicated API maven module, and added it as a dependency for the rest of the modules. Within it I defined the Plugin interface as:&#xA;&#xA;public interface Plugin {&#xA;    @NotNull&#xA;    Response process(@NotNull Request req);&#xA;}&#xA;&#xA;Request and Response were just POJOs encapsulating all input and output parameters of the process method.  All that Kotlin scripts need to do in order to be compatible with the engine is return an instance of a Plugin.&#xA;&#xA;I also wanted to demonstrate how dependencies might be injected into scripts from Java code, so I defined two more interfaces:&#xA;&#xA;public interface Printer {&#xA;    void print(@NotNull String line);&#xA;}&#xA;&#xA;and&#xA;&#xA;public interface PrinterAware {&#xA;    void set(@NotNull Printer printer);&#xA;}&#xA;&#xA;Java code should implement the Printer, and scripts interested in using it should implement PrinterAware interface. To pull it all together I created a PluginLoader class in the engine module:&#xA;&#xA;public class PluginLoader {&#xA;    private final ScriptEngineFactory factory;&#xA;    private final Printer printer;&#xA;&#xA;    public PluginLoader(ScriptEngineFactory factory, Printer printer) {&#xA;        this.factory = factory;&#xA;        this.printer = printer;&#xA;    }&#xA;&#xA;    public Plugin load(File sourceFile, Language kotlinVersion) {&#xA;        Reader sourceFileReader = readerFrom(sourceFile);&#xA;        ScriptEngine engine = factory.newEngine(kotlinVersion);&#xA;        Plugin plugin = runScript(sourceFileReader, engine);&#xA;        autowirePrinter(plugin);&#xA;        return plugin;&#xA;    }&#xA;&#xA;    private Reader readerFrom(File source) {&#xA;        try {&#xA;            FileInputStream stream = new FileInputStream(source);&#xA;            return new InputStreamReader(stream, StandardCharsets.UTF_8);&#xA;        } catch (FileNotFoundException e) {&#xA;            String message = &#34;Couldn&#39;t create a reader for &#34; + source;&#xA;            throw new RuntimeException(message, e);&#xA;        }&#xA;    }&#xA;&#xA;    private Plugin runScript(Reader sourceReader, ScriptEngine engine) {&#xA;        try {&#xA;            Object result = engine.eval(sourceReader);&#xA;            return (Plugin) result;&#xA;        } catch (Exception e) {&#xA;            String message = &#34;Couldn&#39;t evaluate script to a Plugin instance&#34;;&#xA;            throw new RuntimeException(message, e);&#xA;        }&#xA;    }&#xA;&#xA;    private void autowirePrinter(Plugin plugin) {&#xA;        if (PrinterAware.class.isAssignableFrom(plugin.getClass())) {&#xA;            PrinterAware aware = (PrinterAware) plugin;&#xA;            aware.set(printer);&#xA;        }&#xA;    }&#xA;}&#xA;&#xA;PluginLoader could be used to load Kotlin scripts from files and provide the rest of the application with implementations of the Plugin interface.&#xA;&#xA;In conclusion&#xA;&#xA;The final Java application uses a few tricks to enable execution of mutually incompatible Kotlin scripts:&#xA;&#xA;Kotlin&#39;s implementation of JSR 223 script engine is used to evaluate scripts.&#xA;Script engines themselves are loaded into separated class loaders at runtme.&#xA;Various maven plugins are used to package all the different Kotlin dependencies as resources at build time.&#xA;Simple interfaces define a contract between Kotlin scripts and the rest of the application.&#xA;&#xA;As mentioned before, the complete project can be found on GitHub. In addition to the code discussed in this post, the full project contains a few extra bits:&#xA;&#xA;Tests that verify this whole thing actually works.&#xA;An example main method that can be executed to run a script.&#xA;A few Kotlin scripts implementing the Plugin interface.&#xA;Ability to load .kt classes in addition to .kts scripts.&#xA;Caching and reuse of Kotlin version specific class loaders.&#xA;&#xA;Building this prototype was a fun exercise for me, but now I&#39;d be interested in hearing from you as well. Do you see this kind of dynamic plugin system fitting into some of your projects? Have you encountered similar use-cases before, and if so, how did you solve them? Let me know:&#xA;&#xA;via email: josip.antolis@protonmail.com&#xA;or on Mastodon @antolius &#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>In this blog post I&#39;ll go over building a prototype of Java application that can load and run Kotlin scripts at runtime. Extra requirement is to support scripts written in various mutually incompatible Kotlin language versions. This experiment is an isolated, self-contained project, but it does explore a real-world use-case that I&#39;ve encountered.</p>

<h2 id="use-case" id="use-case">Use-case</h2>

<p>Kotlin has language features that make it well suited for scripting and using DSLs. As such it is a good candidate for writing more involved configuration files. A good example of this is <a href="https://docs.gradle.org/current/userguide/kotlin_dsl.html" rel="nofollow">Gradle&#39;s Kotlin DSL</a>. The configuration file use-case can be generalized into a plugin system. In this case the base application can be extended at runtime with any number of Kotlin scripts.</p>

<p>Such plug-able application can be paired with an HTTP server. In this case the server can execute a plugin script in response to an HTTP request, and use its output as an HTTP response. At this point the application is begging to resemble a simplified <a href="https://en.wikipedia.org/wiki/Function_as_a_service" rel="nofollow">Function as a service</a> system. It can read plugin scripts from a public source (e.g. a git repository) and have users submit their own scripts.</p>

<p>With time, as the service grows in popularity, users submit many different scripts. On the other hand development of Kotlin progresses and there are new language version releases. Script developers, enticed by new language features, start requesting support for newer Kotlin versions.</p>

<p>Unfortunately, some of the code in existing scripts is using experimental Kotlin <code>1.1</code> features that have suffered breaking changes in subsequent <code>1.2</code> and <code>1.3</code> releases. This makes upgrading the Kotlin version in the base application problematic. Migrating to <code>1.3</code> would make enthusiastic script developers happy, but would also break some existing scripts. On the other hand, scripts cannot be upgraded to newer Kotlin versions and still run on the existing <code>1.1</code> version used by the server application. This chicken and the egg problem causes a stand still and Kotlin version is locked to <code>1.1</code>.</p>

<h2 id="the-solution" id="the-solution">The solution</h2>

<p>In this experiment I&#39;ve built a simplified plugin engine that can be used to load and execute Kotlin scripts with various language versions. I&#39;ve skipped fetching scripts form public git repositories, running HTTP server and matching requests to scripts. The solution is lacking in security and performance as well.</p>

<p>What it does achieve is illustrate a solution of the stated use-case in an isolated, self contained project. Complete source code can be found on <a href="https://github.com/Antolius/kotlin-engine-experiment" rel="nofollow">GitHub</a>.</p>

<h2 id="running-scripts" id="running-scripts">Running scripts</h2>

<p>My first step was to build Java app that can load and run a Kotlin script at runtime. Java itself provides a <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/index.html" rel="nofollow">scripting API</a> (defined by <a href="https://www.jcp.org/en/jsr/detail?id=223" rel="nofollow">JSR 223</a>) for abstracting the mechanics of running scripts in compatible languages. Form its <a href="https://kotlinlang.org/docs/reference/whatsnew11.html#javaxscript-support" rel="nofollow">version <code>1.1</code></a> Kotlin provides an implementation of this Java API.</p>

<p>API documentation suggests registering scripting engine implementations in a special file inside <code>META-INF</code> directory and using dedicated manager to obtain engine instances. However, since I was planning on doing some jar juggling later on, I decided to instantiate Kotlin script engine programmatically and keep all of it in my source code.</p>

<p>At this stage the application was a straightforward maven project with few lines of Java code.</p>

<pre><code class="language-xml">&lt;project&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;groupId&gt;io.github.antolius&lt;/groupId&gt;
    &lt;artifactId&gt;kotlin-engine-experiment&lt;/artifactId&gt;
    &lt;version&gt;0.1.0-SNAPSHOT&lt;/version&gt;
    &lt;packaging&gt;jar&lt;/packaging&gt;
    &lt;properties&gt;
        &lt;java.version&gt;8&lt;/java.version&gt;
        &lt;kotlin.version&gt;1.1.61&lt;/kotlin.version&gt;
    &lt;/properties&gt;
    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.jetbrains.kotlin&lt;/groupId&gt;
            &lt;artifactId&gt;kotlin-script-util&lt;/artifactId&gt;
            &lt;version&gt;${kotlin.version}&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.jetbrains.kotlin&lt;/groupId&gt;
            &lt;artifactId&gt;kotlin-script-runtime&lt;/artifactId&gt;
            &lt;version&gt;${kotlin.version}&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.jetbrains.kotlin&lt;/groupId&gt;
            &lt;artifactId&gt;kotlin-compiler-embeddable&lt;/artifactId&gt;
            &lt;version&gt;${kotlin.version}&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.jetbrains.kotlin&lt;/groupId&gt;
            &lt;artifactId&gt;kotlin-reflect&lt;/artifactId&gt;
            &lt;version&gt;${kotlin.version}&lt;/version&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
    &lt;build&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
                &lt;configuration&gt;
                    &lt;source&gt;${java.version}&lt;/source&gt;
                    &lt;target&gt;${java.version}&lt;/target&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;
&lt;/project&gt;
</code></pre>

<pre><code class="language-java">public class Main {
    public static void main(String[] args) throws Exception {
        String kotlinScript = &#34;\&#34;Using Kotlin version: &#34;
            + &#34;${KotlinVersion.CURRENT}\&#34;&#34;;
        ScriptEngine engine = new KotlinJsr223JvmLocalScriptEngineFactory()
            .getScriptEngine();
        Object result = engine.eval(kotlinScript);
        System.out.println(result); // Using Kotlin version: 1.1.60
    }
}
</code></pre>

<p><code>ScriptEngine</code> provides a method for evaluating source code from a <code>java.io.Reader</code>, so executing a script from a file was easy too.</p>

<h3 id="multi-module" id="multi-module">Multi module</h3>

<p>Now that the app could load and run Kotlin scripts it was time to support multiple language versions. The maven project described in the previous section declares a compile-time dependency on a specific Kotlin version. Since I needed to support multiple versions I decided to load Kotlin dependencies into separate class loaders at runtime. That way I could work with different versions of Kotlin libraries at the same time.</p>

<p>Next step was to turn the application into a <a href="https://maven.apache.org/guides/mini/guide-multiple-modules.html" rel="nofollow">multi module</a> maven project. That way each module could declare a dependency on a distinct Kotlin version. I created 4 modules:</p>
<ul><li>Three Kotlin modules, each with a dependency on a different Kotlin version and code for instantiating the Kotlin JSR 223 script engine.</li>
<li>Engine module, that contained script loading logic, and didn&#39;t have any Kotlin dependency. Instead it loaded the three Kotlin modules&#39; jars in runtime.</li></ul>

<p>Each of the three Kotlin modules included a single class:</p>

<pre><code class="language-java">package io.github.antolius.engine.kotlin1;
// imports...
 
public class ScriptEngineSupplier implements Supplier&lt;ScriptEngine&gt; {
    @Override
    public ScriptEngine get() {
        return new KotlinJsr223JvmLocalScriptEngineFactory().getScriptEngine();
    }
}
</code></pre>

<p>The only difference was the package name. Module with <code>1.1</code> Kotlin dependency had package <code>kotlin1</code>, module with <code>1.2</code> package <code>kotlin2</code> etc.</p>

<p>The engine module created a dedicated class loader for each language version and loaded individual Kotlin module jar in runtime. It instantiated the <code>Supplier</code> from that jar:</p>

<pre><code class="language-java">public class ScriptEngineFactory {
    public ScriptEngine newEngine(
        URL kotlinModuleJar,
        String fullyQuelifiedSupplierClassName
    ) {
        ClassLoader classLoader = newClassLoaderWith(kotlinModuleJar);
        Supplier&lt;ScriptEngine&gt; supplier = instantiateSupplierFrom(
            fullyQuelifiedSupplierClassName,
            classLoader
        );
        return supplier.get();
    }

    private ClassLoader newClassLoaderWith(URL kotlinModuleJar) {
        try {
            return URLClassLoader.newInstance(
                new URL[] {kotlinModuleJar},
                getClass().getClassLoader()
            );
        } catch (Exception e) {
            throw new RuntimeException(&#34;Couldn&#39;t create class loader&#34;, e);
        }
    }

    private Supplier&lt;ScriptEngine&gt; instantiateSupplierFrom(
        String className,
        ClassLoader classLoader
    ) {
        try {
            Class&lt;?&gt; loadedClass = Class
                .forName(className, true, classLoader);
            Class&lt;Supplier&lt;ScriptEngine&gt;&gt; supplierClass = cast(loadedClass);
            Constructor&lt;Supplier&lt;ScriptEngine&gt;&gt; constructor = supplierClass
                .getConstructor();
            return constructor.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(&#34;Couldn&#39;t load &#34; + className, e);
        }
    }

    @SuppressWarnings(&#34;unchecked&#34;)
    private Class&lt;Supplier&lt;ScriptEngine&gt;&gt; cast(Class&lt;?&gt; loadedClass) {
        return (Class&lt;Supplier&lt;ScriptEngine&gt;&gt;) loadedClass;
    }
}
</code></pre>

<p>This <code>ScriptEngineFactory</code> could be used to obtain an instance of  JSR 223 script engine capable of running Kotlin scripts with different versions. The problem was in knowing where to find those Kotlin module jars.</p>

<p>The application technically worked, however it was difficult to build manually. At this point I had to compile each Kotlin module into a fat jar that contains both the <code>Supplier</code> implementation and its Kotlin dependencies. Then I had to somehow provide paths to those fat jars to the engine application at runtime.</p>

<h2 id="maven-tricks" id="maven-tricks">Maven tricks</h2>

<h3 id="building-jars" id="building-jars">Building jars</h3>

<p>First thing that maven could help with was building fat jars for the three Kotlin modules. For this I used <a href="https://maven.apache.org/plugins/maven-assembly-plugin/" rel="nofollow">maven assembly plugin</a>. Specifically I configured the plugin for Kotlin 1 module with:</p>

<pre><code class="language-xml">&lt;plugin&gt;
    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
    &lt;artifactId&gt;maven-assembly-plugin&lt;/artifactId&gt;
    &lt;version&gt;3.1.1&lt;/version&gt;
    &lt;configuration&gt;
        &lt;descriptorRefs&gt;
            &lt;descriptorRef&gt;jar-with-dependencies&lt;/descriptorRef&gt;
        &lt;/descriptorRefs&gt;
        &lt;finalName&gt;kotlin-1-module&lt;/finalName&gt;
        &lt;appendAssemblyId&gt;false&lt;/appendAssemblyId&gt;
    &lt;/configuration&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;id&gt;assemble-all&lt;/id&gt;
            &lt;phase&gt;package&lt;/phase&gt;
            &lt;goals&gt;
                &lt;goal&gt;single&lt;/goal&gt;
            &lt;/goals&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
&lt;/plugin&gt;
</code></pre>

<p>I defined the final jar&#39;s name as <code>kotlin-1-moule</code>. This is important, since by default maven would have included the project version in the name and that would have complicated things for me later on. Config for other modules was nearly identical, just with different jar names.</p>

<h3 id="packaging-jars" id="packaging-jars">Packaging jars</h3>

<p>The next problem was finding those jars from within the engine module&#39;s code. I solved this by packaging fat jars as resources of the engine module. For this I used <a href="https://maven.apache.org/plugins/maven-resources-plugin/" rel="nofollow">maven resources plugin</a> configured in engine module&#39;s pom with:</p>

<pre><code class="language-xml">&lt;plugin&gt;
    &lt;artifactId&gt;maven-resources-plugin&lt;/artifactId&gt;
    &lt;version&gt;3.1.0&lt;/version&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;id&gt;copy-resources&lt;/id&gt;
            &lt;phase&gt;validate&lt;/phase&gt;
            &lt;goals&gt;
                &lt;goal&gt;copy-resources&lt;/goal&gt;
            &lt;/goals&gt;
            &lt;configuration&gt;
                &lt;outputDirectory&gt;
                    ${project.build.outputDirectory}/kotlin-jars
                &lt;/outputDirectory&gt;
                &lt;resources&gt;
                    &lt;resource&gt;
                        &lt;directory&gt;
                            ${rootdir}/kotlin-1-module/target
                        &lt;/directory&gt;
                        &lt;filtering&gt;false&lt;/filtering&gt;
                        &lt;includes&gt;
                            &lt;include&gt;kotlin-1-module.jar&lt;/include&gt;
                        &lt;/includes&gt;
                    &lt;/resource&gt;
                    &lt;resource&gt;
                        &lt;directory&gt;
                            ${rootdir}/kotlin-2-module/target
                        &lt;/directory&gt;
                        &lt;filtering&gt;false&lt;/filtering&gt;
                        &lt;includes&gt;
                            &lt;include&gt;kotlin-2-module.jar&lt;/include&gt;
                        &lt;/includes&gt;
                    &lt;/resource&gt;
                    &lt;resource&gt;
                        &lt;directory&gt;
                            ${rootdir}/kotlin-3-module/target
                        &lt;/directory&gt;
                        &lt;filtering&gt;false&lt;/filtering&gt;
                        &lt;includes&gt;
                            &lt;include&gt;kotlin-3-module.jar&lt;/include&gt;
                        &lt;/includes&gt;
                    &lt;/resource&gt;
                &lt;/resources&gt;
            &lt;/configuration&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
&lt;/plugin&gt;
</code></pre>

<p>where <code>${rootdir}</code> was defined as:</p>

<pre><code class="language-xml">&lt;properties&gt;
    &lt;rootdir&gt;${project.parent.basedir}&lt;/rootdir&gt;
&lt;/properties&gt;
</code></pre>

<p>For this to work properly I needed maven to build Kotlin modules first. This would generate the fat jars in their individual <code>target</code> directories. Then maven could build the engine module, and include fat jars as resources. Since engine module didn&#39;t declare direct dependencies on Kotlin modules, maven built modules in the order they appeared in the parent&#39;s pom:</p>

<pre><code class="language-xml">&lt;modules&gt;
    &lt;module&gt;kotlin-1-module&lt;/module&gt;
    &lt;module&gt;kotlin-2-module&lt;/module&gt;
    &lt;module&gt;kotlin-3-module&lt;/module&gt;
    &lt;module&gt;engine&lt;/module&gt;
&lt;/modules&gt;
</code></pre>

<h3 id="cleanup" id="cleanup">Cleanup</h3>

<p>With this setup engine module was packaged with all of its runtime dependencies. Since individual jars didn&#39;t include project version in their names, the jar resource names were constant. This allowed me to define the jar URL and the fully qualified name of the <code>Supplier</code> implementation in an enum:</p>

<pre><code class="language-java">public enum Language {

    KOTLIN_1_1(
            &#34;io.github.antolius.engine.kotlin1.ScriptEngineSupplier&#34;,
            &#34;/kotlin-jars/kotlin-1-module.jar&#34;
    ),
    KOTLIN_1_2(
            &#34;io.github.antolius.engine.kotlin2.ScriptEngineSupplier&#34;,
            &#34;/kotlin-jars/kotlin-2-module.jar&#34;
    ),
    KOTLIN_1_3(
            &#34;io.github.antolius.engine.kotlin3.ScriptEngineSupplier&#34;,
            &#34;/kotlin-jars/kotlin-3-module.jar&#34;
    );

    private final String supplierClass;
    private final String resourceName;

    Language(String supplierClass, String resourceName) {
        this.supplierClass = supplierClass;
        this.resourceName = resourceName;
    }

    public String getSupplierClass() {
        return supplierClass;
    }

    public URL getJarURL() {
        return this.getClass().getResource(resourceName);
    }
}
</code></pre>

<p>The <code>ScriptEngineFactory#newEngine</code> method could now be simplified into:</p>

<pre><code class="language-java">public class ScriptEngineFactory {
    public ScriptEngine newEngine(Language version) {
        // rest of the code is more-less the same...
    }
}
</code></pre>

<h2 id="plugin-api" id="plugin-api">Plugin API</h2>

<p>At this point maven could build the project automatically, and the <code>ScriptEngineFactory</code> could be used to obtain JSR 223 script engine for any Kotlin version. The last usability problem left was defining an interface between scripts and the engine.</p>

<p>For this purpose I introduced a dedicated API maven module, and added it as a dependency for the rest of the modules. Within it I defined the <code>Plugin</code> interface as:</p>

<pre><code class="language-java">public interface Plugin {
    @NotNull
    Response process(@NotNull Request req);
}
</code></pre>

<p><code>Request</code> and <code>Response</code> were just POJOs encapsulating all input and output parameters of the <code>process</code> method.  All that Kotlin scripts need to do in order to be compatible with the engine is return an instance of a <code>Plugin</code>.</p>

<p>I also wanted to demonstrate how dependencies might be injected into scripts from Java code, so I defined two more interfaces:</p>

<pre><code class="language-java">public interface Printer {
    void print(@NotNull String line);
}
</code></pre>

<p>and</p>

<pre><code class="language-java">public interface PrinterAware {
    void set(@NotNull Printer printer);
}
</code></pre>

<p>Java code should implement the <code>Printer</code>, and scripts interested in using it should implement <code>PrinterAware</code> interface. To pull it all together I created a <code>PluginLoader</code> class in the engine module:</p>

<pre><code class="language-java">public class PluginLoader {
    private final ScriptEngineFactory factory;
    private final Printer printer;

    public PluginLoader(ScriptEngineFactory factory, Printer printer) {
        this.factory = factory;
        this.printer = printer;
    }

    public Plugin load(File sourceFile, Language kotlinVersion) {
        Reader sourceFileReader = readerFrom(sourceFile);
        ScriptEngine engine = factory.newEngine(kotlinVersion);
        Plugin plugin = runScript(sourceFileReader, engine);
        autowirePrinter(plugin);
        return plugin;
    }

    private Reader readerFrom(File source) {
        try {
            FileInputStream stream = new FileInputStream(source);
            return new InputStreamReader(stream, StandardCharsets.UTF_8);
        } catch (FileNotFoundException e) {
            String message = &#34;Couldn&#39;t create a reader for &#34; + source;
            throw new RuntimeException(message, e);
        }
    }

    private Plugin runScript(Reader sourceReader, ScriptEngine engine) {
        try {
            Object result = engine.eval(sourceReader);
            return (Plugin) result;
        } catch (Exception e) {
            String message = &#34;Couldn&#39;t evaluate script to a Plugin instance&#34;;
            throw new RuntimeException(message, e);
        }
    }

    private void autowirePrinter(Plugin plugin) {
        if (PrinterAware.class.isAssignableFrom(plugin.getClass())) {
            PrinterAware aware = (PrinterAware) plugin;
            aware.set(printer);
        }
    }
}
</code></pre>

<p><code>PluginLoader</code> could be used to load Kotlin scripts from files and provide the rest of the application with implementations of the <code>Plugin</code> interface.</p>

<h2 id="in-conclusion" id="in-conclusion">In conclusion</h2>

<p>The final Java application uses a few tricks to enable execution of mutually incompatible Kotlin scripts:</p>
<ol><li>Kotlin&#39;s implementation of JSR 223 script engine is used to evaluate scripts.</li>
<li>Script engines themselves are loaded into separated class loaders at runtme.</li>
<li>Various maven plugins are used to package all the different Kotlin dependencies as resources at build time.</li>
<li>Simple interfaces define a contract between Kotlin scripts and the rest of the application.</li></ol>

<p>As mentioned before, the complete project can be found on <a href="https://github.com/Antolius/kotlin-engine-experiment" rel="nofollow">GitHub</a>. In addition to the code discussed in this post, the full project contains a few extra bits:</p>
<ul><li>Tests that verify this whole thing actually works.</li>
<li>An example <code>main</code> method that can be executed to run a script.</li>
<li>A few Kotlin scripts implementing the <code>Plugin</code> interface.</li>
<li>Ability to load <code>.kt</code> classes in addition to <code>.kts</code> scripts.</li>
<li>Caching and reuse of Kotlin version specific class loaders.</li></ul>

<p>Building this prototype was a fun exercise for me, but now I&#39;d be interested in hearing from you as well. Do you see this kind of dynamic plugin system fitting into some of your projects? Have you encountered similar use-cases before, and if so, how did you solve them? Let me know:</p>
<ul><li>via email: <a href="mailto:josip.antolis@protonmail.com" rel="nofollow">josip.antolis@protonmail.com</a></li>
<li>or on <a href="https://mastodon.social" rel="nofollow">Mastodon</a> <a href="https://mastodon.social/@antolius" rel="nofollow">@antolius</a></li></ul>
]]></content:encoded>
      <guid>https://qua.name/antolius/kotlin-script-running-experiment</guid>
      <pubDate>Wed, 27 Nov 2019 10:04:54 +0100</pubDate>
    </item>
    <item>
      <title>Architecture drawing exercise</title>
      <link>https://qua.name/antolius/architecture-drawing-exercise</link>
      <description>&lt;![CDATA[When looking at teams of developers it&#39;s rare to find all members at the same skill level. Even in those rare occasions, they are likely to differ in their communication styles and in mental model of the system they are working on. On the other hand, it&#39;s important for team members to be able to communicate efficiently and to have a share common model of the application architecture.!--more--&#xA;&#xA;In the team I lead there are members with different skill levels, and we are developing and supporting multiple production services. I wanted to simultaneously:&#xA;&#xA;Improve the architecture-level overview juniors had of our services.&#xA;Bring our shared visual language to a next level.&#xA;&#xA;Here&#39;s an exercise I came up for achieving this.&#xA;&#xA;Rules of the game&#xA;&#xA;Players sit in a circle, for example around a conference table. They should have some space for themselves on the table, and they should have a clear idea of who the next person around the table is. At the beginning of the game, each player is given a peace of paper with a name of one of the team&#39;s services written on the top.&#xA;&#xA;In the first round, which takes 7 minutes, each player must draw the architecture of the service named on their paper. They must not use any letters or numbers in their diagrams. Other symbols, arrows, etc are permitted. After they&#39;re done drawing they should fold the paper so that only the diagram is visible and pass it to the next person around the table.&#xA;&#xA;In this way papers are shifted by one place, and each player is now presented with a drawing of an architecture diagram. In the second turn each player must guess the service that the diagram is depicting and write its name on the paper. This turn is a bit shorter, lasting at most 5 minutes. After the time expires, or everyone is done, each player should fold the paper again so that only the service name is visible and pass it on to the next player.&#xA;&#xA;The third turn is the same as the first one, with all players drawing the service named on their papers, folding them and passing them on. The game continues with a succession of odd drawing turns and even service naming turns until papers have made a full circle around the table. At the end all papers are unfolded and the group compares and comments on their diagrams and guesses. Each player picks the best ideas for drawing the service they started with and presents the definitive diagram for it. Those diagrams can later on be documented and refereed back to when needed. Additionally, expressed ideas, iconography, patterns etc. become part of the common visual language of the team and can be used in future diagrams to convey ideas more quickly and precisely.&#xA;&#xA;Takeaways from running the exercise&#xA;&#xA;It was immediately apparent how fun the exercise was for all participants. We&#39;ve had many laughs through the drawing and guessing parts of the game. It was equally fun to guess the service from others&#39; diagrams and to despair over ones own predicament when having to draw them. The fun helped more recluse team members to open up, and encouraged experimentation while reducing the fear of failure for less experienced teammates.&#xA;&#xA;It was also interesting to see the difference in approach between team members with more and less experience. The more senior people tended to use  established diagram types and shapes corresponding to certain architecture component. For example using a cilindar for a database or storage component, rectangle for an application, etc. On the other hand juniors tended to freestyle more, with some of them drawing business processes in almost cartoon-like style.&#xA;&#xA;The rule prohibiting the use of letters and numbers meant that team members had to come up with their own ways of labeling certain architecture components. In this aspect seniority did not appear to play a major role, as all participants approached the challenge with different levels of creativity. Common solutions included labeling third party technologies with their respective logos, and making up icons for internal applications that lack such branding. (As a side note, this got us thinking about developing branding for our in-house applications!)&#xA;&#xA;In the end we agreed on a common set of symbols for representing general architecture components and iconography for particular services. We also created a canonical diagram for each of our team&#39;s services.&#xA;&#xA;Review&#xA;&#xA;Later on I collected direct feedback on the exercise from all team members in our by-weekly one-on-one meetings. They all reacted well to it, and reported having fun (that much was always obvious). What was left as an open question is if the gained knowledge warranted the time investment. In the end an equivalent effect might have been achieved if a senior developer on the team took the time to render the architecture diagrams for all services and had juniors examine it and read up on different types of technical drawings.&#xA;&#xA;One benefit of the drawing exercise over this top-down approach is in its team building potential. Since all team members participate in defining the canonical diagrams and common iconography the sense of ownership over the final drawings is also shared. Additionally, those team members who benefit more from affirmation and positive feedback will find the inclusive nature of the exercise rewarding, since everyone&#39;s ideas are incorporated in the final design.&#xA;&#xA;If spending some extra time on this type of exercise sounds like a worthwhile trade-off to you, then feel free to run it with your own team! If you do so, I&#39;d love to hear your own results, reaction of your team members and any additional observations you might have. You can get in touch with me:&#xA;&#xA;Via email: josip.antolis@protonmail.com&#xA;Or on Mastodon @antolius ]]&gt;</description>
      <content:encoded><![CDATA[<p>When looking at teams of developers it&#39;s rare to find all members at the same skill level. Even in those rare occasions, they are likely to differ in their communication styles and in mental model of the system they are working on. On the other hand, it&#39;s important for team members to be able to communicate efficiently and to have a share common model of the application architecture.</p>

<p>In the team I lead there are members with different skill levels, and we are developing and supporting multiple production services. I wanted to simultaneously:</p>
<ul><li>Improve the architecture-level overview juniors had of our services.</li>
<li>Bring our shared visual language to a next level.</li></ul>

<p>Here&#39;s an exercise I came up for achieving this.</p>

<h2 id="rules-of-the-game" id="rules-of-the-game">Rules of the game</h2>

<p>Players sit in a circle, for example around a conference table. They should have some space for themselves on the table, and they should have a clear idea of who the next person around the table is. At the beginning of the game, each player is given a peace of paper with a name of one of the team&#39;s services written on the top.</p>

<p>In the first round, which takes 7 minutes, each player must draw the architecture of the service named on their paper. They must not use any letters or numbers in their diagrams. Other symbols, arrows, etc are permitted. After they&#39;re done drawing they should fold the paper so that only the diagram is visible and pass it to the next person around the table.</p>

<p>In this way papers are shifted by one place, and each player is now presented with a drawing of an architecture diagram. In the second turn each player must guess the service that the diagram is depicting and write its name on the paper. This turn is a bit shorter, lasting at most 5 minutes. After the time expires, or everyone is done, each player should fold the paper again so that only the service name is visible and pass it on to the next player.</p>

<p>The third turn is the same as the first one, with all players drawing the service named on their papers, folding them and passing them on. The game continues with a succession of odd drawing turns and even service naming turns until papers have made a full circle around the table. At the end all papers are unfolded and the group compares and comments on their diagrams and guesses. Each player picks the best ideas for drawing the service they started with and presents the definitive diagram for it. Those diagrams can later on be documented and refereed back to when needed. Additionally, expressed ideas, iconography, patterns etc. become part of the common visual language of the team and can be used in future diagrams to convey ideas more quickly and precisely.</p>

<h2 id="takeaways-from-running-the-exercise" id="takeaways-from-running-the-exercise">Takeaways from running the exercise</h2>

<p>It was immediately apparent how fun the exercise was for all participants. We&#39;ve had many laughs through the drawing and guessing parts of the game. It was equally fun to guess the service from others&#39; diagrams and to despair over ones own predicament when having to draw them. The fun helped more recluse team members to open up, and encouraged experimentation while reducing the fear of failure for less experienced teammates.</p>

<p>It was also interesting to see the difference in approach between team members with more and less experience. The more senior people tended to use  established diagram types and shapes corresponding to certain architecture component. For example using a cilindar for a database or storage component, rectangle for an application, etc. On the other hand juniors tended to freestyle more, with some of them drawing business processes in almost cartoon-like style.</p>

<p>The rule prohibiting the use of letters and numbers meant that team members had to come up with their own ways of labeling certain architecture components. In this aspect seniority did not appear to play a major role, as all participants approached the challenge with different levels of creativity. Common solutions included labeling third party technologies with their respective logos, and making up icons for internal applications that lack such branding. (As a side note, this got us thinking about developing branding for our in-house applications!)</p>

<p>In the end we agreed on a common set of symbols for representing general architecture components and iconography for particular services. We also created a <em>canonical</em> diagram for each of our team&#39;s services.</p>

<h2 id="review" id="review">Review</h2>

<p>Later on I collected direct feedback on the exercise from all team members in our by-weekly one-on-one meetings. They all reacted well to it, and reported having fun (that much was always obvious). What was left as an open question is if the gained knowledge warranted the time investment. In the end an equivalent effect might have been achieved if a senior developer on the team took the time to render the architecture diagrams for all services and had juniors examine it and read up on different types of technical drawings.</p>

<p>One benefit of the drawing exercise over this top-down approach is in its team building potential. Since all team members participate in defining the canonical diagrams and common iconography the sense of ownership over the final drawings is also shared. Additionally, those team members who benefit more from affirmation and positive feedback will find the inclusive nature of the exercise rewarding, since everyone&#39;s ideas are incorporated in the final design.</p>

<p>If spending some extra time on this type of exercise sounds like a worthwhile trade-off to you, then feel free to run it with your own team! If you do so, I&#39;d love to hear your own results, reaction of your team members and any additional observations you might have. You can get in touch with me:</p>
<ul><li>Via email: <a href="mailto:josip.antolis@protonmail.com" rel="nofollow">josip.antolis@protonmail.com</a></li>
<li>Or on <a href="https://mastodon.social" rel="nofollow">Mastodon</a> <a href="https://mastodon.social/@antolius" rel="nofollow">@antolius</a></li></ul>
]]></content:encoded>
      <guid>https://qua.name/antolius/architecture-drawing-exercise</guid>
      <pubDate>Sun, 27 Oct 2019 00:43:38 +0200</pubDate>
    </item>
    <item>
      <title>Incident management DnD</title>
      <link>https://qua.name/antolius/incident-management-dnd</link>
      <description>&lt;![CDATA[Any software system will eventually experience a degradation, outage or a similar incident. Depending on the type of business you&#39;re in this can lead to a loss of revenue and clients or even have legal repercussions. That is why it&#39;s important to have a good incident management process for resolving incidents, reporting on their impact and preventing them from happening again.&#xA;&#xA;In this blog post I&#39;ll describe my personal experience with some challenges of establishing the incident management process and why I built a tabletop role-playing game Deployments and Disasters to deal with them.!--more--&#xA;&#xA;My perspective&#xA;&#xA;I work at Infobip. We are a tech company with over 300 developers and additional 200 customer support engineers. Our developers are divided into teams of around 5 to 10 people. Teams own their services and are responsible for both building and maintaining them in production. Support engineers monitor key business metrics and maintain contact with clients. In total that&#39;s over 500 people and each one of them can be called upon to participate in resolving an ongoing incident.&#xA;&#xA;One benefit of this approach is that people most familiar with a given code-base will directly work on resolving the incident. Additionally, trained support personnel are in contact with clients thus allowing developers to focus on fixing the issue.&#xA;&#xA;On the other hand, there are drawbacks to this approach. Not everyone will work equally well under pressure, different people have different levels of experience, each team might develop their own procedures, use different tools, etc. Most of these can be addressed with a fine-tuned incident management procedure and a set of common tools to back it up. Some good ideas include chatops, centralized logging and metrics, premade dashboards and alerting. I will not go into details on these things here.&#xA;&#xA;Challenges to tackle&#xA;&#xA;What I&#39;d like to focus on instead are the following three challenges that emerge after management procedure and all of the tools are in place:&#xA;&#xA;All involved with incident management should familiarize themselves with the procedure and available tools. The more people the bigger this issue is. At one point even awareness of the process can become a problem.&#xA;Incident management process involves different roles: customer support, programmers, sysadmins, database administrators, devops engineers, etc. They all need to work together, despite having different objectives at any given time during the incident.&#xA;Many roles involved in incident management are technical. They view resolving the incident as their objective and are focused on detecting and removing the immediate cause of the issue. As a result they may not think of affected customers and thus miss out on opportunities to notify them of the impact, or even alleviate parts of it sooner.&#xA;&#xA;Awareness of the procedure&#xA;&#xA;Educating people about procedures and tools can generally be achieved with incident management training. Roughly speaking, there are 2 approaches to it:&#xA;&#xA;Simulating the incident realistically, with participants using actual tools, interacting with high fidelity data and directly applying their real life skills. &#xA;Keeping the training abstract and basing it on gaming techniques. I&#39;ve found success with adopting the mechanics of tabletop role-playing games.&#xA;&#xA;Picking a game based approach has several advantages. For one, it reduces the prohibitive cost of recreating the data required to realistically simulate the incident. It allows for addressing the other two challenges, namely the empathy towards other roles and customer centric mentality.&#xA;&#xA;However, the killer feature of game based training is that it&#39;s fun. Especially when compared to reading procedure documentation and how-to guides, or attending seminars. The benefits of this are twofold. First it makes the exercise more memorable for the attendants. Secondly, it helps with organizing future sessions, as people are more interested in attending.&#xA;&#xA;There&#39;s one additional benefit of role-playing based approach. It turns entire exercise into a structured storytelling experience. This structure provides a safe environment for all attendants to share their insights and knowledge with each other. The benefits are most noticeable with introverted players.&#xA;&#xA;Empathy for other roles&#xA;&#xA;At any one time during the incident, each different role might have a different objective. For example, support engineer needs to inform the clients of exact impact of the incident. On the other hand programmers need to identify the cause of the issue. In this situation support needs information on client facing API from the development team that is focused on debugging the backend. This can create tension between those two roles.&#xA;&#xA;One thing that games excel at is placing players into other people&#39;s shoes. In Deployments and Disasters I facilitate this by defining specific roles with unique mechanical characteristics. When starting the game session I make sure that players shuffle the roles so that they don&#39;t play the same one they have in real world. For example, I encourage developers to play the role of customer support.&#xA;&#xA;This has two benefits:&#xA;&#xA;Players get to experience what incident looks like from the perspective of other roles. This builds empathy by making players go through the tough choices and strive for hard to reach objectives that their colleagues usually experience.&#xA;It also encourages players to share their knowledge and practices. It reverses the real world dependencies between the roles. For example, if developers usually depend on database administrators for optimizing their databases then inverting the roles will make admins more sympathetic towards the other role&#39;s needs.&#xA;&#xA;Customer centric mindset&#xA;&#xA;I&#39;d like my developers to approach incident management with more of a customer centric mindset. Other teams, companies or situations may require some other adjustments. Fortunately, game mechanics are well suited for this.&#xA;&#xA;In games, players regularly receive and accomplish arbitrary objectives. By carefully picking stated objectives and mechanical incentives game designers can impact player mindset.&#xA;&#xA;In Deployments and Disasters I achieve this with a few rules:&#xA;&#xA;The main objective of the game session is to resolve the incident within a set number of turns, represented by an incident clock. At the beginning of the game players have 6 turns to resolve the issue. However, If they devote time to communicate the issues to the clients their time doubles to a total of 12 turns.&#xA;Clients are active actors in the game (controlled by the DM) and they can impact the state of the system. For example, they can escalate the problem by attempting to fix it themselves. Alternatively they can be used to reveal valuable information and hints.&#xA;During the course of the game some important  (gold / platinum) clients can contact the players and ask for status updates or request special attention. This can be used to illustrate different types of clients.&#xA;Incident scenario starts with only some clients impacted. Players can still escalate the situation and spread the impact to other clients. Or, they can proceed with caution and reduce the impact as they go along.&#xA;&#xA;Work so far&#xA;&#xA;So far I&#39;ve set up basic set of rules and game mechanics for Deployments and Disasters which you can find on GitHub. The game presented there is early sample of a work in progress. One significant ommition is the lack of incident scenarios. I&#39;ve created one of them for test runs I&#39;ve played at work, however it is tightly coupled with our internal procedures and custom tools we use. My plan is to create an example scenario with open-source tooling that anyone can use as a base for their exercise.&#xA;&#xA;I&#39;ve held two test training sessions at work and feedback was generally good. Players found the game entertaining, but also reported learning about new tools and procedures. I&#39;m yet to create additional scenarios, but there&#39;s interest in replaying the existing one with teams that haven&#39;t seen it yet. I&#39;m also exploring ways of connecting the exercise with employee evaluation and professional development programs that we have.&#xA;&#xA;Feel free to use the Deployments and Disasters to build your own incident scenarios on top of. Or stay tuned for future developments, as I will strive to publish example scenarios myself. You can watch the GitHub repo for updates, or follow this blog by:&#xA;&#xA;Subscribing to its RSS feed.&#xA;Following @antolius@qua.name in fediverse.&#xA;&#xA;If you have any feedback, comments or improvement ideas you can send me a pull request, or just contact me at:&#xA;&#xA;josip.antolis@protonmail.com&#xA;@antolius on Mastodon]]&gt;</description>
      <content:encoded><![CDATA[<p>Any software system will eventually experience a degradation, outage or a similar incident. Depending on the type of business you&#39;re in this can lead to a loss of revenue and clients or even have legal repercussions. That is why it&#39;s important to have a good incident management process for resolving incidents, reporting on their impact and preventing them from happening again.</p>

<p>In this blog post I&#39;ll describe my personal experience with some challenges of establishing the incident management process and why I built a <a href="https://en.wikipedia.org/wiki/Tabletop_role-playing_game" rel="nofollow">tabletop role-playing game</a> <a href="https://github.com/Antolius/deployments-and-disasters" rel="nofollow"><em>Deployments and Disasters</em></a> to deal with them.</p>

<h2 id="my-perspective" id="my-perspective">My perspective</h2>

<p>I work at Infobip. We are a tech company with over 300 developers and additional 200 customer support engineers. Our developers are divided into teams of around 5 to 10 people. Teams own their services and are responsible for both building and maintaining them in production. Support engineers monitor key business metrics and maintain contact with clients. In total that&#39;s over 500 people and each one of them can be called upon to participate in resolving an ongoing incident.</p>

<p>One benefit of this approach is that people most familiar with a given code-base will directly work on resolving the incident. Additionally, trained support personnel are in contact with clients thus allowing developers to focus on fixing the issue.</p>

<p>On the other hand, there are drawbacks to this approach. Not everyone will work equally well under pressure, different people have different levels of experience, each team might develop their own procedures, use different tools, etc. Most of these can be addressed with a fine-tuned incident management procedure and a set of common tools to back it up. Some good ideas include chatops, centralized logging and metrics, premade dashboards and alerting. I will not go into details on these things here.</p>

<h2 id="challenges-to-tackle" id="challenges-to-tackle">Challenges to tackle</h2>

<p>What I&#39;d like to focus on instead are the following three challenges that emerge after management procedure and all of the tools are in place:</p>
<ol><li>All involved with incident management should familiarize themselves with the procedure and available tools. The more people the bigger this issue is. At one point even awareness of the process can become a problem.</li>
<li>Incident management process involves different roles: customer support, programmers, sysadmins, database administrators, devops engineers, etc. They all need to work together, despite having different objectives at any given time during the incident.</li>
<li>Many roles involved in incident management are technical. They view resolving the incident as their objective and are focused on detecting and removing the immediate cause of the issue. As a result they may not think of affected customers and thus miss out on opportunities to notify them of the impact, or even alleviate parts of it sooner.</li></ol>

<h2 id="awareness-of-the-procedure" id="awareness-of-the-procedure">Awareness of the procedure</h2>

<p>Educating people about procedures and tools can generally be achieved with incident management training. Roughly speaking, there are 2 approaches to it:</p>
<ol><li>Simulating the incident realistically, with participants using actual tools, interacting with high fidelity data and directly applying their real life skills.</li>
<li>Keeping the training abstract and basing it on gaming techniques. I&#39;ve found success with adopting the mechanics of tabletop role-playing games.</li></ol>

<p>Picking a game based approach has several advantages. For one, it reduces the prohibitive cost of recreating the data required to realistically simulate the incident. It allows for addressing the other two challenges, namely the empathy towards other roles and customer centric mentality.</p>

<p>However, the killer feature of game based training is that it&#39;s fun. Especially when compared to reading procedure documentation and how-to guides, or attending seminars. The benefits of this are twofold. First it makes the exercise more memorable for the attendants. Secondly, it helps with organizing future sessions, as people are more interested in attending.</p>

<p>There&#39;s one additional benefit of role-playing based approach. It turns entire exercise into a structured storytelling experience. This structure provides a safe environment for all attendants to share their insights and knowledge with each other. The benefits are most noticeable with introverted players.</p>

<h2 id="empathy-for-other-roles" id="empathy-for-other-roles">Empathy for other roles</h2>

<p>At any one time during the incident, each different role might have a different objective. For example, support engineer needs to inform the clients of exact impact of the incident. On the other hand programmers need to identify the cause of the issue. In this situation support needs information on client facing API from the development team that is focused on debugging the backend. This can create tension between those two roles.</p>

<p>One thing that games excel at is placing players into other people&#39;s shoes. In <em>Deployments and Disasters</em> I facilitate this by defining specific roles with unique mechanical characteristics. When starting the game session I make sure that players shuffle the roles so that they don&#39;t play the same one they have in real world. For example, I encourage developers to play the role of customer support.</p>

<p>This has two benefits:</p>
<ol><li>Players get to experience what incident looks like from the perspective of other roles. This builds empathy by making players go through the tough choices and strive for hard to reach objectives that their colleagues usually experience.</li>
<li>It also encourages players to share their knowledge and practices. It reverses the real world dependencies between the roles. For example, if developers usually depend on database administrators for optimizing their databases then inverting the roles will make admins more sympathetic towards the other role&#39;s needs.</li></ol>

<h2 id="customer-centric-mindset" id="customer-centric-mindset">Customer centric mindset</h2>

<p>I&#39;d like my developers to approach incident management with more of a customer centric mindset. Other teams, companies or situations may require some other adjustments. Fortunately, game mechanics are well suited for this.</p>

<p>In games, players regularly receive and accomplish arbitrary objectives. By carefully picking stated objectives and mechanical incentives game designers can impact player mindset.</p>

<p>In <em>Deployments and Disasters</em> I achieve this with a few rules:</p>
<ol><li>The main objective of the game session is to resolve the incident within a set number of turns, represented by an incident clock. At the beginning of the game players have 6 turns to resolve the issue. However, If they devote time to communicate the issues to the clients their time doubles to a total of 12 turns.</li>
<li>Clients are active actors in the game (controlled by the DM) and they can impact the state of the system. For example, they can escalate the problem by attempting to fix it themselves. Alternatively they can be used to reveal valuable information and hints.</li>
<li>During the course of the game some important  (gold / platinum) clients can contact the players and ask for status updates or request special attention. This can be used to illustrate different types of clients.</li>
<li>Incident scenario starts with only some clients impacted. Players can still escalate the situation and spread the impact to other clients. Or, they can proceed with caution and reduce the impact as they go along.</li></ol>

<h2 id="work-so-far" id="work-so-far">Work so far</h2>

<p>So far I&#39;ve set up basic set of rules and game mechanics for <em>Deployments and Disasters</em> which you can find on <a href="https://github.com/Antolius/deployments-and-disasters" rel="nofollow">GitHub</a>. The game presented there is early sample of a work in progress. One significant ommition is the lack of incident scenarios. I&#39;ve created one of them for test runs I&#39;ve played at work, however it is tightly coupled with our internal procedures and custom tools we use. My plan is to create an example scenario with open-source tooling that anyone can use as a base for their exercise.</p>

<p>I&#39;ve held two test training sessions at work and feedback was generally good. Players found the game entertaining, but also reported learning about new tools and procedures. I&#39;m yet to create additional scenarios, but there&#39;s interest in replaying the existing one with teams that haven&#39;t seen it yet. I&#39;m also exploring ways of connecting the exercise with employee evaluation and professional development programs that we have.</p>

<p>Feel free to use the <em>Deployments and Disasters</em> to build your own incident scenarios on top of. Or stay tuned for future developments, as I will strive to publish example scenarios myself. You can watch the <a href="https://github.com/Antolius/deployments-and-disasters" rel="nofollow">GitHub repo</a> for updates, or follow this blog by:</p>
<ul><li>Subscribing to its <a href="https://qua.name/antolius/feed" rel="nofollow">RSS feed</a>.</li>
<li>Following <code><a href="https://qua.name/@/antolius@qua.name" class="u-url mention" rel="nofollow">@<span>antolius@qua.name</span></a></code> in <a href="https://en.wikipedia.org/wiki/Fediverse" rel="nofollow">fediverse</a>.</li></ul>

<p>If you have any feedback, comments or improvement ideas you can send me a pull request, or just contact me at:</p>
<ul><li><a href="mailto:josip.antolis@protonmail.com" rel="nofollow">josip.antolis@protonmail.com</a></li>
<li><a href="https://mastodon.social/@antolius" rel="nofollow">@antolius</a> on <a href="https://mastodon.social" rel="nofollow">Mastodon</a></li></ul>
]]></content:encoded>
      <guid>https://qua.name/antolius/incident-management-dnd</guid>
      <pubDate>Sun, 29 Sep 2019 21:44:37 +0200</pubDate>
    </item>
    <item>
      <title>CLI Development; Part 3</title>
      <link>https://qua.name/antolius/cli-development-part-3</link>
      <description>&lt;![CDATA[Advanced use cases&#xA;&#xA;In this part of CLI development series I&#39;ll go over some of the more advanced use cases. I&#39;ve previously discussed general tips for making command line apps nice to use. If you missed that blog post you can find it here. &#xA;&#xA;As use cases grow more complex it makes more and more sense to look for existing solutions and reuse / incorporate them into our own applications. That&#39;s why I&#39;ll devote more space in this post to highlighting existing projects, as opposed to talking about my own experiences. !--more--&#xA;&#xA;Source code generation&#xA;&#xA;One use case where CLIs excel is project scaffolding and code generation. For example of such apps you can take a look at Yeoman and its list of generators. Yeoman itself is oriented towards web development, although its most popular generator JHipster outputs Spring Boot applications. As a side note, if you ever find yourself with some spare time, checking out JHipster is a wonderful way to spend few hours. One more old school example of project scaffolding in Java world are Maven archetypes.&#xA;&#xA;If you look at those examples you will quickly find that they provide rich set of features and customizations. One thing that most dedicated code generation tools have in common is a plugin system that allows users to define their own templates. If code generation is your primary use case, developing a plugin for an existing tool is a good idea. That approach will save you a lot of time and you&#39;ll end up with a more polished product.&#xA;&#xA;On the other hand, there are CLIs that offer code generation as an addition to their core features. For example think of init commands in tools like npm or git. Extracting scaffolding features out of these tools and delegating it to dedicated code generations apps would be detrimental to user experience. If you find yourself in a similar situation you should implement code generation within your CLI instead.&#xA;&#xA;Most popular approach to code generation is to treat source files as plain text. In order to generate them you will need a good templating library. I&#39;ve had to use some clumsy and cumbersome templating libs in legacy projects so I appreciate the importance of picking a library that works for you. One experiment I like to do when evaluating a templating library is to try to make a template for serializing some data structure into a pretty formatted json. Json format has a few tricky rules, like requiring comma after all but the last property, escaping quotes in string values, proper indentation for pretty format etc. If a templating library makes writing json templates enjoyable you&#39;ll probably have no problems with source code.&#xA;&#xA;One last trick that can simplify source code generation is running output of your CLI through standard formatters for the language you are generating. This doesn&#39;t work if there are competing formatting standards, or if community uses widely different formats. Example of this would be Java world where no two code bases look the same. On the other hand, Go programming language comes with prescribed gofmt formatter that code generation tools use. Having properly formatted source code becomes important when it comes to pull requests and similar situation that require diffing 2 files / versions.&#xA;&#xA;Introspection&#xA;&#xA;Another advanced use case for CLIs is source code analysis. This one is more complicated that source code generation. While generation can be implemented using text manipulation, in order to analyze source code you will generally need to tokenize it and build a syntax tree out of it. This is getting away from templating and into compiler theory.&#xA;&#xA;Fortunately, most modern languages provide tools for introspection of their own source code. So, if you know you&#39;ll need to analyze Java code it might be a good idea to write your CLI in Java. You can probably find a library for parsing your language of choice, which you can reuse in your tool.&#xA;&#xA;Problems with this approach arise if you need your tool to analyze multiple languages. One example of this is code editors and IDEs. A common solution for that type of apps is to use Language Server protocol to communicate to dedicated language server implementations. That way the application code is decoupled from language servers which can be implemented for each language. A more advanced example is source{d} engine, an application for source code analysis. Under the hood it is using Babelfish, a universal code parser that can produce syntax trees for various languages. Like LSP, it too has dedicated language drivers executing in separate Docker containers that communicate with a single app server over gRPC.&#xA;&#xA;If your CLI requires analysis of source code from multiple languages you should probably use one of existing solutions. If features of LSP are enough for you that seems like the most widely adopted solution. If you need full flexibility of abstract syntax trees, then Babelfish might be a bit more complex, but more powerful solution.&#xA;&#xA;Text-based UI&#xA;&#xA;You might find that a simple loop of reading the arguments, processing them and outputting results is no longer enough for your use case. Processing can be complex, so you may need to update users on it&#39;s progress. You may need extra input from your users. Workflow you are implementing might be complex and require continuous interaction from users. At this point you may need to build a Text-based User Interface (TUI).&#xA;&#xA;Input prompts are the most basic use case. Example of this is how npm init (and may other scaffolding tools) guide users through process of setting up a project. When designing such interactions you should allow for all prompts to be customized with CLI flags, so that command can execute without any prompts. Common pattern for doing this is to add a -y / --yes flag that will automatically accept default options. In doing this you will make your command usable by larger scripts for which user interaction is impractical.&#xA;&#xA;Next up, there&#39;s the use case of informing users of the progress of CLI command execution. Modern dependency management tools (again npm is a good example) will display a live progress bar while downloading dependencies. Another example is HTTP load testing tool vegeta. It can dynamically output the progress of a stress test while its running. It also does something interesting: it allows you to pipe its output through a formatter tool to a dedicated plotting terminal application jplot. Jplot then renders live charts in the terminal. This is a good pattern to follow if you need live plotting and don&#39;t feel like re-implementing it yourself.&#xA;&#xA;Lastly, there are full-blown TUI applications, starting with &#34;simple&#34; ones like htop and on to the likes of vim and emacs. If you are thinking of building similar TUI apps you should be able to find a framework in your language of choice that can help with laying out your application&#39;s UI elements. However, if you are expecting other developers&#39; contribution to your application, it might be a better idea to go with something like a web app UI. That way you will have a larger pool of contributors to attract to your project.&#xA;&#xA;What I did&#xA;&#xA;In the CLI I built for work I implemented some code generation features. For project scaffolding I actually reused an existing parent project that all subsequent ones fork off of. Because of this my init command basically does a shallow git clone of the parent repository. &#xA;&#xA;I also implemented an add commands for generating config and code required to expose a new API endpoints. Since I picked Go for my language I went with standard library&#39;s template package. I found it expressive enough to write all my templates and generate properly formatted json, Groovy and Kotlin code. It has just enough features for all my use cases, and not too many as to make it complicated to use. Much like Go language itself, using it was a zen-like experience.&#xA;&#xA;I did not have any use for code analysis or TUI in that particular project. However, I&#39;ve recently been playing around with termui, a terminal dashboard library also written in Go. It&#39;s easy enough to work with, but my use cases are not all that advanced either.&#xA;&#xA;In conclusion&#xA;&#xA;This blog post concludes the series on CLI development. You can find first post that deals with picking the technology and distribution stack here, and general CLI usability tips here. While the series is done, I might have some more thought on CLI development in the future. In case you are interested in this type of content, you can:&#xA;&#xA;Subscribe to this blog&#39;s RSS feed.&#xA;Follow @antolius@qua.name in fediverse.]]&gt;</description>
      <content:encoded><![CDATA[<h2 id="advanced-use-cases" id="advanced-use-cases">Advanced use cases</h2>

<p>In this part of CLI development series I&#39;ll go over some of the more <em>advanced</em> use cases. I&#39;ve previously discussed general tips for making command line apps nice to use. If you missed that blog post you can find it <a href="https://qua.name/antolius/cli-development-part-2" rel="nofollow">here</a>.</p>

<p>As use cases grow more complex it makes more and more sense to look for existing solutions and reuse / incorporate them into our own applications. That&#39;s why I&#39;ll devote more space in this post to highlighting existing projects, as opposed to talking about my own experiences. </p>

<h3 id="source-code-generation" id="source-code-generation">Source code generation</h3>

<p>One use case where CLIs excel is project scaffolding and code generation. For example of such apps you can take a look at <a href="https://yeoman.io/" rel="nofollow">Yeoman</a> and its list of <a href="https://yeoman.io/generators/" rel="nofollow">generators</a>. Yeoman itself is oriented towards web development, although its most popular generator <a href="https://www.jhipster.tech/" rel="nofollow">JHipster</a> outputs Spring Boot applications. As a side note, if you ever find yourself with some spare time, checking out JHipster is a wonderful way to spend few hours. One more old school example of project scaffolding in Java world are <a href="https://maven.apache.org/guides/introduction/introduction-to-archetypes.html" rel="nofollow">Maven archetypes</a>.</p>

<p>If you look at those examples you will quickly find that they provide rich set of features and customizations. One thing that most dedicated code generation tools have in common is a plugin system that allows users to define their own templates. If code generation is your primary use case, developing a plugin for an existing tool is a good idea. That approach will save you a lot of time and you&#39;ll end up with a more polished product.</p>

<p>On the other hand, there are CLIs that offer code generation as an addition to their core features. For example think of <code>init</code> commands in tools like <code>npm</code> or <code>git</code>. Extracting scaffolding features out of these tools and delegating it to dedicated code generations apps would be detrimental to user experience. If you find yourself in a similar situation you should implement code generation within your CLI instead.</p>

<p>Most popular approach to code generation is to treat source files as plain text. In order to generate them you will need a good templating library. I&#39;ve had to use some clumsy and cumbersome templating libs in legacy projects so I appreciate the importance of picking a library that works for you. One experiment I like to do when evaluating a templating library is to try to make a template for serializing some data structure into a pretty formatted json. Json format has a few tricky rules, like requiring comma after all but the last property, escaping quotes in string values, proper indentation for pretty format etc. If a templating library makes writing json templates enjoyable you&#39;ll probably have no problems with source code.</p>

<p>One last trick that can simplify source code generation is running output of your CLI through standard formatters for the language you are generating. This doesn&#39;t work if there are competing formatting standards, or if community uses widely different formats. Example of this would be Java world where no two code bases look the same. On the other hand, Go programming language comes with prescribed <code>gofmt</code> formatter that code generation tools use. Having properly formatted source code becomes important when it comes to pull requests and similar situation that require diffing 2 files / versions.</p>

<h3 id="introspection" id="introspection">Introspection</h3>

<p>Another advanced use case for CLIs is source code analysis. This one is more complicated that source code generation. While generation can be implemented using text manipulation, in order to analyze source code you will generally need to tokenize it and build a <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree" rel="nofollow">syntax tree</a> out of it. This is getting away from templating and into compiler theory.</p>

<p>Fortunately, most modern languages provide tools for introspection of their own source code. So, if you know you&#39;ll need to analyze Java code it might be a good idea to write your CLI in Java. You can probably find a library for parsing your language of choice, which you can reuse in your tool.</p>

<p>Problems with this approach arise if you need your tool to analyze multiple languages. One example of this is code editors and IDEs. A common solution for that type of apps is to use <a href="https://langserver.org/" rel="nofollow">Language Server protocol</a> to communicate to dedicated language server implementations. That way the application code is decoupled from language servers which can be implemented for each language. A more advanced example is <a href="https://docs.sourced.tech/community-edition/" rel="nofollow">source{d} engine</a>, an application for source code analysis. Under the hood it is using <a href="https://doc.bblf.sh/" rel="nofollow">Babelfish</a>, a universal code parser that can produce syntax trees for various languages. Like LSP, it too has dedicated language drivers executing in separate Docker containers that communicate with a single app server over gRPC.</p>

<p>If your CLI requires analysis of source code from multiple languages you should probably use one of existing solutions. If features of LSP are enough for you that seems like the most widely adopted solution. If you need full flexibility of abstract syntax trees, then Babelfish might be a bit more complex, but more powerful solution.</p>

<h3 id="text-based-ui" id="text-based-ui">Text-based UI</h3>

<p>You might find that a simple loop of reading the arguments, processing them and outputting results is no longer enough for your use case. Processing can be complex, so you may need to update users on it&#39;s progress. You may need extra input from your users. Workflow you are implementing might be complex and require continuous interaction from users. At this point you may need to build a Text-based User Interface (TUI).</p>

<p>Input prompts are the most basic use case. Example of this is how <code>npm init</code> (and may other scaffolding tools) guide users through process of setting up a project. When designing such interactions you should allow for all prompts to be customized with CLI flags, so that command can execute without any prompts. Common pattern for doing this is to add a <code>-y</code> / <code>--yes</code> flag that will automatically accept default options. In doing this you will make your command usable by larger scripts for which user interaction is impractical.</p>

<p>Next up, there&#39;s the use case of informing users of the progress of CLI command execution. Modern dependency management tools (again <code>npm</code> is a good example) will display a live progress bar while downloading dependencies. Another example is HTTP load testing tool <a href="https://github.com/tsenart/vegeta" rel="nofollow">vegeta</a>. It can dynamically output the progress of a stress test while its running. It also does something interesting: it allows you to pipe its output through a formatter tool to a dedicated plotting terminal application <a href="https://github.com/rs/jplot" rel="nofollow">jplot</a>. Jplot then renders live charts in the terminal. This is a good pattern to follow if you need live plotting and don&#39;t feel like re-implementing it yourself.</p>

<p>Lastly, there are full-blown TUI applications, starting with <em>“simple”</em> ones like <code>htop</code> and on to the likes of <code>vim</code> and <code>emacs</code>. If you are thinking of building similar TUI apps you should be able to find a framework in your language of choice that can help with laying out your application&#39;s UI elements. However, if you are expecting other developers&#39; contribution to your application, it might be a better idea to go with something like a web app UI. That way you will have a larger pool of contributors to attract to your project.</p>

<h3 id="what-i-did" id="what-i-did">What I did</h3>

<p>In the CLI I <a href="https://qua.name/antolius/you-dont-need-a-frontend#internal-framework-support-tool" rel="nofollow">built for work</a> I implemented some code generation features. For project scaffolding I actually reused an existing parent project that all subsequent ones fork off of. Because of this my <code>init</code> command basically does a shallow git clone of the parent repository.</p>

<p>I also implemented an <code>add</code> commands for generating config and code required to expose a new API endpoints. Since I picked Go for my language I went with standard library&#39;s <a href="https://golang.org/pkg/text/template/" rel="nofollow">template package</a>. I found it expressive enough to write all my templates and generate properly formatted json, Groovy and Kotlin code. It has just enough features for all my use cases, and not too many as to make it complicated to use. Much like Go language itself, using it was a zen-like experience.</p>

<p>I did not have any use for code analysis or TUI in that particular project. However, I&#39;ve recently been playing around with <a href="https://github.com/gizak/termui" rel="nofollow">termui</a>, a terminal dashboard library also written in Go. It&#39;s easy enough to work with, but my use cases are not all that advanced either.</p>

<h3 id="in-conclusion" id="in-conclusion">In conclusion</h3>

<p>This blog post concludes the series on CLI development. You can find first post that deals with picking the technology and distribution stack <a href="https://qua.name/antolius/cli-development-part-1" rel="nofollow">here</a>, and general CLI usability tips <a href="https://qua.name/antolius/cli-development-part-2" rel="nofollow">here</a>. While the series is done, I might have some more thought on CLI development in the future. In case you are interested in this type of content, you can:</p>
<ul><li>Subscribe to this blog&#39;s <a href="https://qua.name/antolius/feed" rel="nofollow">RSS feed</a>.</li>
<li>Follow <code><a href="https://qua.name/@/antolius@qua.name" class="u-url mention" rel="nofollow">@<span>antolius@qua.name</span></a></code> in <a href="https://en.wikipedia.org/wiki/Fediverse" rel="nofollow">fediverse</a>.</li></ul>
]]></content:encoded>
      <guid>https://qua.name/antolius/cli-development-part-3</guid>
      <pubDate>Sun, 01 Sep 2019 22:01:37 +0200</pubDate>
    </item>
  </channel>
</rss>