<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Dmitry&apos;s Blog</title>
    <description>Dmitry&apos;s blog about programming</description>
    <link>https://dkandalov.github.io/</link>
    <atom:link href="https://dkandalov.github.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Thu, 21 May 2026 15:54:19 +0000</pubDate>
    <lastBuildDate>Thu, 21 May 2026 15:54:19 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Mcp Sse The Hard Way</title>
        <description>&lt;p&gt;Based on &lt;a href=&quot;https://deadprogrammersociety.com/2025/03/calling-mcp-servers-the-hard-way.html&quot;&gt;https://deadprogrammersociety.com/2025/03/calling-mcp-servers-the-hard-way.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In one terminal:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;➜ curl http://127.0.0.1:64342/sse                                                            
data: /message?sessionId=41d13160-1698-420c-b5d3-3f925ac5c019
event: endpoint
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In another terminal (copying session id from above):&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;➜ MCP_ENDPOINT=http://127.0.0.1:64342/message?sessionId=41d13160-1698-420c-b5d3-3f925ac5c019
➜ curl -X POST &quot;${MCP_ENDPOINT}&quot; -H &quot;Content-Type: application/json&quot; -d &apos;{
    &quot;jsonrpc&quot;: &quot;2.0&quot;,
    &quot;id&quot;: 1,
    &quot;method&quot;: &quot;tools/call&quot;,
    &quot;params&quot;: {
        &quot;name&quot;: &quot;get_file_problems&quot;,
        &quot;arguments&quot;: {
            &quot;errorsOnly&quot;: false,
            &quot;filePath&quot;: &quot;pro/ai/mcp/client/src/main/kotlin/org/http4k/ai/mcp/client/McpClient.kt&quot;
        }
    }
}&apos;
Accepted%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first terminal shows the response:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;data: {&quot;id&quot;:1,&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;result&quot;:{&quot;content&quot;:[{&quot;text&quot;:&quot;{\&quot;filePath\&quot;:\&quot;pro/ai/mcp/client/src/main/kotlin/org/http4k/ai/mcp/client/McpClient.kt\&quot;,\&quot;errors\&quot;:[{\&quot;severity\&quot;:\&quot;WARNING\&quot;,\&quot;description\&quot;:\&quot;Function \\\&quot;staaop\\\&quot; is never used\&quot;,\&quot;lineContent\&quot;:\&quot;    fun staaop() = close()\&quot;,\&quot;line\&quot;:29,\&quot;column\&quot;:9}]}&quot;,&quot;type&quot;:&quot;text&quot;}],&quot;isError&quot;:false,&quot;_meta&quot;:{}}}
event: message
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Sun, 14 Sep 2025 00:00:00 +0000</pubDate>
        <link>https://dkandalov.github.io/mcp-sse-the-hard-way</link>
        <guid isPermaLink="true">https://dkandalov.github.io/mcp-sse-the-hard-way</guid>
        
        
      </item>
    
      <item>
        <title>Tidy Kotlin</title>
        <description>&lt;p&gt;This blog post is a catalog of Kotlin tidyings based on my experience of writing server-side Kotlin. The term “tidying” is inspired by the &lt;a href=&quot;https://www.oreilly.com/library/view/tidy-first/9781098151232&quot;&gt;“Tidy First?” book&lt;/a&gt; and essentially means a small refactoring. Some of them are specific to Kotlin, while others are applicable to any programming language. I plan to keep this catalog updated so it might naturally evolve over time.&lt;/p&gt;

&lt;p&gt;Be aware these are not rules but suggestions on how to improve the code. It’s also not a comprehensive list, so there are other forces affecting the design not mentioned here. These forces can be technical, for example, objects’ lifetime or &lt;a href=&quot;https://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot;&gt;DRY&lt;/a&gt;, and non-technical, for example,   code style preferences of other people or priorities of the project. Depending on the context it might be better to avoid or delay tidying.&lt;/p&gt;

&lt;p&gt;Many of these tidyings are about code style and formatting, which are sometimes regarded as cursory issues. While it’s true that projects always have more significant issues, and it’s possible to read and navigate the code presented in any sensible way, the main premise of the tidyings is that fixing small things does matter. One reason is that small fixes are more likely to happen than bigger ones because they normally require a limited amount of effort and it’s easier to see the end state. Instead of planning a large-scale improvement at some point later, which might never happen, we can benefit from small improvements of code ergonomics now, which will accumulate over time. Another reason to fix small and seemingly insignificant code issues is that the interaction with the code via tydings gives us more of a tactile experience of the code, which can help us discover better design, and really understand the code and its changeability constraints. Finally, some of the issues are bigger than they seem to be or they act as gatekeepers for bigger refactorings. By tidying we can unlock a bigger area of improvement or get an insight to ask the right question.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;==== This is work-in-progress. Feel free to share the link but be aware that the content will change. Feedback is welcome via email or social media. ====&lt;/i&gt;&lt;/p&gt;

&lt;h3 id=&quot;contents&quot;&gt;Contents&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#high-level-declarations-first&quot;&gt;High-level declarations first&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#maximum-privacy&quot;&gt;Maximum privacy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#keep-variables-close-to-their-usages&quot;&gt;Keep variables close to their usages&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#inline-variables-with-single-usage&quot;&gt;Inline variables with single usage&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#remove-argument-names-when-their-types-are-distinct&quot;&gt;Remove argument names when their types are distinct&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#add-argument-names-when-types-are-the-same-or-generic&quot;&gt;Add argument names when types are the same or generic&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#pass-named-arguments-in-the-order-of-parameter-declaration&quot;&gt;Pass named arguments in the order of parameter declaration&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#put-parameters-on-one-line&quot;&gt;Put parameters on one line&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#put-arguments-on-one-line&quot;&gt;Put arguments on one line&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#put-parameters-on-separate-lines&quot;&gt;Put parameters on separate lines&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#stop-the-constant-shouting&quot;&gt;Stop the CONSTANT SHOUTING&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#consider-using-tiny-types&quot;&gt;Consider using tiny types&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;…&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;high-level-declarations-first&quot;&gt;High-level declarations first&lt;/h3&gt;

&lt;p&gt;Declare high-level interfaces, classes, functions, or properties before implementation details. A more formal way to think about it is by presenting code as a directed graph, where nodes are declarations and edges point from the declaration to its usages. The code should be ordered so that all edges point to the beginning of the file (unless there are circular dependencies). With the edges pointing up, declarations at the top of the file will be visually higher, matching the “high/low-level” metaphor.&lt;/p&gt;

&lt;p&gt;The main motivation for this tidying is to improve the navigability of the codebase.&lt;/p&gt;

&lt;p&gt;Let’s assume we’re mostly familiar with the codebase and would like to remind ourselves what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStore&lt;/code&gt; interface looks like. 
We open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStore.kt&lt;/code&gt; containing the following code. We have to skim the file from points 1️⃣ to 4️⃣ until we finally get to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStore&lt;/code&gt; interface at points 5️⃣ and 6️⃣.&lt;/p&gt;

&lt;kotlin&gt;
sealed interface Fruit {...} 1️⃣ 👀

data class Apple(...) : Fruit {...} 2️⃣ 👀

data class Banana(...) : Fruit {...} 3️⃣ 👀

data class StorageId(...) {...} 4️⃣ 👀

interface FruitStore {
    fun store(apples: List&amp;lt;Apple&amp;gt;): Result&amp;lt;StorageId&amp;gt; 5️⃣ 👀
    fun store(bananas: List&amp;lt;Banana&amp;gt;): Result&amp;lt;StorageId&amp;gt; 6️⃣ 👀
}

class FruitStoreInTheCloud(...) : FruitStore {
    override fun store(apples: List&amp;lt;Apple&amp;gt;): Result&amp;lt;StorageId&amp;gt; {...}
    override fun store(bananas: List&amp;lt;Banana&amp;gt;): Result&amp;lt;StorageId&amp;gt; {...}
}
&lt;/kotlin&gt;

&lt;p&gt;Real-world APIs can be much bigger and might have intermediate interfaces, so we can’t just stop skimming at the first interface. We also can’t start scrolling bottom-up (as if reading bottom-up was normal) in case there are implementation(s) of the interface.&lt;/p&gt;

&lt;p&gt;The best solution is to put the most important thing in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStore.kt&lt;/code&gt;, i.e. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStore&lt;/code&gt; interface at the top of the file. After opening the file, we can go straight to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStore&lt;/code&gt; at points 1️⃣ and 2️⃣.&lt;/p&gt;
&lt;kotlin&gt;
interface FruitStore {
    fun store(apples: List&amp;lt;Apple&amp;gt;): Result&amp;lt;StorageId&amp;gt; 1️⃣ 👀
    fun store(bananas: List&amp;lt;Banana&amp;gt;): Result&amp;lt;StorageId&amp;gt; 2️⃣ 👀
}

sealed interface Fruit {...}

data class Apple(...) : Fruit {...}

data class Banana(...) : Fruit {...}

data class StorageId(...) {...}

class FruitStoreInTheCloud : FruitStore {
    override fun store(apples: List&amp;lt;Apple&amp;gt;): Result&amp;lt;StorageId&amp;gt; {...}
    override fun store(bananas: List&amp;lt;Banana&amp;gt;): Result&amp;lt;StorageId&amp;gt; {...}
}
&lt;/kotlin&gt;

&lt;p&gt;In this example, putting higher-level abstraction first saved us from skimming four other classes, which you might argue is not that much. This is a fair point. One problem is that the cost can be higher in a real code and it tends to grow as the codebase grows. Another is that small issues (as well as improvements) can have a cumulative effect. Ignoring the navigation issue in one place is ok, ignoring it across the whole codebase is much worse.&lt;/p&gt;

&lt;h3 id=&quot;maximum-privacy&quot;&gt;Maximum privacy&lt;/h3&gt;

&lt;p&gt;Make values, functions and classes as private as possible.
There are a few reasons for that:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Private declaration is easier to understand because the context in which it’s used is limited and it’s likely to have fewer usages to analyse.&lt;/li&gt;
  &lt;li&gt;Because it’s easier to understand, it’s easier to modify (or delete). With fewer usages, there are fewer things that can go wrong when we change the function/class.&lt;/li&gt;
  &lt;li&gt;It’s also easier for the compiler/IDE/editor to type check or analyse the code because there are fewer places to check.&lt;/li&gt;
  &lt;li&gt;Reduced coupling. As the codebase evolves private code is less likely to be used and pull the design of the function/class in various directions, so there is less design tension.&lt;/li&gt;
  &lt;li&gt;Namespace pollution. Unnecessarily public functions/classes show up in auto-completion making it harder to choose the right function/class.&lt;/li&gt;
  &lt;li&gt;Specific to Kotlin support in IntelliJ, when searching for short public names and fields of data classes can be really (unusably) slow, so you’ll have to resort to pure text search.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine we open a file with the code below and try to understand what it’s doing. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStoreInTheCloud&lt;/code&gt; class somewhat makes sense. It stores apples/bananas and returns an ID on success. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;handle()&lt;/code&gt; function is a bit of a mystery though. The name is too generic, its type signature is not particularly revealing and its implementation (&lt;a href=&quot;https://www.jetbrains.com/help/rider/Code_Folding.html&quot;&gt;collapsed&lt;/a&gt; in the code below) makes us wonder if it’s mostly redundant. We try &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Find Usages&lt;/code&gt;, but the name is too generic and the IDE search doesn’t finish in a reasonable time. We get bored wondering if the search will ever finish. Text search finishes quickly with too many results to be sure they all match the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;handle()&lt;/code&gt; function. We try the final trick of leaning on the compiler. We make the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt; and compile the project. Luckily, it just works meaning that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;handle()&lt;/code&gt; function is not used anywhere else, so running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStoreInTheCloudTests&lt;/code&gt; should be enough to validate our tidying if we choose to go ahead with it. We could’ve saved some time and a few WTFs if only the function was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt; in the first place.&lt;/p&gt;

&lt;kotlin&gt;
class FruitStoreInTheCloud : FruitStore {
    override fun store(apples: List&amp;lt;Apple&amp;gt;): Result&amp;lt;StorageId&amp;gt; {...}
    override fun store(bananas: List&amp;lt;Banana&amp;gt;): Result&amp;lt;StorageId&amp;gt; {...}
}

fun handle(fruit: Fruit, f: (Fruit) -&amp;gt; Unit): Fruit {...} 👀 😕
&lt;/kotlin&gt;

&lt;p&gt;There is a question if fields in test classes need to be as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt; as possible. All the reasons above still apply and it’s good to have fewer special cases by using the same rules for production and test code, so this would be my preference. The main argument against it is that test classes rarely share their fields so adding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt; keyword for each field and function is unnecessarily verbose. This is a valid reason and interestingly earlier versions of  Kotlin had &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;internal&lt;/code&gt; as a default visibility (see &lt;a href=&quot;https://blog.jetbrains.com/kotlin/2015/09/kotlin-m13-is-out/#visibilities&quot;&gt;this blog post&lt;/a&gt;). If you go down this path, you might want to reconfigure IntelliJ to apply inspection which suggests making the field/function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt; only to tests.&lt;/p&gt;

&lt;p&gt;Looking at this tidying from the &lt;a href=&quot;https://en.wikipedia.org/wiki/Code_as_data&quot;&gt;code as data&lt;/a&gt; point of view, this is a form of &lt;a href=&quot;https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)&quot;&gt;encapsulation&lt;/a&gt;. This might be a reasonable analogy considering the code base and people involved in software development as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Sociotechnical_system&quot;&gt;sociotechnical system&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;keep-variables-close-to-their-usages&quot;&gt;Keep variables close to their usages&lt;/h3&gt;

&lt;p&gt;Keep variables (both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;val&lt;/code&gt;s and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var&lt;/code&gt;s) close to where you use them. This is a simple way of saying to declare variables in the innermost scope and within the minimum amount of lines/statements from usages. The main goal of this tidying is higher code cohesion or more specifically:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Reduced cognitive load while reading code. With fewer things to remember, you can focus on other aspects of the code.&lt;/li&gt;
  &lt;li&gt;Discover/communicate that variables are only related to a specific scope. Since a smaller scope can provide a higher privacy level, you also get the benefits of &lt;a href=&quot;#maximum-privacy&quot;&gt;Maximum privacy&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Discover/communicate dependencies. As soon as you try moving a variable, it will “pull” on all the variables/functions that are using it. You might find that they can all be moved into a smaller scope. This is a way to organise code into “clusters”.&lt;/li&gt;
  &lt;li&gt;Cohesive code can lead to other tidyings like inline single usage, or extract function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://kotlinlang.org/spec/scopes-and-identifiers.html&quot;&gt;Scopes in Kotlin&lt;/a&gt; have a specific well-defined meaning but the for purpose of this tidying it might be useful to think of “scope” in a more vague way as “an area of code which makes sense as a whole”. For example, paragraphs can be cohesive enough to make sense on their own (sure, there is a question if they should be extracted into functions, but we don’t know yet if it’s possible before doing the tidying).&lt;/p&gt;

&lt;p&gt;To illustrate the distance between variable declaration and its usage(s) imagine we come across a function with the following code. There are two lines between point 1️⃣ and the only usage of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apple&lt;/code&gt;, and four lines between point 2️⃣ and the only usage of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;banana&lt;/code&gt;. This creates coupling between the paragraphs of code, or “tension” which we could overall quantify as 2 + 4 = 6.&lt;/p&gt;
&lt;kotlin&gt;
val apple = Apple(...)    1️⃣ 👀
val banana = Banana(...)  │  2️⃣ 👀
                          │  │
process(apple)          ◄─┘  │
doSomething()                │
                             │
process(banana)         ◄────┘
doSomethingElse()
&lt;/kotlin&gt;
&lt;p&gt;After the tidying, the code might look like in the snippet below.&lt;/p&gt;
&lt;kotlin&gt;
val apple = Apple(...)    1️⃣ 👀
process(apple)          ◄─┘
doSomething()

val banana = Banana(...)  2️⃣ 👀
process(banana)         ◄─┘
doSomethingElse()
&lt;/kotlin&gt;

&lt;p&gt;It now has only two paragraphs and the tension between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apple&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;banana&lt;/code&gt; and their usages is zero (this makes us wonder if they should be inlined). Sure declaraing variable in the paragraph does not guarantee it can’t be used somewhere else, but it still makes it easier to skim the code especially once we have done a few of these tidyings and can trust the codebase. What the compiler does enforce though is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;banana&lt;/code&gt; cannot be used above point 2️⃣ (we did reduce its scope after all).&lt;/p&gt;

&lt;p&gt;To illustrate reduced variable scope imagine we look at the following function. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; is declared in the scope of the whole function but is only used within &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forEach&lt;/code&gt;.&lt;/p&gt;
&lt;kotlin&gt;                                 
val type = Blended                   ─┐ 👀
fruits.forEach { fruit -&amp;gt;             │
    process(fruit, type)              │
    log(&quot;Processed $fruit as $type&quot;)  │
}                                     │
doSomething()                         │
doSomethingElse()                    ─┘
&lt;/kotlin&gt;
&lt;p&gt;After the tidy-up the code looks like this:&lt;/p&gt;
&lt;kotlin&gt;
fruits.forEach { fruit -&amp;gt;
    val type = Blended               ─┐ 👀
    process(fruit, type)              │
    log(&quot;Processed $fruit as $type&quot;) ─┘
}
doSomething()
doSomethingElse()
&lt;/kotlin&gt;
&lt;p&gt;The amount of lines where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; can be used has reduced from 6 to 2 lines. Now when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; usages are all within the same paragraph, we might wonder if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; can be inlined. It’s not ideal to duplicate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Blended&lt;/code&gt; in two places, so maybe we don’t need to log the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt;? Or maybe we do, and then the question might be why the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;process()&lt;/code&gt; function won’t log it for us. These questions are examples of how simple tidying can help us explore/discover software design.&lt;/p&gt;

&lt;p&gt;Interestingly, this tidying implies that, for example, a single usage of a magic value in a function might be better off extracted into a local variable rather than a constant.&lt;/p&gt;

&lt;p&gt;Moving variables close to their usages is often a good idea but it’s not a fixed rule. Sometimes it might be worth moving all/most declarations to some outer scope and see if it reveals a better structure of the code. It is an exploration.&lt;/p&gt;

&lt;p&gt;Similar to a few other tidyings this one is fractal. While the examples above discuss low-level abstractions, it’s possible to apply the same principles at the class, file, module, service, application, or architectural level.&lt;/p&gt;

&lt;h3 id=&quot;inline-variables-with-single-usage&quot;&gt;Inline variables with single usage&lt;/h3&gt;

&lt;p&gt;Variables (both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;val&lt;/code&gt;s and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var&lt;/code&gt;s) with single usage are often better off inlined. You might think of it as an extreme version of &lt;a href=&quot;#keep-variables-close-to-their-usages&quot;&gt;keeping variables close to their usages&lt;/a&gt;, so some of the motivations overlap. The reasons to inline single usage are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Inlined variables are obviously not used elsewhere in the code, so we save time and effort by not checking if there are other usages.&lt;/li&gt;
  &lt;li&gt;To communicate the structure of nested objects or function calls.&lt;/li&gt;
  &lt;li&gt;The order of variable initialisation doesn’t dictate how variables are ordered in the code, so it’s easier to have &lt;a href=&quot;#high-level-declarations-first&quot;&gt;high-level declarations first&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Extracting a single usage variable made sense in Java to give the argument a name. Kotlin has named arguments that have the same expressiveness (unless you want to have a name different from the parameter).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To illustrate how inlining variables can help, imagine we are trying to figure out how exactly &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStoreInTheCloud()&lt;/code&gt; is constructed. We search for the usages of the constructor (by invoking “Show Usages” before the first “(“) and end up in the following code at point 1️⃣. We would like to see how the constructor arguments are created, so we navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uri&lt;/code&gt; declaration which takes us to point 2️⃣. URI construction looks ok, but it’s not clear if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uri&lt;/code&gt; might be used elsewhere in the function. We search for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uri&lt;/code&gt; usages. There is only one usage, so we end up back at point 1️⃣. We repeat the same process for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;credentials&lt;/code&gt; navigating to point 3️⃣ and back to 1️⃣ (it’s the only usage). Navigation is a bit more tricky with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config&lt;/code&gt; because we first go to point 4️⃣, then to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;connectionTimeout&lt;/code&gt; 5️⃣ and back, then to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;retryAttempts&lt;/code&gt; 6️⃣ and back. This is a lot of non-linear navigation for the construction of two nested objects!&lt;/p&gt;

&lt;p&gt;To be fair, we could’ve been more efficient by using the “Highlight Usages in File” action on all variables and visually checking the editor scrollbar area if there are any matches outside of visible code. It’s still not worth it though considering that all usages can be inlined.&lt;/p&gt;

&lt;kotlin&gt;
val uri = Uri(&quot;https://fruit.cloud&quot;)                       2️⃣
val credentials = Credentials(...)                         3️⃣
val connectionTimeout = 10.seconds                         5️⃣
val retryAttempts = 3                                      6️⃣
val config = Config(connectionTimeout, retryAttempts)      4️⃣
val store = FruitStoreInTheCloud(uri, credentials, config) 1️⃣ 👀 😵‍💫

doSomething()
doSomethingElse()
...
&lt;/kotlin&gt;
&lt;p&gt;After inlining variable usages, we can follow the constructor arguments points 1️⃣ to 6️⃣ in a linear way. We don’t need to guess if the variables are used elsewhere. And it’s nice that indentation at points 5️⃣ and 6️⃣ communicates the nested structure of objects.&lt;/p&gt;
&lt;kotlin&gt;
val store = FruitStoreInTheCloud(       1️⃣ 👀 
    uri = Uri(&quot;https://fruit.cloud&quot;),   2️⃣
    credentials = Credentials(...),     3️⃣
    config = Config(                    4️⃣
        connectionTimeout = 10.seconds, 5️⃣
        retryAttempts = 3               6️⃣
    )
)
doSomething()
doSomethingElse()
...
&lt;/kotlin&gt;

&lt;p&gt;As a side note, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStoreInTheCloud()&lt;/code&gt; constructor in the example above has arguments with distinct types, so it might be ok to &lt;a href=&quot;#remove-argument-names-when-all-types-are-distinct&quot;&gt;remove argument names&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What if some of the arguments have multiple usages (for example, if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uri&lt;/code&gt; was passed to a function), is it still worth inlining variables with single usage? I would argue that it’s almost always worth trying. Reduced scope is likely to pay off the inconsistency of declaring arguments both in place and as variables.&lt;/p&gt;

&lt;h3 id=&quot;remove-argument-names-when-their-types-are-distinct&quot;&gt;Remove argument names when their types are distinct&lt;/h3&gt;
&lt;p&gt;When all arguments have distinct incompatible types, named arguments might be redundant and can be removed. Named arguments can help with accidentally passing value to the wrong parameter when types are the same. But if all types are different, this is not a problem as it will be checked by the compiler. Assuming that argument values have descriptive names, named arguments don’t bring any benefits to justify verbosity. This is more likely to be the case when using &lt;a href=&quot;#use-tiny-types&quot;&gt;tiny types&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, given that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uri&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;credentials&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config&lt;/code&gt; all have different types, argument names can be removed in the code below. Once removed, we end up with one argument per line and can &lt;a href=&quot;#put-arguments-on-one-line&quot;&gt;put them on one line&lt;/a&gt;.&lt;/p&gt;
&lt;kotlin&gt;
val store = FruitStoreInTheCloud(
    uri = uri,
    credentials = credentials,
    config = config
)
...
&lt;/kotlin&gt;
&lt;p&gt;The code after tidying:&lt;/p&gt;
&lt;kotlin&gt;
val store = FruitStoreInTheCloud(uri, credentials, config)
...
&lt;/kotlin&gt;

&lt;p&gt;Note that in IntelliJ there is a “Remove all argument names” intention, which can be invoked via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alt+Enter&lt;/code&gt; popup menu or assigned its own shortcut.&lt;/p&gt;

&lt;h3 id=&quot;add-argument-names-when-types-are-the-same-or-generic&quot;&gt;Add argument names when types are the same or generic&lt;/h3&gt;
&lt;p&gt;When arguments have the same or generic types, add argument names to make them distinct and clarify their meaning. One reason is that it can take some effort to tell the difference between the arguments of the same type. This is error-prone because we can pass values in the wrong order or introduce a bug while reordering parameters. Another reason is that generic types don’t communicate the meaning of the value, so it’s harder to understand the code without IDE/editor help, which is also an invitation for subtle bugs.&lt;/p&gt;

&lt;p&gt;IntelliJ can help us by showing names as &lt;a href=&quot;https://www.jetbrains.com/help/idea/inlay-hints.html&quot;&gt;inlay hints&lt;/a&gt; or &lt;a href=&quot;https://www.jetbrains.com/help/idea/viewing-reference-information.html#view-parameter-info&quot;&gt;parameter information&lt;/a&gt; at the cursor. The inlay hints are useful, but they don’t provide the guarantees of the compiler. And because you can’t know if the reader of the code will have hints enabled, it’s safer to assume nothing. Parameter information is displayed in a popup window, so we might end up checking every argument while the popup is visible or try remembering the order. Either way, it’s a bit too much effort.&lt;/p&gt;

&lt;p&gt;For example, given the following constructor, the meaning of empty strings and numbers &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3&lt;/code&gt; is not very clear without looking up the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FruitStoreInTheCloud&lt;/code&gt; declaration or using IDE support.&lt;/p&gt;
&lt;kotlin&gt;
val store = FruitStoreInTheCloud(&quot;https://fruit.cloud&quot;, &quot;&quot;, &quot;&quot;, 10, 3)
...
&lt;/kotlin&gt;

&lt;p&gt;The code after tidying makes the meaning of the arguments more obvious.&lt;/p&gt;

&lt;kotlin&gt;
val store = FruitStoreInTheCloud(
    url = &quot;https://fruit.cloud&quot;,
    user = &quot;&quot;, 
    password = &quot;&quot;,
    connectionTimeout = 10,
    retryAttempts = 3
)
...
&lt;/kotlin&gt;

&lt;p&gt;Argument names have increased the length of the line to the point that we had to &lt;a href=&quot;#put-parameters-on-separate-lines&quot;&gt;put parameters on separate line&lt;/a&gt;. So while the argument names made the code less error-prone and more understandable, they did it at the cost of verbosity. It’s up to us to decide if it was worth it or if there is another avenue for tidying, e.g. introducing &lt;a href=&quot;#consider-using-tiny-types&quot;&gt;tiny types&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that in IntelliJ there is an “Add names to call arguments” intention, which can be invoked via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alt+Enter&lt;/code&gt; popup menu or assigned its own shortcut.&lt;/p&gt;

&lt;h3 id=&quot;pass-named-arguments-in-the-order-of-parameter-declaration&quot;&gt;Pass named arguments in the order of parameter declaration&lt;/h3&gt;
&lt;p&gt;Pass named arguments in function/constructor invocations in the same order as parameter declaration. The reason is that if parameters are declared in a meaningful order, then arguments can only benefit from following it. Consistent ordering can also be useful when comparing multiple function/constructor invocations by doing a visual comparison or textual diff. Finally, because the “Change signature” refactoring automatically reorders arguments to be in the order of parameters even on an unrelated change, it is beneficial to have arguments in this order so that the refactoring is not mixed with the argument reordering.&lt;/p&gt;

&lt;p&gt;For example, given the following invocations of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Config&lt;/code&gt; constructor, it’s not obvious what the differences are between them.&lt;/p&gt;
&lt;kotlin&gt;
val config = Config(
    retryAttempts = 10,
    callTimeout = INFINITE,
    connectionTimeout = 3.seconds
)
...
val anotherConfig = Config(
    connectionTimeout = 10.seconds,
    retryAttempts = 3, 
    callTimeout = 5.minutes
)
&lt;/kotlin&gt;

&lt;p&gt;With the arguments arranged in the same order, it’s easier to notice the differences (and maybe ask ourselves why these differences exist).&lt;/p&gt;
&lt;kotlin&gt;
val config = Config(
    connectionTimeout = 3.seconds,
    callTimeout = INFINITE,
    retryAttempts = 10
)                                  
...                                
val anotherConfig = Config(
    connectionTimeout = 10.seconds,
    callTimeout = 5.minutes,
    retryAttempts = 3
)
&lt;/kotlin&gt;

&lt;h3 id=&quot;put-parameters-on-one-line&quot;&gt;Put parameters on one line&lt;/h3&gt;

&lt;p&gt;When a function or class constructor declaration has only a few parameters, put them on one line. How few is enough to justify the tidying is subjective and depends on the length of parameter names, the length and complexity of parameter types, the length of the default values, the surrounding code, readers’ attention span, etc. The motivation is to have “optimal” information density on the screen.&lt;/p&gt;

&lt;p&gt;With one or two parameters per line, the information density per line is a bit low, so we might end up scrolling the source code up and down a lot, reading it almost as a single column.&lt;/p&gt;
&lt;kotlin&gt;
data class Password(
    val value: String
)

data class Credentials(
    val user: String,
    val password: Password
)
&lt;/kotlin&gt;

&lt;p&gt;Putting class or function parameters on a single line will increase the information density and can make it easier to skim.&lt;/p&gt;
&lt;kotlin&gt;
data class Password(val value: String)

data class Credentials(val user: String, val password: Password)
&lt;/kotlin&gt;

&lt;p&gt;Note that in IntelliJ there is a “Put parameters on one line” intention, which can be invoked via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alt+Enter&lt;/code&gt; popup menu or assigned its own shortcut.&lt;/p&gt;

&lt;h3 id=&quot;put-arguments-on-one-line&quot;&gt;Put arguments on one line&lt;/h3&gt;
&lt;p&gt;When a function or constructor invocation has only a few arguments, put them on one line. How few is enough to justify the tidying is subjective and depends on the length of argument names (especially with named arguments), the surrounding code, readers’ attention span, etc. The motivation is to have “optimal” information density on the screen.&lt;/p&gt;

&lt;p&gt;One or two arguments on separate lines are often a good opportunity for the tidy-up. You might notice in the example below that arguments are vertically misaligned with constructors, so we have to read the code from right to left. Sometimes this is inevitable, but in this case, it’s easy to fix by putting arguments on one line.&lt;/p&gt;
&lt;kotlin&gt;
val password = Password( ↙️ 👀
    &quot;********&quot;     
)
val credentials = Credentials( ↙️ 👀
    user = &quot;Bob&quot;,
    password = password
)
&lt;/kotlin&gt;
&lt;p&gt;The code after tidying:&lt;/p&gt;
&lt;kotlin&gt;
val password = Password(&quot;********&quot;)
val credentials = Credentials(user = &quot;Bob&quot;, password = password)
&lt;/kotlin&gt;
&lt;p&gt;The next tidying might be to &lt;a href=&quot;#inline-variables-with-single-usage&quot;&gt;inline single usage&lt;/a&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;password&lt;/code&gt; or to &lt;a href=&quot;#remove-argument-names-when-all-types-are-distinct&quot;&gt;remove argument names&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that in IntelliJ there is a “Put arguments on one line” intention, which can be invoked via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alt+Enter&lt;/code&gt; popup menu or assigned its own shortcut.&lt;/p&gt;

&lt;h3 id=&quot;put-parameters-on-separate-lines&quot;&gt;Put parameters on separate lines&lt;/h3&gt;
&lt;p&gt;When a function or class constructor declaration has too many parameters, put them on separate lines. How many is too many is subjective and depends on the length of parameter names, the length and complexity of parameter types, the length of the default values, the surrounding code, etc. Too many parameters can also be a good point to ask ourselves if some of them should be extracted into a separate class.&lt;/p&gt;

&lt;p&gt;For example, having five constructor parameters might be too much for a single line.&lt;/p&gt;
&lt;kotlin&gt;
class FruitStoreInTheCloud(val uri: Uri, val user: String, val password: Password, val connectionTimeout: Duration, val retryAttempts: Int = 5)
&lt;/kotlin&gt;

&lt;p&gt;So we can try putting them on separate lines.&lt;/p&gt;
&lt;kotlin&gt;
class FruitStoreInTheCloud(
    val uri: Uri,
    val user: String,
    val password: Password,
    val connectionTimeout: Duration,
    val retryAttempts: Int = 5
)
&lt;/kotlin&gt;

&lt;p&gt;Since some of the parameters are related, we might be tempted to group them.&lt;/p&gt;
&lt;kotlin&gt;
class FruitStoreInTheCloud(
    val uri: Uri,
    val user: String, val password: Password,
    val connectionTimeout: Duration, val retryAttempts: Int = 5
)
&lt;/kotlin&gt;

&lt;p&gt;The problem with this layout is that it is more irregular than one parameter per line. What we really mean by grouping the parameters is that there is cohesion and each group could be expressed as a separate class.&lt;/p&gt;
&lt;kotlin&gt;
class FruitStoreInTheCloud(
    val uri: Uri,
    val credentials: Credentials,
    val config: Config
)
&lt;/kotlin&gt;
&lt;p&gt;And with only three parameters in the constructor, we might consider &lt;a href=&quot;#put-parameters-on-one-line&quot;&gt;putting them on one line&lt;/a&gt; (never mind the irony).&lt;/p&gt;

&lt;p&gt;Note that in IntelliJ there is a “Put parameters on separate lines” intention, which can be invoked via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alt+Enter&lt;/code&gt; popup menu or assigned its own shortcut.&lt;/p&gt;

&lt;h3 id=&quot;stop-the-constant-shouting&quot;&gt;Stop the CONSTANT SHOUTING&lt;/h3&gt;

&lt;p&gt;Constants should be lowercase following the same convention as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;val&lt;/code&gt;s and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var&lt;/code&gt;s. I realise this tidying contradicts &lt;a href=&quot;https://kotlinlang.org/docs/coding-conventions.html#property-names&quot;&gt;Kotlin coding conventions&lt;/a&gt; but there are NO GOOD REASONS for constant names to be uppercase other than history.&lt;/p&gt;

&lt;p&gt;As a short summary of the &lt;a href=&quot;https://accu.org/journals/overload/22/121/wakely_1923&quot;&gt;Stop the Constant Shouting&lt;/a&gt; article by Jonathan Wakely (which heavily inspired this tidying), in the C programming language it’s common to use macros in cases when we would use a constant in Kotlin. This is because initially constants were not part of the language and even now they still have limitations. Using uppercase for macros made sense because they’re not normal code so it wasn’t a bad idea for macros to STAND_OUT_IN_THE_CODE, especially at the time when smart code editors and IDEs didn’t exist. The coding style for constants (actually macros) was copied from C to C++, to Java, and then to Kotlin.&lt;/p&gt;

&lt;p&gt;As you might have noticed, uppercase text REALLY DRAWS OUR ATTENTION. At the same time constants are one of the most boring parts of the code. They don’t change and don’t have any important side-effects (unlike, for example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.exit(1)&lt;/code&gt;). Yet we use the most expressive text style for constants. There is an argument that the uppercase convention is too widespread to ignore. I’m not convinced though that familiarity outweighs the harm done by unnecessary screaming uppercase. The accidental code style for constants needs to be fixed and the sooner the easier it will be.&lt;/p&gt;

&lt;p&gt;Instead of SHOUTING CONSTANTS:&lt;/p&gt;
&lt;kotlin&gt;
companion object {
    private const val INITIAL_BUFFER_SIZE = 8192
}
private val buffer = ByteArray(INITIAL_BUFFER_SIZE)
&lt;/kotlin&gt;
&lt;p&gt;you can use lowercase:&lt;/p&gt;
&lt;kotlin&gt;
companion object {
    private const val initialBufferSize = 8192
}
private val buffer = ByteArray(initialBufferSize)
&lt;/kotlin&gt;

&lt;p&gt;As a side note, in the example above it would be good to &lt;a href=&quot;#inline-variables-with-single-usage&quot;&gt;inline single usage constant&lt;/a&gt; and explain the reasons for choosing number 8192 (no particular reason is still useful information). Often extracting a magic number into a constant doesn’t make the number less magic.&lt;/p&gt;

&lt;p&gt;Once constants follow the same naming convention as variables, it’s easier to change constants to variables and the other way round because we don’t need to update all usages.&lt;/p&gt;

&lt;h3 id=&quot;consider-using-tiny-types&quot;&gt;Consider using tiny types&lt;/h3&gt;

&lt;p&gt;…&lt;/p&gt;

</description>
        <pubDate>Tue, 26 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://dkandalov.github.io/tidy-kotlin</link>
        <guid isPermaLink="true">https://dkandalov.github.io/tidy-kotlin</guid>
        
        
      </item>
    
      <item>
        <title>Sane Intellij Plugin Development With Live Plugin</title>
        <description>&lt;p&gt;Pretty much all modern web browsers have &lt;a href=&quot;https://en.wikipedia.org/wiki/Web_development_tools&quot;&gt;developer tools console&lt;/a&gt; which lets you type some JavaScript code and run it in the browser. In theory, this allows you to do any kind of automation and extend browser functionality at runtime. In practice, it’s not suitable for the purpose, and, to be fair, most users are probably not even aware of the developer console, so for a browser development team spending extra effort to make it possible to extend the browser at runtime via console might not be justified.&lt;/p&gt;

&lt;p&gt;This is different for code editors and IDEs with their target audience being &lt;a href=&quot;https://en.wikipedia.org/wiki/Power_user&quot;&gt;power users&lt;/a&gt;, so it seems like a sensible idea to make extending editor/IDE functionality and task automation as easy as possible. Surprisingly, this is not the case, and most code editors and IDEs don’t have the functionality to develop extensions at runtime. It doesn’t have to be this way though.&lt;/p&gt;

&lt;p&gt;This blog post is about &lt;a href=&quot;https://github.com/dkandalov/live-plugin&quot;&gt;LivePlugin&lt;/a&gt; - a plugin for adding/modifying IntelliJ IDEs functionality at runtime without IDE restarts using Kotlin (or Groovy). Even though this blog has details specific to IntelliJ platform and the JVM, some concepts and ideas are universal enough to be applied in other environments.&lt;/p&gt;

&lt;h3 id=&quot;contents&quot;&gt;Contents&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#why&quot;&gt;Why?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#what-does-it-look-like&quot;&gt;What does it look like?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#how-does-it-work&quot;&gt;How does it work?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#notifications-logging-basic-input&quot;&gt;Notifications, logging, basic input&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#actions&quot;&gt;Actions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#action-groups&quot;&gt;Action groups&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#editor-and-document&quot;&gt;Editor and Document&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#intentions-and-inspections&quot;&gt;Intentions and Inspections&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#intellij-apis-mini-cheat-sheet&quot;&gt;IntelliJ APIs Mini Cheat Sheet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#final-thoughts&quot;&gt;Final thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;why&quot;&gt;Why?&lt;/h3&gt;
&lt;p&gt;The main reason is faster and simpler workflow for plugin development. From the IDE user point of view, this means that you can write plugins for things you wouldn’t bother writing plugins otherwise, e.g. project-specific scripts and workflows that can be added to IDE. In a way it’s like creating IDE macros using a programming language. It also makes it easier to add “missing” IDE features and try these features before creating a “proper” plugin.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Minimal setup&lt;/strong&gt; — no need to create a separate project for plugin development.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fast feedback loop&lt;/strong&gt; — plugins are executed without IDE restarts.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Simpler API&lt;/strong&gt; — smaller surface area API to make extending IDE functionality easier.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;what-does-it-look-like&quot;&gt;What does it look like?&lt;/h3&gt;
&lt;p&gt;Once you install LivePlugin, you can open any project and notice that there is a panel called “Plugins”. It contains a list of folders with plugins source code. LivePlugin comes with a few example plugins, some of which, including “hello-world”, are installed by default. By convention &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plugin.kts&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plugin.groovy&lt;/code&gt; files are plugin entry points. To get started, you can select the “hello-world” plugin and press the green “Run Plugin” button to compile and run it. The IDE should display some notification messages which should also be available in the “Event Log” tool window.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/liveplugin/0.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The next thing to try is modifying the plugin code. You can, for example, leave only one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;show()&lt;/code&gt; function and change the message. If you press the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rerun Plugin&lt;/code&gt; button, the IDE will display a notification with an updated message. (You can also try writing syntactically invalid code or throw an exception from the code to see how it fails.)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/liveplugin/1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you’re using IntelliJ IDEA or Android Studio, and have Kotlin plugin installed, all standard IDE features like auto-completion and navigation should work out-of-the-box when editing plugin code. LivePlugin is bundled with its own source code, so you should be able to navigate, for example, to the definition of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;show()&lt;/code&gt; function. Other IntelliJ IDEs, which are not compatible with Kotlin plugin, will only have basic syntax highlighting.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/liveplugin/2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are few more details, which are described in the bundled examples starting from “hello-world”, but overall this is it. LivePlugin compiles and runs code in the same JVM instance as IDE with access to all IDE classes and objects.&lt;/p&gt;

&lt;h3 id=&quot;how-does-it-work&quot;&gt;How does it work?&lt;/h3&gt;
&lt;p&gt;Overall, the whole workflow can be summarized in three steps:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;dispose resources from previous plugin execution&lt;/li&gt;
  &lt;li&gt;compile plugin source code into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.class&lt;/code&gt; file(s)&lt;/li&gt;
  &lt;li&gt;load plugin classes into newly created classloader and execute the code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This sounds simple but there are more details at each step. In the first place, why do you need to clean up resources from the previous execution? The reason for the cleanup is that if a plugin registers, for example, an IDE event listener, there is no way for the garbage collector to know when the listener is no longer used. So there is a common pattern in IntelliJ IDEs to pass an instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.intellij.openapi.Disposable&lt;/code&gt; class which represents a lifetime of the listener (or some other resource). Each time LivePlugin executes a script, it creates a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pluginDisposable&lt;/code&gt; object and passes it to the script. The script then will need to use it with IDE APIs or add an explicit cleanup callback (e.g. using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.whenDisposed()&lt;/code&gt; function). When LivePlugin unloads the script, or before script is executed again, it disposes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pluginDisposable&lt;/code&gt; from the previous execution.&lt;/p&gt;

&lt;p&gt;At the next step LivePlugin compiles plugin source code. This obviously requires a compiler, so the question is where do you get one? IntelliJ IDEs used to come with an embedded Kotlin compiler jar, but it’s not the case anymore, and it was hard to know when Kotlin compiler would be updated (with potentially breaking changes), so LivePlugin is bundled with its own Kotlin compiler. Another question is how to compile code which uses IDE APIs. Luckily, since IDE is running on the JVM, it’s possible to look up the location of IDE jar files and use them for compilation classpath. This is limiting in a sense that you cannot write code for an older or newer version of IDE, but most of the time it’s not a problem and compiling again current version of IDE just makes setup much easier. LivePlugin can also compile code which uses external libraries or other plugins.&lt;/p&gt;

&lt;p&gt;It might seem a bit strange why LivePlugin creates a new classloader for each execution of a script. The answer is that a new classloader is needed to make sure that classes from the previous script executions can be unloaded. &lt;a href=&quot;https://en.wikipedia.org/wiki/Java_Classloader&quot;&gt;Classloaders&lt;/a&gt; are special classes which can bring other classes into existence, e.g. by reading bytecode from disk, network or generating bytecode. Classloaders form a &lt;a href=&quot;https://docs.oracle.com/cd/E19501-01/819-3659/beadf/index.html&quot;&gt;hierarchy&lt;/a&gt; in which child classloaders can see classes from their parents, but not the other way round. Classloaders can only load classes with unique names, so plugin classloader won’t be able to load another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.lang.String&lt;/code&gt; (which is already loaded by bootstrap classloader). On the other hand, sibling classloaders don’t “see” each other’s classes, so two leaf classloaders can both load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my.project.Foo&lt;/code&gt; class at the same time. From that point of view, classloaders are like namespaces. When there are no more references to the classloader and the objects created from its classes, the classloader and the classes become eligible for garbage collection. This is the main reason for creating a new classloader for each script execution.&lt;/p&gt;

&lt;p&gt;The final step is running plugin code. At the JVM level, plugin script is really just a class which can be reflectively instantiated with some parameters (including &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pluginDisposable&lt;/code&gt;). The construction basically runs all the code in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plugin.kts&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plugin.groovy&lt;/code&gt;) file. This happens on the event dispatch thread (EDT) so it is safe to modify IDE state at the top level of the plugin script (see IntelliJ &lt;a href=&quot;https://plugins.jetbrains.com/docs/intellij/general-threading-rules.html&quot;&gt;threading rules&lt;/a&gt;). On the other hand, this means that blocking operations (like CPU intense calculations or long-running IO) should be done on a background thread, to avoid freezing IDE UI. Just like any other plugin it has access to all objects in the IDE JVM, so it is possible to use any functionality from other plugins and IDE itself.&lt;/p&gt;

&lt;p&gt;Here is a diagram with an overview of the components described above, where filled lines represent control flow and dotted lines represent dependencies. It’s not a very detailed or precise one, but hopefully it is still useful as a visual guide:
&lt;img src=&quot;/assets/images/liveplugin/how-it-works.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is all there is to it. If you want to extend IDE functionality by, for example, adding some actions, it’s up to you to invoke specific functions, i.e. there is no special syntax or some XML/JSON/YAML file with configuration. It’s all just Kotlin code.&lt;/p&gt;

&lt;h3 id=&quot;notifications-logging-basic-input&quot;&gt;Notifications, logging, basic input&lt;/h3&gt;
&lt;p&gt;Being able to show notifications or print messages is one of the most fundamental ways to get feedback when using LivePlugin. There is no way to debug plugins with breakpoints because there is only one instance of the JVM. In theory, you could test-drive all plugin functionality, but in practice, many APIs are not very TDD-friendly. So notifications are the most useful way to know why something is (not) working.&lt;/p&gt;

&lt;p&gt;To show a standard IDE notification you can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;show()&lt;/code&gt; function (the name is inspired by the &lt;a href=&quot;https://hackage.haskell.org/package/base-4.12.0.0/docs/Text-Show.html&quot;&gt;Show&lt;/a&gt; typeclass in Haskell and the fact that “notify” would clash with method on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.lang.Object&lt;/code&gt;). The function takes few optional parameters and in its most complex form can look like this:&lt;/p&gt;
&lt;kotlin&gt;
show(
    message = &quot;Hello &amp;lt;a href=&apos;&apos;&amp;gt;world&amp;lt;/a&amp;gt;&quot;,
    title = &quot;Foo&quot;,
    groupDisplayId = &quot;MyDisplayGroup&quot;,
    notificationListener = { notification, hyperlinkEvent -&amp;gt;
        show(&quot;Hi ${notification.content} ${hyperlinkEvent.sourceElement}&quot;)
    }
)
&lt;/kotlin&gt;
&lt;p&gt;Where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;message&lt;/code&gt; is an object which will be converted to a string; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;, as you can guess, is a title of the message; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;groupDisplayId&lt;/code&gt; is a string id which can be configured in “Event Log” settings so that for example IDE plays a sound on events with a particular group id; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notificationListener&lt;/code&gt; is callback invoked when user clicks on hyperlinks in the HTML formatted message. (Note that the support for basic HTML formatting and hyperlink callbacks are really just part of IntelliJ notification API which is pretty cool 😎)&lt;/p&gt;

&lt;p&gt;If the notification message is too long, IDE will not show the whole content of the message. In this case, you can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;showInConsole()&lt;/code&gt; function which creates and opens a tool window with the specified text. It’s an extension function on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt; object which you can get as a part of the script context or via standard IDE API, e.g. from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnActionEvent&lt;/code&gt; in an action callback:&lt;/p&gt;
&lt;kotlin&gt;
project?.showInConsole(
    message = &quot;a really long message, or maybe even a stacktrace&quot;,
    consoleTitle = &quot;Some title&quot;,
    contentType = ERROR_OUTPUT
)
&lt;/kotlin&gt;

&lt;p&gt;Using notifications and tool windows for what is essentially logging is ok on a small scale to get fast feedback, but not ideal for a larger volume of data. There is a logging API based on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.intellij.openapi.diagnostic.Logger&lt;/code&gt; which works pretty much as expected appending info/warn/error messages to the IDE log file. And if you want something really simple, you can always use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;println()&lt;/code&gt; which ends up in the IDE log anyway:&lt;/p&gt;
&lt;kotlin&gt;
val logger = Logger.getInstance(&quot;MyPlugin&quot;)
logger.info(&quot;info message&quot;)
logger.warn(&quot;warn message&quot;)
logger.error(&quot;error message&quot;) // Will log and show error notification in IDE.
println(&quot;info message&quot;)
&lt;/kotlin&gt;

&lt;p&gt;Finally, there are couple Kotlin functions in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.intellij.openapi.ui&lt;/code&gt; package and few static functions in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.intellij.openapi.ui.Messages&lt;/code&gt; Java class for basic UI dialogs:&lt;/p&gt;
&lt;kotlin&gt;
val isYes = com.intellij.openapi.ui.showYesNoDialog(
    &quot;Dialog Title&quot;,
    &quot;And this is a question?&quot;,
    project
)
show(if (isYes) &quot;Yes!&quot; else &quot;No 😿&quot;)

val userInput = com.intellij.openapi.ui.Messages.showInputDialog(
    project,
    &quot;Please enter something useful&quot;,
    &quot;Dialog Title&quot;,
    AllIcons.Ide.Gift,
    &quot;initial value&quot;,
    null
)
show(&quot;userInput = $userInput&quot;)
&lt;/kotlin&gt;

&lt;h3 id=&quot;actions&quot;&gt;Actions&lt;/h3&gt;
&lt;p&gt;Actions are one of the most fundamental ways of user interaction with IDE. All menu items, text editing activities (e.g. moving cursor) and all items in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Settings -&amp;gt; Keymap&lt;/code&gt; are actions. Actions are essentially stateless functions which can be presented in UI and produce side effects when invoked. Once registered, action becomes available in all projects and will be invoked when you click on a menu item, use corresponding shortcut or, for example, choose an action in the “Find Action…” action. Actions are executed on the UI thread, so long-running tasks must be done in the background to avoid freezing UI.&lt;/p&gt;

&lt;p&gt;All actions need to implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.intellij.openapi.actionSystem.AnAction&lt;/code&gt; abstract class which is not that difficult, but to make it a bit easier, LivePlugin has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;registerAction()&lt;/code&gt; function with lambda as a callback. In the simplest form it looks like this (the new action will appear in the “Find Action…” list, where it can be invoked):&lt;/p&gt;
&lt;kotlin&gt;
registerAction(&quot;Show Project Name&quot;) { 
    show(it.project?.name) 
}
&lt;/kotlin&gt;
&lt;p&gt;Since there is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;registerAction()&lt;/code&gt;, it would be reasonable to expect the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unregisterAction()&lt;/code&gt; function. There isn’t one though. The reason is that unregistering actions and other callbacks is essentially resource cleanup and done by passing an instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.intellij.openapi.Disposable&lt;/code&gt;. In the example above, disposable is passed as part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LivePluginScript&lt;/code&gt; object which is an extension function receiver of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;registerAction()&lt;/code&gt;. In a more explicit form, each plugin execution has its own instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pluginDisposable&lt;/code&gt; which can be passed to various APIs, e.g. this is a more verbose way of registering action:&lt;/p&gt;
&lt;kotlin&gt;
registerAction(&quot;Show Project Name&quot;, disposable = pluginDisposable) {
    show(it.project?.name)
}
&lt;/kotlin&gt;
&lt;p&gt;When a plugin is rerun or unloaded (via the “Unload Plugin” button in the “Plugins” tool window), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pluginDisposable&lt;/code&gt; is disposed unregistering actions and freeing other resources. You can test it by unloading the plugin and checking that the action disappeared from the “Find Action…” list.&lt;/p&gt;

&lt;p&gt;There are few more useful details about actions which can be illustrated by expanding on the example above:&lt;/p&gt;
&lt;kotlin&gt;
registerAction(
    id = &quot;Show Project Name&quot;,
    keyStroke = &quot;alt shift .&quot;,
    actionGroupId = &quot;ToolsMenu&quot;
) { actionEvent: AnActionEvent -&amp;gt;
    show(actionEvent.project?.name)
}
&lt;/kotlin&gt;
&lt;ul&gt;
  &lt;li&gt;Here &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; is the action id which must be unique within the IDE. For convenience, it’s also used by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;registerAction()&lt;/code&gt; as a textual representation of the action.&lt;/li&gt;
  &lt;li&gt;Keyboard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keyStroke&lt;/code&gt; to invoke the action, where modification keys are lowercase (e.g. “ctrl”, “alt”, “shift”, “cmd”), letters are uppercase, and other keys are uppercase based on the constant names in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.awt.event.KeyEvent&lt;/code&gt; (e.g. “ENTER”, “ESCAPE”, “SPACE”, “LEFT”, “UP”, “F1”, “F12”).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;actionGroupId&lt;/code&gt; which is a string identifying a menu/popup/toolbar to which action will be added. Unfortunately, there is no single place to find all these ids, but there are common menu ids listed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;liveplugin.ActionGroupIds&lt;/code&gt; object.&lt;/li&gt;
  &lt;li&gt;Instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnActionEvent&lt;/code&gt; with invocation “context” which passed into the lambda. This is usually how actions know about the project, editor or UI component in which they were invoked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;registerAction()&lt;/code&gt; function is part of LivePlugin and uses lambda just for convenience. It’s entirely legal to implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnAction&lt;/code&gt; abstract class from IntelliJ API. Creating a subclass of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnAction&lt;/code&gt; is a bit more effort, but it also has more configurability. For example, you can specify an action icon or configure if the action is enabled/disabled in the current context.&lt;/p&gt;
&lt;kotlin&gt;
registerAction(id = &quot;Show Project Name&quot;, action = ShowProjectName())

class ShowProjectName : AnAction(AllIcons.Ide.Gift) {
    override fun actionPerformed(event: AnActionEvent) {
        show(event.project?.name)
    }
    override fun update(event: AnActionEvent) {
        event.presentation.isEnabled = true
    }
}
&lt;/kotlin&gt;

&lt;p&gt;Even though LivePlugin comes with some helper functions, you don’t have to use any of them. Instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;registerAction()&lt;/code&gt;, you could use IntelliJ API to register actions. The problem is that in this particular case, API is used by IDE to add actions from XML config files, and unlike newer APIs doesn’t support &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Disposable&lt;/code&gt;s.&lt;/p&gt;
&lt;kotlin&gt;
val actionManager = com.intellij.openapi.actionSystem.ActionManager.getInstance()
actionManager.registerAction(&quot;action id&quot;, action)
&lt;/kotlin&gt;

&lt;p&gt;Finally, since actions are just like functions, it’s natural to ask if actions can invoke other actions. The answer is “yes” with the caveat that you need to look up or create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnAction&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnActionEvent&lt;/code&gt; objects. Some actions have simple constructors, so it might be easy to just create a new instance. Some might not be public or hard to construct. In this case, they can be looked up via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActionManager.getAction(actionId)&lt;/code&gt;. The easiest way to get an instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnActionEvent&lt;/code&gt; is to pass on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;event&lt;/code&gt; argument from already invoked action (or if you really need to construct one, see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;liveplugin.implementation.Actions#anActionEvent()&lt;/code&gt; for ideas):&lt;/p&gt;
&lt;kotlin&gt;
registerAction(&quot;Invoke Another Action&quot;) { event -&amp;gt;
    val action = ActionManager.getInstance().getAction(&quot;ToggleBookmark1&quot;)
    action.actionPerformed(event) // Bookmark current line
}
&lt;/kotlin&gt;

&lt;h3 id=&quot;action-groups&quot;&gt;Action groups&lt;/h3&gt;
&lt;p&gt;Actions can be grouped into action groups which are actions themselves. The main reason for creating an action group is that it’s a good way to present a bunch of actions in the UI as a submenu or a popup window.&lt;/p&gt;

&lt;p&gt;All action groups implement the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.intellij.openapi.actionSystem.ActionGroup&lt;/code&gt; class. The simplest way to create one is by instantiating &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DefaultActionGroup&lt;/code&gt;, however, when used as a menu item it will add all actions without sub-menu, unless the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isPopup&lt;/code&gt; property is set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;. For this reason there is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;liveplugin.PopupActionGroup()&lt;/code&gt; which makes the group a popup.&lt;/p&gt;
&lt;kotlin&gt;
val action1 = registerAction(&quot;Action 1&quot;) { show(&quot;1&quot;) }
val action2 = registerAction(&quot;Action 2&quot;) { show(&quot;2&quot;) }
registerAction(
    id = &quot;Some Actions&quot;,
    actionGroupId = ActionGroupIds.EditorPopupMenu,
    action = DefaultActionGroup(action1, action2).also { it.isPopup = true }
)
&lt;/kotlin&gt;

&lt;p&gt;Another option is to display an action group as a popup window. LivePlugin comes with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createPopup()&lt;/code&gt; extension function which has few useful default parameters and uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JBPopupFactory&lt;/code&gt; under the hood. Note that there is a special &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Separator&lt;/code&gt; action in IntelliJ API which represents a separator in the menu.&lt;/p&gt;
&lt;kotlin&gt;
registerAction(&quot;Show Action Group&quot;) {
    PopupActionGroup(name = &quot;Some Actions&quot;,
        action1,
        action2,
        Separator.getInstance(),
        PopupActionGroup(&quot;Sub Menu&quot;,
            action3,
            action4,
        )
    ).createPopup()
     .showCenteredInCurrentWindow(it.project!!)
}&lt;/kotlin&gt;

&lt;p&gt;All of the above is straightforward but there are few subtle things worth mentioning. One is that &lt;strong&gt;actions should not share &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnActionEvent&lt;/code&gt;s between each other&lt;/strong&gt;. For example, in the code snippet below, “action 1” is using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;event&lt;/code&gt; from the outer “Show Action Group” action. This is wrong. The reason is that events capture the content in which an action was invoked, and this context might change by the time another action is invoked. Even if you’re sure that sharing an event will be fine, in some cases IDE checks if there was a shared event and will display an error. Another caveat is that when creating a popup, we do want to pass some of the context to actions in the popup window via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;event.dataContext&lt;/code&gt;, otherwise, in the example below “action 2” will not know what the current file is.&lt;/p&gt;
&lt;kotlin&gt;
registerAction(&quot;Show Action Group&quot;) { event: AnActionEvent -&amp;gt;
    PopupActionGroup(name = &quot;Some Actions&quot;,
        AnAction(&quot;action 1&quot;) { show(event.virtualFile?.path) },
        AnAction(&quot;action 2&quot;) { show(it.virtualFile?.path) }
    ).createPopup(event.dataContext)
     .showCenteredInCurrentWindow(event.project!!)
}
&lt;/kotlin&gt;

&lt;p&gt;Actions and action groups are the lowest hanging fruit in terms of the plugin development. Even with this minimal IDE integration there are few useful things that can be done, e.g. by sharing bookmarks and doing various automation via shell scripts and HTTP requests. I will not explain the examples below in detail because they are roughly based on the examples bundled with LivePlugin. It’s worth noting though that it’s possible to use third-party libraries (e.g. &lt;a href=&quot;https://www.http4k.org&quot;&gt;http4k&lt;/a&gt;) and execute long-running tasks in the background without blocking UI thread.&lt;/p&gt;
&lt;kotlin&gt;
// add-to-classpath $PLUGIN_PATH/libs/*

PopupActionGroup(name = &quot;Some Actions&quot;,
    AnAction(&quot;LivePlugin on GitHub&quot;) { 
        openInBrowser(&quot;https://github.com/dkandalov/live-plugin&quot;) 
    },
    AnAction(&quot;LivePlugin on GitHub 2&quot;) { 
        it.project?.openInIdeBrowser(&quot;https://github.com/dkandalov/live-plugin&quot;) 
    },
    AnAction(&quot;Open plugin.kts&quot;) { 
        it.project?.openInEditor(&quot;$pluginPath/plugin.kts&quot;) 
    },
    AnAction(&quot;Http Request&quot;) {
        val client = org.http4k.client.OkHttp()
        val response = client(Request(GET, &quot;https://duckduckgo.com&quot;))
        show(response.status)
    },
    AnAction(&quot;Run a Script&quot;) {
        runBackgroundTask(taskTitle = &quot;Running shell script&quot;, task = {
            show(runShellScript(&quot;&quot;&quot;
                &apos;$pluginPath/hello.sh&apos;
                sleep 5
                &quot;&quot;&quot;.trimIndent()
            ).stdout)
        })
    },
)
&lt;/kotlin&gt;

&lt;h3 id=&quot;editor-and-document&quot;&gt;Editor and Document&lt;/h3&gt;
&lt;p&gt;Writing software is still mostly based on textual representation of code and even though IDEs are good at manipulating syntax tree, being able to programmatically control text editor can be quite useful. This can be achieved using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.intellij.openapi.editor.Editor&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Document&lt;/code&gt; APIs.&lt;/p&gt;

&lt;p&gt;If you feel like experimenting, one of the simplest ways might be to use the current editor without any actions directly in the plugin script. The code below uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;caretModel&lt;/code&gt; to move cursor to the beginning of the file and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;selectionModel&lt;/code&gt; to select all text:&lt;/p&gt;
&lt;kotlin&gt;
val editor = project?.currentEditor ?: error(&quot;No editor&quot;)
editor.caretModel.moveToOffset(0)
editor.selectionModel.setSelection(0, editor.document.textLength)
&lt;/kotlin&gt;

&lt;p&gt;However, as a motivating example, let’s write “Random Case” action which will change letters of the current word to be randomly upper or lower case. I would normally write the code incrementally, manually testing each new piece of functionality. The first thing to check in the action is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;editor&lt;/code&gt; are available. The following action will show a message when invoked in an editor but will not show notification if the focus is, for example, in the “Project” tool window.&lt;/p&gt;
&lt;kotlin&gt;
registerAction(&quot;Random Case&quot;, &quot;alt shift .&quot;) { event -&amp;gt;
    val document = event.document
    val editor = event.editor
    if (document != null &amp;amp;&amp;amp; editor != null) {
        show(&quot;Document and editor are available&quot;)
    }
}
&lt;/kotlin&gt;

&lt;p&gt;The next step is to get the word under the caret. The trick here is to use offset from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;editor.caretModel&lt;/code&gt; which represents a shift in characters from the beginning of the current file. There is always a potential for off-by-one errors on the edges around words and beginning/end of file but the code below seems to be good enough for the job.&lt;/p&gt;
&lt;kotlin&gt;
registerAction(&quot;Random Case&quot;, &quot;alt shift .&quot;) { event -&amp;gt;
    val document = event.document
    val offset = event.editor?.caretModel?.offset
    if (document != null &amp;amp;&amp;amp; offset != null) {
        val textAfter = document.text.drop(offset).takeWhile { it.isLetterOrDigit() }
        val textBefore = document.text.take(offset).takeLastWhile { it.isLetterOrDigit() }
        show(textBefore + textAfter)
    }
}
&lt;/kotlin&gt;

&lt;p&gt;Randomising letters is an easy task in Kotlin (I have to mention though that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Random&lt;/code&gt; object has side effects and should be ideally passed in from outside so that it’s possible to give it a seed and write an automated test for the action):&lt;/p&gt;
&lt;kotlin&gt;
val text = (textBefore + textAfter)
    .map { if (Random.nextBoolean()) it.toUpperCase() else it.toLowerCase() }
    .joinToString(separator = &quot;&quot;)
show(text)
&lt;/kotlin&gt;

&lt;p&gt;The final step is to update text in the document. It is a trivial thing to do using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Document.replaceString()&lt;/code&gt; function which takes from/to offsets and a replacement string. However, if you run the code below, it doesn’t modify the document but instead fails with &lt;em&gt;“Assertion failed: Write access is allowed inside write-action only (see com.intellij.openapi.application.Application.runWriteAction())”&lt;/em&gt;.&lt;/p&gt;
&lt;kotlin&gt;
document.replaceString(
    offset - textBefore.length,
    offset + textAfter.length,
    text
)
&lt;/kotlin&gt;

&lt;p&gt;This happens because modifying the state of a document without a write lock violates IntelliJ &lt;a href=&quot;https://plugins.jetbrains.com/docs/intellij/general-threading-rules.html&quot;&gt;Threading Rules&lt;/a&gt;. I recommend reading the rules to understand the details, but overall the rules can be summarized by the following table, where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadAction&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WriteAction&lt;/code&gt; are classes with static &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run(ThrowableRunnable)&lt;/code&gt; method and in spite of the name are not related to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnAction&lt;/code&gt; class described in the section above (yes, naming is hard 🙈️).&lt;/p&gt;

&lt;table class=&quot;post-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt; &lt;/th&gt;
      &lt;th&gt;Read&lt;/th&gt;
      &lt;th&gt;Write&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;UI thread&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;WriteAction&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Other threads&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;ReadAction&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Since “Random Case” action code is executed on the UI thread, the  document modification code can be wrapped with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WriteAction&lt;/code&gt;:&lt;/p&gt;
&lt;kotlin&gt;
WriteAction.run(ThrowableRunnable {
    document.replaceString(
        offset - textBefore.length,
        offset + textAfter.length,
        text
    )
})
&lt;/kotlin&gt;

&lt;p&gt;Unfortunately, it still fails but this time with a different message &lt;em&gt;“IncorrectOperationException: Must not change document outside command or undo-transparent action. See com.intellij.openapi.command.WriteCommandAction or CommandProcessor”&lt;/em&gt;. The reason is that there is &lt;a href=&quot;https://plugins.jetbrains.com/docs/intellij/documents.html#what-are-the-rules-of-working-with-documents&quot;&gt;an additional rule&lt;/a&gt; that document modification can only happen within an undoable command, meaning that the modification can be undone/redone and will be available in the “Main Menu -&amp;gt; Edit -&amp;gt; Undo/Redo”. To make document modification code a bit less nested, LivePlugin comes with an extension function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;executeCommand&lt;/code&gt;, so the final code for the “Random Case” action looks like this:&lt;/p&gt;
&lt;kotlin&gt;
registerAction(&quot;Random Case&quot;, &quot;alt shift .&quot;) { event -&amp;gt;
    val document = event.document
    val offset = event.editor?.caretModel?.offset
    if (document != null &amp;amp;&amp;amp; offset != null) {
        val textAfter = document.text.drop(offset).takeWhile { it.isLetterOrDigit() }
        val textBefore = document.text.take(offset).reversed().takeWhile { it.isLetterOrDigit() }.reversed()
        val text = (textBefore + textAfter)
            .map { if (Random.nextBoolean()) it.toUpperCase() else it.toLowerCase() }
            .joinToString(&quot;&quot;)
        document.executeCommand(event.project!!, description = &quot;Random Case&quot;) {
            replaceString(
                offset - textBefore.length,
                offset + textAfter.length,
                text
            )
        }
    }
}
&lt;/kotlin&gt;

&lt;h3 id=&quot;intentions-and-inspections&quot;&gt;Intentions and Inspections&lt;/h3&gt;
&lt;p&gt;There are two similar concepts in IntelliJ based IDEs: &lt;a href=&quot;https://www.jetbrains.com/help/idea/intention-actions.html&quot;&gt;intentions&lt;/a&gt; and &lt;a href=&quot;https://www.jetbrains.com/help/idea/code-inspection.html&quot;&gt;inspections&lt;/a&gt;. Both intentions and inspections run in the background analysing code in the current editor. If a particular intention/inspection can be applied, it shows up in the light bulb popup menu available on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alt+enter&lt;/code&gt;, where you can select it to perform a code transformation. The main conceptual difference is that inspections provide a way to transform code (e.g. invert &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; condition or replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;||&lt;/code&gt;) and inspections are looking for problems in the code (e.g. unreachable code or potential &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NullPointerException&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Both intentions and inspections work with &lt;a href=&quot;https://plugins.jetbrains.com/docs/intellij/psi-elements.html&quot;&gt;PSI elements&lt;/a&gt; (short for Program Structure Interface) which are basically nodes in an &lt;a href=&quot;https://en.wikipedia.org/wiki/Abstract_syntax_tree&quot;&gt;abstract syntax tree&lt;/a&gt;. PSI elements are represented by different classes in different programming languages, so usually intentions/inspections are written for a specific language. There is &lt;a href=&quot;https://plugins.jetbrains.com/docs/intellij/uast.html&quot;&gt;UAST&lt;/a&gt; (Unified Abstract Syntax Tree) API for JVM languages (Java, Kotlin, Scala, Groovy) but it’s still somewhat experimental at the moment of writing.&lt;/p&gt;

&lt;p&gt;The best way to learn about PSI is to see what it looks like for particular code examples. This is what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;println(&quot;OMG!!&quot;)&lt;/code&gt; looks like using &lt;a href=&quot;https://plugins.jetbrains.com/plugin/227-psiviewer&quot;&gt;PsiViewer plugin&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/liveplugin/psi-viewer.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are only two things you need to know to write intentions/inspections in LivePlugin. One is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;registerIntention()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;registerInspection()&lt;/code&gt; functions which will register intention/inspection on execution and unregister when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pluginDisposable&lt;/code&gt; is disposed. And another is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;// depends-on-plugin plugin-id&lt;/code&gt; instruction which can be added after imports and tells LivePlugin to add dependency on a plugin which is not part of core IDE API. The rest is just standard IntelliJ API for working with PSI.&lt;/p&gt;

&lt;p&gt;The example below shows a simplistic Kotlin inspection which replaces “OMG” with “🙀” inside string literals. Its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isAvailable()&lt;/code&gt; function will be called on the current PSI element in the editor and if it returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;, the intention will be displayed in the light bulb popup menu. When invoked, the intention uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KtPsiFactory&lt;/code&gt; to construct a string literal PSI node from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newText&lt;/code&gt; and replaces the current element with it. Note that unlike the “Random Case” action example above, PSI transformation doesn’t need &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WriteAction&lt;/code&gt; or undoable command because it’s already done in its superclass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PsiElementBaseIntentionAction&lt;/code&gt;.&lt;/p&gt;
&lt;kotlin&gt;
// depends-on-plugin org.jetbrains.kotlin

registerIntention(object : PsiElementBaseIntentionAction() {
    override fun isAvailable(project: Project, editor: Editor?, element: PsiElement) =
        element.parentOfType&amp;lt;KtStringTemplateExpression&amp;gt;() != null 
            &amp;amp;&amp;amp; element.text.contains(&quot;OMG&quot;)

    override fun invoke(project: Project, editor: Editor?, element: PsiElement) {
        val newText = element.text.replace(&quot;OMG&quot;, &quot;🙀&quot;)
        val newElement = KtPsiFactory(element).createLiteralStringTemplateEntry(newText)
        element.replace(newElement)
    }

    override fun startInWriteAction() = true
    override fun getText() = &quot;Replace with 🙀&quot;
    override fun getFamilyName() = &quot;Hello&quot;
})
&lt;/kotlin&gt;

&lt;p&gt;Similarly, we can define an inspection which finds “!!” in string literals and replaces it with “💥”. Inspections have a different API which instead of returning a boolean, registers a “problem” with a suggested quick fix, but conceptually it’s quite similar to intention.&lt;/p&gt;
&lt;kotlin&gt;
// depends-on-plugin org.jetbrains.kotlin

registerInspection(object : AbstractKotlinInspection() {
    override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
        return expressionVisitor { expression: KtExpression -&amp;gt;
            if (expression is KtStringTemplateExpression &amp;amp;&amp;amp; expression.text.contains(&quot;!!&quot;)) {
                holder.registerProblem(expression, &quot;Found !!&quot;, MyQuickFix())
            }
        }
    }
    override fun getShortName() = &quot;Usage of !!&quot;
    override fun getDisplayName() = &quot;Usage of !!&quot;
    override fun getGroupDisplayName() = &quot;Hello&quot;
    override fun isEnabledByDefault() = true
})

inner class MyQuickFix: LocalQuickFix {
    override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
        val element = descriptor.psiElement
        val newText = element.text.replace(&quot;!!&quot;, &quot;💥&quot;)
        val newElement = KtPsiFactory(element).createExpression(newText)
        element.replace(newElement)
    }
    override fun getName() = &quot;Replace with 💥&quot;
    override fun getFamilyName() = &quot;Hello&quot;
}
&lt;/kotlin&gt;

&lt;h3 id=&quot;intellij-apis-mini-cheat-sheet&quot;&gt;IntelliJ APIs mini cheat sheet&lt;/h3&gt;
&lt;p&gt;There is an obvious and a very reasonable question of how you can find which functions or classes to use. Or, in other words, given a blank screen, how do you figure out what to type? Just like with any other large code base there is no simple answer.&lt;/p&gt;

&lt;p&gt;LivePlugin wraps some of IDE APIs, so you can check what is available in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;liveplugin&lt;/code&gt; package and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;liveplugin.PluginUtil&lt;/code&gt; class (this is a Groovy class, but it can be used from Kotlin). The simplest way is to type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;liveplugin.&lt;/code&gt; and use auto-complete.&lt;/p&gt;

&lt;p&gt;You can explore IntelliJ platform source code on GitHub, &lt;a href=&quot;https://upsource.jetbrains.com/idea-ce/structure/HEAD&quot;&gt;Upsourse&lt;/a&gt; or clone and explore it locally: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git clone https://github.com/JetBrains/intellij-community.git&lt;/code&gt;. One useful code exploration strategy is to find existing IDE functionality which does almost what you want to do or is likely to use the API you’re interested in. You can then find source code and see how it actually works. If some functionality is presented in the user interface, you can search for the text you see on the screen as a way to find an entry point into the code.&lt;/p&gt;

&lt;p&gt;Finally, it is useful to read &lt;a href=&quot;https://plugins.jetbrains.com/docs/intellij/welcome.html&quot;&gt;IntelliJ Platform SDK docs&lt;/a&gt; and be familiar with common IDE APIs. Below I listed APIs which I found useful in the form of a mini cheat sheet, but it is by no means exhaustive or complete.&lt;/p&gt;

&lt;p&gt;“Core” classes:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/application/Application.java&quot;&gt;Application&lt;/a&gt; - core application-wide functionality and methods for working with threads&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/extensions/src/com/intellij/util/messages/MessageBus.java&quot;&gt;MessageBus&lt;/a&gt; - subscribe/publish messaging infrastructure&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/project/Project.java&quot;&gt;Project&lt;/a&gt; - represents project in IDE, used in many APIs for project-specific functionality&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManager.java&quot;&gt;ProjectManager&lt;/a&gt; - open/close/get list of projects (see also &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java&quot;&gt;ProjectManagerListener&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/project/DumbAware.java&quot;&gt;DumbAware&lt;/a&gt; - marker interface for actions and tool windows that can work while indices are being updated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Actions:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java&quot;&gt;AnAction&lt;/a&gt; - all user interactions are performed through actions (see also EditorAction)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionManager.java&quot;&gt;ActionManager&lt;/a&gt; - register/unregister/find actions&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionAction.java&quot;&gt;IntentionAction&lt;/a&gt; - interface for intention actions&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionManager.java&quot;&gt;IntentionManager&lt;/a&gt; - register/unregister intentions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Editing files:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/Editor.java&quot;&gt;Editor&lt;/a&gt; - represents an instance of text editor (see also &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/analysis-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java&quot;&gt;FileEditorManager&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretModel.java&quot;&gt;CaretModel&lt;/a&gt; - caret(s) position in editor&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/SelectionModel.java&quot;&gt;SelectionModel&lt;/a&gt; - text selection(s) in editor&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/markup/MarkupModel.java&quot;&gt;MarkupModel&lt;/a&gt; - custom text range highlighting, markers on the gutter, etc&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/editor-ui-api/src/com/intellij/openapi/editor/FoldingModel.java&quot;&gt;FoldingModel&lt;/a&gt; - custom text range folding&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/editor/Document.java&quot;&gt;Document&lt;/a&gt; - represents the contents of a text file loaded into memory and possibly opened in a text editor
(see also &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java&quot;&gt;FileDocumentManager&lt;/a&gt; and &lt;a href=&quot;https://plugins.jetbrains.com/docs/intellij/documents.html&quot;&gt;IntelliJ Platform SDK docs&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java&quot;&gt;VirtualFile&lt;/a&gt; - represent a file on disk, in archive, HTTP server, etc.
(see also &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileSystem.java&quot;&gt;VirtualFileSystem&lt;/a&gt;, &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileListener.java&quot;&gt;VirtualFileListener&lt;/a&gt;, &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileManager.java&quot;&gt;VirtualFileManager&lt;/a&gt; and &lt;a href=&quot;http://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/virtual_file.html&quot;&gt;IntelliJ Platform SDK docs&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Syntax tree:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/psi/PsiElement.java&quot;&gt;PsiElement&lt;/a&gt; - common base interface for all PSI elements (see also &lt;a href=&quot;https://plugins.jetbrains.com/docs/intellij/psi-files.html&quot;&gt;IntelliJ Platform SDK docs&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/psi/PsiFile.java&quot;&gt;PsiFile&lt;/a&gt; - PSI element representing a file&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/psi/PsiManager.java&quot;&gt;PsiManager&lt;/a&gt; - gets PsiFile for VirtualFile&lt;/li&gt;
  &lt;li&gt;“PsiUtil” classes - misc methods for PSI manipulation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;UI components:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/platform-api/src/com/intellij/openapi/ui/Messages.java&quot;&gt;Messages&lt;/a&gt; - various yes/no/ok/cancel and basic input dialogs&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/platform-api/src/com/intellij/openapi/ui/DialogBuilder.java&quot;&gt;DialogBuilder&lt;/a&gt; - builder for custom dialogs&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.kt&quot;&gt;ToolWindowManager&lt;/a&gt; - get registered tool windows, balloon notification for tool windows&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactory.java&quot;&gt;ToolWindowFactory&lt;/a&gt; - creates tool windows&lt;/li&gt;
  &lt;li&gt;See also &lt;a href=&quot;https://plugins.jetbrains.com/docs/intellij/user-interface-components.html&quot;&gt;User Interface Components IntelliJ Platform SDK page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other interesting APIs:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;com.intellij.codeInsight.completion.CompletionContributor&lt;/li&gt;
  &lt;li&gt;com.intellij.lang.LanguageExtension&lt;/li&gt;
  &lt;li&gt;com.intellij.patterns.PsiElementPattern (and com.intellij.patterns.PlatformPatterns, com.intellij.patterns.StandardPatterns)&lt;/li&gt;
  &lt;li&gt;com.intellij.psi.util.PsiUtilCore&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h3&gt;
&lt;p&gt;If writing plugins/extensions at runtime is such a good idea, why is it not more widespread? This is the question I ask myself and one of the answers I have is that this might be a &lt;a href=&quot;https://en.wikipedia.org/wiki/Chicken_or_the_egg&quot;&gt;chicken and egg problem&lt;/a&gt;. There is a stereotype that creating an editor or IDE plugin/extension is really hard and advanced, so very few people actually try it. Editor/IDE developers correctly conclude that there isn’t a lot of demand, so they don’t see the need to make plugin/extension development easier. The development experience remains difficult, and reinforces the stereotype of plugin development being hard, so nothing really happens.&lt;/p&gt;

&lt;p&gt;There are some inherently difficult problems related to plugin development at runtime which I didn’t mention above. One is the state migration between plugin reloads. In dynamic languages like Groovy the new “version” of plugin can use objects from the previous “version” as long as they have the same shape (old objects will prevent old classloader and classes from being garbage collected, which is a “small” memory leak, but at least it will work). In strongly typed languages like Kotlin, it’s even harder because classes from different classloaders are incompatible even if their API and implementation are identical. So the solution is to use serialisation/deserialisation which is a problem of its own.&lt;/p&gt;

&lt;p&gt;Another difficulty is creating a good API for extending IDE functionality. Ideally, it should cover the areas which are most likely to be extended by users. It should be discoverable, reusable and designed for reloadability. On top of that, just like with any other published API used by many users, once it’s public, it might be difficult to evolve. This is a really hard problem, and I don’t claim that LivePlugin solves it.&lt;/p&gt;

&lt;p&gt;There are a lot of benefits though. One is “outsourcing” IDE features to users, so instead of creating feature requests and waiting for them to be completed (if ever), users could add the functionality themselves. Some user interfaces naturally evolve into a complex conditional configuration anyway. For example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Run Configuration&lt;/code&gt; has options to run other tasks before/after the current task and many other options which could be expressed via some API instead of a complex user interface. Another benefit is customisation specific to a particular project or library. The simplest automation is to run project-specific scripts in the context of the currently open file or selected text. More advanced uses might include navigation or code completion specific to a library/framework. This is in the territory of traditional plugins and the point here is that if plugin development is easy enough, then it might reach a point when it’s a cultural norm to create a plugin with library, framework or project support. To be fair, it might be too much to ask for example, for a Python project, but it seems more reachable for Kotlin. There is one major platform targeting Kotlin development, so having a standard practice of creating tailored plugins is achievable within the Kotlin community. To be precise, there is IntelliJ IDEA and there is now &lt;a href=&quot;https://www.jetbrains.com/fleet&quot;&gt;Fleet&lt;/a&gt; editor by Jetbrains which supports Kotlin. But Fleet backend is still based on IntelliJ and is likely to be compatible with existing plugins. And the Fleet frontend might be a good chance to explore the minimal most useful user-facing API for both Fleet and IntelliJ. Very exciting times for the ultimate power of custom plugins 🎉&lt;/p&gt;

</description>
        <pubDate>Thu, 30 Dec 2021 00:00:00 +0000</pubDate>
        <link>https://dkandalov.github.io/liveplugin</link>
        <guid isPermaLink="true">https://dkandalov.github.io/liveplugin</guid>
        
        
      </item>
    
      <item>
        <title>Limited WIP — test &amp;&amp; commit || revert</title>
        <description>&lt;p&gt;Limited work-in-progress doesn’t seem to be a very well-known idea in the software development world but there are few practices which we use without realising that they’re limited work-in-progress (WIP) techniques. One example is &lt;a href=&quot;https://en.wikipedia.org/wiki/Pomodoro_Technique&quot;&gt;pomodoro&lt;/a&gt; which suggests to focus on a task for 25 minutes and then take a break (without checking email or social networks), i.e. pomodoro limits the amount of tasks that can be done in parallel. A less obvious example is &lt;a href=&quot;http://wiki.c2.com/?TestDrivenDevelopment&quot;&gt;TDD&lt;/a&gt; which makes us focus on the problem taking one step at a time, i.e. TDD limits what we can do at each stage of the red-green-refactor cycle (for example, we can’t add production code when tests are green). Another not-so-obvious example is continuous integration (CI) which is about regularly combining all changes into a working piece of software, i.e. CI is about limiting &lt;a href=&quot;http://www.chrisoldwood.com/articles/branching-strategies.html&quot;&gt;merge debt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately, there is no common practice to quantify merge debt and &lt;a href=&quot;https://benjiweber.co.uk/blog/2020/02/12/do-you-ci&quot;&gt;doing CI&lt;/a&gt; can be a bit more subtle than most CI tools want us to think. In particular, it might seem ok to stay on a branch as long as it can be merged into trunk (aka main/master branch). The problem is that there is no guarantee that pending changes on the branch can be integrated with the pending changes on all other active branches. You can optionally make the problem more interesting by adding code reviews via pull-requests and multiple “main” branches (e.g. dev/uat/prod).&lt;/p&gt;

&lt;p&gt;Without suggesting that it’s the best, easy or even practical solution, one extreme way of doing CI might be developing on trunk using &lt;a href=&quot;https://medium.com/@kentbeck_7670/test-commit-revert-870bbd756864&quot;&gt;“test &amp;amp;&amp;amp; commit || revert”&lt;/a&gt; (TCR). TCR is a workflow inspired by TDD and intended to encourage small changes which are safe to integrate.&lt;/p&gt;

&lt;h3 id=&quot;the-idea&quot;&gt;The idea&lt;/h3&gt;
&lt;p&gt;TCR can be summarised with the following three rules:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;You can’t commit without running tests.&lt;/li&gt;
  &lt;li&gt;If the tests pass, all changes are automatically committed.&lt;/li&gt;
  &lt;li&gt;If the tests fail, all changes are automatically reverted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is an analogy with some arcade computer games where if you reach a safe point in the game, then the next time the character dies, it respawns at the last safe point. Similarly, with TCR if the code is broken (i.e. has any failing tests), you’re taken to the last safe point when all the tests were green. Unlike arcade games it’s up to you to decide where the safe points are and there are no lives or score in TCR (it might be an interesting idea to explore though).&lt;/p&gt;

&lt;p&gt;TCR might seem hard because of the constant pressure to get the code and the tests right on the first attempt. If anything goes wrong (even a typo in assertion), all uncommitted work is deleted. The trick is to find ways of working in tiny increments so that at each step it’s nearly impossible to fail and if you do fail, there isn’t much to lose anyway (this is quite similar to &lt;a href=&quot;/auto-revert&quot;&gt;auto-revert&lt;/a&gt; constraint).&lt;/p&gt;

&lt;h3 id=&quot;the-most-continuous-integration&quot;&gt;The most continuous integration&lt;/h3&gt;
&lt;p&gt;Because TCR makes us work in small increments, merging code becomes much easier. Small frequent changes are less likely to have conflicts and even when a conflict occurs, it’s easier to resolve it or to just drop local changes and do them again. Since TCR only allows to commit on passing tests, all commits should be safe to share with other people. Obviously, frequent pushes will also ensure that you receive updates from everyone else, so it might be somewhat like using a collaborative code editor except that it’s done via version control. From this point of view, “test &amp;amp;&amp;amp; push || revert” (TPR) could be a better name to promote continuous integration at the smallest possible level.&lt;/p&gt;

&lt;p&gt;Given that the commits are done automatically, there is a question of when/how to specify commit messages. One straightforward solution might be to edit the commit message just before it’s done automatically. Or you can try specifying a commit message in advance before making changes, e.g. in some environment variable. Although these options are likely to get in the way of TCR flow and with lots of small changes you might discover that writing a commit message after each modification is too tedious. So another approach is to use a “default” commit message for a series of commits and squash them later. Or use a placeholder message and later squash commits into more meaningful chunks with better commit messages.&lt;/p&gt;

&lt;p&gt;It’s also interesting to challenge the whole idea of writing a commit message for each code modification. Having an explanation of why code has changed is good, but should it really be part of the commit? Maybe there is more value in decoupling incremental changes from the task description and decisions made on a project which often span many commits anyway. And as a nice bonus we’ll get a detailed history of code modifications.&lt;/p&gt;

&lt;h3 id=&quot;tcr-with-tdd&quot;&gt;TCR with TDD?&lt;/h3&gt;
&lt;p&gt;Following the basic TCR rules, there is no way to have a failing test without code being reverted. This means that you can’t really use TCR with TDD but there are few workarounds. One approach is to bend TCR rules a bit and only revert production code. Another approach is to write negated assertion(s) before implementation and fix it once the implementation is done. Or you can try negating/modifying assertions after a successful commit to confirm that they fail (somewhat like a manual mutation testing).&lt;/p&gt;

&lt;p&gt;TCR is perfect for refactoring though. It encourages the refactoring strategy to run tests after each change and go back if anything went wrong without wasting time trying to figure out why refactoring didn’t work. After a failed attempt you can do a simpler, smaller or just different refactoring. Trying to analyse failure from a stacktrace or debugging code with TCR is problematic anyway, because the stacktrace will be pointing to the code which doesn’t exist anymore, and you can’t rerun a failed test with a debugger (although I suppose you could run tests in debugger in the first place).&lt;/p&gt;

&lt;p&gt;There is a question of which tests should be run when using TCR. The ideal answer is all tests. In practice, running all tests might be too slow, so a subset of tests which are the most relevant for modification is a pragmatic choice. Unfortunately, on many code bases even running a single test might be too slow because of build/compilation time. It’s not a great experience to spend 2 minutes writing a bit of code and then wait for a minute to see it all reverted. There are two possible conclusions. One is that TCR is not usable on some projects and with certain toolsets. Another is that some projects and toolsets are not very usable themselves. The second conclusion is particularly interesting because it’s hard to say that many mainstream toolsets are really focusing on performance. This is especially sad because as software developers we created all these tools ourselves (editors, compilers and testing frameworks). What stops us from focusing on a really good tool performance in the range of milliseconds so that it’s instant from a human perception point of view? Maybe a hanging code editor or one minute compilation time should be socially unacceptable similar to a major security breach or personal data leak. Maybe testing frameworks should be more opinionated and fail unit tests which run for longer than a second.&lt;/p&gt;

&lt;h3 id=&quot;try-it-yourself&quot;&gt;Try it yourself!&lt;/h3&gt;
&lt;p&gt;The easiest way to try TCR is by setting up a toy project or a &lt;a href=&quot;http://codekata.com&quot;&gt;code kata&lt;/a&gt; and manually following the rules. Writing a small script (or finding one on the Internet) might be a bit more effort but is worth it to make TCR more interactive and a bit like playing a mini-arcade game. I ended up adding TCR-mode to the &lt;a href=&quot;https://github.com/dkandalov/limited-wip&quot;&gt;Limited WIP plugin&lt;/a&gt; for IntelliJ IDEs which already had similar functionality. Either way don’t take it too seriously, experiment with the rules and make sure to have fun.&lt;/p&gt;

</description>
        <pubDate>Tue, 04 May 2021 00:00:00 +0000</pubDate>
        <link>https://dkandalov.github.io/tcr</link>
        <guid isPermaLink="true">https://dkandalov.github.io/tcr</guid>
        
        
      </item>
    
      <item>
        <title>Limited WIP — Auto-revert</title>
        <description>&lt;p&gt;&lt;em&gt;(Updated 17th October 2024)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As software developers, we seem to be mostly interested in technology and tools rather than the human side of the process such as software development workflows. For example, consider &lt;a href=&quot;http://wiki.c2.com/?TestDrivenDevelopment&quot;&gt;TDD&lt;/a&gt; — one of the few workflows that made it into the mainstream. These days pretty much every project has some kind of unit testing library imported and everyone has TDD on their CV. However, in practice even when people do write tests, they often do it after writing production code (which contradicts the definition of TDD) and instead of the &lt;a href=&quot;https://martinfowler.com/bliki/TestDrivenDevelopment.html&quot;&gt;red-green-refactor&lt;/a&gt; cycle do something like red-code-debug-refactor-code-green.&lt;/p&gt;

&lt;p&gt;An easy way to fail at red-green-refactor is by making too many changes. We focus on the solution, start exploring how it can be done, find a couple of problems in the code that need fixing, and end up writing/changing way more code than is necessary to pass existing tests. When we finally add more tests for the implemented functionality, the new code might not work as expected, so we start debugging it. It might also feel convenient and efficient to do the refactoring while we change everything anyway, so it’s often done with failing tests. These are common enough patterns, that &lt;a href=&quot;https://twitter.com/adibolb&quot;&gt;Adrian Bolboaca&lt;/a&gt; came up with the baby steps constraint for &lt;a href=&quot;https://www.coderetreat.org&quot;&gt;code retreats&lt;/a&gt; which essentially adds a time limit to red-green-refactor steps, so you can’t go off on a tangent and have to concentrate on tiny steps or your code is reverted.&lt;/p&gt;

&lt;p&gt;The idea of time-limited work-in-progress (WIP) is not specific to TDD. Similar to other limited WIP techniques, the benefits are about doing more focused work with fewer mistakes while constantly keeping the project in a working state. In this blog post, I’ll describe a generic version of the baby steps constraint which I call “auto-revert”.&lt;/p&gt;

&lt;h3 id=&quot;what-is-auto-revert&quot;&gt;What is auto-revert?&lt;/h3&gt;
&lt;p&gt;As the name suggests, auto-revert is about automatically reverting uncommitted changes after a time interval:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Start a countdown timer, e.g. 5 minutes.&lt;/li&gt;
  &lt;li&gt;On each commit, reset the timer.&lt;/li&gt;
  &lt;li&gt;On a timeout, revert all changes.&lt;/li&gt;
  &lt;li&gt;You can only commit when all tests pass.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you never heard about auto-revert, it probably sounds like an absolute waste of time. It is ridiculous to give up control of when the code is reverted and use a timer instead. Imposing time pressure on yourself to finish the task (as if doing work isn’t hard enough) to achieve what, more stress? With a short timeout duration, it will be impossible to get anything done.&lt;/p&gt;

&lt;p&gt;All of the above is valid, but… The trick is to learn how to change your ways of working to make small incremental code modifications (aka baby steps) so that the code is never too far away from being in a working state that can be committed. Once you get into this flow, auto-revert fades into the background, and reverts become rare. Even when some changes are reverted, it’s not a big deal anymore because it’s only a few minutes of work. You can also think about redoing reverted changes as a micro-&lt;a href=&quot;http://codekata.com&quot;&gt;codekata&lt;/a&gt;. The code rewrite after a revert might not follow the same steps or end up in the same place as before. And that’s ok. The process of making the change again often gives a good insight into a better way of doing it.&lt;/p&gt;

&lt;p&gt;Another positive effect of auto-revert is time awareness. We often underestimate even the most basic tasks (perhaps, because we think about the size of the change in terms of text editing and downplay the conceptual complexity and the probability of us not fully understanding the problem). Using an explicit timeout makes the duration of tasks very visible. It also helps to avoid distractions because you know you only need to concentrate only for a limited time. This is similar to &lt;a href=&quot;https://en.wikipedia.org/wiki/Pomodoro_Technique&quot;&gt;pomodoro technique&lt;/a&gt; which suggests working in 25-minute blocks with regular breaks.&lt;/p&gt;

&lt;h3 id=&quot;thought-experiments&quot;&gt;Thought experiments&lt;/h3&gt;
&lt;p&gt;To explore auto-revert, let’s perform a couple of thought experiments:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Auto-revert with a 10-year timeout is unlikely to be noticed by anyone. Uncommitted code from years ago will be long forgotten and will be out-of-date anyway. Considering the probability of hardware failures, we are already working with this constraint.&lt;/li&gt;
  &lt;li&gt;Similarly, auto-revert with a timeout of months, weeks, or several days will make no difference for most people because changes are done and committed within shorter time intervals. From this point of view, there is nothing radical about auto-revert.&lt;/li&gt;
  &lt;li&gt;It becomes more interesting with a timeout measured in hours and minutes. This is the range where the learning opportunities are and auto-revert will be uncomfortable until you change your ways of working.&lt;/li&gt;
  &lt;li&gt;Finally, if the auto-revert timeout is just a couple of seconds (or less!), making any change becomes impossible. One interesting solution could be to come up with code transformation tools that can do safe code modifications and immediately commit them. There is a parallel here with using the smallest &lt;a href=&quot;/max-change-size&quot;&gt;maximum change size&lt;/a&gt; threshold.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;what-about-real-world-projects&quot;&gt;What about real-world projects?&lt;/h3&gt;
&lt;p&gt;Using auto-revert on real-world projects comes with its own challenges. The main issue I’ve seen is complex code which takes a long time to explore and understand, let alone change it within a few minutes. An obvious solution might be to not make any changes during the exploration phase (except for small improvements which can be done and committed within timeout). If it looks like the complexity makes it impossible to implement a feature in a series of small steps, it might be worth asking “Why”, “How did we get here”, “Can the code be refactored to make it possible”, etc.&lt;/p&gt;

&lt;p&gt;Another problem is slow build and tests. To be usable, the auto-revert timeout needs to be noticeably longer than the duration of an average feedback loop. For example, if you modify code for 2 minutes, compile/run all relevant tests for 2 minutes, then it’s not practical to revert changes every 5 minutes because if the tests fail, there will be only 1 minute left to fix them. Long feedback loops require longer auto-revert timeout which requires a larger change size. And nobody wants to lose large code changes. What’s worse is that if the feedback loop is too long, we naturally get distracted and forget about the auto-revert timeout (until all the changes are gone). This can be interpreted as auto-revert doesn’t work on projects with long build times. Or you can use this as an opportunity to ask yourself “why”. In particular, if running tests takes too long, was it a conscious decision based on some trade-offs, or did the tests happen to slow down over time because nobody cared enough? Slow compilers, build tools, and editors/IDEs also get in the way of fast feedback. It’s not very common to continuously measure the speed of a compiler or a build tool on the project — it feels that it’s outside our circle of influence. But maybe we should! Looking at modern programming environments, many of them don’t provide particularly fast feedback, so unless we collectively make a big deal out of toolchain performance, it’s unlikely to improve.&lt;/p&gt;

&lt;p&gt;Finally, when using auto-revert, you might start committing often. This brings up the question about the meaning of commits and commit messages. If there are changes every few minutes, commits can become too fine-grained to write a separate message for each of them. One option is to squash tiny commits into more chunky ones with meaningful commit messages. Another idea is to decouple integration of code changes with other people from explaining the changes and documenting project history (so commits on the trunk / main branch can be essentially a “Save” button for distributed work).&lt;/p&gt;

&lt;h3 id=&quot;try-it-yourself&quot;&gt;Try it yourself!&lt;/h3&gt;
&lt;p&gt;The simplest way to try auto-revert is to use a timer (on the command line or on your phone). Be aware that if you’re not pair-programming, it’s easy to negotiate with yourself and skip the revert “just this one time”. A bit more advanced approach might be to write a script that will perform a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reset&lt;/code&gt; every few minutes and restart the timer if there are no local changes. Going down this path I ended up creating &lt;a href=&quot;https://github.com/dkandalov/limited-wip&quot;&gt;Limited WIP plugin&lt;/a&gt; for IntelliJ IDEs.&lt;/p&gt;

&lt;p&gt;Auto-revert is an essential constraint to try with a &lt;a href=&quot;http://codekata.com&quot;&gt;codekata&lt;/a&gt; to challenge your current ways of working and to observe your reaction to code being reverted. It can be more tricky on a large-scale project, but it’s worth trying to find the bottlenecks in your working environment. Similar to other workflows, nothing is set in stone with auto-revert. Feel free to experiment with it and have fun.&lt;/p&gt;

</description>
        <pubDate>Wed, 28 Apr 2021 00:00:00 +0000</pubDate>
        <link>https://dkandalov.github.io/auto-revert</link>
        <guid isPermaLink="true">https://dkandalov.github.io/auto-revert</guid>
        
        
      </item>
    
      <item>
        <title>Limited WIP — Maximum change size</title>
        <description>&lt;p&gt;There is a lot of focus on the technical side of software development: programming languages, libraries/frameworks, architecture, etc. But not that much focus on what humans are supposed to do while using the tools. There seems to be an implicit assumption that developers will do things in the most optimal way. Unfortunately, this assumption is often false. In the same way that people don’t always follow the lifestyle which is best for them, we don’t always take the best path when creating software.&lt;/p&gt;

&lt;p&gt;To give a specific example, let’s say while working on a feature, you spot some code which can be improved. So you go ahead with the improvement and go back to the feature. This happens a few more times, and before you know it there are twenty modified files with changes including both code improvements and the feature itself. The feature is not complete yet but the change feels big enough that it needs to be committed. The bad news is that it’s now hard to disentangle code improvements from the feature, and you have to choose between (1) figuring out what to include into a partial commit, (2) committing mixed changes with an incomplete feature or (3) continuing with an already oversize change. Not ideal. It would be good to not end up in situations like this in the first place.&lt;/p&gt;

&lt;p&gt;This is where techniques to limit &lt;a href=&quot;https://en.wikipedia.org/wiki/Work_in_process&quot;&gt;work-in-progress&lt;/a&gt; (WIP) come to the rescue by stopping us from doing too many things in parallel. The benefits of limiting work-in-progress are not just about better commits (which is often a symptom), they are about more focused work, fewer mistakes and improved workflow. In this blog I’ll describe the technique of setting the maximum change size.&lt;/p&gt;

&lt;h3 id=&quot;the-idea&quot;&gt;The idea&lt;/h3&gt;
&lt;p&gt;Using maximum change size to limit work-in-progress is quite simple — if the size of changes is bigger than some threshold, you’re not allowed to commit. Instead, you have to find a way to split the work into smaller committable chunks. It also means that as soon as you reach the threshold, there is no point making more changes because you won’t be able to commit them anyway. Reaching the threshold should be a rare event though. You should keep yourself aware of the current change size, for example, by monitoring diff size in version control or IDE, and dealing with it before it gets too big.&lt;/p&gt;

&lt;p&gt;Many developers already have some kind of implicit change size limit. It manifests itself as the feeling that it’s time to commit during a long coding session. So you might be already using the maximum change size constraint without being fully aware of it. The advantage of an explicit change size limit is that you can quantify it and keep yourself honest by comparing change size to some threshold. You can also use a tool or script which will watch uncommitted changes and notify you as soon as the change size gets close to or exceeds the threshold instead of relying on the gut feeling to know when there are too many changes. It’s also usually harder to “negotiate” with a script (e.g. a Git hook) compared to convincing yourself that the commit still has a reasonable size “just this one time”.&lt;/p&gt;

&lt;p&gt;After a while this technique should naturally nudge you into working in a more focused way (unless you’re doing it already) along the lines of making one change at a time until it’s finished and committed. And if something else comes up during the change, you can add the new task to a TODO list for later or shelve the current modifications, finish the new task and unshelve. Sounds simple but it’s surprising how often we divert into more complex workflows.&lt;/p&gt;

&lt;h3 id=&quot;calculating-change-size&quot;&gt;Calculating change size&lt;/h3&gt;
&lt;p&gt;Calculating change size is a bit more tricky than it seems. The most obvious question is what to count: lines, words, characters or even the amount of actions/keystrokes in the editor since last commit? Should empty lines and whitespace characters be excluded? Regardless of the choice, there is a problem that modifications of the same size might have different real-world weight. For example, in Java adding an import statement is usually less work compared to writing a line of code that will be executed. Another problem is that conceptually simple changes can produce large diffs. For example, renaming a function which is used across the project will create a large diff even though it’s a single rename. There are other problems of this kind and none of them have simple solutions just because it’s extremely hard to measure complexity and impact of code. In practice though, I found that using a simple metric like non-empty lines of code works quite well.&lt;/p&gt;

&lt;p&gt;Another question is how to calculate modifications on diffs. If we are measuring change size in lines, then adding a brand-new file with 10 lines of code should count as 10. But what if the change is replacing 10 lines of code with completely different 5 lines? Should the change size include only the new code, both old and new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10 + 5 = 15&lt;/code&gt; or maybe the average &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(10 + 5) / 2 = 7.5&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Finally, there is a question about how to quantify file system changes such as moving/renaming files or creating directories and how well the diff algorithm can determine if a file was moved or it’s a new file with similar content.&lt;/p&gt;

&lt;p&gt;Given the above, the maximum change size is obviously a heuristic which you will need to experiment with to make it useful. A good strategy might be to start with a threshold which is quite low and gradually increase it. Note that you can also track your progress in version control by analysing how commit sizes changed over time.&lt;/p&gt;

&lt;h3 id=&quot;thought-experiments&quot;&gt;Thought experiments&lt;/h3&gt;
&lt;p&gt;To explore the idea, let’s perform a couple of thought experiments:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;With the maximum change of 1_000_000 lines of code you will never notice that there is a change size limit because pretty much nobody changes a million lines of code on daily basis.&lt;/li&gt;
  &lt;li&gt;If we go down to the maximum change size of 10_000, once again it’s unlikely to be noticed, except for large-scale code migration and restructuring.&lt;/li&gt;
  &lt;li&gt;It becomes more interesting with the change size limit around 100 and below. This is where the learning opportunities are.&lt;/li&gt;
  &lt;li&gt;Finally, with the limit of 1 or 2 lines, it becomes impossible to make any significant changes. Unless we cheat and redefine the constraint to be 1 or 2 actions/keystrokes in the editor. Then automated code transformations are allowed (for example, inline refactoring or create new class). The interesting aspect of it is that if transformations don’t break existing functionality, then they are perfectly fine to commit and share the with other people after every single change. There is probably not enough functionality in your editor/IDE to actually do this but it was just a thought experiment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;try-it-yourself&quot;&gt;Try it yourself!&lt;/h3&gt;
&lt;p&gt;Maximum change size is an easy constraint to try. You can start by watching change size manually on the command line (e.g. with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git diff&lt;/code&gt;). Or you can roll out a proper script to regularly check the change size and prohibit commits above threshold. I went down a different rabbit hole of writing a &lt;a href=&quot;https://github.com/dkandalov/limited-wip&quot;&gt;Limited WIP plugin&lt;/a&gt; for IntelliJ IDEs. Whatever path you choose, please remember that just like with other techniques nothing is set in stone, so feel free to experiment with it and have fun.&lt;/p&gt;

</description>
        <pubDate>Thu, 22 Apr 2021 00:00:00 +0000</pubDate>
        <link>https://dkandalov.github.io/max-change-size</link>
        <guid isPermaLink="true">https://dkandalov.github.io/max-change-size</guid>
        
        
      </item>
    
      <item>
        <title>Hello Http4k</title>
        <description>&lt;p&gt;This is a quick intro into &lt;a href=&quot;https://www.http4k.org&quot;&gt;http4k&lt;/a&gt; — a Kotlin library for writing HTTP servers and clients.
Unlike many other libraries and frameworks with (over)complicated core abstractions and workflows, 
http4k uses a few simple concepts which encourage good design and testability.&lt;/p&gt;

&lt;p&gt;The examples below are based on the “&lt;a href=&quot;https://www.youtube.com/watch?v=vsueRJCJuLI&quot;&gt;Live coding: Server as a function with http4k&lt;/a&gt;” talk I’ve been doing earlier this year.&lt;/p&gt;

&lt;h3 id=&quot;hello-handler&quot;&gt;Hello handler&lt;/h3&gt;
&lt;p&gt;The main concept in http4k is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpHandler&lt;/code&gt;, which is literally a function 
that takes immutable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Request&lt;/code&gt; and returns immutable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Response&lt;/code&gt; 
(where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Request&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Response&lt;/code&gt; support all the usual HTTP things like headers and queries):&lt;/p&gt;
&lt;kotlin&gt;
typealias HttpHandler = (Request) -&amp;gt; Response
&lt;/kotlin&gt;

&lt;p&gt;So the simplest server in http4k is just a lambda which returns an instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Response&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OK&lt;/code&gt; status and (optional) body content. Of course, lambdas can’t send/receive HTTP requests over the network — for that we need an actual HTTP server.
Http4k doesn’t attempt to reinvent the wheel and instead of implementing its own server/client, it has adapters to integrate
with existing HTTP Java servers/clients.
In this case, let’s use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApacheServer&lt;/code&gt; which is an adapter for &lt;a href=&quot;https://hc.apache.org/index.html&quot;&gt;Apache HttpComponents&lt;/a&gt;:&lt;/p&gt;
&lt;kotlin&gt;
import org.http4k.core.*
import org.http4k.server.*
import org.http4k.core.Status.Companion.OK

fun main() {
    val httpHandler: HttpHandler = { request: Request -&amp;gt;
        Response(OK).body(&quot;Hello 🌍&quot;)
    }
    httpHandler.asServer(ApacheServer(port = 1234)).start()
}
&lt;/kotlin&gt;

&lt;p&gt;We can run the code above in IDE and test it from command line with curl:&lt;/p&gt;
&lt;plain-text&gt;
$ curl -D - http://localhost:1234
HTTP/1.1 200 OK
...
Hello 🌍%
&lt;/plain-text&gt;

&lt;p&gt;The output looks good but it would be nice to use server code directly from Kotlin.
To do this we need an HTTP client. In particular, we can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OkHttp&lt;/code&gt; which is an adapter for &lt;a href=&quot;https://square.github.io/okhttp&quot;&gt;OkHttp&lt;/a&gt; library. 
Note that HTTP client is also &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpHandler&lt;/code&gt;, i.e. it has the same type as the server!&lt;/p&gt;
&lt;kotlin&gt;
fun main() {
    val httpHandler: HttpHandler = { request: Request -&amp;gt;
        Response(OK).body(&quot;Hello 🌍&quot;)
    }
    httpHandler.asServer(ApacheServer(port = 1234)).start()

    val httpClient: HttpHandler = OkHttp()
    val response: Response = httpClient(Request(GET, &quot;http://localhost:1234&quot;))
    println(response)
}
&lt;/kotlin&gt;
&lt;p&gt;If we run the code above, the output will be almost identical to the curl output:&lt;/p&gt;
&lt;plain-text&gt;
HTTP/1.1 200 OK
...
Hello 🌍
&lt;/plain-text&gt;

&lt;p&gt;Since both server and client have the same signature, we can refactor the code 
to remove &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApacheServer&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OkHttp&lt;/code&gt; adapters so that the server handler is called directly:&lt;/p&gt;
&lt;kotlin&gt;
fun main() {
    val httpServer: HttpHandler = { request: Request -&amp;gt;
        Response(OK).body(&quot;Hello 🌍&quot;)
    }
    val httpClient = httpServer
    val response = httpClient(Request(GET, &quot;http://localhost:1234&quot;))
    println(response)
}
&lt;/kotlin&gt;
&lt;p&gt;And after a couple more refactorings:&lt;/p&gt;
&lt;kotlin&gt;
fun main() {
    val httpServer: HttpHandler = { _: Request -&amp;gt;
        Response(OK).body(&quot;Hello 🌍&quot;)
    }
    println(httpServer(Request(GET, &quot;http://localhost:1234&quot;)))
}
&lt;/kotlin&gt;
&lt;p&gt;In general, this outlines the http4k approach for making HTTP servers testable: start the servers in the same process and use in-memory communication, or if it’s an external server, replace it with a fake server (supported by contract tests) or with &lt;a href=&quot;https://www.http4k.org/howto/record_and_replay_http_traffic&quot;&gt;record/replay client&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;hello-routes&quot;&gt;Hello routes&lt;/h3&gt;
&lt;p&gt;The server above works just fine except that it replies to any request regardless of the URI. For example, it will reply with “Hello 🌍” even if we POST to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:1234/foo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order to fix this, we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;routes()&lt;/code&gt; function which takes one or more &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RoutingHttpHandler&lt;/code&gt;s and aggregates them into a composite &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RoutingHttpHandler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The simplest way to create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RoutingHttpHandler&lt;/code&gt; is by using the following mini-DSL. First, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;/hello&quot; bind GET&lt;/code&gt; bundles path and HTTP method into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PathMethod&lt;/code&gt; data class, and then, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;... to { request: Request -&amp;gt; ... }&lt;/code&gt; creates &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RoutingHttpHandler&lt;/code&gt;.&lt;/p&gt;
&lt;kotlin&gt;
import org.http4k.core.*
import org.http4k.server.*
import org.http4k.core.Method.GET
import org.http4k.core.Status.Companion.OK

fun main() {
    val httpHandler: HttpHandler = routes(
        &quot;/hello&quot; bind GET to { request: Request -&amp;gt;
            Response(OK).body(&quot;Hello 🌍&quot;)
        }
    )
    httpHandler.asServer(ApacheServer(port = 1234)).start()

    val httpClient: HttpHandler = OkHttp()
    val response: Response = httpClient(Request(GET, &quot;http://localhost:1234&quot;))
    println(response)
}
&lt;/kotlin&gt;

&lt;p&gt;If we run the code above, it will print &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;404&lt;/code&gt; response from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RoutingHttpHandler&lt;/code&gt; because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;httpClient&lt;/code&gt; still requests “/” while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;httpHandler&lt;/code&gt; only responds to the “/hello” path. Obviously, to fix this we should modify the request:&lt;/p&gt;
&lt;kotlin&gt;
val response: Response = httpClient(Request(GET, &quot;http://localhost:1234/hello&quot;))
&lt;/kotlin&gt;

&lt;h3 id=&quot;hello-filter&quot;&gt;Hello filter&lt;/h3&gt;
&lt;p&gt;Another important concept in http4k is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Filter&lt;/code&gt;, which is essentially an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpHandler&lt;/code&gt; wrapper:&lt;/p&gt;
&lt;kotlin&gt;
interface Filter : (HttpHandler) -&amp;gt; HttpHandler
&lt;/kotlin&gt;

&lt;p&gt;To illustrate this, let’s create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Filter&lt;/code&gt; from scratch. The simplest possible &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Filter&lt;/code&gt; is the one that just returns its argument (note in the code below the usage of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Filter { ... }&lt;/code&gt; function which saves us the effort of creating an anonymous object):&lt;/p&gt;
&lt;kotlin&gt;
fun main() {
    // Equivalent to `Filter.NoOp`
    val filter = Filter { nextHandler -&amp;gt;
        nextHandler
    }
}
&lt;/kotlin&gt;

&lt;p&gt;Let’s wrap &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nextHandler&lt;/code&gt; into another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpHandler&lt;/code&gt; called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wrapperHandler&lt;/code&gt;. 
Functionally, the code still works in the same way (and doesn’t do anything useful):&lt;/p&gt;
&lt;kotlin&gt;
fun main() {
    val filter = Filter { nextHandler -&amp;gt;
        val wrapperHandler: HttpHandler = { request -&amp;gt;
             nextHandler(request)
        }
        wrapperHandler
    }
}
&lt;/kotlin&gt;
&lt;p&gt;However, we can now add more functionality to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wrapperHandler&lt;/code&gt;. For example, to create “catch all” filter we can surround &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nextHandler(request)&lt;/code&gt; with try/catch expression and return &lt;a href=&quot;https://en.wikipedia.org/wiki/Hyper_Text_Coffee_Pot_Control_Protocol&quot;&gt;I_M_A_TEAPOT&lt;/a&gt; status in case of Exception:&lt;/p&gt;
&lt;kotlin&gt;
fun main() {
    val catchAll = Filter { nextHandler -&amp;gt;
        val wrapperHandler: HttpHandler = { request -&amp;gt;
            try {
                nextHandler(request)
            } catch (e: Exception) {
                Response(I_M_A_TEAPOT) // not the best error handling strategy
            }
        }
        wrapperHandler
    }
}
&lt;/kotlin&gt;
&lt;p&gt;To try out the filter, let’s make the server extract the “name” query parameter from the request and throw an exception if the “name” parameter is missing: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;request.query(&quot;name&quot;) ?: error(&quot;No name&quot;)&lt;/code&gt;. We can apply the filter using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.withFilter(catchAll)&lt;/code&gt;:&lt;/p&gt;
&lt;kotlin&gt;
fun main() {
    val catchAll = Filter { nextHandler -&amp;gt;
        val wrapperHandler: HttpHandler = { request -&amp;gt;
            try {
                nextHandler(request)
            } catch (e: Exception) {
                Response(I_M_A_TEAPOT)
            }
        }
        wrapperHandler
    }

    val httpHandler: HttpHandler = routes(
        &quot;/hello&quot; bind GET to { request: Request -&amp;gt;
            val name = request.query(&quot;name&quot;) ?: error(&quot;No name&quot;)
            Response(OK).body(&quot;Hello $name&quot;)
        }
    ).withFilter(catchAll)
    httpHandler.asServer(ApacheServer(port = 1234)).start()
}
&lt;/kotlin&gt;
&lt;p&gt;As expected, it’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;200&lt;/code&gt; response on “hello?name=world” GET request:&lt;/p&gt;
&lt;plain-text&gt;
$ curl -D - http://localhost:1234/hello?name=world
HTTP/1.1 200 OK
...
Hello world%
&lt;/plain-text&gt;

&lt;p&gt;And it’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;418&lt;/code&gt; “I’m a teapot” response if we forget to specify the “name”:&lt;/p&gt;
&lt;plain-text&gt;
$ curl -D - &apos;http://localhost:1234/hello&apos;
HTTP/1.1 418 I&apos;m a teapot
...
&lt;/plain-text&gt;

&lt;p&gt;You can find more filters bundled with http4k in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.http4k.filter.ServerFilters&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.http4k.filter.ClientFilters&lt;/code&gt; objects.&lt;/p&gt;

&lt;h3 id=&quot;http-as-a-function&quot;&gt;HTTP as a function&lt;/h3&gt;
&lt;p&gt;Just like any other library or framework http4k is only an abstraction on top of the HTTP protocol. Even the simplest GET request can end up talking to multiple servers (think DNS, SSL) and with containerised clouds (using kubernetes, etc.) there is even more stuff going on in the background. So the library design is by no means a representation of reality but rather it’s an abstraction for the library users. Arguably, for the majority of users plain old function (POF?) with an immutable request/response is the best abstraction over HTTP.&lt;/p&gt;

&lt;p&gt;The design of http4k was inspired by &lt;a href=&quot;https://monkey.org/~marius/funsrv.pdf&quot;&gt;“Your Server as a Function” paper&lt;/a&gt; which defines &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpHandler&lt;/code&gt; in a bit more complicated way and roughly translates to Kotlin like this:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;interface HttpHandler&amp;lt;Request, Response&amp;gt;: (Request) -&amp;gt; Future&amp;lt;Response&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The main difference compared to http4k is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; in the return type which highlights the asynchronous nature of HTTP requests. The advantage is that requests can be treated as tasks to be scheduled for execution asynchronously. The disadvantage is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; complicates every request and response. There are potential performance benefits, and no doubt some large-scale companies can benefit from this, but the chances are you’re not one of them. Another argument against using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; is that HTTP abstraction should only be dealing with HTTP and stay away from threading strategy, similar to how you would avoid mixing HTTP and domain logic.&lt;/p&gt;

&lt;p&gt;From the simple design point of view, it’s also not easy to justify the conceptual complexity of an average HTTP framework with its own lifecycle and special testing suite. That’s not to mention the use of annotations, which are pretty much &lt;a href=&quot;https://blog.jetbrains.com/kotlin/2015/08/modifiers-vs-annotations&quot;&gt;custom keywords&lt;/a&gt; and should be used sparingly.&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;One thing to remember from this blog, is that &lt;strong&gt;HTTP servers and clients are uniform&lt;/strong&gt;, i.e. both server and client have the same type (in Kotlin terms &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(Request) -&amp;gt; Response&lt;/code&gt; or variation of it). This is exactly what makes it possible to write “your server as a function” and http4k takes this approach to its simplest form. So if you’re thinking about writing a new web-framework or library, please really consider using this as its core concept!&lt;/p&gt;

&lt;p&gt;It’s worth mentioning that http4k has been successfully used in large-scale enterprise systems.
There are quite a few http4k modules and this blog just scratches the surface of &lt;a href=&quot;https://www.http4k.org/ecosystem/http4k&quot;&gt;the core module&lt;/a&gt;.
You can find out more about http4k on &lt;a href=&quot;https://www.http4k.org&quot;&gt;its website&lt;/a&gt;.
For a bit more in-depth overview, here is a video by http4k authors:&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;
	&lt;iframe width=&quot;800&quot; height=&quot;450&quot; src=&quot;https://www.youtube.com/embed/p1VTfcQJefk&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Given the amount of web-frameworks and technical marketing (things that come to mind are Spring and, obviously, this blogpost), it can be genuinely hard to know what is the right tool for the problem at hand. The important thing is to avoid Resume Driven Development by actually solving the problem instead of focusing on a particular technology.&lt;/p&gt;

</description>
        <pubDate>Thu, 30 Jul 2020 00:00:00 +0000</pubDate>
        <link>https://dkandalov.github.io/hello-http4k</link>
        <guid isPermaLink="true">https://dkandalov.github.io/hello-http4k</guid>
        
        
      </item>
    
      <item>
        <title>Squasher</title>
        <description>&lt;p&gt;Recently &lt;a href=&quot;https://twitter.com/codecopkofler&quot;&gt;Peter Kofler&lt;/a&gt; wrote a &lt;a href=&quot;https://blog.code-cop.org/2020/06/conways-squasher-coroutine.html&quot;&gt;blog post&lt;/a&gt; in which he looks at the &lt;a href=&quot;https://www.melconway.com/Home/pdf/compiler.pdf&quot;&gt;Design of a Separable Transition-Diagram Compiler&lt;/a&gt; paper by &lt;a href=&quot;https://twitter.com/conways_law&quot;&gt;Melvin E. Conway&lt;/a&gt; (which was published in 1963 and considered to be the first paper mentioning coroutines) and reimplements a basic coroutine in the modern assembly for Windows. Since I don’t have access to any Windows machines, Peter kindly agreed to pair up with me on porting &lt;a href=&quot;https://github.com/codecop/Conways-Squasher-Coroutine&quot;&gt;the code from his blog post&lt;/a&gt; to macOS and 64-bit assembly. While doing this I ended up reading the paper and then cloning and refactoring the code to make it a bit simpler at the expense of the code not matching the paper anymore.&lt;/p&gt;

&lt;p&gt;Below you will find my interpretation of the problem as described in the first two pages of the paper and solutions with/without coroutines in Kotlin and NASM (see this &lt;a href=&quot;https://github.com/dkandalov/squasher&quot;&gt;github repo&lt;/a&gt; for full source code and tests). It’s worth mentioning that NASM solutions and implementation of basic coroutines are based on Peter’s code.&lt;/p&gt;

&lt;h3 id=&quot;the-problem&quot;&gt;The problem&lt;/h3&gt;
&lt;p&gt;Imagine a simple task of replacing all occurrences of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;**&lt;/code&gt; (two asterisks) with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^&lt;/code&gt; in a stream of data. For example, given &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;***abc&lt;/code&gt;, the output should be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^*abc&lt;/code&gt;. In the paper this process is called “squashing” and can be implemented in Kotlin as a one-liner:&lt;/p&gt;
&lt;kotlin&gt;
fun String.squash() = this.replace(&quot;**&quot;, &quot;^&quot;)
&lt;/kotlin&gt;

&lt;p&gt;However, there is an additional constraint which makes the problem a bit more interesting. In particular, squasher can only consume or output &lt;strong&gt;one character at a time&lt;/strong&gt;. In Kotlin this can be expressed as an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterator&amp;lt;Char&amp;gt;&lt;/code&gt; which wraps another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterator&amp;lt;Char&amp;gt;&lt;/code&gt;. (In the paper the input is being read infinitely from &lt;a href=&quot;https://en.wikipedia.org/wiki/Punched_card&quot;&gt;punch cards&lt;/a&gt; but it’s safe to skip these details.)&lt;/p&gt;

&lt;h3 id=&quot;kotlin-implementation&quot;&gt;Kotlin implementation&lt;/h3&gt;
&lt;p&gt;Given the constraint, a straightforward squasher implementation might look like this:&lt;/p&gt;
&lt;kotlin&gt;
fun squasher(input: Iterator&amp;lt;Char&amp;gt;) = object : Iterator&amp;lt;Char&amp;gt; {
    var hasLastChar = false
    var lastChar = 0.toChar()
 
    override fun next() =
        if (hasLastChar) {
            hasLastChar = false
            lastChar
        } else {
            var char = input.next()
            if (char == &apos;*&apos;) {
                lastChar = input.next()
                if (lastChar == &apos;*&apos;) char = &apos;^&apos;
                else hasLastChar = true
            }
            char
        }

    override fun hasNext() = input.hasNext() || hasLastChar
}
&lt;/kotlin&gt;

&lt;p&gt;Because of the requirement to output only one char at a time, the code has additional non-essential complexity of keeping the state of the iterator between invocations in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasLastChar&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lastChar&lt;/code&gt; properties. In a way, we can think about the code block guarded by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasLastChar&lt;/code&gt; as a callback or even as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Finite-state_machine&quot;&gt;state machine&lt;/a&gt; with only two states.&lt;/p&gt;

&lt;p&gt;This is exactly the situation when coroutines can help by “returning” values in the middle of a function and resuming from that point later. The squasher implementation below doesn’t need the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasLastChar&lt;/code&gt; flag since this logic is already embedded in the control flow of the code.&lt;/p&gt;

&lt;kotlin&gt;
fun squasher(input: Iterator&amp;lt;Char&amp;gt;): Iterator&amp;lt;Char&amp;gt; = sequence {
    while (input.hasNext()) {
        val char = input.next()
        if (char != &apos;*&apos;) yield(char)
        else {
            val lastChar = input.next()
            if (lastChar == &apos;*&apos;) {
                yield(&apos;^&apos;)
            } else {
                yield(char)
                yield(lastChar)
            }
        }
    }
}.iterator()
&lt;/kotlin&gt;

&lt;p&gt;I don’t think there is anything particularly revealing in the examples above but it feels nice to be able to translate such an old problem to a modern language and it, hopefully, explains the problem domain before diving into assembly code.&lt;/p&gt;

&lt;h3 id=&quot;nasm-implementation-with-functions&quot;&gt;NASM implementation (with functions)&lt;/h3&gt;
&lt;p&gt;From this point, I’ll assume that you are familiar with x86 assembler enough to be able to get the gist of the following code snippets (which are written using &lt;a href=&quot;https://nasm.us&quot;&gt;NASM&lt;/a&gt; and can be found in this &lt;a href=&quot;https://github.com/dkandalov/squasher&quot;&gt;github repo&lt;/a&gt;). If not, you can try &lt;a href=&quot;https://www.nayuki.io/page/a-fundamental-introduction-to-x86-assembly-programming&quot;&gt;this intro&lt;/a&gt;, &lt;a href=&quot;https://www.cs.virginia.edu/~evans/cs216/guides/x86.html&quot;&gt;this guide&lt;/a&gt; or &lt;a href=&quot;https://software.intel.com/content/www/us/en/develop/articles/introduction-to-x64-assembly.html&quot;&gt;this article&lt;/a&gt; on 64-bit assembly.&lt;/p&gt;

&lt;p&gt;For simplicity, the NASM implementation doesn’t attempt to mimic an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterator&lt;/code&gt; but rather reads a fixed size input from stdin.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; function is just a loop which for each input char calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squasher&lt;/code&gt; and prints to stdout one character at a time:&lt;/p&gt;

&lt;x86asm&gt;
main:
        _call   read_input
        mov     qword [hasLastChar], FALSE
.loop:
        _call   squasher        ; squash char from input and put result into rax
        _call   write           ; print char from rax

        mov     rax, [i]
        cmp     rax, INPUT_SIZE 
        jne     .loop           ; jump back if i != INPUT_SIZE 
&lt;/x86asm&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squasher&lt;/code&gt; function uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next_char&lt;/code&gt; to get the next input character and puts the output character into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rax&lt;/code&gt; register before returning to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt;. Similar to the Kotlin version without coroutines, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squasher&lt;/code&gt; has to keep global state and includes additional logic to return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lastChar&lt;/code&gt;.&lt;/p&gt;

&lt;x86asm&gt;
squasher:
        mov     rax, [hasLastChar]
        cmp     rax, FALSE
        je      .no_lastChar
        mov     qword [hasLastChar], FALSE
        mov     rax, [lastChar]
        _ret
.no_lastChar:
        _call   next_char                  ; puts return value into rax
        cmp     rax, &apos;*&apos;
        je     .check_second_asterisk
        _ret
.check_second_asterisk:
        mov     rbx, rax                   ; temporary save first char to rbx
        _call   next_char                  ; puts return value into rax
        cmp     rax, &apos;*&apos;
        je      .do_squashing

        mov     [lastChar], rax
        mov     qword [hasLastChar], TRUE  ; remember to write lastChar next time
        mov     rax, rbx                   ; load first char from rbx
        _ret
.do_squashing:
        mov     rax, &apos;^&apos;
        _ret
&lt;/x86asm&gt;

&lt;p&gt;As you may have noticed, the code above uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_call&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_ret&lt;/code&gt; macros (instead of built-in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ret&lt;/code&gt;). This is to show implementation details of simplistic function &lt;a href=&quot;https://en.wikipedia.org/wiki/X86_calling_conventions&quot;&gt;calling convention&lt;/a&gt;.&lt;/p&gt;
&lt;x86asm&gt;
%macro _call 1
        mov     rdx, %%_end
        push    rdx         ; save returning point on stack
        jmp     %1          ; call sub-function
%%_end: nop                 ; returning point
%endmacro

%macro _ret 0
        pop     rdx         ; load returning point from stack
        jmp     rdx         ; jump back into caller function
%endmacro
&lt;/x86asm&gt;

&lt;h3 id=&quot;nasm-implementation-with-coroutines&quot;&gt;NASM implementation (with coroutines)&lt;/h3&gt;
&lt;p&gt;Since x86 assembler doesn’t have coroutines, let’s implement them. The idea is to reserve additional memory for each coroutine to store the address of its resuming point (initially set to the first instruction of coroutine) so when coroutine is called again, it continues from where it left off.&lt;/p&gt;
&lt;x86asm&gt;
section .data
instruction_at_main:       dq    main     ; stores resuming point of main
instruction_at_squasher:   dq    squasher ; stores resuming point of squasher
&lt;/x86asm&gt;
&lt;p&gt;To pass control to a coroutine we can use the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;co_call&lt;/code&gt; macro. The macro expects to be called from a coroutine so it updates the resuming point of the current coroutine (in case the coroutine gets control back some time later). Then the macro looks up the resuming point of the coroutine it’s about to call and jumps to that address. No doubt, this is a toy implementation which doesn’t save/restore registers or stack when switching between coroutines but, hopefully, it’s simple enough to illustrate the concept.&lt;/p&gt;

&lt;x86asm&gt;
%macro co_call 1
        ; update resuming point of the current coroutine
        pop     rdx                     ; load address of the store
        mov     rcx, %%_end             ;
        mov     [rdx], rcx              ; update resuming point in the store

        ; pass control to the next coroutine
        mov     rdx, instruction_at_%1  ; get address of the store
        push    rdx                     ; save address of the store for later
        jmp     [rdx]                   ; resume the next coroutine

%%_end: nop                             ; resuming point
%endmacro
&lt;/x86asm&gt;

&lt;p&gt;This &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; function is the same as the version without coroutines except for the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;co_call&lt;/code&gt; macro and having to prepare the stack so the macro thinks it’s called from a coroutine.&lt;/p&gt;
&lt;x86asm&gt;
main:
        call    read_input
        mov     rax, instruction_at_main
        push    rax             ; prepare stack for coroutine call
.loop:
        co_call squasher        ; squash char from input and put result into rax
        call    write           ; print char from rax

        mov     rax, [i]
        cmp     rax, INPUT_SIZE 
        jne     .loop           ; jump back if i != INPUT_SIZE
&lt;/x86asm&gt;

&lt;p&gt;There are more changes in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squasher&lt;/code&gt; though. The most interesting change is that there are no “returns” because conceptually &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squasher&lt;/code&gt; is not any different from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; coroutine and there is nowhere to return to, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squasher&lt;/code&gt; can only call sub-functions or pass control to another coroutine. As a consequence the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squasher&lt;/code&gt; now is an infinite loop (see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp squasher&lt;/code&gt; instructions). Similar to the Kotlin version with coroutines, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squasher&lt;/code&gt; doesn’t need the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasLastChar&lt;/code&gt; variable anymore because the branching is stored as a resuming point.&lt;/p&gt;
&lt;x86asm&gt;
squasher:
        call    next_char
        cmp     rax, &apos;*&apos;
        je     .check_second_asterisk
        co_call main
        jmp     squasher

.check_second_asterisk:
        mov     rbx, rax                ; temporary save first char to rbx
        call    next_char
        cmp     rax, &apos;*&apos;
        je      .do_squashing

        mov     [lastChar], rax         ; save rax so its not erased by main
        mov     rax, rbx                ; load first char from rbx
        co_call main

        mov     rax, [lastChar]
        co_call main
        jmp     squasher

.do_squashing:
        mov     rax, &apos;^&apos;
        co_call main
        jmp     squasher
&lt;/x86asm&gt;

&lt;p&gt;You can find the full source code for 64-bit Linux and macOS in &lt;a href=&quot;https://github.com/dkandalov/squasher&quot;&gt;this github repo&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;how-is-that-different-from-threads&quot;&gt;How is that different from threads?&lt;/h3&gt;
&lt;p&gt;Fundamentally, OS kernel switching between threads has no magic and is based on the &lt;a href=&quot;https://en.wikipedia.org/wiki/Program_counter&quot;&gt;instruction pointer&lt;/a&gt; manipulation similar to the macro above (for example, see &lt;a href=&quot;https://stackoverflow.com/questions/6525905/how-does-scheduleswitch-to-functions-from-linux-kernel-actually-work&quot;&gt;this&lt;/a&gt; stackoverflow question). The main difference compared to coroutines is that conceptually switching between threads is preemptive, i.e. the function which is being executed doesn’t decide when to switch to another function, instead, thread scheduler does it. Another difference is that thread scheduler normally doesn’t provide any guarantees about which CPU core thread will run on and, therefore, the need for “thread safety” which really is all about “multi-core safety”. (As an interesting side note there are no special assembly instructions for switching between CPU cores. Instead, several CPUs just run instructions independently with access to common shared memory. See &lt;a href=&quot;https://code-examples.net/en/q/6669e&quot;&gt;The Unofficial SMP FAQ&lt;/a&gt;). Overall, even though the underlying mechanism might be similar, coroutines give you more control over context switches compared to threads.&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Kotlin being a high-level language has a more sophisticated coroutine implementation, than the one shown above, with a lot of details related to other language features and type system but at the core it’s the same trick of storing the latest entry point of a coroutine and, when the coroutine is resumed, jumping to the right part of the code (you can find the implementation in &lt;a href=&quot;https://github.com/JetBrains/kotlin/blob/v1.3.72/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt#L161&quot;&gt;CoroutineTransformerMethodVisitor&lt;/a&gt; which uses &lt;a href=&quot;https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html#jvms-6.5.tableswitch&quot;&gt;tableswitch&lt;/a&gt; instruction to do the jump).&lt;/p&gt;

&lt;p&gt;Hopefully, this blog helps with understanding basic coroutine implementation details. For a description of coroutine flavours from the point of view of programming language user, you can try reading the following posts:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;/coroutines-as-threads&quot;&gt;coroutines as threads&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/yielding-generators&quot;&gt;yielding generators&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/async-await&quot;&gt;async await&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/call-with-current-continuation&quot;&gt;call with current continuation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
        <pubDate>Sat, 18 Jul 2020 00:00:00 +0000</pubDate>
        <link>https://dkandalov.github.io/squasher</link>
        <guid isPermaLink="true">https://dkandalov.github.io/squasher</guid>
        
        
      </item>
    
      <item>
        <title>Intellij Settings</title>
        <description>&lt;p&gt;For the benefit of anyone interested and as a reference for myself, here are some of the IntelliJ and related macOS settings I normally use. This page will be occasionally updated as IntelliJ and my preferences evolve.&lt;/p&gt;

&lt;p&gt;Last updated on 20th May 2025 for IntelliJ IDEA &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2025.2 EAP&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;settings&quot;&gt;Settings&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main Menu &amp;gt; View &amp;gt; Appearance&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Navigation Bar &amp;gt; Don&apos;t Show&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Compact Mode&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Toolbar&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Editor &amp;gt; General&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Appearance &amp;gt; Show intention bulb&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Breadcrumbs &amp;gt; Show breadcrumbs&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Smart Keys &amp;gt; Use &quot;CamelHumps&quot; words&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Smart Keys &amp;gt; Honor &quot;CamelHumps&quot; words on double click&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Smart Keys &amp;gt; Surround selection on typing quote or brace&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rich-Text Copy &amp;gt; Copy as rich text&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sticky Lines &amp;gt; Show sticky lines when scrolling&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Editor Tab &amp;gt; Tab placement&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Editor &amp;gt; Code Editing&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Usages of element at caret&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Show quick documentation on hover&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;The &apos;Next Error&apos; action goes through&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;All problems&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Editor &amp;gt; Inlay Hints&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Enable all, and then disable with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Toggle Inlay Hints Globally&lt;/code&gt; action&lt;br /&gt;
(optionally assign a shortcut to the action for a better to way show hints on-demand)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Editor &amp;gt; Font&lt;/code&gt; set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Size&lt;/code&gt; to 15.0&lt;/li&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Appearance &amp;amp; Behavior &amp;gt; Appearance&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Smooth scrolling&lt;/code&gt; (so that the scrolling position is on the border between lines)&lt;/li&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System Settings &amp;gt; Updates &amp;gt; Show What&apos;s New in the editor after an IDE update&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Version Control &amp;gt; Git&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Update method&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rebase&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Use credential helper&lt;/code&gt; — don’t save passwords in IDE (see &lt;a href=&quot;https://youtrack.jetbrains.com/issue/IDEA-211251&quot;&gt;IDEA-211251&lt;/a&gt;)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Advanaced Settings&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User Interface &amp;gt; Position mouse cursor on default button in dialogs&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User Interface &amp;gt; Use native faile chooser dialog on Windows/macOS&lt;/code&gt; — because IntelliJ file chooser dialog is just better&lt;/li&gt;
      &lt;li&gt;Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Version Control &amp;gt; Toggle commit controls&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Version Control &amp;gt; Enable Commit tool window&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;registry&quot;&gt;Registry&lt;/h3&gt;
&lt;p&gt;Invoke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Find Action&lt;/code&gt; and search for “Registry…”:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ide.allow.merge.buttons&lt;/code&gt; — &lt;br /&gt;
don’t merge buttons in VCS dialogs (see &lt;a href=&quot;https://youtrack.jetbrains.com/issue/IJPL-87262&quot;&gt;IJPL-87262&lt;/a&gt;, &lt;a href=&quot;https://youtrack.jetbrains.com/issue/IJPL-80718&quot;&gt;IJPL-80718&lt;/a&gt;, etc.)&lt;/li&gt;
  &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;light.edit.file.open.enabled&lt;/code&gt; — &lt;br /&gt;
because light editor it’s not ready yet (see &lt;a href=&quot;https://youtrack.jetbrains.com/issue/IDEA-236868&quot;&gt;IDEA-236868&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;analyze.exceptions.on.the.fly&lt;/code&gt; — &lt;br /&gt;
automatically analyze clipboard content for stacktrace on IDE frame activation&lt;/li&gt;
  &lt;li&gt;Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ide.completion.delay.autopopup.until.completed&lt;/code&gt; — &lt;br /&gt;
deterministic auto-completion results (see &lt;a href=&quot;https://youtrack.jetbrains.com/issue/KT-29042&quot;&gt;KT-29042&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;debugger.valueTooltipAutoShow&lt;/code&gt; — no debugger tooltip on mouse over&lt;/li&gt;
  &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;show.live.templates.in.completion&lt;/code&gt; (see &lt;a href=&quot;https://youtrack.jetbrains.com/issue/IDEA-216928&quot;&gt;IDEA-216928&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Increase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undo.globalUndoLimit&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undo.documentUndoLimit&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toolwindow.disable.overlay.by.double.key&lt;/code&gt; — &lt;br /&gt;
because when using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alt+...&lt;/code&gt; shortcuts (e.g. with &lt;a href=&quot;https://github.com/dkandalov/ijkl-shortcuts-plugin&quot;&gt;IJKL shortcuts plugin&lt;/a&gt;) 
it can be annoying in presentation mode to accidentally open tool window overlay (see &lt;a href=&quot;https://youtrack.jetbrains.com/issue/IDEA-112097&quot;&gt;IDEA-112097&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ide.switcher.tool.window.list&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ide.recent.files.tool.window.list&lt;/code&gt; — don’t show tool windows in switcher and recent file popups (see &lt;a href=&quot;https://youtrack.jetbrains.com/issue/IDEA-131137&quot;&gt;IDEA-131137&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Disable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;project.tree.structure.show.url&lt;/code&gt; to hide the path next to the project name in the Project tool window&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;keymap-based-on-intellij-idea-classic&quot;&gt;Keymap (based on “IntelliJ IDEA Classic”)&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Use &lt;a href=&quot;https://github.com/dkandalov/ijkl-shortcuts-plugin&quot;&gt;IJKL shortcuts plugin&lt;/a&gt; for navigation&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;F1&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Quick Fix&lt;/code&gt; (see &lt;a href=&quot;https://github.com/dkandalov/quick-fix&quot;&gt;QuickFix plugin&lt;/a&gt;), remove it from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Context Help&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alt+\&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Show Context Menu&lt;/code&gt; (i.e. the popup window displayed on the right click)&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alt+1&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt; tool window&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+2&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alt+2&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Version Control&lt;/code&gt; tool window&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+9&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Live Plugins&lt;/code&gt; tool window (see &lt;a href=&quot;https://github.com/dkandalov/live-plugin&quot;&gt;LivePlugin plugin&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+§&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alt+§&lt;/code&gt; (i.e. to the key left of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;) to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main Menu &amp;gt; View &amp;gt; Tool Windows&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+M&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Scroll to Center&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+F4&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Close Project&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+shift+G&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Execute Gradle Task&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+ctrl+shift+P&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enter Presentation Mode&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alt+shift+9&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Put arguments/parameters on separate lines&lt;/code&gt; intentions&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alt+shift+8&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Put arguments/parameters on one line&lt;/code&gt; intentions&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alt+shift+7&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Add names to call arguments&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Remove all argument names&lt;/code&gt; intentions&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+alt+H&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Window &amp;gt; Notifications &amp;gt; Close First / Close All&lt;/code&gt; (see &lt;a href=&quot;https://youtrack.jetbrains.com/issue/IDEA-218434&quot;&gt;IDEA-218434&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl+d&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Show Diff for Lines&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Assign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl+b&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Version Control Systems &amp;gt; Git &amp;gt; Branches&lt;/code&gt; popup window&lt;/li&gt;
  &lt;li&gt;Remove &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Markdown &amp;gt; Create Link&lt;/code&gt; shortcut because it clashes with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Toggle Case&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Remove &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Increase/Decrease Font Size in All Editors&lt;/code&gt; shortcuts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;macos-sonoma-and-above&quot;&gt;macOS (Sonoma and above)&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Disable accents &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defaults write -g ApplePressAndHoldEnabled -bool false&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Max values for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Preferences &amp;gt; Keyboard &amp;gt; Key Repeat&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delay Until Repeat&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Map CapsLock to Control in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Preferences &amp;gt; Keyboard &amp;gt; Modifier Keys...&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Enable “Use scroll gesture with modifier keys to zoom” in &lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Preferences &amp;gt; Accessibility &amp;gt; Zoom&lt;/code&gt; and select Control as the modifier key for gesture&lt;/li&gt;
  &lt;li&gt;Select “Three-Finger Drag” as dragging style in &lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Preferences &amp;gt; Accessibility &amp;gt; Pointer Control &amp;gt; Trackpad Options...&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Disable shortcuts in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Preferences &amp;gt; Keyboard &amp;gt; Shortcuts&lt;/code&gt; that clash with IntelliJ (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+shift+/&lt;/code&gt;; there is usually a popup notification with the conflict after IDE install)&lt;/li&gt;
  &lt;li&gt;Disable option-space, see &lt;a href=&quot;https://superuser.com/questions/78245&quot;&gt;https://superuser.com/questions/78245&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Tue, 26 May 2020 00:00:00 +0000</pubDate>
        <link>https://dkandalov.github.io/intellij-settings</link>
        <guid isPermaLink="true">https://dkandalov.github.io/intellij-settings</guid>
        
        
      </item>
    
      <item>
        <title>Note On Loudness</title>
        <description>&lt;h3 id=&quot;theory&quot;&gt;Theory&lt;/h3&gt;

&lt;p&gt;These days audio loudness is measured in &lt;a href=&quot;https://en.wikipedia.org/wiki/LKFS&quot;&gt;LUFS&lt;/a&gt; (Loudness Units relative to Full Scale).
This is a relative measurement, where, as I understand, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 LUFS&lt;/code&gt; is the loudest audio you’re allowed to broadcast according to the standard by &lt;a href=&quot;https://en.wikipedia.org/wiki/European_Broadcasting_Union&quot;&gt;European Broadcasting Union&lt;/a&gt;. 
And &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-10 LUFS&lt;/code&gt; is 10 decibel quieter than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 LUFS&lt;/code&gt;. Although LUFS is a bit more involved than decibel and measures “weighted perceived loudness”.&lt;/p&gt;

&lt;p&gt;Youtube guarantees that videos are not louder than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-13 LUFS&lt;/code&gt;, i.e. if you upload content louder than that, it will be normalised to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-13 LUFS&lt;/code&gt;. In terms of the loudness of actual youtube videos, I looked at couple channels and found that some of them try to be as loud as possible at -13 or -15 (maybe because that’s the loudness of youtube ads), while other channels are not that loud, around -30 (in particular, I looked at conference talks).&lt;/p&gt;

&lt;p&gt;I didn’t come to a conclusion what is the “right” loudness level for youtube but in general &lt;strong&gt;the recommended broadcasting level is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-23 LUFS&lt;/code&gt;&lt;/strong&gt; (see &lt;a href=&quot;https://www.youtube.com/watch?v=iuEtQqC-Sqo&quot;&gt;EBU R128 Introduction&lt;/a&gt; video for details).&lt;/p&gt;

&lt;h3 id=&quot;practice&quot;&gt;Practice&lt;/h3&gt;

&lt;p&gt;You can measure LUFS of a video using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt;.
For example,&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ffmpeg -nostats -i &apos;video.mp4&apos; -filter_complex ebur128 -f null -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;will print few lines to console and in the end a summary with something like:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Integrated loudness:
I:         -15.9 LUFS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;where “integrated” means it was calculated for the whole video, not just a part of it.&lt;/p&gt;

&lt;p&gt;You can also download videos from youtube using &lt;a href=&quot;https://github.com/ytdl-org/youtube-dl&quot;&gt;youtube-dl&lt;/a&gt; and then run them through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt; to determine their loudness.&lt;/p&gt;

&lt;p&gt;To increase volume of a video you can do&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ffmpeg -i inputfile -vcodec copy -af &quot;volume=10dB&quot; outputfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Thu, 18 Apr 2019 00:00:00 +0000</pubDate>
        <link>https://dkandalov.github.io/note-on-loudness</link>
        <guid isPermaLink="true">https://dkandalov.github.io/note-on-loudness</guid>
        
        
      </item>
    
  </channel>
</rss>
