<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Jeff Riggle]]></title><description><![CDATA[A public playground where I conduct small projects, technical experiments, and write-ups across a varied set of programming interests.]]></description><link>https://ilusr.com</link><generator>GatsbyJS</generator><lastBuildDate>Wed, 10 Jun 2026 16:46:30 GMT</lastBuildDate><item><title><![CDATA[How deep does the callback go?]]></title><description><![CDATA[Building a scheduler   Despite being single-threaded, JavaScript has concurrency as a...]]></description><link>https://dev.to/jeffrey_riggle_e261fba011/the-settimeout-rabbit-hole-5ff4</link><guid isPermaLink="false">https://dev.to/jeffrey_riggle_e261fba011/the-settimeout-rabbit-hole-5ff4</guid><pubDate>Tue, 09 Jun 2026 19:50:47 GMT</pubDate><content:encoded>&lt;p&gt;Building a scheduler   Despite being single-threaded, JavaScript has concurrency as a...&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://dev.to/jeffrey_riggle_e261fba011/the-settimeout-rabbit-hole-5ff4&quot;&gt;Read on dev.to&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Understanding Event Loops Through File I/O]]></title><description><![CDATA[In the last blog series, I referenced a presentation by Ryan Dahl on NodeJS and wanted to explore the concepts in that talk more. It can be…]]></description><link>https://ilusr.com/understanding-eventing/</link><guid isPermaLink="false">https://ilusr.com/understanding-eventing/</guid><pubDate>Fri, 29 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the last blog series, I referenced a &lt;a href=&quot;https://www.youtube.com/watch?v=EeYvFl7li9E&quot;&gt;presentation&lt;/a&gt; by Ryan Dahl on NodeJS and wanted to explore the concepts in that talk more. It can be easy to dismiss JavaScript as a low-performance language based on the observation that it is a single-threaded environment. However, this talk directly opposes that mindset. Instead, it suggests that the real problem is removing I/O from the hot path. Data locality is often the place where performance tradeoffs live. Generally speaking, even the slowest arithmetic operations, like division, cosine, and sine, are significantly faster than reading from RAM. Reading from disk or the network is orders of magnitude slower than reading from RAM. The key argument is that if you keep a single loop completely saturated while pushing blocking IO out of the hot path, you can get better performance at a reduced memory cost. This is because threading comes at a performance cost. For starters, each thread comes with its own memory. At a minimum, every thread has its own stack, which easily consumes 1 megabyte or more of memory. Also, once you have shared memory between threads, you have mutexes that can create bigger problems than single-threaded code.&lt;/p&gt;
&lt;p&gt;Thinking about this a bit more, I decided it might be fun to try building out a simple event loop on a contained problem to better understand this space.&lt;/p&gt;
&lt;h2&gt;Doing some research&lt;/h2&gt;
&lt;p&gt;Before I got too into this, I wanted to get a better understanding of what was under the hood of NodeJS. Going into this, I knew that NodeJS was largely a C++ project with &lt;a href=&quot;https://v8.dev/&quot;&gt;V8&lt;/a&gt; bindings. However, I was a bit less familiar with the machinery it used to handle its non-blocking IO. After some research, I found that modern NodeJS uses &lt;a href=&quot;https://libuv.org/&quot;&gt;libuv&lt;/a&gt; to handle this. This library handles everything from file access and child processes to sockets and DNS resolution. This struck me as a little bit odd. In the presentation I referenced, Ryan mentioned using &lt;a href=&quot;https://software.schmorp.de/pkg/libev.html&quot;&gt;libev&lt;/a&gt; to handle eventing. In an attempt to figure out what happened, I started digging. Looked into that library I found it was related to yet another eventing library, &lt;a href=&quot;https://libevent.org/&quot;&gt;libevent&lt;/a&gt;. Each library added its own unique features to improve performance in event loops. As it turns out, Ryan Dahl even &lt;a href=&quot;https://tinyclouds.org/iocp-links/&quot;&gt;wrote&lt;/a&gt; about all of these libraries and why they decided to create libuv.&lt;/p&gt;
&lt;p&gt;In many of these libraries, the key difference revolves around the OS support they provide and the APIs they build on. Many point to the difference between &lt;a href=&quot;https://man7.org/linux/man-pages/man2/select.2.html&quot;&gt;select&lt;/a&gt;, &lt;a href=&quot;https://man7.org/linux/man-pages/man2/poll.2.html&quot;&gt;poll&lt;/a&gt;, and &lt;a href=&quot;https://man7.org/linux/man-pages/man7/epoll.7.html&quot;&gt;epoll&lt;/a&gt;. Each gives different performance benefits along the way. Since many of these optimizations operate at the boundary between userland and the kernel, it can be quite difficult to create a multi-platform, performant, and coherent API.&lt;/p&gt;
&lt;h2&gt;Setting up an experiment&lt;/h2&gt;
&lt;p&gt;While most of the literature on these eventing libraries had focused on sockets, I was a bit more preoccupied with file access. I was still fixated on the original code that brought this all up, forcing a synchronous call for file access in NodeJS. Unfortunately, this was the one case where not all kernels provided good non-blocking IO APIs. Because of this, utilizing things like epoll didn&apos;t fit naturally into this problem. However, there was still a way to move forward with building an event loop and taking blocking IO off of the hot path.&lt;/p&gt;
&lt;h3&gt;Building up the scenario&lt;/h3&gt;
&lt;p&gt;Before I could do anything, I had to set something up to test file access. I decided it would be easy to test reading JavaScript files and doing some very basic parsing. Each file would have a collection of imports, a handful of constants, and some functions. The processing code would count the total constants and functions found across all files and queue up processing the imports.&lt;/p&gt;
&lt;p&gt;Doing some basic research, I found that a reasonable range of files for a project would be around 10 files for a smaller project and closer to 1000 for a larger project. Since I didn&apos;t want to manually create that many files, I decided the best way to bootstrap this experiment was to write a NodeJS program to generate these projects. I wanted imports, but I also didn&apos;t want any circular references. I assumed circular references could lead to complications during processing. I pulled out &lt;a href=&quot;https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm&quot;&gt;Tarjan&apos;s algorithm&lt;/a&gt; to make sure no circular references got generated. Also, to make it easier to parse, I parsed the graph at the very end and I referenced all roots in an index.js.&lt;/p&gt;
&lt;p&gt;Also, to entertain myself, I created a list of predefined words to combine for the naming of files and variables. This led to funny file names like &lt;code&gt;help-overwhelming-random.js&lt;/code&gt;, &lt;code&gt;malware-darwin.js&lt;/code&gt;, and &lt;code&gt;sqs-agentic-wheel-tokenizer.js&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Figuring out what to test&lt;/h3&gt;
&lt;p&gt;Armed with the ability to create JavaScript projects, I now needed to decide what to test. Part of my interest was comparing the performance of different cases across NodeJS and C. This resulted in the following applications being created.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A NodeJS application that blocks on IO by using the sync APIs.&lt;/li&gt;
&lt;li&gt;A NodeJS application that used the async libraries correctly.&lt;/li&gt;
&lt;li&gt;A C application that blocked on IO.&lt;/li&gt;
&lt;li&gt;A C application that used an event loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, since projects could be of different sizes, I decided each program would be tested against a handful of different projects.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A tiny project with 10 files.&lt;/li&gt;
&lt;li&gt;A small project with 50 files.&lt;/li&gt;
&lt;li&gt;A medium project with 100 files.&lt;/li&gt;
&lt;li&gt;A large project with 500 files.&lt;/li&gt;
&lt;li&gt;An extra-large project with 1500 files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With all of these, I would gather timings and compare how they did.&lt;/p&gt;
&lt;h3&gt;Benchmarking file access is tricky&lt;/h3&gt;
&lt;p&gt;Before I go into the specifics of each example, I want to preface with a little benchmarking tidbit. While I was conducting this experiment, I realized that I was getting some crazy outliers in my initial testing. Those who are closer to the OS and file-based performance will know where I am going with this. OS&apos;s know that file access is slow and attempt to compensate for this. In some cases, quite aggressively. In my case, I would see a massive boost on the second run of a program. For these tests, I was running on a MacBook using an M3 chip. The best way I could find to get the lowest variance in these tests was to &lt;code&gt;sudo purge&lt;/code&gt; between each run.&lt;/p&gt;
&lt;p&gt;I was a bit concerned about how specialized the M series architecture was, so I conducted another round of tests on a Linux-based machine. Linux also had similar caching that needed to be cleared between each run.&lt;/p&gt;
&lt;p&gt;I suggest taking the exact numbers with a grain of salt, and instead focus more on the trend than the result.&lt;/p&gt;
&lt;h2&gt;Running the test&lt;/h2&gt;
&lt;p&gt;Each of these programs had required a bit of different effort. Admittedly, I hadn&apos;t written much C in the past 15 years, so it took me a while to get back into the swing of things.&lt;/p&gt;
&lt;h3&gt;Blocking NodeJS example&lt;/h3&gt;
&lt;p&gt;This was the easiest one to write. I didn&apos;t want to do a full JavaScript parse for any implementation. The problem set was very well contained, so I just needed to write something that worked. I abused that to its fullest. So instead of pulling out a proper parser, building an AST, and traversing the tree, I did a simple line-by-line check. The original form of this used a regular expression to get the import file path, but I ended up scrapping it. I didn&apos;t like the Regex differences between JavaScript and C, and didn&apos;t want this to be a comparison of Regex processing engines.&lt;/p&gt;
&lt;p&gt;This program can be found &lt;a href=&quot;https://github.com/JeffreyRiggle/event-queue-testing/blob/main/simple-node/index.js&quot;&gt;here&lt;/a&gt;. The most important part is that I used a while loop to do the processing.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword control-flow&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filesToProcess&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; filesToProcess&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Do processing&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This took surprisingly little time to write, and even at the largest scale, it was a fairly quick program. The slowest execution time for 1500 files was ~273ms on Mac and ~363 on Linux.&lt;/p&gt;
&lt;h3&gt;Async Node example&lt;/h3&gt;
&lt;p&gt;Moving on, I implemented the callback-compatible version of the same program to see the difference with just using the event loop properly. The biggest change I had to make was around that while loop. Now, instead of blocking each file, I would block in batches as I found them.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword control-flow&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filesToProcess&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; fileRequests &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword control-flow&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; file &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; filesToProcess&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      fileRequests&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;processFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword control-flow&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token known-class-name class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fileRequests&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This program can be found &lt;a href=&quot;https://github.com/JeffreyRiggle/event-queue-testing/blob/main/async-node/index.js&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The resulting difference in performance was notable. In all but the tiny dataset, the program ran nearly twice as fast. The slowest observed time was ~124ms on Mac and ~278ms on Linux.&lt;/p&gt;
&lt;h3&gt;Basic C example&lt;/h3&gt;
&lt;p&gt;This is where implementation speed started to slow down a bit. Since it had been so long since I had written C, it took me way too long to get back into it. Eventually, I produced a working program. Again, I used a similar loop as seen before.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;c&quot;&gt;&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FILES_TO_PROCESS&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FILE_TO_PROCESS_INDEX&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;processFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FILES_TO_PROCESS&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FILE_TO_PROCESS_INDEX&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FILE_TO_PROCESS_INDEX&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The program can be found &lt;a href=&quot;https://github.com/JeffreyRiggle/event-queue-testing/blob/main/simple-c/main.c&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unfortunately, due to inefficient array scanning used in this program, execution slows down at larger scales. This had performance as bad as ~350ms on Mac and ~363ms on Linux.&lt;/p&gt;
&lt;h3&gt;Eventing C example&lt;/h3&gt;
&lt;p&gt;This one required a bit of work. Originally, I just tried putting some threads on the problem without building a legible abstraction. The main execution was done on a single thread, but the way file memory was managed created terrible performance due to the inefficiencies of the threading and mutexes required. In the end, I scrapped that &lt;a href=&quot;https://github.com/JeffreyRiggle/event-queue-testing/blob/main/async-c/main.c&quot;&gt;implemenation&lt;/a&gt;. Eventually, I got to a much more &lt;a href=&quot;https://github.com/JeffreyRiggle/event-queue-testing/blob/main/event-c/main.c&quot;&gt;stable version&lt;/a&gt; version that had a dynamically sized thread pool and a proper event loop. Now, as I mentioned before, the file APIs provided are a bit awkward, so it&apos;s not a perfect event loop. In this case, the implementation looks more like a managed thread pool for reading files and an event loop that dispatches work to the pool. All of the processing work  still resides directly in a single thread in a loop.&lt;/p&gt;
&lt;p&gt;The main event loop ended up being similar to this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;c&quot;&gt;&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EventLoop&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; loop&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loop&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;completed &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// grow pool to maximum if we are not at the maximum&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threadPool&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; MAX_POOL_SIZE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Calculate idle time.&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;idleTime &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; GROW_THRESHOLD&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;GrowPool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threadPool&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// dispatch events&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loop&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;lastDispatchedEvent &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; loop&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;nextEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Find and dispatch pending read file events to idle threads.&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; threadPool&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Determine if the thread has a valid result&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isValid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// Invoke file handler on a single main thread&lt;/span&gt;
            loop&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loop&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; threadPool&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;readers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; threadPool&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;readers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;fileSize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            
            &lt;span class=&quot;token comment&quot;&gt;// Reset thread state&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the end, this version produced the fastest overall results, with the slowest result being ~113ms on Mac and ~195ms on Linux. Similar to the other C example, since I didn&apos;t use an efficient array search algorithm, this could likely be faster.&lt;/p&gt;
&lt;h2&gt;Considering the results&lt;/h2&gt;
&lt;p&gt;With all the runs completed, it was time to look at the results and see how things turned out. First, the original hypothesis of NodeJS tells us that using async APIs instead of sync APIs should produce a meaningful difference.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/understanding-eventing/NodeCompare.png&quot; alt=&quot;Node Comparision&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this chart, we can see the difference between the sync node implementation (red) and the async node implementation (blue). At the smallest scale, the difference is negligible, but at larger scales, the difference is notable. The real benefit of the async pattern is distributing the wait time for file IO. This means the performance benefit scales with the number of files to be read, and we can see that clearly in this example.&lt;/p&gt;
&lt;p&gt;Now, if we compare the same in the C implementations, we see a similar pattern. Even though we are using a single thread for all the processing, we are still getting the same performance benefits we see in Node.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/understanding-eventing/CComparison.png&quot; alt=&quot;C Comparision&quot;&gt;&lt;/p&gt;
&lt;p&gt;Conventional wisdom states that low-level languages are faster, so let&apos;s take a look at how the C implementation fairs against the Node implementation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/understanding-eventing/NodevC.png&quot; alt=&quot;Node and C Comparision&quot;&gt;&lt;/p&gt;
&lt;p&gt;This shows that the C implementation is consistently faster. However, these differences are not nearly as significant as one might expect. If we consider this workload more deeply, a majority of the required time complexity comes from reading from the file system. This problem is not directly owned by either language. The time to load a file is largely dictated by the kernel and underlying hardware. Now, where things can get interesting and where some of the benefits lie is that C gives you direct control over memory. In the C implementation, I was able to get just a bit more performance by being clever with my memory allocations.&lt;/p&gt;
&lt;p&gt;Lastly, let&apos;s consider the cost of getting things wrong. Remember how I mentioned the original C abstraction I created wasn&apos;t working well? If we compare this to the Node example, we can see that a poor implementation in C is quite detrimental.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/understanding-eventing/BadC.png&quot; alt=&quot;Bad C Implementation&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this case, the results clearly show that the misuse of allocations and creation of additional thread contention on shared data will result in performance problems. Just because you have access to low-level primitives doesn&apos;t mean you are faster by default. If you are not careful, you have more ways to slow yourself down.&lt;/p&gt;
&lt;p&gt;If you would like to look at the data and draw your own conclusions, you can find the raw data &lt;a href=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/understanding-eventing/EventTimingData.csv&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What I learned from this experiment&lt;/h2&gt;
&lt;p&gt;In this project, I got to have a lot of fun learning about the lower level of event loops. I also got to see firsthand how building something in an event loop correctly can produce much better results. While writing C again was a bit of a learning curve, I was reminded just how much fun it is for me to think about low-level details like memory allocation and pointers. However, it was also a reminder that just because something is written in a low-level language doesn&apos;t mean it will be fast. It is all too easy to write a low-level program that runs way slower than a high-level language because you didn&apos;t think about the low-level primitives correctly. In the next blog, we will see that in action all over again.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Farm Scene]]></title><description><![CDATA[Description
Basic study of motion and procedural generation in a farm setting Medium: 2D Canvas Topics Researched Basic motion (acceleration…]]></description><link>https://ilusr.com/farm-animation/</link><guid isPermaLink="false">https://ilusr.com/farm-animation/</guid><pubDate>Thu, 07 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;View animation &lt;a href=&quot;https://ilusr.com/farm-animation&quot;&gt;here&lt;/a&gt;&lt;/p&gt;&lt;details&gt;
    &lt;summary&gt;More details&lt;/summary&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;
Basic study of motion and procedural generation in a farm setting&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Medium&lt;/strong&gt;: 2D Canvas&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Topics Researched&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Basic motion (acceleration, deceleration)&lt;/li&gt;
&lt;li&gt;Basic predictive collision detection&lt;/li&gt;
&lt;li&gt;Procedural generation&lt;/li&gt;
&lt;li&gt;Time cycles based on radial movement&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;</content:encoded></item><item><title><![CDATA[First excursion into Electron]]></title><description><![CDATA[Why use Electron anyway? After a bit of a meandering journey through a silly little Discord bot, we now find ourselves evaluating the…]]></description><link>https://ilusr.com/discord-electron-study/</link><guid isPermaLink="false">https://ilusr.com/discord-electron-study/</guid><pubDate>Sat, 18 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why use Electron anyway?&lt;/h2&gt;
&lt;p&gt;After a bit of a meandering journey through a silly little Discord bot, we now find ourselves evaluating the Electron application. My first experience with Electron was using the &lt;a href=&quot;https://atom-editor.cc/&quot;&gt;Atom editor&lt;/a&gt;. At the time, Atom was my daily driver. It was faster than &lt;a href=&quot;https://visualstudio.microsoft.com/vs/&quot;&gt;Visual Studio&lt;/a&gt;, more feature-rich than &lt;a href=&quot;https://notepad-plus-plus.org/&quot;&gt;Notepad++&lt;/a&gt;, and it was free, unlike &lt;a href=&quot;https://www.sublimetext.com/&quot;&gt;Sublime Text&lt;/a&gt;. I was intrigued by the idea of combining Node and Chrome to develop desktop applications. This sounded like a much better experience than I had previously using &lt;a href=&quot;https://en.wikipedia.org/wiki/Swing_(Java)&quot;&gt;Swing&lt;/a&gt;, &lt;a href=&quot;https://openjfx.io/&quot;&gt;JavaFX&lt;/a&gt;, &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/desktop/winforms/&quot;&gt;WinForms&lt;/a&gt;, &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/desktop/wpf/&quot;&gt;WPF&lt;/a&gt;, or &lt;a href=&quot;https://doc.qt.io/&quot;&gt;Qt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What made this a uniquely good opportunity to use Electron was that I wanted to manage another application running on my local machine. Since Node has access to the system and can spawn child processes, this was my chance to finally give the tool a go.&lt;/p&gt;
&lt;h2&gt;Diving back in&lt;/h2&gt;
&lt;p&gt;In my first attempt to review the code, I found myself fixated on issues that amounted to preferences about code style. Upon reflection, I realized that many of these changes would amount to nearly identical bytecode. For example, many of them were new features, such as optional &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot;&gt;optional chaining&lt;/a&gt; or &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring&quot;&gt;destructuring&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As I moved past the superficial critiques, I noticed a few things that seemed non-standard. The first was that I had no unit tests in any of the code in my Electron application or rendered application code. The second was that I was using plain JavaScript, no TypeScript anywhere to be seen. At first, I saw this as an issue, but upon reflection, I think this was wise.&lt;/p&gt;
&lt;p&gt;Unit tests are wonderful when you are building a production product. However, when you are just tinkering and learning, it only gets in your way. Making assertions on fundamentally flawed prototypes is a perfect waste of time.&lt;/p&gt;
&lt;p&gt;When the domain is not well understood, as is common in learning and prototyping, a type system provides little benefit at a real cost. In these cases, types haven’t had time to solidify, and the usage of &lt;code&gt;any&lt;/code&gt;, &lt;code&gt;unknown&lt;/code&gt;, and &lt;code&gt;Function&lt;/code&gt; are likely to come up. It’s hard to defend using Typescript in these cases. TypeScript is not a first-class citizen. If you give raw TypeScript to the browser or Node, it will fail. Leveraging TypeScript means adding a build step to compile your TypeScript. This adds complexity and additional time, both in compile time and setup.&lt;/p&gt;
&lt;h2&gt;Getting started with Electron&lt;/h2&gt;
&lt;p&gt;Now that I have had a good rant about the general ecosystem, let’s focus more on this Electron application. The first choice I had to make for the electron application was how to render the UI. Most examples will have you open a new BrowserWindow to show content. Then you will display your application using standard web technologies. Generally, the hardest choice is managing these static assets. Generally, I have seen two patterns. The first involves building your static assets and running the browser to load those local files. The other approach involves using a web server to host the static assets. Then the browser window can leverage those via a URL.&lt;/p&gt;
&lt;p&gt;In this case, I opted for the web server hosting the static assets. This allowed me to create two different experiences. The first experience was in-browser. If you viewed the website, you would be able to create a configuration file and download it. The other experience was loading the website from the Electron application. This experience would layer on the option to start and manage the Robit server on your local machine.&lt;/p&gt;
&lt;h3&gt;Enter IPC&lt;/h3&gt;
&lt;p&gt;To support these kinds of features, you need to have an interprocess communication channel between the browser and the Node process. At the time, the only way to do this was by using &lt;a href=&quot;https://www.electronjs.org/docs/latest/api/ipc-main&quot;&gt;ipcMain&lt;/a&gt;. This gave you an event emitter to handle messages between the browser and the Node process.&lt;/p&gt;
&lt;p&gt;This worked well, but it didn’t fit my mental model. I wanted to be able to express two modes of communication. A client should be able to send a request and await its response. It should also be able to subscribe to some event and get notifications over time. Since I couldn’t find an easy way to do that with the standard feature set, I built &lt;a href=&quot;https://ilusr.com/ipc-bridge/&quot;&gt;ipc-bridge&lt;/a&gt; to support my use cases. This abstraction allowed me to use my mental model across the IPC provided by Electron.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;@jeffriggle/ipc-bridge-client&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Sending single request to Node runtime.&lt;/span&gt;
client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;sendMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;doSomething&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;someData&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Logic for when the request passes&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword control-flow&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Logic for when the request failed&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Getting incremental updates from Node runtime&lt;/span&gt;
client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;subscribeEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;customizablemessage&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Logic for when a message comes from the main process&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Adding in the dual experience&lt;/h2&gt;
&lt;p&gt;As I mentioned before, I wanted to create multiple experiences on the website using the same static assets. This was something I had built into the &lt;code&gt;ipc-bridge&lt;/code&gt;. This library exposes a property that lets the frontend know if the Electron application was hooked up.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleElectronState&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;available&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token console class-name&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Is electron available? &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; available &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Yes&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;No&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;handleElectronState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;available&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;availableChanged&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleElectronState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By having the available state and a handler, I was able to dynamically load additional routes into my application.&lt;/p&gt;
&lt;h2&gt;Building the front-end&lt;/h2&gt;
&lt;p&gt;Since Electron uses Chromium as its rendering layer, you have all the same choices you would have for building any other website. The first is choosing whether to use a framework and which framework you would want to use. In this case, I decided to use React. Before this project, I had rarely used React. I was still skeptical of the memory required for the virtual DOM. However, what I did find compelling was the mental model of a single render function. To make this as easy as possible, I used the react-start-app that existed at the time. This opted into a default test framework, build process, and even a service worker.&lt;/p&gt;
&lt;h3&gt;Class versus function&lt;/h3&gt;
&lt;p&gt;When I started this project, class-based React components were the only option. As a result, I constantly ran into problems with callbacks. I kept running into the common problem of forgetting to bind callback functions. The way I dealt with this problem was problematic from a memory use perspective.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyComponent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;stateString&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sup&apos;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token console class-name&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;stateString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This would create a new bound instance of &lt;code&gt;doSomething&lt;/code&gt; on every render call. Some alternatives I have seen cache the bind or utilize arrow functions.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyComponent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;stateString&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sup&apos;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;doSomethingBound&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token console class-name&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;stateString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;doSomethingBound&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyComponent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;stateString&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sup&apos;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function-variable function&quot;&gt;doSomething&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token console class-name&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;stateString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Functional components handle this problem much better by completely avoiding this class of problem, as there is no &lt;code&gt;this&lt;/code&gt; to contend with.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;&lt;span class=&quot;token maybe-class-name&quot;&gt;MyComponent&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;stateString&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;sup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; doSomething &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token console class-name&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stateString&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;doSomething&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Every time I come back to this project, I have to fight the urge to update all components to be functional components. While it would feel better, it is not strictly required.&lt;/p&gt;
&lt;h3&gt;A missed opportunity&lt;/h3&gt;
&lt;p&gt;Most of the frontend code in this project was building a dynamic configuration file using components. The way I approached this problem was interesting in hindsight. I created a &lt;code&gt;configManager&lt;/code&gt; . This was not a class but a closure that housed a global configuration object. As you added actions, you would mutate the global actions array. A similar thing would happen for updating an action. Every time you created an action component, it would pull the related action metadata from the global state and mutate it in place.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// relevant bits of configManager.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;greeting&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Robit online. Boop Boop&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;audioSources&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;access&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword module&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;deniedMessage&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;You do not have the rights to perform this action&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;deferredactions&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword module&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;addAction&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;action&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword module&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getActionById&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; retVal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;retVal &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            retVal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; retVal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// relevant bits of Action component.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Action&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getActionById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// event handler to mutate state&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;typeChanged&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; newType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;selectedType&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newType
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are a couple of issues I have with this. I didn’t store the action in the state. Instead, it was a member of the class. However, the more egregious offender was the implicit changes. This built up its configuration by modifying the same underlying action object as was in the global. A much more modern and acceptable solution to this same problem would have been to use &lt;a href=&quot;https://redux.js.org/&quot;&gt;Redux&lt;/a&gt;. By using Redux, I would have the same global state I wanted, but with a couple of benefits. The first would be that I wouldn’t have implicit changes. The Redux pattern results in a global immutable state being changed over time by deterministic actions. The second benefit would be state consistency in the component. In this example, I am managing the state of the action outside the props or state. Going with a Redux pattern, this would not have been the case.&lt;/p&gt;
&lt;h3&gt;Finally, a better way&lt;/h3&gt;
&lt;p&gt;As I was reviewing the code, I happened upon this pattern I am all too familiar with seeing.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;save&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fileName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; el &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token dom variable&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;href&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;data:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;type&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;charset=utf-8,&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;download&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fileName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token dom variable&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token dom variable&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;removeChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Convinced that there had to be a better way, I set out to survey the landscape. Much to my excitement, a year ago, that better way is finally &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FileSystemWritableFileStream/write&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Getting to the Node runtime&lt;/h2&gt;
&lt;p&gt;Up until now, almost all of the logic I covered has been for the client assets. These would run fine with or without the desktop part. However, I think it is worthwhile to evaluate some of the choices in the Node runtime as well. There is far less of this code, so there is a bit less to uncover here.&lt;/p&gt;
&lt;h3&gt;Detecting environment&lt;/h3&gt;
&lt;p&gt;Debugging the application was something I needed early on. I wanted the full application running on my local machine. I also wanted access to the devtools in the Chromium view. I was able to control this behavior by setting a &lt;code&gt;NODE_ENV&lt;/code&gt; variable. When the variable was production, I would be able to do both of these behaviors.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isDev &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; appUrl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; isDev &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http://localhost:3000/robit&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http://ilusr.com/robit&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// opening the browser window&lt;/span&gt;
&lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isDev&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token dom variable&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;webContents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;openDevTools&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token dom variable&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;loadURL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appUrl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;An excessive dependency&lt;/h3&gt;
&lt;p&gt;A key flow involved starting the web server locally. To do this, I would download the compiled Robit “application”, more like a JavaScript file, from GitHub. That’s right, I checked in the compiled version as well as the source, blasphemy. To download this single asset, I added &lt;a href=&quot;https://github.com/octokit/octokit.js&quot;&gt;octokit&lt;/a&gt; as a dependency. However, I could have made an HTTP GET and prevented including the extra dependency. The effort to use the HTTP library would have been low. To avoid this low effort, I took on the risk of including a large dependency and its current 222 dependencies. That wildly expanded the amount of code I had consumed. This, in turn, expanded the surface area for security issues.&lt;/p&gt;
&lt;h3&gt;An overly aggressive timeout&lt;/h3&gt;
&lt;p&gt;Coming back to this, the Docker startup logic caught my attention. If the application determined you had Docker, it would allow you to start Robit as a Docker container. To detect Docker, a child process would be spawned.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;dockerEnabled&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;docker --version&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stdout&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stderr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;err &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;stderr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once eligibility was determined, you could choose to start this application in Docker. This was done by pulling the Docker container, starting it, and waiting for a health check to succeed. The problem was that this was a very aggressive health check. If you couldn’t start the application in 5 seconds, it would abandon the attempt.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;waitUp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; startTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token known-class-name class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        pollingInterval &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;http://localhost:8080/robit/state&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token known-class-name class-name&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                
                &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Stopped&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pollingInterval&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword control-flow&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timeout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token known-class-name class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; startTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pollingInterval&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;timed out waiting for docker server&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;startRunningDockerServer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;docker pull jeffriggle/robit &amp;amp;&amp;amp; docker run -p 8080:8080 -d jeffriggle/robit&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stdout&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stderr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
            &lt;span class=&quot;token function&quot;&gt;waitUp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;http://localhost:8080/robit/start&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token literal-property property&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; config
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; response &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;token console class-name&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Failed to set robit config. error &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;err&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, response: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token known-class-name class-name&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;. body: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token known-class-name class-name&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                        &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                        &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

                    &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword control-flow&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I cannot think of many Docker containers I have pulled from the internet, started, and interacted with in under 5 seconds.&lt;/p&gt;
&lt;h2&gt;Composition of services&lt;/h2&gt;
&lt;p&gt;This electron application was a multi-process architecture that required consideration at multiple levels. This had a web server hosting a frontend that interfaced with a desktop backend, which in turn interacted with a web server. This was a neat little problem all rolled up into one silly little application. What was especially interesting in this project was how many of the processes had been built to work in isolation. Despite it being the core focus area, you could run this entire application without ever using the electron part. While this sounds like it would have added a lot of extra scope, it was just a few lines of JavaScript to hide some visual elements controlled by a single event from the &lt;code&gt;ipc-bridge&lt;/code&gt; abstraction I made. In this case, a small decision on how to load static assets made a world of difference in the final feature set. In retrospect, this was one of the more impactful decisions in the project, not because of its complexity, but because of how it shaped the way the system could be composed.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Building a Discord Bot]]></title><description><![CDATA[With the high-level overview of Robit out of the way, it’s time to cover how the server was built. As I mentioned in the last blog, the main…]]></description><link>https://ilusr.com/building-a-discord-bot/</link><guid isPermaLink="false">https://ilusr.com/building-a-discord-bot/</guid><pubDate>Thu, 09 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;With the high-level overview of Robit out of the way, it’s time to cover how the server was built. As I mentioned in the last blog, the main goal of this project was to learn Electron, so working on the server was not the primary focus. What I wanted the bot to do was handle messages from Discord channels and perform a set of actions based on the content. To create the path of least resistance, the server was written in Node.js. By this point in my career, I was completely preoccupied with JavaScript. Setting up a proper C# or Java server simply required more effort than using Node.&lt;/p&gt;
&lt;h2&gt;Choosing a package&lt;/h2&gt;
&lt;p&gt;To interface with Discord, I did a quick search and found &lt;a href=&quot;https://discord.js.org/&quot;&gt;discord.js&lt;/a&gt;. As is typical, I spent the bare minimum time to find the popular package. I did not consider any alternatives and learned the bare minimum about the package. The result: I built a system that ignored most of what the package I was pulling in provided.&lt;/p&gt;
&lt;p&gt;The way I used the package involved subscribing to message events on all channels for the server in question. Then Robit would parse each message. If the message started with &lt;code&gt;!robit&lt;/code&gt; the server would proceed to process the message content. Much of what I did was supported by default in Discord.js with &lt;a href=&quot;https://discordjs.guide/legacy/slash-commands/advanced-creation&quot;&gt;commands&lt;/a&gt;. A little more time spent researching, and I could have narrowed the surface area of my backend even more.&lt;/p&gt;
&lt;p&gt;In retrospect, this was a failure on my part to understand what I had chosen to interface with.&lt;/p&gt;
&lt;h2&gt;Running the server&lt;/h2&gt;
&lt;p&gt;Once again, the runtime of this project changed over time. The entire configuration of this application was determined by a single JSON file. This configuration file had all the permissions, actions, etc defined inside of it. In the beginning, this would only run on a local machine. It assumed the program would be run using Node with the configuration file as an argument.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; main.js myconfig.json&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In retrospect, the argument processing is a bit humorous to me.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; configFile&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;val&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; arr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;endsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        configFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you could see, this will enumerate all arguments and then take the last JSON file. If you provided multiple JSON files, it would just read the last one. This may or may not be the desired case. Now there are many ways I could have handled this better. I could have made this an option instead of a positional argument. For this, I could have gone with an arguments parser like &lt;a href=&quot;https://yargs.js.org/&quot;&gt;Yargs&lt;/a&gt;. However, positional arguments are not the worst thing ever. What bothers me most now is just how much I felt compelled to use &lt;code&gt;forEach&lt;/code&gt;. There are many other ways to get the same effect with more precision and efficiency.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// So you just have to use functional programming.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; configFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;findLast&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; val&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;endsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// The forgotten for loop.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; configFile&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword control-flow&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; val &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;endsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        configFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Why not just apply a convention?&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Maybe a forced file name&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; configFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./robit-config.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Possibly a proper positional variable&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; configFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Eventually, I decided to expand the scope of this. Docker is cool, so everything, even toy projects, should run in Docker, right? Instead, this added deployment complexity without having a distribution problem to justify it.&lt;/p&gt;
&lt;h2&gt;Containerization&lt;/h2&gt;
&lt;p&gt;With containers comes an interesting problem. If I build an artifact and give it to you, I have created an issue. How can I get your specific config into my built container? A naive solution would be to provide the Dockerfile. Then you could define your configuration, provide it to the image, and build your own Docker container. However, if you are going to do that, why use Docker at all?&lt;/p&gt;
&lt;p&gt;There are many ways I could have solved this problem: use &lt;a href=&quot;https://docs.docker.com/engine/storage/bind-mounts/&quot;&gt;bind mounts&lt;/a&gt;, pass the configuration JSON as an insanely long argument, require the configuration to be hosted so CURL could be used to get the file, the list goes on. Instead, my application was extended to have an HTTP API using &lt;a href=&quot;https://expressjs.com/&quot;&gt;Express&lt;/a&gt;. This API provided a way to initialize and update the configuration.&lt;/p&gt;
&lt;h2&gt;Building the API&lt;/h2&gt;
&lt;p&gt;The primary goal of the API was to allow a user to create a configuration file and send it to a running Robit server to update the configuration. This also added the ability to start and stop the server. However, this also added another seemingly weird API, log collection.&lt;/p&gt;
&lt;p&gt;While not the topic of this particular blog post, the reason for this was rooted in the Electron application. The Electron application would interface with this API to manage the server. This included a view of the log messages from the running process. I could have piped the stdout from the container back to the electron application using the child process. What I did instead was pull the logs via an HTTP request. The result was the loss of access to the &lt;code&gt;console&lt;/code&gt; API for my logging. There are plenty of libraries that I could have used, like &lt;a href=&quot;https://github.com/winstonjs/winston&quot;&gt;Winston&lt;/a&gt;, but instead, I just built my own thing.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; watching &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; batchedLogs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;setWatching&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    watching &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; watch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;log&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;watching&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        batchedLogs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token console class-name&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;flush&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; retVal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; batchedLogs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    batchedLogs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; retVal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    setWatching&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    log&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    flush
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This solution is missing all sorts of features. Differing log levels and log formatting are just not part of the deal here. There are many options I could have evaluated to make my life easier, including using a third party or properly leveraging stdout. This was another case of over-engineering instead of using the ecosystem I had already bought into.&lt;/p&gt;
&lt;h2&gt;Security strikes again&lt;/h2&gt;
&lt;p&gt;Once again, I see that security was not my primary consideration. This surfaced in two different ways. The first and more unfortunate one pertained to command permissions. With these commands, I built a simple permission system. The idea was that there might be some commands that you didn&apos;t want everyone on the server to be able to invoke. The solution I created for permissions was a key-value pair. The key was the user&apos;s name, and the value was an array of all the commands the user had access to.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;permissions&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;steve&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;help&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;currentSong&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;sally&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;help&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;coolMessage&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you haven&apos;t figured it out yet, the big problem is that the solution keyed off the display name. The funny thing about display names in Discord is that you can change them. So, if, for instance, Sally changed their Discord name to Admin, they would get permission for all actions.&lt;/p&gt;
&lt;p&gt;The other area where security issues surfaced was on the web server. The interaction with the server when using Docker was via an HTTP API. This API had no permissioning. That choice &quot;might&quot; be considered safe if you are running on your local machine without the port exposed to the outside world. However, it is certainly poor form and not secure. To make matters worse, regardless of whether you ran in Docker, the HTTP server was always used. This was despite the fact that it wasn&apos;t needed. This reminds me of a &lt;a href=&quot;https://nvd.nist.gov/vuln/detail/cve-2019-13450&quot;&gt;Zoom security issue&lt;/a&gt; in which a local web server was the culprit. If you don&apos;t need the web server, maybe you shouldn&apos;t run it.&lt;/p&gt;
&lt;h2&gt;Get that bundler out of here&lt;/h2&gt;
&lt;p&gt;Another regret could be summed up with &lt;code&gt;webpack.config.js&lt;/code&gt;. I don&apos;t have a great memory of this decision. Either I thought it would be efficient to bundle my Node application, or it was bundled to make it easier to download from GitHub. Whatever the reason, I ended up using webpack to bundle my Node.js application. As a result, strange tools like Babel ended up being a part of my system.&lt;/p&gt;
&lt;p&gt;Every time I upgrade a project, the biggest pain point is around the build tooling. Sadly, in this case, I inflicted the pain on myself when it was not required. This introduced build complexity without a clear need for doing so.&lt;/p&gt;
&lt;h2&gt;The features I forgot&lt;/h2&gt;
&lt;p&gt;Looking through the code, I was reminded of some interesting features I had not mentioned before.&lt;/p&gt;
&lt;h3&gt;Harassment as a feature&lt;/h3&gt;
&lt;p&gt;I am not proud of this, and I don&apos;t think I realized the issue I was creating. However, I created what I can only describe as the perfect harassment feature. You could configure an action to repeat any message you wanted to another channel. This could allow a user to send a message directly to Robit, and it would happily repeat that message without a record of the originating user. I even created the action on my local server for a while and called it &quot;whisperbroadcast&quot;. In practice, the following message, &quot;!robit whisperbroadcast Lenny&apos;s mother was a hamster and his father smelt of elderberries,&quot; sent directly to the bot, would have broadcast to a larger channel to harass poor Lenny.&lt;/p&gt;
&lt;h3&gt;Why shouldn&apos;t Discord be a music player?&lt;/h3&gt;
&lt;p&gt;As it turns out, I spend an extraordinary amount of time turning Discord into a music player. I created a set of actions that would allow Robit to read the file system, gather all the files, and then provide commands for you to play those in a voice channel. If you configured that correctly in the JSON, you could do something like &quot;!robit playMusic&quot; which would start a voice channel to play music in that channel. You could then control the music with commands like &quot;next&quot;, &quot;shuffle&quot;, and &quot;stop&quot;.&lt;/p&gt;
&lt;p&gt;Looking at this code, I realized I committed the cardinal sin of Node.js programming.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getMusicFilesFromDirectory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; files &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;readdirSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    files&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;dir&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;file&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;statSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;isDirectory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;walkDir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;validAudioFile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;addMusicFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&apos;s right, I used a &quot;sync&quot; API from the &lt;code&gt;fs&lt;/code&gt; module. The initial thesis of Node.js was that even though JavaScript is single-threaded, it is not the thread that makes things faster. Instead, proper handling of IO is the primary concern. &lt;a href=&quot;https://www.youtube.com/watch?v=EeYvFl7li9E&quot;&gt;This talk&lt;/a&gt; does a far better job explaining this than I could ever do. Since this happened only once, it is fine, but a solution more in the spirit of Node would have been the following.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getMusicFilesFromDirectory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; files &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword control-flow&quot;&gt;await&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;readdir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword control-flow&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; file &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; files&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;dir&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;file&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fStat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword control-flow&quot;&gt;await&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;stat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fStat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;isDirectory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword control-flow&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getMusicFilesFromDirectory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword control-flow&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validAudioFile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;addMusicFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;JavaScript is a weird language&lt;/h2&gt;
&lt;p&gt;This project reminds me that JavaScript is a melting pot. In this project alone, I see an interesting mix of functional and object-oriented programming paradigms. The HTTP handling code and Discord message processing code are written in a functional way. However, the composition of actions, their metadata, and associated actions was done in an object-oriented manner. These actions even had a base class that handled the sending of messages back to channels. For these actions, I could just as easily have used a series of functions without a class, but instead I decided to mix paradigms. I assume this difference is because libraries like Express adopt a functional paradigm, but I was thinking in an object-oriented fashion. The parts closer to the library followed a more functional paradigm, but I was more comfortable with an object-oriented paradigm. As a result, core business logic would use a more object-oriented style.&lt;/p&gt;
&lt;h2&gt;Rounding it out&lt;/h2&gt;
&lt;p&gt;I consistently introduced tools and abstractions before I had a concrete need for them. Most of the complexity in this system came from decisions like that, not from the problem itself. These problems appear to be all too common in these projects I have taken on. Also, chasing fads caused me issues later on. Having to support the choice of yarn and Webpack created continued friction over time. As we close out this chapter of Robit&apos;s development, we prepare for a dive into the client that powered this server. This will focus on learnings specific to Electron and React.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What is a robit?]]></title><description><![CDATA[Building for someone else Continuing the thread of past projects in creation order, we arrive at robit. Robit was never anything I took too…]]></description><link>https://ilusr.com/whats-a-robit/</link><guid isPermaLink="false">https://ilusr.com/whats-a-robit/</guid><pubDate>Sun, 29 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Building for someone else&lt;/h2&gt;
&lt;p&gt;Continuing the thread of past projects in creation order, we arrive at robit. Robit was never anything I took too seriously, and yet somehow it ended up being another multi-repo application that was barely used. This started as some projects do: someone, in passing, was unhappy with &lt;a href=&quot;https://discord.com/&quot;&gt;Discord&apos;s&lt;/a&gt; feature set. The problem they had was that they wanted to set up scheduled daily messages. I did no research at the time to know if that feature is part of the application. However, given the size of the community, I would be surprised if this wasn&apos;t a standard feature by now.&lt;/p&gt;
&lt;h2&gt;So then why build it?&lt;/h2&gt;
&lt;p&gt;There was nothing to gain from this work. I was not and still am not a daily Discord user. While I provided steps on how to run this application to the person who started it, I am unaware if it was ever used. I certainly didn&apos;t ask for any payment for it.&lt;/p&gt;
&lt;p&gt;So what did I stand to gain from this? I was interested in learning how to build with &lt;a href=&quot;https://www.electronjs.org/&quot;&gt;Electron&lt;/a&gt;, and this felt like a perfect excuse. Since the core focus was on learning, I decided to take the path of least resistance on everything else.&lt;/p&gt;
&lt;h2&gt;Setting up the project&lt;/h2&gt;
&lt;p&gt;By this point, I was quite proficient in JavaScript, so I decided to write all the code in JavaScript. Creating the server in Java or C# would have been possible, but I found that it was way faster to bootstrap and prototype with JavaScript. Given those reasons, I decided to use a Node.js server.&lt;/p&gt;
&lt;p&gt;Below is the architecture I created for this project.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/whats-a-robit/robit-architecture.png&quot; alt=&quot;Robit Architecture&quot;&gt;&lt;/p&gt;
&lt;p&gt;On the server machine, which in this case was a random computer I owned, there was the &lt;a href=&quot;https://ilusr.com/robitclientnative/&quot;&gt;Electron application&lt;/a&gt;. That communicated with my personal domain to access the &lt;a href=&quot;https://ilusr.com/robit/&quot;&gt;static assets&lt;/a&gt;. Now, depending on whether you viewed the web page in the browser or on the Electron application, you would get a different experience.&lt;/p&gt;
&lt;p&gt;If you viewed the site in a browser, you would see the UI, which would build a config JSON file that you could provide to &lt;a href=&quot;https://ilusr.com/somerobit/&quot;&gt;the server&lt;/a&gt; via the command line.&lt;/p&gt;
&lt;p&gt;However, if you used the Electron application, you would get that experience plus the ability to start the Robit server directly, either by spawning a node process or by starting a Docker container.&lt;/p&gt;
&lt;h2&gt;The typical scope expansion&lt;/h2&gt;
&lt;p&gt;Once again, the scope expanded far beyond what I needed. The original goal was just to learn Electron and build a Discord bot that could send scheduled messages. By the time I was done, I had gone overboard on features again. In this case, I had built a bot that supported three types of communication, eight different configurable actions, and an access control system to top it off.&lt;/p&gt;
&lt;p&gt;Of course, knowing me, the scope creep was not just in features. This project resurfaced the problem of having too many run options. While it was more constrained than in the past, having the option to run in a local node process or in Docker was more than was required.&lt;/p&gt;
&lt;h2&gt;Getting back into this project&lt;/h2&gt;
&lt;p&gt;Before getting back into this project, I wasn&apos;t sure how I would feel about it. As I have mentioned before, I like to run these applications again before writing about them. There are a couple of things that struck me with this one in particular. First, I am not a Discord user, so trying to remember how the application worked was a bit of a challenge. This featured issues like: &quot;What email did I register my account under again?&quot; &quot;How do I create a private server again?&quot;, and who can forget &quot;How has the bot permission model changed over the last 6 years?&quot;&lt;/p&gt;
&lt;p&gt;Once all those questions had been answered, I had to get the application working again. All repositories in question hadn&apos;t been updated since Node 10 was LTS. Six years is also an eternity in JavaScript. The tooling landscape had, of course, changed. This began the drudgery of upgrading every Node version to be compatible with LTS, fixing all the project dependencies, and dropping yarn.&lt;/p&gt;
&lt;h2&gt;Not everything needs to be maintained&lt;/h2&gt;
&lt;p&gt;As I reflect on this project as a whole, it&apos;s clear I learned a fair amount about Electron and Discord. However, upon returning to this project, what was once interesting had become a chore. Because I am not a frequent Discord user, it is hard for me to form a strong attachment to this project. Having projects to learn a new tool or framework is incredibly valuable, but maintaining those projects after they have provided the desired learning is a recipe for discontentment. Sometimes, keeping a project as a static asset locked in time is best. Without this blog series, I would agree that treating Robit more like an ancient artifact to be observed, not touched, would have been for the best.&lt;/p&gt;
&lt;p&gt;Now that I have endured some pain and dissatisfaction, the real fun can begin. What I have been enjoying with these blogs is seeing what I can learn from my past projects. Now that I have done the drudgery, I can get on to the fun. In the next blog, I will start exploring the build-out of the Node.js server.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[JavaScript’s Promise Rejected Its Namesake]]></title><description><![CDATA[JavaScript promises aren’t actually the promises they were named after. The concept of a promise...]]></description><link>https://dev.to/jeffrey_riggle_e261fba011/javascripts-promise-rejected-its-namesake-345a</link><guid isPermaLink="false">https://dev.to/jeffrey_riggle_e261fba011/javascripts-promise-rejected-its-namesake-345a</guid><pubDate>Tue, 17 Mar 2026 11:30:00 GMT</pubDate><content:encoded>&lt;p&gt;JavaScript promises aren’t actually the promises they were named after. The concept of a promise...&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://dev.to/jeffrey_riggle_e261fba011/javascripts-promise-rejected-its-namesake-345a&quot;&gt;Read on dev.to&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[A Promise diverged]]></title><description><![CDATA[An unexpected journey As I was finishing my last blog, I felt compelled to understand the relationship between promises and async/await…]]></description><link>https://ilusr.com/promises-history/</link><guid isPermaLink="false">https://ilusr.com/promises-history/</guid><pubDate>Thu, 12 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;An unexpected journey&lt;/h2&gt;
&lt;p&gt;As I was finishing my last blog, I felt compelled to understand the relationship between promises and async/await. What I expected was a quick review of JavaScript history. Instead, I found something stranger.&lt;/p&gt;
&lt;p&gt;The concept of a &quot;promise&quot; in JavaScript traces back to a 1988 paper by Barbara Liskov. However, what JavaScript eventually implemented diverges in several important ways from the original concept. What began as a tool for structured distributed computation slowly evolved into a callback orchestration library.&lt;/p&gt;
&lt;p&gt;The following is a strange walk through history.&lt;/p&gt;
&lt;h2&gt;Setting a starting point&lt;/h2&gt;
&lt;p&gt;Early on, I realized if I kept pulling this thread, I would probably land at the dawn of computation. I decided to draw the line at the first mention of the word promise. This puts our starting point at a paper published by &lt;a href=&quot;https://en.wikipedia.org/wiki/Barbara_Liskov&quot;&gt;Barbara Liskov&lt;/a&gt; in 1988. I had to stop myself from following MultiLisp and its concept of futures. If you would like to follow this and risk going mad digging through history, this would be your &lt;a href=&quot;https://dl.acm.org/doi/10.1145/4472.4478&quot;&gt;starting point&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Coining Promises&lt;/h2&gt;
&lt;p&gt;The foundational paper that started it all is &lt;a href=&quot;https://dl.acm.org/doi/10.1145/960116.54016&quot;&gt;&quot;Promises: linguistic support for efficient asynchronous procedure calls in distributed systems&quot;&lt;/a&gt;. In this paper, Barbara discusses the difficulty of managing message exchange between systems. The message passing that is focused on is RPC and call streams. Barbara argues that we need a linguistic abstraction to assign to these concepts, making them easier to work with. Then the “promise” was born. These promises are not quite like the promises that you may be used to if you come from JavaScript. In these promises, you create a promise, and then you claim that promise. There is no then, catch, fulfill, or reject.&lt;/p&gt;
&lt;p&gt;The following are the benefits of Promises.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Strong types&lt;/strong&gt;: the result and failure modes of a promise were strongly typed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multiple Claims&lt;/strong&gt;: the result of a promise could be claimed any number of times.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blocking&lt;/strong&gt;: When a promise is claimed, the process blocks until the value is available.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The abstraction for promises also needed to work with RPC and call streams.&lt;/p&gt;
&lt;p&gt;When a promise is claimed, it blocks the current executing process until the claim is ready. Reading a claim that is already ready would not result in blocking. Instead, it would immediately return the known value. The following is an example directly from the paper written in the Argus language.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;sinfo record [ stu string, grade: grade ]
info array [sinfo]

pt = promise returns (real)
averages = array [pt]

grades: info := % some pre-recorded info not of interest

begin
	a: averages := averages$create(info$low(grades)) % create empty array with lower bound
	
	% record grades
	for s: sinfo in info$elements(grades) do
		averages$addh(a, stream record_grade (s.stu, s.grade))
		end
	flush record_grade

	%print
	for i: int in averages$indexes(a) do
		stream print(make_string(grades[i].stu, pt$claim(a[i])))
		end
	synch print
	end expect .. end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this example, recording a grade updates an average and returns a promise for when the grade is recorded. The &lt;code&gt;flush record_grade&lt;/code&gt; waits for the call-stream to be cleared so that future &lt;code&gt;claim&lt;/code&gt; operations do not have to block. If you come from JavaScript, you could loosely think of this as waiting for all outstanding asynchronous work to finish, similar to &lt;code&gt;Promise.all&lt;/code&gt;. Finally, it claims all the promises and writes the averages.&lt;/p&gt;
&lt;h2&gt;Advent of a new language&lt;/h2&gt;
&lt;p&gt;Now we are going to jump forward to 1997. At this time, Mark S. Miller was working on the programming language E. In this programming language, promises are a language feature. This language aimed to address the problems of distributed computing better than other languages of the time. A full paper surrounding this language is &lt;a href=&quot;http://www.erights.org/talks/promises/paper/tgc05-submitted.pdf&quot;&gt;here&lt;/a&gt;. Unlike Argus, E was not trying to hide asynchrony. Instead, it embraced it as a core part of the programming model. As a result, promises shifted to represent modern-day promises in JavaScript.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;def asyncAnd(answers) {
    var countDown := answers.size()
    if (countDown == 0) { return true }
    def [result, resolver] := Ref.promise()
    for answer in answers {
        when (answer) -&gt; {
            if (answer) {
                countDown -= 1
                if (countDown == 0) {
                    resolver.resolve(true)
                }
            } else {
                resolver.resolve(false)
            }
        } catch exception {
        	resolver.smash(exception)
    	}
	}
	return result
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can see the callbacks start to emerge a bit. You &lt;code&gt;when&lt;/code&gt; a promise and you &lt;code&gt;catch&lt;/code&gt; its error. Also note the emergence of the resolve concept.&lt;/p&gt;
&lt;h2&gt;Getting twisted&lt;/h2&gt;
&lt;p&gt;The work Mark did inspired our next character. In 2001, &lt;a href=&quot;https://blog.glyph.im/pages/about.html&quot;&gt;Glyph Lefkowitz&lt;/a&gt; was working on the &lt;a href=&quot;https://twisted.org/&quot;&gt;Twisted&lt;/a&gt; library in Python. In this library, the concept of &lt;strong&gt;deferred&lt;/strong&gt; was added. This was heavily inspired by Mark&apos;s work, and at &lt;a href=&quot;https://docs.twisted.org/en/twisted-22.8.0/historic/index.html&quot;&gt;PyCon 2003&lt;/a&gt;, he wrote a paper on this topic that cited Mark’s paper on the E language. In this &lt;a href=&quot;https://github.com/twisted/twisted/commit/53dc26020ce1075e6a2936e7ab012cadfb05eaf6&quot;&gt;initial implementation&lt;/a&gt;, you would create a deferred and register callbacks as well as error callbacks.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; twisted&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internet &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; reactor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; defer

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getDummyData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inputData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;getDummyData called&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    deferred &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; defer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Deferred&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    reactor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;callLater&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deferred&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;callback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; inputData &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; deferred

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cbPrintData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Result received: {}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

deferred &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; getDummyData&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
deferred&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;addCallback&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cbPrintData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

reactor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;callLater&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reactor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stop&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Starting the reactor&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
reactor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;run&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This condensed example from the twisted documentation site shows the new pattern. Now you can chain multiple callbacks on a deferred. These callbacks take the form of a success or error callback. Notice that this was called a deferred, not a promise. This seems like a deliberate choice. Notice how this isn&apos;t quite the same as a promise but is heavily inspired by them.&lt;/p&gt;
&lt;h2&gt;Dojo did it first&lt;/h2&gt;
&lt;p&gt;In the early 2000&apos;s, &lt;a href=&quot;https://infrequently.org/about-me/&quot;&gt;Alex Russell&lt;/a&gt; was busy working on &lt;a href=&quot;https://dojotoolkit.org/&quot;&gt;Dojo&lt;/a&gt;. At the time, the only way to handle asynchronous workloads was with callbacks in JavaScript. The dojo team looked to Twisted for their solution in the &lt;a href=&quot;https://dojotoolkit.org/reference-guide/1.7/dojo/Deferred.html&quot;&gt;deferred feature&lt;/a&gt;. This was originally created sometime around 2005.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; deferred &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;dojo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Deferred&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; deferred&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
deferred&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Do something on success.&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Do something on failure.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this, we can see even more patterns emerge. Now, &lt;code&gt;addCallback&lt;/code&gt; has been replaced with &lt;code&gt;then&lt;/code&gt;, and this then contains both the success and error callbacks.&lt;/p&gt;
&lt;h2&gt;Promises/A&lt;/h2&gt;
&lt;p&gt;Starting in 2009, Kris Zyp was busy trying to bring promises to CommonJS. What started off as a spirited &lt;a href=&quot;https://groups.google.com/g/commonjs/c/6T9z75fohDk&quot;&gt;discussion&lt;/a&gt; resulted in a &lt;a href=&quot;https://promisesaplus.com/&quot;&gt;Promises/A document&lt;/a&gt;. If you had been paying close attention, you would have noticed that Mark S. Miller corresponded on that discussion. Also of note, Kris and Russel had some interaction in the past, per this &lt;a href=&quot;https://infrequently.org/2008/01/kris-zyp-joins-sitepen/&quot;&gt;blog post&lt;/a&gt;. Kris went on to create &lt;a href=&quot;https://github.com/kriszyp/promised-io&quot;&gt;promise-io&lt;/a&gt; and &lt;a href=&quot;https://github.com/kriszyp/node-promise&quot;&gt;node-promise&lt;/a&gt;. In promises-io, the original approach was to continue using the term deferred, but that appears to have been superceeded by node-promise, which uses a very familiar syntax.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token spread operator&quot;&gt;...&lt;/span&gt; when the action is complete &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt; is executed &lt;span class=&quot;token spread operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token spread operator&quot;&gt;...&lt;/span&gt; executed when the promise fails
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From this work, many other libraries arose, such as &lt;a href=&quot;https://github.com/kriskowal/q&quot;&gt;Q&lt;/a&gt; with its wizard creator &lt;a href=&quot;https://kriskowal.com&quot;&gt;Kris Kowal&lt;/a&gt;, &lt;a href=&quot;http://bluebirdjs.com/docs/getting-started.html&quot;&gt;Bluebird&lt;/a&gt; with its creator &lt;a href=&quot;https://github.com/petkaantonov&quot;&gt;Petka Antonov&lt;/a&gt;, and &lt;a href=&quot;https://github.com/cujojs/when&quot;&gt;When&lt;/a&gt; with its creator &lt;a href=&quot;http://www.briancavalier.com/&quot;&gt;Brian Cavalier&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Standardization&lt;/h2&gt;
&lt;p&gt;Due to the popularity of these languages, &lt;a href=&quot;https://262.ecma-international.org/6.0/#sec-promise-constructor&quot;&gt;ES2015&lt;/a&gt; added support for promises. The API was defined by the libraries from the CommonJS community. This was shortly followed by &lt;a href=&quot;https://nodejs.org/en/blog/release/v4.0.0&quot;&gt;Node.js v4&lt;/a&gt;, which added Promises directly into the Node.js ecosystem. This marks the entry point for most modern web developers.&lt;/p&gt;
&lt;p&gt;This particular snip from the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promises documentation&lt;/a&gt; seems to indicate a history of tension in the term &quot;promise.&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Several other languages have mechanisms for lazy evaluation and deferring a computation, which they also call &quot;promises&quot;, e.g., Scheme. Promises in JavaScript represent processes that are already happening, which can be chained with callback functions. If you are looking to lazily evaluate an expression, consider using a function with no arguments e.g., f = () =&gt; expression to create the lazily-evaluated expression, and f() to evaluate the expression immediately.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;The gap&lt;/h2&gt;
&lt;p&gt;What was once a distributed computation solution snowballed into a library in JavaScript, hated for the callback hell it created. However, in its roots, there was no callback hell. This callback hell was a result of building a library when a native language feature was needed. Async is closer in spirit to the original promise concept. However, I would argue that all implementations in the JavaScript ecosystem have failed to meet the original requirement of error handling. If we think back, JavaScript Promises lost some incredibly valuable capabilities.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The strong typing on failures was lost.&lt;/li&gt;
&lt;li&gt;The semantics of a claim no longer exist&lt;/li&gt;
&lt;li&gt;The visibility of a promise state is now gone.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To me, the most unfortunate among these is the loss of failure types. Even TypeScript wasn&apos;t able to resurrect this, as the types for promise only include a result type and do not have an error type.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[SONA frontend and changing times]]></title><description><![CDATA[The face of SONA To round out the SONA blog series, I will be focusing on the front-end. Looking back on this project, I’m reminded how…]]></description><link>https://ilusr.com/sona-fe-review/</link><guid isPermaLink="false">https://ilusr.com/sona-fe-review/</guid><pubDate>Thu, 05 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;The face of SONA&lt;/h2&gt;
&lt;p&gt;To round out the SONA blog series, I will be focusing on the front-end. Looking back on this project, I’m reminded how quickly the front-end ecosystem evolves. A while back, I wrote a &lt;a href=&quot;https://ilusr.com/aurelia/&quot;&gt;short piece on Aurelia&lt;/a&gt;. This piece lamented the state of Aurelia. In this blog, I will instead focus on general issues with my front-end. Much of what I noticed during my post-mortem review was patterns that have fallen out of favor and mistakes that exist regardless of framework choice.&lt;/p&gt;
&lt;h2&gt;Event passing&lt;/h2&gt;
&lt;p&gt;In modern frameworks, the way state is passed between components is largely decided for us. This passing of state is so well abstracted in the framework that you might not realize there is a way to pass state without a framework. For example, in Angular, you can use either an event emitter or an output signal to pass state between components.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Component&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;component-a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  template&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;component-b (action)=&quot;handle($event)&quot; /&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ComponentA&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;evt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Got event &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; evt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Component&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;component-b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  template&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;button (click)=&quot;actioned()&quot;&gt;Click Me&amp;lt;/button&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ComponentB&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  action &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;actioned&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    action&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Yo!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Even in React, this is a straightforward pattern, assuming you don&apos;t want to use a Redux-style pattern.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ComponentB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; action &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; act &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Yo!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;action&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;act&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Click me&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ComponentA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ComponentB&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;evt &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token console class-name&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Got event &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; evt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, there is another way to pass state without these frameworks. You can emit a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent&quot;&gt;CustomEvent&lt;/a&gt; from DOM elements directly. This is the pattern used in Aurelia. This pattern looks like the following.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!--component-b template--&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;click.delegate&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;actioned&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Click me&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;@&lt;span class=&quot;token function&quot;&gt;customElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;component-b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
@&lt;span class=&quot;token function&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token maybe-class-name&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword module&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ComponentB&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;actioned&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; evt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CustomEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;action&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;detail&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Yo!&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;dispatchEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;evt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!--Component A template--&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;component-b&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;actioned.trigger&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;handle($event)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;@&lt;span class=&quot;token function&quot;&gt;customElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;component-a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
@&lt;span class=&quot;token function&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token maybe-class-name&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword module&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ComponentA&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token console class-name&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Got event &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; evt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;detail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Style preprocessors&lt;/h2&gt;
&lt;p&gt;In this project, I used &lt;a href=&quot;https://lesscss.org/&quot;&gt;Less&lt;/a&gt;. From what I can tell, Less has lost a lot of popularity. Angular has embraced a similar framework, &lt;a href=&quot;https://sass-lang.com/&quot;&gt;Sass&lt;/a&gt;. What React is doing seems to be constantly shifting. The last I knew, JSS-style frameworks like &lt;a href=&quot;https://emotion.sh/docs/introduction&quot;&gt;emotion&lt;/a&gt; were the popular choice. I wouldn&apos;t be surprised to find another community that doesn&apos;t use a preprocessor but instead uses &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;TailwindCSS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With how this project used Less, I could have dropped the preprocessor completely. Everything I needed is now handled with the introduction of CSS &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Cascading_variables/Using_custom_properties&quot;&gt;custom properties&lt;/a&gt;. Increasingly, I find it hard to find a compelling case for a CSS preprocessor. The base CSS feature set has gotten better over the years. Many of these abstractions should be phased out by native browser functionality, similar to what happened with &lt;a href=&quot;https://jquery.com/&quot;&gt;jQuery&lt;/a&gt; and the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector&quot;&gt;querySelector&lt;/a&gt; API.&lt;/p&gt;
&lt;h2&gt;Accessibility issues&lt;/h2&gt;
&lt;p&gt;One major issue I see in this project revolves around accessibility. I found countless accessibility violations, but decided to cover two.&lt;/p&gt;
&lt;h3&gt;Button contents affect screen readers&lt;/h3&gt;
&lt;p&gt;A major violation I see repeated in this project is the continued use of x as the text for a button. While this works for many users, the screen reader experience is terrible. Here is one such example.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;attachment-remove&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;click.delegate&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;remove()&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;x&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using the not-so-handy &lt;a href=&quot;https://www.w3.org/TR/WCAG20-TECHS/ARIA14.html&quot;&gt;rule guide&lt;/a&gt;, we can see this should have been.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;attachment-remove&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;click.delegate&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;remove()&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;remove&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;x&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Applying this treatment would cause the screen reader to read something closer to &quot;button remove&quot; instead of &quot;button x&quot;.&lt;/p&gt;
&lt;h3&gt;Live text&lt;/h3&gt;
&lt;p&gt;The notification system is another place where I had issues. In this application, if a request failed, the user was informed by a failure notification. This notification was a toast that would appear on the screen after an error occurred. Then it would slowly fade out. The problem with this is that it didn&apos;t use a &lt;a href=&quot;https://www.w3.org/TR/WCAG20-TECHS/ARIA19.html&quot;&gt;live region&lt;/a&gt;. Because of this, it is unlikely that a screen reader would have alerted the user to the failure.&lt;/p&gt;
&lt;p&gt;Here is the example from the notification area component.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Notification Area --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;require&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;./notification-item&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;notification-area&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;${notifications.length &gt; 0 ? &apos;show-notification&apos; : &apos;hide-notification&apos;}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;notification-item&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;repeat.for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;notification of notifications&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;notification.bind&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;notification&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;notification-item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A version of this that would have been compliant would be the following.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Notification Area --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;require&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;./notification-item&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;notification-area&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;${notifications.length &gt; 0 ? &apos;show-notification&apos; : &apos;hide-notification&apos;}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;alert&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-atomic&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;notification-item&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;repeat.for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;notification of notifications&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;notification.bind&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;notification&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;notification-item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Promises vs async&lt;/h2&gt;
&lt;p&gt;This project was written during an interesting period in JavaScript history. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promises&lt;/a&gt; had recently been introduced, but &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&quot;&gt;async/await&lt;/a&gt; had not landed yet. As a result, all asynchronous code in the project used the Promises API. This resulted in callback chaining that was very hard to follow.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;httpManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/sona/v1/incidents/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;incident&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;token comment&quot;&gt;// Process incident&lt;/span&gt;

     httpManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/sona/v1/incidents/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;incident&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/attachments&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// process attachments&lt;/span&gt;
     &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword control-flow&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// handle attachment failure&lt;/span&gt;
     &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword control-flow&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;token comment&quot;&gt;// handle incident failure&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The async version is a bit easier to follow, but it would be more legible if the error handling in both cases were the same.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword control-flow&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; incident &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword control-flow&quot;&gt;await&lt;/span&gt; httpManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/sona/v1/incidents/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// process incident&lt;/span&gt;
    &lt;span class=&quot;token keyword control-flow&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword control-flow&quot;&gt;await&lt;/span&gt; httpManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/sona/v1/incidents/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;incident&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/attachments&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword control-flow&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// handle attachment failure&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword control-flow&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// handle incident failure&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Tools I don&apos;t miss&lt;/h2&gt;
&lt;p&gt;I also used &lt;a href=&quot;https://webpack.js.org/&quot;&gt;Webpack&lt;/a&gt; and &lt;a href=&quot;https://gulpjs.com/&quot;&gt;gulp&lt;/a&gt;. Webpack, in particular, is powerful, but it creates something that is hard to maintain. Effective use of Webpack requires many plugins. For example, if you need to ship in multiple browsers, you will need the Babel plugin. The same holds true for CSS preprocessors like Less. It also applies to the minification of JavaScript. Installing all these plugins to build a web app creates a problem. Over time, plugins stop being maintained or fall out of favor. This is the inevitable nightmare I face when returning to a side project years later. Hopefully, up-and-coming build tools like &lt;a href=&quot;https://vite.dev/&quot;&gt;Vite&lt;/a&gt; will be better, but plugins are still involved.&lt;/p&gt;
&lt;h2&gt;Getting more specific on SONA&lt;/h2&gt;
&lt;p&gt;For the most part, I have been rambling on about how the JavaScript ecosystem has changed. However, it would be beneficial to elaborate on some specific learnings from this project.&lt;/p&gt;
&lt;h3&gt;My design isn&apos;t getting better&lt;/h3&gt;
&lt;p&gt;I can see I was exploring with this UI, but when I use this project, it looks like a watered-down version of JIRA. The design flair I added was some gradients and a few animations. This project continues to showcase that I could use improvement in my design skills.&lt;/p&gt;
&lt;h3&gt;Auth pain&lt;/h3&gt;
&lt;p&gt;As I mentioned previously, the authorization pattern involved the following. First, you need to log in. Then you will get a &quot;token&quot;. Finally, you need to send that token in an &lt;code&gt;X-Sona-Token&lt;/code&gt; header. This, however, created a problem. To keep the token between page refreshes, it had to be stored somewhere. What I ended up doing was managing the token manually in JavaScript by putting the token in localStorage. This would have been much simpler if the token had been set in a cookie instead. The client-side JavaScript wouldn&apos;t have had to interact with local storage, nor would it have needed custom logic in its fetch calls to make sure the header was set.&lt;/p&gt;
&lt;h3&gt;A lack of routes&lt;/h3&gt;
&lt;p&gt;This is SPA, but it barely uses routes. There were three different routes: login, incidents list, and incident. Some routes that could have been helpful would have been: a 404 page, a 401 page, and a user profile page. Not having the 404 and 401 pages seems strange to me anymore.&lt;/p&gt;
&lt;h2&gt;What I learned from SONA&lt;/h2&gt;
&lt;p&gt;I have other critiques of my code, like specific CSS choices and some other miscellaneous issues. However, I didn&apos;t want to spend a lot of time talking about these very specific opinions.&lt;/p&gt;
&lt;p&gt;What has stuck with me when considering Aurelia again was why I was drawn to it in the first place. It seemed reasonable that some subset of what Aurelia would become standardized in the browsers. This creates an interesting observation for me. I also enjoyed using HTMX. I know it also &lt;a href=&quot;https://htmx.org/essays/future/&quot;&gt;has similar aspirations&lt;/a&gt;. While I hope they get traction, this is a cautionary tale that HTMX may never find its way into the standards.&lt;/p&gt;
&lt;p&gt;Over the last decade, the front-end ecosystem has undergone massive change. If you extend that period by another decade, the changes are even more shocking. Layers of abstraction are added, then removed. Configuration vs convention is a constantly evolving battle. In the meantime, the browser primitives have been improving. A fixation on frameworks can hide this fact. On your next project, try JavaScript without a framework; you might be surprised at what you can do.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Lessons from the SONA Backend]]></title><description><![CDATA[The engine behind SONA Building on the last blog, I want to focus on the backend decisions behind the SONA project.. Looking back on this…]]></description><link>https://ilusr.com/sona-all-the-db/</link><guid isPermaLink="false">https://ilusr.com/sona-all-the-db/</guid><pubDate>Tue, 03 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;The engine behind SONA&lt;/h2&gt;
&lt;p&gt;Building on the last blog, I want to focus on the backend decisions behind the SONA project.. Looking back on this project, I see growth in some areas, but I also see new areas of weakness emerge. Now there are enough weaknesses in this that I cannot cover them all. Since I approached this like a code review, things like commenting style made it to my notes. To avoid making this a painful, drawn-out code review, I will focus on the most egregious issues.&lt;/p&gt;
&lt;h2&gt;Starting off on a good note&lt;/h2&gt;
&lt;p&gt;While I didn&apos;t realize it at the time, I showed some maturity in my process. Because my goal went beyond simply learning or a sense of misplaced pride in building everything myself, I used third-party libraries. Had I followed the path of my last project, I might have been tempted to build my own abstraction to create a RESTful API; instead, I used &lt;a href=&quot;https://github.com/gorilla/mux&quot;&gt;gorilla/mux&lt;/a&gt;. This saved me hours, if not days, of dealing with the HTTP library directly. It also allowed me to focus on the core problem. In addition to this library, I used many others, like database drivers and AWS clients.&lt;/p&gt;
&lt;p&gt;Another very positive aspect was avoiding the creation of a premature abstraction in an attempt to solve all problems. In the past, I might have been tempted to create a webhook library that aimed to solve everyone&apos;s problems with webhooks. This would have inevitably failed. The result would have been an abstraction that failed to meet even my own needs.&lt;/p&gt;
&lt;h2&gt;Database hell&lt;/h2&gt;
&lt;p&gt;In this project, I noticed a pattern. There was a deliberate effort to allow the end user to pick their desired technology. Now I see this as a failed attempt to remove vendor lock-in.&lt;/p&gt;
&lt;p&gt;I supported three major databases: Datastore, MySQL, and DynamoDB. This created a terrible straddle between relational and non-relational databases. If the goal was to avoid vendor lock-in, the usual culprit is the cloud vendor, not the database vendor. Making the system work well on a single database, such as MySQL, Postgres, or MongoDB, would have accomplished the same goal without the consequences.&lt;/p&gt;
&lt;h3&gt;The pitfall of abstraction&lt;/h3&gt;
&lt;p&gt;There is no shortage of documentation and blogs talking about the differences between relational and non-relational databases. However, my experience in this project taught me something a bit different. While you can make either model work behind a single interface, one or both implementations will be inefficient. I don&apos;t think I respected that enough going into this. Abstraction is a powerful tool, but it can also make you blind to inefficiencies inherent in it. These may be acceptable, but there is no such thing as a free abstraction. In my abstraction, I wanted to support any type of query on any column. The net result was implementation misses in both implementations.&lt;/p&gt;
&lt;h3&gt;Failures of Non-Relational Representation&lt;/h3&gt;
&lt;p&gt;To limit scope, I will focus only on the failings of my DynamoDB implementation. If you know anything about DynamoDB, you will know that you can either query or scan the database. Queries are the optimal route for retrieving data from the database because they use the database’s partitions effectively. However, you can do a suboptimal scan to perform other queries you may need. Notice the key focus is on performance. To use DynamoDB effectively, you should query, not scan. However, to query, you need to filter on an index, and indexes have to be predefined. This means a well-designed DynamoDB deployment requires planned query patterns. This abstraction allowed the creation of dynamic queries on any attribute that might not have an index. The net result was having to scan for all my incident search requests. At scale, this would have shown as a performance problem.&lt;/p&gt;
&lt;h3&gt;But you did better on MySQL, right?&lt;/h3&gt;
&lt;p&gt;The relational implementation fared better, but the abstraction still leaked in some interesting ways. Additionally, I do see some implementation misses. To support dynamic queries, I created the following data structure.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; Filter &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	Property       &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;`json:&quot;property&quot;`&lt;/span&gt;
	ComparisonType &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;`json:&quot;comparison&quot;`&lt;/span&gt;
	Value          &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;`json:&quot;value&quot;`&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; ComplexFilter &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	Children &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;ComplexFilter &lt;span class=&quot;token string&quot;&gt;`json:&quot;children&quot;`&lt;/span&gt;
	Filter   &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;Filter         &lt;span class=&quot;token string&quot;&gt;`json:&quot;filters&quot;`&lt;/span&gt;
	Junction &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;           &lt;span class=&quot;token string&quot;&gt;`json:&quot;junction&quot;`&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; FilterRequest &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	Filters  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;ComplexFilter &lt;span class=&quot;token string&quot;&gt;`json:&quot;complexfilters&quot;`&lt;/span&gt;
	Junction &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;          &lt;span class=&quot;token string&quot;&gt;`json:&quot;union&quot;`&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, this should allow you to chain together filter conditions with a junction (AND/OR). This has two issues. The first is similar to the NoSQL problem. While relational databases can do these queries, they tend to do better when you generate indexes. In this case, there is no good index to create. The secondary issue is somewhat painful for me to look at. It appears that the implementation missed a requirement. Do you see the issue with this code?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; filter &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;range&lt;/span&gt; filter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Filters &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;WriteString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;AND &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; iter&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; complexFilter &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;range&lt;/span&gt; filter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Filter &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; iter &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
				buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;WriteString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;AND &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
			buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;WriteString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;complexFilter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Property &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;convertToSQLComparisonType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;complexFilter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			args &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; complexFilter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One last commentary on this solution. As defined in the prior blog post, any incident can have any number of attributes. Here is how I built the data model.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; Incidents &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    Id &lt;span class=&quot;token keyword&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UNSIGNED&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	Description &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1048&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	Reporter &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	State &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; IncidentAttributes &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    IncidentId &lt;span class=&quot;token keyword&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UNSIGNED&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	AttributeName &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	AttributeValue &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IncidentId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; AttributeName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;FOREIGN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IncidentId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; Incidents&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Conventional wisdom says this is the correct solution, and it likely was. However, it may have been interesting to benchmark the difference between this model and a more non-standard model.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; Incidents &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    Id &lt;span class=&quot;token keyword&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UNSIGNED&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	Description &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1048&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	Reporter &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	State &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    Attributes JSON
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because every attribute query required joining these tables, the flexibility came at a cost. A JSON column may have simplified reads at the expense of more complicated inserts and updates.&lt;/p&gt;
&lt;h2&gt;Identity as an afterthought&lt;/h2&gt;
&lt;p&gt;A feature I bolted on later was authentication and authorization. This project highlights the dangers of rolling your own authentication and authorization. Now, before I completely rip apart the solution, I would like to point out one thing I handled passably. I did not store user passwords as plaintext in the database. Instead, I peppered the password with the user’s email and ran that through a SHA256 hash before storing it in the database, which is better than nothing.&lt;/p&gt;
&lt;h3&gt;Tokens matter.&lt;/h3&gt;
&lt;p&gt;The way I permissioned the application was the following. Once a user completed a login, they would be handed a token. No, not a sensible JWT. This was a special token of my own creation. This token contained some key data that was base64 encoded. The encoded value was then sent back to the client. The client would then have to provide this token in subsequent API requests via an &lt;code&gt;X-Sona-Token&lt;/code&gt; header.&lt;/p&gt;
&lt;p&gt;At this point, you might start asking some valid questions, including &quot;Why was this base64 encoded?&quot; This appears to be a classic case of security through obscurity. What I effectively wanted was to prevent the user from knowing what was in the token. However, a halfway decent security researcher would immediately realize this and attempt to abuse the fact. The token contains the following attributes: the user&apos;s ID, the expiration time for the token, and the permissions associated with the token. At this point in my read-through of the code, I was quite concerned. One could imagine the following cases that could cause unexpected token outcomes: extending the expiration date, masquerading as another user by changing the user ID, or even privilege escalation by changing the permissions in the token.&lt;/p&gt;
&lt;p&gt;Oddly enough, these cases didn&apos;t end up applying as I feared they might. I did something a bit clever, not to be confused with good, that reduced the surface area of the attack. When a user logs in, a token will be generated. This token would then actually be stored in the database in its initially created state. When a user used the &lt;code&gt;X-Sona-Token&lt;/code&gt;, it would check to see if that specific token string was issued in the past. If it weren&apos;t, it would reject the request. It would also prune the requests over time. So, while it is not good in practice, what this would mean is that to escalate your privileges, you would have to use a formerly issued, valid, and non-expired token in your request. I think this code best summarizes this almost seemingly accidental handling of these escalation concerns.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;manager MySQLUserManager&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ValidateUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	userId &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetTokenUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	tokens&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTokens&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	found &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; v &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;range&lt;/span&gt; tokens &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; v &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; token &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			found &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; i
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; found &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		logManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;LogPrintf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Token not found for user %v&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	expired &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TokenExpired&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	logManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;LogPrintf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Token expired %v&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expired&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;go&lt;/span&gt; manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pruneTokens&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tokens&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;expired
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Some things that would have made this better are the following. The first group would be focused on reducing the risk of token interception. Storing the token in an HttpOnly cookie would have prevented JavaScript from reading it, reducing the risk of token theft via XSS. There would still be a risk of man-in-the-middle attacks, but since the server deployment used an SSL certificate, even that would be limited. Another thing that would have helped would be encrypting or signing the token with a server-side key. This would have prevented users from inspecting or modifying the token&apos;s contents, including user IDs and permissions.&lt;/p&gt;
&lt;h2&gt;Looking forward&lt;/h2&gt;
&lt;p&gt;In many ways, I saw improvements from my last project, but in other ways, I saw a failure to properly build a web application. I had some obvious failings in deployment strategy, database management, and authorization. I found that many of these helped form my opinions on later projects. The risk was isolated to a project that was never commercialized, talk about a win. As this evaluation of the backend comes to a close, we look to the future with an analysis of the front-end in the next blog.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Creating an issue tracker]]></title><description><![CDATA[Who needs an issue tracker anyway? In the last series of blogs, I wrote about the first public project I worked on. It only seems natural…]]></description><link>https://ilusr.com/sona-an-introduction/</link><guid isPermaLink="false">https://ilusr.com/sona-an-introduction/</guid><pubDate>Fri, 27 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Who needs an issue tracker anyway?&lt;/h1&gt;
&lt;p&gt;In the last series of blogs, I wrote about the first public project I worked on. It only seems natural that my next long-winded series would be on the second application to join my graveyard. So begins the tale of the Support Orient Notification Application, or SONA for short.&lt;/p&gt;
&lt;h2&gt;What the heck was I making?&lt;/h2&gt;
&lt;p&gt;While working on the text adventure creator application, I had the thought, &quot;What if someone actually used this?&quot; Certainly, they should be able to flag issues with it. Then the even more absurd thought occurred to me, &quot;What if that user doesn&apos;t even know what GitHub is?&quot; Clearly, if the user were unaware of GitHub, they wouldn&apos;t be able to create a GitHub issue. Those two thoughts alone caused me to create my own issue tracker.&lt;/p&gt;
&lt;h3&gt;What&apos;s in a name?&lt;/h3&gt;
&lt;p&gt;It was time to level up. &quot;issuetracker&quot; is about as good a name as &quot;textadventurecreator&quot;. Coming up with cool names for projects is not a skill I possess. I am just not cut out to create the next BRB-DLL. Despite my best efforts, I landed on IONS, the Incident Oriented Notification System. That was until a quick search revealed several existing companies with the same idea. Instead, I landed on SONA, which, as it turns out, was already globally indexed by a video game instead.&lt;/p&gt;
&lt;h2&gt;Getting the requirements sorted&lt;/h2&gt;
&lt;p&gt;What I wanted was a hybrid between JIRA and GitHub issues. If you had been paying attention, there was a constant emphasis on &quot;notification system&quot;. The plan was that this application would interact with whatever application you needed to by using webhooks. Created an issue, cool, there is a webhook for that. Aside from that, these were the features I wanted&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unauthenticted creation of issues. I didn&apos;t want users to have to create an account to file an issue.&lt;/li&gt;
&lt;li&gt;Dynamic attribution. Each ticket should be allowed to have any attributes you want.&lt;/li&gt;
&lt;li&gt;File upload. The original use case involved uploading a log file.&lt;/li&gt;
&lt;li&gt;Notes per ticket. Each ticket should have a collection of notes to track the ticket status. Just plain text would do. No need for fancy HTML or markdown.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Choosing the right tech&lt;/h2&gt;
&lt;p&gt;Having a working service was a nice-to-have. The primary goal for me in this project was to learn some new skills. At the time, I was itching to use &lt;a href=&quot;https://go.dev/&quot;&gt;Go&lt;/a&gt;, so I decided the back-end for this application would be Go.&lt;/p&gt;
&lt;p&gt;The front-end was a bit more complicated. By this time, the industry was starting to fall out of love with good ol&apos; fashioned thick clients. For those who are unaware, these applications used a TCP socket to send data to a desktop client. These applications were usually written in C++, C#, or Java. My day job was primarily &lt;a href=&quot;https://angularjs.org/&quot;&gt;Angular.js&lt;/a&gt; with obscure pockets of &lt;a href=&quot;https://dojotoolkit.org/&quot;&gt;Dojo&lt;/a&gt; and &lt;a href=&quot;https://emberjs.com/&quot;&gt;Ember&lt;/a&gt;. This was also a turbulent time in the industry. &lt;a href=&quot;https://react.dev/&quot;&gt;React&lt;/a&gt; was rising, the death of Angular.js was on the horizon, and the uncertain future of &lt;a href=&quot;https://angular.dev/&quot;&gt;Angular 2&lt;/a&gt; was present. Why would anyone want to add a compiler when JavaScript ran in the browser without it? One framework that appealed to me at the time was &lt;a href=&quot;https://aurelia.io/&quot;&gt;Aurelia&lt;/a&gt;. As this was a project that only impacted me, I decided to use Aurelia.&lt;/p&gt;
&lt;p&gt;Over time, this morphed to include &lt;a href=&quot;https://nginx.org/&quot;&gt;NGINX&lt;/a&gt; and &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt;. While the front-end was drowning in options, the back-end was dumping virtual machines to chase after Docker. At least that was what I was experiencing in my bubble.&lt;/p&gt;
&lt;h2&gt;Some lessons take a while to sink in&lt;/h2&gt;
&lt;p&gt;In this project, I was starting to learn from my past mistakes. This time, I was building software to solve my problems. Even better, the scope was limited to my desires and requirements. However, there was one little thing I couldn&apos;t decide on: how should I run this application?&lt;/p&gt;
&lt;p&gt;I fell into the trap of making the backend work for all sorts of technologies. I had created a JSON config file that would be loaded at application startup. This would control a wide variety of options. For the file storage, you could use the file system or an &lt;a href=&quot;https://aws.amazon.com/s3/?nc2=type_a&quot;&gt;S3 bucket&lt;/a&gt;. Where things got more complicated was on the persistent storage side. By the end of this project, you could store issues in RAM (ephemeral runtime space), &lt;a href=&quot;https://www.mysql.com/&quot;&gt;MySQL&lt;/a&gt;, &lt;a href=&quot;https://aws.amazon.com/dynamodb/?nc2=type_a&quot;&gt;DynamoDB&lt;/a&gt;, or &lt;a href=&quot;https://cloud.google.com/products/datastore&quot;&gt;DataStore&lt;/a&gt;. If you hadn&apos;t noticed, this was a mix of relational and non-relational databases. This forced me to torture these databases to support a very dynamic filter system.&lt;/p&gt;
&lt;h2&gt;Running the system&lt;/h2&gt;
&lt;p&gt;For a while, I had an instance of this running. I even used &lt;a href=&quot;https://swagger.io/&quot;&gt;Swagger&lt;/a&gt; to generate a Java client for my text adventure creator to use. This was running in AWS on a single t1.small instance for a time. However, after a year of no tickets, I decided it was time to save the small amount of money the system was costing me.&lt;/p&gt;
&lt;h2&gt;Coming back years later&lt;/h2&gt;
&lt;p&gt;To prepare for writing these blogs, I needed to remember how it worked. I find the best way to do this is to run the application. Normally, coming back to projects 6+ years later can be exceptionally painful. This time it wasn&apos;t too bad. I only ended up having to solve two problems, and it only took me an hour or so. The first issue was that Go 1.8 and Go 1.26 are very different. As it so happens, you cannot run an application without a &lt;code&gt;go.mod&lt;/code&gt; file anymore. Getting this working was as simple as running two commands.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;go mod init &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;repo&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
go mod tidy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I cannot overstate my joy in how simple this was compared to what I am used to for upgrades. I am looking at you, Jigsaw. The second issue was around my Node version on the front-end. The last time I ran Aurelia, I was using Node 10. As it turns out, Apple silicon and Node 10 don&apos;t play nicely together. After a bit of digging, I updated to Node 16, and I was up and running.&lt;/p&gt;
&lt;h3&gt;The feature I didn&apos;t remember&lt;/h3&gt;
&lt;p&gt;I began to interrogate the source code for a postmortem code review. Then I noticed something strange in my nginx config.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;nginx&quot;&gt;&lt;pre class=&quot;language-nginx&quot;&gt;&lt;code class=&quot;language-nginx&quot;&gt;&lt;span class=&quot;token directive&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;location&lt;/span&gt; /repos&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token directive&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;proxy_pass&lt;/span&gt; https://api.github.com/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What was I doing here? I searched the &lt;a href=&quot;https://ilusr.com/sona-client&quot;&gt;front-end&lt;/a&gt; and &lt;a href=&quot;https://ilusr.com/sona-server&quot;&gt;back-end&lt;/a&gt; documentation I created to no avail. Finally, I found a component in the front-end, and it started to click. I had a &lt;code&gt;GitIssueViewer&lt;/code&gt; component, and I remembered. The original pain point was, &quot;What if a user couldn&apos;t file a GitHub issue?&quot; I had created a hook in my use of the application to create GitHub issues when SONA created a ticket. Then I would link them back to the SONA issue via a &lt;code&gt;gitissue&lt;/code&gt; attribute. If a ticket had that attribute present, the front-end would call GitHub&apos;s public API to load the issue and its comments, which would be displayed in the application.&lt;/p&gt;
&lt;p&gt;This might seem obscure, and it was. However, there was a justification for my madness. I wanted to display this in my application without a link. Originally, I wanted to iframe the issue, but if you know anything about security, you know where this is going. &lt;a href=&quot;https://owasp.org/www-community/attacks/Clickjacking&quot;&gt;Clickjacking&lt;/a&gt; is a problem, and GitHub does protect against it. As a result, I rebuilt a minimal set of GitHub issues in my application just for this flow.&lt;/p&gt;
&lt;h2&gt;Looking to the future&lt;/h2&gt;
&lt;p&gt;Much like my other posts, I wanted to establish the context before revisiting the code with a more critical lens. That’s where the next blog begins.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Best animation you have seen or created?]]></title><description><![CDATA[It could be the way I interact with the internet, but most sites I use today follow a pretty...]]></description><link>https://dev.to/jeffrey_riggle_e261fba011/best-animation-you-have-seen-or-created-d0b</link><guid isPermaLink="false">https://dev.to/jeffrey_riggle_e261fba011/best-animation-you-have-seen-or-created-d0b</guid><pubDate>Tue, 24 Feb 2026 22:48:47 GMT</pubDate><content:encoded>&lt;p&gt;It could be the way I interact with the internet, but most sites I use today follow a pretty...&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://dev.to/jeffrey_riggle_e261fba011/best-animation-you-have-seen-or-created-d0b&quot;&gt;Read on dev.to&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[I Assumed Java Streams Had Minimal Overhead. They Didn’t]]></title><description><![CDATA[Many of us have heard the same mantra: idiomatic code comes at little to no cost. The benefit to...]]></description><link>https://dev.to/jeffrey_riggle_e261fba011/i-assumed-java-streams-had-minimal-overhead-they-didnt-163e</link><guid isPermaLink="false">https://dev.to/jeffrey_riggle_e261fba011/i-assumed-java-streams-had-minimal-overhead-they-didnt-163e</guid><pubDate>Wed, 11 Feb 2026 02:57:38 GMT</pubDate><content:encoded>&lt;p&gt;Many of us have heard the same mantra: idiomatic code comes at little to no cost. The benefit to...&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://dev.to/jeffrey_riggle_e261fba011/i-assumed-java-streams-had-minimal-overhead-they-didnt-163e&quot;&gt;Read on dev.to&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Descending the Java Stack]]></title><description><![CDATA[Some ideas won't leave you alone As I was publishing the last series of blogs, I had a constant nagging feeling that I left the biggest pain…]]></description><link>https://ilusr.com/java-perf/</link><guid isPermaLink="false">https://ilusr.com/java-perf/</guid><pubDate>Tue, 03 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Some ideas won&apos;t leave you alone&lt;/h2&gt;
&lt;p&gt;As I was publishing the last series of blogs, I had a constant nagging feeling that I left the biggest pain point underexplored. In the blog, I often lament the decision I made to support multiple attributes with dynamic values. At some point, I even suggested an approach to make the code more maintainable. While I enjoy the developer ergonomics of the solution, the thing I couldn&apos;t let go of was, &quot;What is the cost of this abstraction?&quot;&lt;/p&gt;
&lt;p&gt;In general, I find this to be an undervalued consideration that can lead to designs that have questionable performance characteristics. The common argument is that the developer velocity makes up for it. In many cases, that is a reasonable tradeoff. However, doing a postmortem on a project that is unused gives me the flexibility to be as unreasonable as I want and stretch the limits.&lt;/p&gt;
&lt;h2&gt;Setting up the experiment&lt;/h2&gt;
&lt;p&gt;In this experiment, I wanted to test the cases discussed in the blog.&lt;/p&gt;
&lt;h3&gt;Original implementation (Base Case)&lt;/h3&gt;
&lt;p&gt;While this is not the exact same implementation of the original code the project was using, this is very close to what it would have been doing. The important thing to note is that the value is just stored as an Object. There is no help for the consumer to know what the underlying value is.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Attribute&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Object&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Attribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Object&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Implemented solution (Generics Case)&lt;/h3&gt;
&lt;p&gt;As mentioned in the blog, the solution that is currently in the project is based on generics. This case is intended to mimic the implemented case, but with a data type field. This allows for slightly better handling on the consumer side, but still requires the primitive to be stored as an Object.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GenericCaseAttribute&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Object&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DataType&lt;/span&gt; dataType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GenericCaseAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Object&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DataType&lt;/span&gt; dataType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dataType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DataType&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getDataType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; dataType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Suggested solution (Strong Case)&lt;/h3&gt;
&lt;p&gt;This is the suggestion I made in the recent blog post that was never implemented. The important thing to note here is that Object is now gone and replaced with a strongly typed primitive.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StrongCaseAttributeBase&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DataType&lt;/span&gt; dataType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StrongCaseAttributeBase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DataType&lt;/span&gt; dataType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dataType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DataType&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getDataType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; dataType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StrongCaseInt&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StrongCaseAttributeBase&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StrongCaseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DataType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Optimal Solution (Best case)&lt;/h3&gt;
&lt;p&gt;In this case, I just did the solution I assumed would be the fastest. This breaks the requirements in an attempt to speed up the algorithm. This does not allow for multiple types and forces every value to be a double.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BestCaseAttribute&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BestCaseAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;The testing methodology&lt;/h2&gt;
&lt;p&gt;Now that I knew the implementations I wanted to test, I needed to set up a way to test the implementations. I settled on testing three different paths through the implementations. The first would be a full test that would build a list of 1,000,000 entities in the related data structure. I called this the population test. The second test would start with the population, but then iterate over all the values. However, only the iteration was measured. That test was referred to as the iteration test. Lastly, a full test would be done. This combined the population and iteration cases in what I call the full test.&lt;/p&gt;
&lt;h2&gt;Finding the benchmark&lt;/h2&gt;
&lt;p&gt;Originally, I thought I could do a basic stopwatch test. In this case, I would grab the time, run the test, and then compute the delta to get the time the implementation took. Simple enough, right?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt; startTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;nanoTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Test here&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt; endTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;nanoTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Test took &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;endTime &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; startTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Upon some reflection, I knew this was insufficient. The problem with timing Java is that it is a JIT-compiled language and as such it requires multiple passes over code before it’s optimized. If I really wanted a good representation of the real impact, I needed to do something better. As it turns out, people have spent a lot more time thinking about this than I have. There is an entire tool &lt;a href=&quot;https://github.com/openjdk/jmh&quot;&gt;JMH&lt;/a&gt; built for doing this type of test. Armed with a new tool, I decided to go with a pretty barebones setup in which I would test operations per second. As I mentioned, many benchmarks had to be created.&lt;/p&gt;
&lt;h3&gt;Full run benchmark&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Benchmark&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bestCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;BestCase&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BestCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;populate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;aggregateTotal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Population benchmark&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Benchmark&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bestCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;BestCase&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BestCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;populate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Iteration benchmark&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@State&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Scope&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Benchmark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BestCase&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BestCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Setup&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;populate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1_000_000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyBenchmark&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Benchmark&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bestCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;aggregateTotal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Looking at the results&lt;/h2&gt;
&lt;p&gt;After spending more time than I care to admit running all of these tests, I ended up with a &lt;a href=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/java-perf/benchmarks.csv&quot;&gt;dataset&lt;/a&gt; I could play around with. If you filter out the V2 data points, you will notice something shocking. The best case doesn&apos;t just beat the other cases; it completely demolishes them. See, there is one thing I didn&apos;t mention. In the best case, I actually use a plain &lt;code&gt;Attribute[]&lt;/code&gt; data type instead of an &lt;code&gt;ArrayList&amp;#x3C;Attribute&gt;&lt;/code&gt;, which has a huge implication. I will come back to this, but I made a minor change and generated some V2 benchmarks that lined the values up better.&lt;/p&gt;
&lt;h3&gt;Impact of different approaches&lt;/h3&gt;
&lt;p&gt;Considering all of the originally considered approaches, we can see that the difference between them is more or less within the margin of error.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/java-perf/impactofchoice.png&quot; alt=&quot;Suggested Solutions&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Best case consideration&lt;/h3&gt;
&lt;p&gt;Much like I assumed, the best case outperformed the other cases, and it did so by a pretty noticeable amount.
&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/java-perf/fullcompare.png&quot; alt=&quot;Total Compare&quot;&gt;&lt;/p&gt;
&lt;h2&gt;So wait, what was the big difference between V1 and V2?&lt;/h2&gt;
&lt;p&gt;I am so glad you asked. In the first version, all implementations except the base case used an unsized ArrayList. Now, some of you may know where this is going. It turns out that if you don&apos;t pre-size your ArrayList and grow it on insert, you pay a real performance cost. In this case, I insert 1,000,000 values sequentially, growing the ArrayList in the most inefficient way. As it turns out, the base size of an ArrayList in Java is &lt;a href=&quot;https://github.com/openjdk/jdk/blob/5152fdcd490412025ba5f608378982abc1eadc07/src/java.base/share/classes/java/util/ArrayList.java#L119&quot;&gt;10 entries&lt;/a&gt;, and when you exceed the boundary, it &lt;a href=&quot;https://github.com/openjdk/jdk/blob/5152fdcd490412025ba5f608378982abc1eadc07/src/java.base/share/classes/java/util/ArrayList.java#L237&quot;&gt;grows by 1.4x&lt;/a&gt;. This means in the end my arrays were resized nearly 30 times and produced an excess of 250k entries. This adds up to an insane amount of time, as the resizing event requires array copying and is a costly operation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/java-perf/arraysizeimpact.png&quot; alt=&quot;Array Size impact&quot;&gt;&lt;/p&gt;
&lt;h2&gt;But why stop there?&lt;/h2&gt;
&lt;p&gt;Now I could stop there, but where is the fun in that? At this point, I knew approximately the time it required, but I noticed that I was getting variability in my test runs with JMH. While it does provide direction, it is not the end source of truth. The question I had was, “How can you get closer to the source of truth?“ I decided the best way to find out what is going on is to see the actual disassembly generated by the JVM and interpret that.&lt;/p&gt;
&lt;h3&gt;Getting the tools&lt;/h3&gt;
&lt;p&gt;This required a fair amount of setup. First, to reason about the assembly generated, I set up IntelliJ IDEA with &lt;a href=&quot;https://plugins.jetbrains.com/plugin/25979-jitwatch4i/home&quot;&gt;Jitwatch4j&lt;/a&gt;. Since the benchmarking was run as a jar, I had to ensure the run generated a HotSpot log file. These log files contain all of the disassembly. To do this, I ran some crazy command like this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;shell&quot;&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;java&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-XX:+UnlockDiagnosticVMOptions&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-XX:+PrintAssembly&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-XX:+LogCompilation&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-jar&lt;/span&gt; target/benchmarks.jar&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once I had the log files, I could then load them into Jitwatch4j and look at the disassembly. However, I still wasn&apos;t finding everything I wanted to see. As it turns out, some instructions are predefined in the JVM. The result is that the disassembly might just jump to some instruction you cannot see. After some searching, I found &lt;a href=&quot;https://chriswhocodes.com/hsdis/&quot;&gt;hsdis&lt;/a&gt; which gave me everything I was looking for.&lt;/p&gt;
&lt;h3&gt;Looking at the disassembly&lt;/h3&gt;
&lt;p&gt;Now that I had the disassembly, it was time to find anything interesting in there. The first challenge I had to overcome was learning the ARM architecture. In the past, the only assembly I had done was based on the x86 architecture, and ARM was a learning curve for me. After spending a while figuring out how to read the &lt;a href=&quot;https://developer.arm.com/documentation/ddi0487/latest/&quot;&gt;manual&lt;/a&gt; and using &lt;a href=&quot;https://www.scs.stanford.edu/~zyedidia/arm64/&quot;&gt;this cheat sheet&lt;/a&gt;, I was able to piece together some basics.&lt;/p&gt;
&lt;p&gt;I had understood that there was a cost in some languages when storing as an object and casting it back to a primitive. What I found interesting in the disassembly is that it does not appear to be the case. Instead, we just find the underlying data, put it in a register, and add it.&lt;/p&gt;
&lt;p&gt;Let&apos;s consider this Java source.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;aggregateTotal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; retVal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;GenericCaseAttribute&lt;/span&gt; attr &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getDataType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
                    value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
                    value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            retVal &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; retVal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When the double branch is hit, we do a straight-forward addition.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;assembly&quot;&gt;&lt;pre class=&quot;language-assembly&quot;&gt;&lt;code class=&quot;language-assembly&quot;&gt;0x0000000115a623e4: ldr d16, [x0,  #16] ; Get field containing double value and store in d16
0x0000000115a623e8: b 0x0000000115a62400
; intermediate steps truncated
0x0000000115a62400: add w17, w10  #0x1 ; Increment ArrayList iterator
0x0000000115a62404: fadd d0, d0, d16  ; Add double attribute value d16 to retVal d0 and store in d0  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, converting an integer double is not free and requires an extra operation.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;assembly&quot;&gt;&lt;pre class=&quot;language-assembly&quot;&gt;&lt;code class=&quot;language-assembly&quot;&gt;0x0000000115a62470: ldr w10, [x0,  #12] ; Get field containing int value and store in w10
0x0000000115a62474: scvtf d16, w10  ; convert int value in w10 to double value in d16
0x0000000115a62478: add w10, w17  #0x1 ; Increment ArrayList iterator
0x0000000115a6247c: fadd d0, d0, d16  ; Add double value in d16 to retVal d0 and store in d0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What I noticed was that in both cases, there hadn&apos;t been special instructions to go from Object to double or Object to int.&lt;/p&gt;
&lt;h3&gt;Finding metrics to pull from the disassembly&lt;/h3&gt;
&lt;p&gt;After spending time inspecting the disassembly, I realized it was hard to find significant findings. Looking at 800+ lines of assembly and comparing them to another 800+ lines where there is an illegible diff just wasn&apos;t cutting it. At that point, I remembered something: the slowest operations on the CPU should be memory access, especially. These are even more pronounced if memory access misses the L1 cache. In the disassembly of this program, most operations outside of memory access should have fairly low time complexity. All operations had been very simple arithmetic. Things like sin, cos, or even division didn&apos;t show up.&lt;/p&gt;
&lt;p&gt;With this new insight, I decided to count all of the memory access operations for each case and plot them in this &lt;a href=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/java-perf/asmmetrics.csv&quot;&gt;dataset&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Correlation between data sets&lt;/h2&gt;
&lt;p&gt;I realize that just the number of memory access operations or the number of lines of assembly code is a flawed metric for determining performance. This is because you don&apos;t actually know how the branches will be used at runtime. However, I found it to be shockingly correlated to the timing dataset from JMH. Basically, the more memory access operations you have defined in the routine, the fewer operations you can do per second.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Correlation between memory access and operations in iteration runs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/java-perf/asmimpactiteration.png&quot; alt=&quot;Correlation Memory Access and Ops Iteration&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Correlation between memory access and operations in population runs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/java-perf/asmimpactpopulation.png&quot; alt=&quot;Correlation Memory Access and Ops Population&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Lessons learned&lt;/h2&gt;
&lt;p&gt;Depending on where you are willing to set your limit, Java performance evaluations can go much deeper than many people may realize. From intuition to slow path to a JIT-compiled path, there are many opportunities for performance to be difficult to measure. This whole test didn&apos;t even consider the differences between HotSpot optimizations for different CPU architectures, which could have been explored.&lt;/p&gt;
&lt;p&gt;However, if the numbers tell you one thing, it is to pay close attention to your collections and how you initialize them. Failure to do so will result in a serious decrease in performance.&lt;/p&gt;
&lt;p&gt;In this case, it turns out that the costs I cared about for legibility weren’t the ones the machine cared about.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Execution Is Easy Now. That’s the Problem]]></title><description><![CDATA[At the end of last year, I had come to a stopping point on one of my many long-running side projects....]]></description><link>https://dev.to/jeffrey_riggle_e261fba011/execution-is-everywhere-deep-understanding-is-rare-50pk</link><guid isPermaLink="false">https://dev.to/jeffrey_riggle_e261fba011/execution-is-everywhere-deep-understanding-is-rare-50pk</guid><pubDate>Sun, 18 Jan 2026 20:52:31 GMT</pubDate><content:encoded>&lt;p&gt;At the end of last year, I had come to a stopping point on one of my many long-running side projects....&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://dev.to/jeffrey_riggle_e261fba011/execution-is-everywhere-deep-understanding-is-rare-50pk&quot;&gt;Read on dev.to&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[IDE for Text Adenture Games?]]></title><description><![CDATA[Building an IDE for text adventure games By this point, I have covered most of the core libraries used; now it is time to get into the core…]]></description><link>https://ilusr.com/creating-text-adventures/</link><guid isPermaLink="false">https://ilusr.com/creating-text-adventures/</guid><pubDate>Sat, 17 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Building an IDE for text adventure games&lt;/h2&gt;
&lt;p&gt;By this point, I have covered most of the core libraries used; now it is time to get into the core game building. The end product of my work was an IDE for making text adventure games. This IDE was intended to feel somewhat familiar to developers used to using an IDE.&lt;/p&gt;
&lt;h2&gt;Building a UI Framework&lt;/h2&gt;
&lt;p&gt;The last core library I haven&apos;t covered to this point was IROShell. Looking back, I don&apos;t have many grievances about this software. However, I will say its shortcoming came from overengineering. I had built a Java UI framework on top of JavaFX that I intended to use going forward. The problem was that, after this project, all of the work I did was in the web ecosystem. So, I didn&apos;t get to use this again.&lt;/p&gt;
&lt;p&gt;This framework required a mindset where users had complete control over the layout of multiple tabs. The result was layers of abstraction between you and the end layout. You would define views, menus, and toolbars. Then the framework would put them in their correct place and allow the user to move them further.&lt;/p&gt;
&lt;p&gt;This framework also included features for different layout strategies, namely a multiple-document interface and a single-document interface. It also had the ability to define custom pre-load screens, such as a splash screen or a login screen.&lt;/p&gt;
&lt;p&gt;Looking back, some of the biggest issues with this had been building on Java-core and Logrunner. While it was very helpful for me to generate logs, having your framework generate logs for debugging your application shell on an end user&apos;s machine was a bad idea in hindsight.&lt;/p&gt;
&lt;p&gt;Also, while the feature was incredibly helpful, the execution of the dynamic styling feature was problematic. I had built a feature that allowed for dynamically changing the application&apos;s styles just by changing a CSS file. This would watch the file for changes and host an internal Java protocol for reapplying the styles. The problem was that this required a new protocol to be defined, and the protocol I chose was called &lt;code&gt;internal://&lt;/code&gt;. In hindsight, that was a terrible and careless naming decision. It also required constantly creating new URLs, which likely led to memory leaks.&lt;/p&gt;
&lt;h2&gt;Issues in the Core&lt;/h2&gt;
&lt;p&gt;The textadventurelib was the core of the game engine. This is where all the real game logic occurred, which just so happened to be turning an XML representation of some game state into a functioning game.&lt;/p&gt;
&lt;h3&gt;In pursuit of clean code&lt;/h3&gt;
&lt;p&gt;To create the cleanest code I could think of, I ended up creating multiple cases of indirection that were hard to follow but also quite common in front-end development. One specific case that comes to mind is game state processing.&lt;/p&gt;
&lt;p&gt;To set the stage, the general operation model broke down into the following&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A game has game states&lt;/li&gt;
&lt;li&gt;A game state has options&lt;/li&gt;
&lt;li&gt;Options have triggers and actions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In many cases, you would want to send a message from an action to the game state. However, since the game state was the holder of the action, you wouldn&apos;t want that action to interact with the game state; that isn&apos;t clean, right? How I addressed this created a different problem. The actions would call back on an interface that the game state had. The problem was to wire all of this up; the game state had to understand all possible actions to hook up any action that might call it back later. This created a problem where the game state had to infer the type of the action at startup time.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Startup
load game state --&gt; iterate all options --&gt; find actions --&gt; if action of type x add listener y&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Send event
action triggered --&gt; find all listeners --&gt; call specific interface callback&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make matters worse, the design of these actions was overkill. These actions allowed multiple callback handlers, but in practice, there would only ever be one.&lt;/p&gt;
&lt;p&gt;This created ugly code like the following.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;IOption&lt;/span&gt; option &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;option&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CompletionAction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token class-name&quot;&gt;CompletionAction&lt;/span&gt; act &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CompletionAction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;option&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	    act&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;option&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppendTextAction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token class-name&quot;&gt;AppendTextAction&lt;/span&gt; action &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AppendTextAction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;option&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	    action&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;option&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FinishAction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token class-name&quot;&gt;FinishAction&lt;/span&gt; fAction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FinishAction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;option&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	    fAction&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFinishListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Instead of creating this mess, I could have used a message broker pattern or provided all actions access to the game state.&lt;/p&gt;
&lt;h3&gt;Just let people figure out images for themselves&lt;/h3&gt;
&lt;p&gt;This one is quick and minor, but early on, I decided it was very important that images be stretched to fit the image area, aspect ratio be dammed. In hindsight, this was clearly a silly choice.&lt;/p&gt;
&lt;h3&gt;Maybe the entity model wasn&apos;t that good&lt;/h3&gt;
&lt;p&gt;So much of this code is a complicated mess. This mess was most noticeable when you needed to act on the data in an action or trigger. This complication originated from building mental models of real-world concepts in code. What I mean is that if I had simplified the player down to: a player is an entity that can have many properties, I could have saved a lot of complexity. The important distinction between that and what I build is the dimensionality. In this alternative, I would have had a flat list of properties. Mapping classes to the real-world abstraction created friction in actions, triggers, and macros. I had to build overly complex, loosely typed models just to allow you to modify or read the specific data you needed to act on. This resulted in more cases of &lt;code&gt;Object&lt;/code&gt; instead of type, as well as some unnecessary reflection.&lt;/p&gt;
&lt;h3&gt;Macro&apos;s needlessly complicated&lt;/h3&gt;
&lt;p&gt;Another feature that was important to me was macro substitution. If you have attribution on a player, you should show it in the game at some point. For this, I created a complex substitution pattern that was somewhere between a substitution engine and a DSL. Let&apos;s consider a player with the attribute age. To get the value, you would have to create this macro &lt;code&gt;{[player(PlayerName)@attribute(age)@value]}&lt;/code&gt;. Since that wasn&apos;t complex enough, I decided to abstract out the separators so that it could be written in other ways. At execution time, this translated to dynamically building regular expressions and using reflection to find the properties on objects that you wanted to display.&lt;/p&gt;
&lt;p&gt;Looking back, I think there are a couple of ways I could have done this differently. First, there is the recurring observation that the entity model was too complex. However, if I couldn&apos;t have done that, there are other options, such as creating a DSL or even maintaining a simple map of a unique identifier to a substitution value.&lt;/p&gt;
&lt;h3&gt;Manual persistence code?&lt;/h3&gt;
&lt;p&gt;An overwhelming amount of code and classes were duplicated entities that had been defined for the sake of persisting with persistlib. A noticeable amount of the code written would simply not exist if metaprogramming were used to persist classes. There are ways to do this in Java, but even if I wanted to accomplish this with my own system, making persistlib metadata-driven using Java annotations would have saved a great deal of effort.&lt;/p&gt;
&lt;h2&gt;Bringing it all together in an IDE&lt;/h2&gt;
&lt;p&gt;All of this work had built up to the text adventure creator. This was an IDE for generating text adventure games. It built on all of the prior libraries, plus some JavaScript ports I didn&apos;t mention. The mistakes of the existing libraries would resonate here, but there had been a few new ones.s&lt;/p&gt;
&lt;h3&gt;Code generation is brittle&lt;/h3&gt;
&lt;p&gt;Originally, the end result asset was going to be either an XML file that could be provided to another application or a compiled jar. In the end, I instead supported all of these&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An XML-based file that could be provided to another application that did not exist.&lt;/li&gt;
&lt;li&gt;A generated jar.&lt;/li&gt;
&lt;li&gt;A generated Maven project for a developer to later generate a jar.&lt;/li&gt;
&lt;li&gt;A generated game in an HTML file format.&lt;/li&gt;
&lt;li&gt;A generated game as an electron app.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The choice to support all of these with no users was painful. To make matters worse, the HTML asset generation used a Webpack build system and React. When you are not actively working on a web project every day, you will find yourself in a legacy state that is hard to get out of. In modern web development libraries, build systems, and Node.js versions change at a nauseating pace. A failure to update every 6 months means you will feel incredibly behind if you wait two or more years to update something.&lt;/p&gt;
&lt;p&gt;Another thing that made this quite painful was that I used very large format strings for all of this. Using a framework like Handlebars or having a template file with clear substitutions would have made this much easier when making changes to the generated assets. Here is one example of the crazy code I ended up writing instead of creating a sane template.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;GAMESTATEINITIALIZER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;package org.%s.%s;\r\n\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;import ilusr.gamestatemanager.GameState;\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;import ilusr.gamestatemanager.GameStateManager;\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;import javafx.stage.Stage;\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;import textadventurelib.persistence.TextAdventurePersistenceManager;\r\n\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;public class GameStateInitializer {\r\n\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\tprivate Stage mainStage;\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\tprivate GameStateManager manager;\r\n\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\tpublic GameStateInitializer(Stage mainStage) {\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\tthis.mainStage = mainStage;\r\n\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\tinitialize();\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t}\r\n\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\tprivate void initialize() {\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\tmanager = new &amp;lt;String&gt;GameStateManager(\&quot;NA\&quot;, new GameState(null));\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\tMainMenuGameState mainGameState = new MainMenuGameState(manager, mainStage);\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\tmanager.addGameState(GameStates.MAIN, mainGameState);\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\tmanager.addGameState(GameStates.TRANSITION, new TransitionGameState(mainStage, manager, buildPersistenceManager()));\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\tmanager.addGameState(GameStates.LOAD, new LoadGameState(manager, mainStage));\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\tmanager.currentGameState(mainGameState);\r\n&quot;&lt;/span&gt;
	        &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t}\r\n\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\tprivate TextAdventurePersistenceManager buildPersistenceManager() {\r\n&quot;&lt;/span&gt;
	        &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\tTextAdventurePersistenceManager retVal = null;\r\n\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\ttry {\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\t\tretVal = new TextAdventurePersistenceManager(getClass().getResource(\&quot;%s.xml\&quot;).toExternalForm());\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\t} catch (Exception e) {\r\n&quot;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\t\te.printStackTrace();\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\t}\r\n\r\n&quot;&lt;/span&gt;		
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\treturn retVal;\r\n&quot;&lt;/span&gt;
	        &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t}\r\n\r\n&quot;&lt;/span&gt;
	        &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\tpublic void run() {\r\n&quot;&lt;/span&gt;
		    &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t\tmanager.start();\r\n&quot;&lt;/span&gt;
	        &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\t}\r\n&quot;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Good luck trying to line up those %s substitutions!&lt;/p&gt;
&lt;h3&gt;Player model strikes again&lt;/h3&gt;
&lt;p&gt;As we now know, a complex player model made player-specific triggers, actions, and macros hard. As it turns out, this resurfaces when you are building a UI for those actions, triggers, and macros. For a decent user experience, you don&apos;t want to keep a user guessing. For example, if you want to create a trigger that fires every time a player&apos;s health is below 10, you would want the UI to help you. The player model knows what attributes the player has, their types, and even their default value. To accomplish this, I built a complex set of dynamic combo boxes, or selects if you prefer that terminology. These would be dynamically added or removed based on the combo box prior, and their values would be tied to the entity model.&lt;/p&gt;
&lt;p&gt;Despite getting this to work functionally, the UX was still clunky.&lt;/p&gt;
&lt;h3&gt;I am not a designer&lt;/h3&gt;
&lt;p&gt;As evidenced by the beautiful artwork below, I am not a designer and probably will never be great at it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/creating-text-adventures/newerror.png&quot; alt=&quot;crappy artwork&quot;&gt;&lt;/p&gt;
&lt;p&gt;As a result, my style choices came off looking crude and childish. Since it was not my core focus, I didn&apos;t spend much time refining it. This often appeared as unstyled UI, but in other cases, it was just styled poorly. A prime example of this is the debugging experience I built into the IDE. While I found it useful to a degree, the debugger looked terrible. It also lacked the functionality you might expect from a debugger. The result was a poorly styled entity state tracker. Every time an action was triggered that changed a player&apos;s state, you would see removed entities in red, updated entities in blue, and added entities in green. The problem was that these had been styled so big and bulky that it was hard to read the change.&lt;/p&gt;
&lt;p&gt;Example of this visualization&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/creating-text-adventures/add.png&quot; alt=&quot;Add Characteristic&quot;&gt;
&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/creating-text-adventures/update.png&quot; alt=&quot;Change Attribute&quot;&gt;&lt;/p&gt;
&lt;p&gt;While this primative debugger was helpful for me, doubling down on making this better instead of focusing on other features would have been to my benefit.&lt;/p&gt;
&lt;h3&gt;Feature bloat gets in the way of deep work&lt;/h3&gt;
&lt;p&gt;Constantly going wide on this means having to support questionable value work without improving the core experience. This often leads to making UI changes just to support a new feature that provides little value. One example where this surfaced in this project was in the initial game creation wizard. Over time, something simple grew into a three-page wizard that was constantly changing. To make matters worse, most of the options provided little value. Every time I wanted to run another test, it added unnecessary time to just create a test game.&lt;/p&gt;
&lt;p&gt;Had I focused on the core problem, I could have spent more time making the experience better and wasted less time on UIs that reflected the ever-changing options.&lt;/p&gt;
&lt;h3&gt;Dynamic styling was very helpful&lt;/h3&gt;
&lt;p&gt;The investment in being able to dynamically style IROShell came in very handy. While developers who have only worked on Web 2.0 likely won&apos;t understand, having to wait for an entire compile of a Java application just to test one CSS change was miserable. Investing the time into that saved me a ton of recompile time.&lt;/p&gt;
&lt;h2&gt;High-level lessons learned&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Prototypes are valuable!&lt;/strong&gt; Believe it or not, you are allowed to write crappy or unclean code to learn what does and doesn&apos;t work in a system. Spending too much time making something clean can distract from understanding the core problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Iteration time is everything!&lt;/strong&gt; I think this is part of why the web is doing so well. The time it takes to iterate on HTML, JS, and CSS assets is faster than that of a typical compiled application. If you disagree with this, focus on your toolchain. You don&apos;t actually need a build system for the web, and your iteration time is just a save and refresh away.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you are hand-writing persistence code for each entity, you are probably doing something wrong!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Each feature comes at a maintenance cost!&lt;/strong&gt; Without careful selection of features, you will end up with so much bloat that you cannot move forward. In all likelihood, most of those features don&apos;t matter anyway. Treat your features like cattle, not pets!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Failure to read]]></title><description><![CDATA[In my last blog entry, I detailed how I came to build a text adventure creator application. Much of that focused on high-level learning…]]></description><link>https://ilusr.com/java-core-learnings/</link><guid isPermaLink="false">https://ilusr.com/java-core-learnings/</guid><pubDate>Sat, 10 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In my last blog entry, I detailed how I came to build a text adventure creator application. Much of that focused on high-level learning. These learnings were more focused on project structure and reception of the work. However, to do a retrospective, I wanted to focus more on the specific code choices to see what I think of them years later.&lt;/p&gt;
&lt;p&gt;With the complicated web of dependencies created, breaking this analysis across core libraries and the application seemed appropriate. In this case, core libraries are anything other than iroshell, textadventurelib, and textadventurecreator.&lt;/p&gt;
&lt;h2&gt;Who needs telemetry anyway?&lt;/h2&gt;
&lt;p&gt;Logrunner is very small and serves a simple purpose: write log entries to a series of TSV files as well as stdout.&lt;/p&gt;
&lt;p&gt;Now, you might think TSV is a funny format, and I will give you credit for that. However, at the time, I was using a log analysis tool that enabled querying TSV files in a SQL-like syntax, and I found that very beneficial.&lt;/p&gt;
&lt;p&gt;In most cases, others would reach for &lt;a href=&quot;https://logging.apache.org/log4j/2.x/index.html&quot;&gt;log4j&lt;/a&gt;, but I didn&apos;t need those features for my purposes.&lt;/p&gt;
&lt;p&gt;Looking back, I don&apos;t have many complaints about this library. A more advanced collection of data is required for some projects. In my case, I didn&apos;t need this kind of telemetry. If someone wanted help, they could just send me their log files.&lt;/p&gt;
&lt;h2&gt;Bad to the core&lt;/h2&gt;
&lt;p&gt;When I look back on java-core I see some obvious mistakes. If I were to start this project over, this would be a very different library. Since I made plenty of mistakes here, I will choose them carefully.&lt;/p&gt;
&lt;h3&gt;Failed wrapper abstractions&lt;/h3&gt;
&lt;p&gt;A common pattern I noticed, especially around the XML logic, is a failure to create a meaningful abstraction. In many cases, I took an existing standard library and wrapped it in a method that did the same thing. This can be a powerful abstraction if you want to switch out libraries, but in my case, I got this completely wrong. Firstly, one stated goal of this project was to use only the standard library. Wrapping the standard library with a limited feature added no value, as I was never going to use a different third party in the future. Secondly, I would wrap the standard library but return the standard library classes to the consumer. This created a leaky abstraction and did not effectively abstract out the standard library.&lt;/p&gt;
&lt;h3&gt;Failure to learn the ecosystem&lt;/h3&gt;
&lt;p&gt;If you are going to work in an ecosystem, you should use the tools from that ecosystem in the intended way. Instead, I decided to create my own pattern. Reevaluating at this library, I can elaborate on two examples where a little more time spent researching would have created less friction.&lt;/p&gt;
&lt;h4&gt;Swing is not WPF&lt;/h4&gt;
&lt;p&gt;None of this code is public, but at one point, I had a Swing-based application in the mix. This application loaded the created games and ran them. This was completely written in Swing and was created before I found JavaFX. I was influenced by WPF at the time. I was all in on MVVM (model-view-viewmodel), MVP (model-view-presenter), pick your acronym poison of choice. Of course, Swing didn&apos;t easily fit into that pattern. I could have just stuck with a single view class, as was common with Swing. However, I found it more fitting to create a monster.&lt;/p&gt;
&lt;p&gt;If you don&apos;t know this pattern, this analysis is most likely foreign to you. However, if you want to know or want a refresher, this is a way to separate your view and interaction/data model logic. The often stated goal is that it is easier to have &quot;just UI&quot; and &quot;just behavior&quot; changes. The flow between components is relevant, so here is a visual aid.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/java-core-learnings/mvvm.png&quot; alt=&quot;MVVM Pattern&quot;&gt;&lt;/p&gt;
&lt;p&gt;To create a similar effect, I decided on using: a model with no view logic, a view that was the Swing control, and a presenter. The implementation was an absolute mess. I ended up having all views and models extend from some base classes. These base classes would then allow you to raise a change event. This event would then be picked up by the presenter, and the presenter would use reflection to invoke the appropriate method on the linked view or model. This produced completely absurd code and failed to meet the desired abstraction.&lt;/p&gt;
&lt;p&gt;Not only did this build MVP incorrectly, but it forced you to pay the reflection tax. If I had scaled up this pattern, the application would have run much slower, as none of the UI interactions would have been able to be effectively JITted.&lt;/p&gt;
&lt;h4&gt;Localization is solved in the standard library&lt;/h4&gt;
&lt;p&gt;Another mistake I made in the implementation was creating my own language file format for localization. If I had done a little research, I would have found that Java has a robust solution for localization. Instead, I created an abstraction that was very similar to standard properties files but used the delimiter &lt;code&gt;;=;&lt;/code&gt; instead of &lt;code&gt;=&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Pulling in Spring&lt;/h3&gt;
&lt;p&gt;I have no issue with &lt;a href=&quot;https://spring.io/projects/spring-boot&quot;&gt;Spring&lt;/a&gt;, but one of my stated goals was to only use the standard library. Instead, I pulled in one of the biggest common libraries for a very small purpose. I wanted to be able to do IoC, and Spring had it. In doing so, I saved myself a headache by not trying to implement IoC myself, but I missed out on some of the learning I wanted to achieve.&lt;/p&gt;
&lt;h2&gt;Data formats are tricky&lt;/h2&gt;
&lt;p&gt;Much of what I built takes in an abstract state, serializes it to XML, then reads it back into classes. When I created this abstraction, I assumed I would eventually use other formats. The problem is, I made a very classic mistake. I built an abstraction before I had multiple use cases. This ended in a poor abstraction that was the Java XML library with a few opinions. At one point, I had considered adding JSON support, but the abstraction I had built didn&apos;t make sense for any other data format. What the heck does it even mean to add an attribute to a JSON property?&lt;/p&gt;
&lt;h2&gt;Building an entity model&lt;/h2&gt;
&lt;p&gt;The core of playerlib is the ability to create an entity that describes how I thought a player should work. This entity had many opinions about players. Players have attributes, characteristics, inventory, and so on. This even built in some features, such as listening for changes to the player entity.&lt;/p&gt;
&lt;p&gt;I didn&apos;t have too much of a problem with this, but then I remembered something. There was one thing that this abstraction did, which caused me much grief. The value type was not known at compile time. Let&apos;s take a simple example: a player can have attributes. In these attributes, there can be different value types. For example, you might have an attribute &lt;code&gt;age&lt;/code&gt; that is an &lt;code&gt;int&lt;/code&gt; and another attribute &lt;code&gt;surname&lt;/code&gt; that is a &lt;code&gt;string&lt;/code&gt;. The original implementation stored the value as an Object. The caller of the code had to figure out how to unwrap the value. Later on, I remembered that Java had generics; certainly, those would fix my problem! Of course, that wasn&apos;t quite right in my implementation. What I effectively did was take a method like this&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and turn it into this mess.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, in hindsight, there are probably a couple of ways I could have made this easier to reason about. One option would have been to create a pseudo-type union.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ValueType&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Boolean&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BaseValue&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ValueType&lt;/span&gt; valueType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BaseValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ValueType&lt;/span&gt; valueType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;valueType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; valueType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StringValue&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BaseValue&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StringValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ValueType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IntValue&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BaseValue&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StringValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ValueType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// etc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This would have removed many type checks that had not been applied consistently. In addition, it would have allowed for unboxing primitive value types.&lt;/p&gt;
&lt;h2&gt;Building a state machine&lt;/h2&gt;
&lt;p&gt;In gsmlib, I assumed that I could represent any possible game with the abstraction created. This mental model being all games are a series of game states, and there is data that moves between states. Also, all games would have a finished state. This state would tell you the game is over. In addition, there was a concept of game state buffering. For buffering, you would be able to load a couple of game states into memory. Then, as the game states proceed, the current game state would be evaluated to load the next game states needed.&lt;/p&gt;
&lt;p&gt;I don&apos;t have much to complain about with this abstraction. However, to be fair in this analysis, I must admit that this had the same shortcoming as playerlib. The game state data that was passed around from game state to game state was &lt;code&gt;Object&lt;/code&gt; and did cause some issues. This also made an overgeneralization; this clearly would not apply to all possible games. In essence, I just created another state machine.&lt;/p&gt;
&lt;h2&gt;So what did I learn?&lt;/h2&gt;
&lt;p&gt;If I had to distill this long analysis down into key lessons learned, this would be the TL;DR.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Take some time to read about the ecosystem&lt;/strong&gt;. Reinventing patterns in an ecosystem is rarely to your benefit. This is doubly true if you are a junior. You can learn a lot doing this, but more often than not, you are just creating a mess.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Have more than one implementation before creating an abstraction&lt;/strong&gt;. Failure to do otherwise will create a premature abstraction that is almost certainly insufficient.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If your abstraction is clever, it&apos;s probably wrong.&lt;/strong&gt; Just because you can do something and get it working doesn&apos;t mean it was a good idea. Consider your trade-offs and understand the cost you are paying.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Strong types are preferred.&lt;/strong&gt; If you are just passing &lt;code&gt;Object&lt;/code&gt; around or accepting a generic whose type hint cannot be statically inferred, you are going to end up paying for it in the future. The runtime cost to find the underlying type is not free, and the developer time wasted writing and maintaining that code will be staggering.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Side Project Beginnings]]></title><description><![CDATA[Public side projects, a beginning As I mentioned in my last blog entry, I will be covering my past projects and evaluating them. The only…]]></description><link>https://ilusr.com/text-adventure-beginnings/</link><guid isPermaLink="false">https://ilusr.com/text-adventure-beginnings/</guid><pubDate>Sat, 03 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Public side projects, a beginning&lt;/h1&gt;
&lt;p&gt;As I mentioned in my last blog entry, I will be covering my past projects and evaluating them. The only logical step is to start from the beginning, or at least close to it. This brings me back to when I was leaving college and starting my first job as a software engineer. At this time, it became clear to me that college had provided me with core foundational knowledge in computer science, but I was lacking practical application skills. To better understand the field, I decided it was time to start building some applications instead of focusing completely on algorithms and theory.&lt;/p&gt;
&lt;p&gt;Since I had the most cliché introduction to computer science, I decided something with games would be a great start. Given this, I decided the easiest place to start would be something with text adventure games. Since I tend to lack creativity and storyline creation, I set out to create a text adventure framework so that others could create games on my system. So began one of the largest projects I have done outside of work. This was also for an audience of zero people. As far as I know, no one has ever attempted to use it.&lt;/p&gt;
&lt;h2&gt;Hello World&lt;/h2&gt;
&lt;p&gt;Energized with a fun idea, I set out to build this framework. I had decided to go in with a couple of constraints.&lt;/p&gt;
&lt;h3&gt;Built on Java&lt;/h3&gt;
&lt;p&gt;At the time, I was mostly proficient with third-generation programming languages, and the majority of code I had written was in Java and C#. At the time, I was working heavily in C#. I had justified this choice in a few different ways. First, I wanted it to be cross-platform, and I knew that Java was built to be cross-platform. This focus on cross-platform was one of the major reasons I didn&apos;t do the project in C#. Also, I knew that the all too popular up-and-coming game &lt;a href=&quot;https://en.wikipedia.org/wiki/Minecraft&quot;&gt;Minecraft&lt;/a&gt; was written in Java. I figured if a 3D-rendered game could run in Java, so could a text adventure engine.&lt;/p&gt;
&lt;h3&gt;Only standard Library&lt;/h3&gt;
&lt;p&gt;I had decided that if I wanted to learn something deeply, I should only use the standard library and import nothing else. In the end, I fell short of this one. While I intend to cover this more later, the notable exceptions are Java Spring, JavaFx, and IzPack.&lt;/p&gt;
&lt;h2&gt;Evolution of the project&lt;/h2&gt;
&lt;p&gt;Before we consider the end state, it seems fitting to discuss how this project evolved over time.&lt;/p&gt;
&lt;h3&gt;Early days&lt;/h3&gt;
&lt;p&gt;One of the first decisions I made was to use &lt;a href=&quot;https://maven.apache.org/&quot;&gt;Maven&lt;/a&gt; for this project. In the earliest versions of this, I had a single project that I was working on in &lt;a href=&quot;https://eclipseide.org/&quot;&gt;Eclipse&lt;/a&gt; and building with Maven. This started as something that I kept on my local computer and backed up on an external hard drive and flash drive for a few years. Over time, the project grew, and before I knew it, a monorepo with around nine different libraries was created.&lt;/p&gt;
&lt;h3&gt;Growing up&lt;/h3&gt;
&lt;p&gt;At some point, I had lost my flash drive. This made me realize that I could lose the project completely. After this little scare, I decided it was time to start backing up my project online. For some reason, I was worried about sharing my code publicly. So, I decided to create a Bitbucket account to back the project up in a private repository.&lt;/p&gt;
&lt;p&gt;During this time, the industry had decided it was no longer cool to store all code in a single repository. Instead, a ton of small repositories should be managed and versioned independently. As a good engineer, obviously, I had to follow the rest of the industry. I spent a notable amount of time creating separate projects for each of my  libraries. This involved breaking the library out of the monorepo, creating a new Bitbucket repository, publishing an artifact to an S3 bucket on my AWS account, just so I could download it again via Maven for the projects that depended on that code.&lt;/p&gt;
&lt;h3&gt;Getting ready for &quot;Release&quot;&lt;/h3&gt;
&lt;p&gt;At some point, I had decided enough is enough! “I am going to put this code on GitHub as a public repository”, and that will be my released version. I was worried that once it was out there, people would see what I was working on, so I decided to work feverishly on the project to make it &quot;release-ready&quot;. What I defined as release-ready was the following.&lt;/p&gt;
&lt;p&gt;First, the project needed very high test coverage. If there was a class it needed to be unit tested. It did not matter how small or pointless. To put this into context, even the about dialog in the main application had unit tests.&lt;/p&gt;
&lt;p&gt;The next major requirement I had decided on being a &quot;blocker&quot; was that every public library needed to have every single method documented with Javadoc. and that all projects needed to have generated documents. This began with spending more time than I care to admit writing questionable Javadoc for absolutely everything. Then I had to fight with Maven to make sure the docs would actually generate correctly.&lt;/p&gt;
&lt;p&gt;Lastly, if I were going to send this out into the world, every respectable program that runs on a user&apos;s machine needs an installer, right? This began a long journey of creating an install workflow. Which basically just dropped a batch script into Windows to start the game builder. In this effort, I found &lt;a href=&quot;https://izpack.org/&quot;&gt;IzPack&lt;/a&gt; and spent a long time learning how to create an install flow.&lt;/p&gt;
&lt;h3&gt;Post Release&lt;/h3&gt;
&lt;p&gt;Soon after moving everything to GitHub and making everything public, I realized that no one was watching. If you want people to actually see what you are building, you need to be able to market your work, and that was not something I was good at or wanted to get good at. From that point on, I felt free to just work on the things that I had found interesting or wanted to learn.&lt;/p&gt;
&lt;p&gt;One of the first major changes happened when I was building my personal website. I decided I wanted that website to scrape all of my GitHub content and have pages for everything I put in the docs folder of any of my projects, along with any associated Java documentation. During that time, I moved a lot of documentation. Mostly, this involved converting HTML documents that detailed how to use the application to markdown files on GitHub.&lt;/p&gt;
&lt;p&gt;Not long after I created my website, I decided to create GitHub workflows for all my projects. During that time, all of these repositories got their own set of actions to build and test the repository on every PR. In doing this, I realized that how I was integrating with Maven and S3 was not going to work in GitHub actions. Due to this, I switched over to having my projects published to GitHub&apos;s Java repository.&lt;/p&gt;
&lt;p&gt;At some point along the way, Java updated to Jigsaw, and I decided it would be nice to make some of my &quot;internals&quot; actually internal, so I updated to Java 9. I wrote about this in the following &lt;a href=&quot;https://ilusr.com/revisit-java/&quot;&gt;blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While I never really completed it, the last thing I decided to focus on was creating end-to-end tests for the main application. For this, I was playing around with test-fx. Ultimately, this never got completed because I was having a hard time getting the tests to pass on the GitHub runners. The tests had worked just fine on my local, but, for some reason I never really cared to debug, I couldn&apos;t get them to pass in the runner.&lt;/p&gt;
&lt;h2&gt;Current state of the project&lt;/h2&gt;
&lt;p&gt;Once the dust had settled, I had been working on and off on the project for close to a decade. To my knowledge, it remains used and unheard of.&lt;/p&gt;
&lt;h3&gt;Project setup&lt;/h3&gt;
&lt;p&gt;The final makeup of the project was the following repositories. While I do not think lines of code is a great metric, I do think in a pre-AI world, it highlights the amount of time spent on the project more so than anything.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Lines of code&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/java-core&quot;&gt;java-core&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Library containing anything I deemed a core utility&lt;/td&gt;
&lt;td&gt;3562&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/logrunner&quot;&gt;logrunner&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Abstraction to log output to csv or tsv file&lt;/td&gt;
&lt;td&gt;293&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/java-persistencelib&quot;&gt;java-persistencelib&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Library to save xml files to disk&lt;/td&gt;
&lt;td&gt;1586&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/persist-lib&quot;&gt;persist-lib&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Javascript&lt;/td&gt;
&lt;td&gt;Javascript reimplementation of java-persistencelib&lt;/td&gt;
&lt;td&gt;270&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/playerlib&quot;&gt;playerlib&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Library for entity models and abstractions&lt;/td&gt;
&lt;td&gt;4100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/player-lib&quot;&gt;player-lib&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Javascript&lt;/td&gt;
&lt;td&gt;Javascript reimplementation of playerlib&lt;/td&gt;
&lt;td&gt;956&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/playerlib-example&quot;&gt;playerlib-example&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Example application using playerlib&lt;/td&gt;
&lt;td&gt;1459&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/gsmlib&quot;&gt;gsmlib&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Library for game state models and abstractions&lt;/td&gt;
&lt;td&gt;935&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/gamestate-manager&quot;&gt;gamestate-manager&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Javascript&lt;/td&gt;
&lt;td&gt;javascript reimplemenation of gsmlib&lt;/td&gt;
&lt;td&gt;306&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/iroshell&quot;&gt;iroshell&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Multipurpose JavaFx application shell abstraction&lt;/td&gt;
&lt;td&gt;10940&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/iroshell-examples&quot;&gt;iroshell-examples&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Example applications build on iroshell&lt;/td&gt;
&lt;td&gt;1444&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/textadventurelib&quot;&gt;textadventurelib&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Core library required to play the text adventure games&lt;/td&gt;
&lt;td&gt;25045&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/text-adventure-lib&quot;&gt;text-adventure-lib&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Javascript&lt;/td&gt;
&lt;td&gt;Javascript reimplemenation of textadventurelib&lt;/td&gt;
&lt;td&gt;7437&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/textadventurecreator&quot;&gt;textadventurecreator&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;The main application that created text adventure games&lt;/td&gt;
&lt;td&gt;55066&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In total, that is close to 115k lines of code split between Java and JavaScript.&lt;/p&gt;
&lt;p&gt;This breaks out into the following dependency graph.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/text-adventure-beginnings/tav-deps.png&quot; alt=&quot;Dependency graph&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Features&lt;/h3&gt;
&lt;p&gt;In the spirit of a fair analysis, I find it is useful to document all of the features wrapped up in this project. Much of this is documented on my personal site. As such, I will avoid repeating all of it. Instead, I will highlight some core features. If you are interested, the main documentation can be found &lt;a href=&quot;https://ilusr.com/textadventurecreator&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;high level details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Export as App&lt;/td&gt;
&lt;td&gt;Export&lt;/td&gt;
&lt;td&gt;The ability to export the game as a jar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Export as Web&lt;/td&gt;
&lt;td&gt;Export&lt;/td&gt;
&lt;td&gt;The ability to export the game as an html document&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Export as Electron&lt;/td&gt;
&lt;td&gt;Export&lt;/td&gt;
&lt;td&gt;The ability to export as an electron app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entity creation&lt;/td&gt;
&lt;td&gt;Core&lt;/td&gt;
&lt;td&gt;The ability to define players and NPC&apos;s/enemies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Macros&lt;/td&gt;
&lt;td&gt;Core&lt;/td&gt;
&lt;td&gt;The ability to replace text with some player details&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Game State creation&lt;/td&gt;
&lt;td&gt;Core&lt;/td&gt;
&lt;td&gt;The ability to define all actions and triggers in a game state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text Trigger&lt;/td&gt;
&lt;td&gt;Core-Triggers&lt;/td&gt;
&lt;td&gt;The ability to trigger some action on user text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timed Trigger&lt;/td&gt;
&lt;td&gt;Core-Triggers&lt;/td&gt;
&lt;td&gt;The ability to trigger some action on a timer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Player Triger&lt;/td&gt;
&lt;td&gt;Core-Triggers&lt;/td&gt;
&lt;td&gt;The ability to trigger some action based on player state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scripted Trigger&lt;/td&gt;
&lt;td&gt;Core-Triggers&lt;/td&gt;
&lt;td&gt;The ability to trigger based on some executed javascript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-part trigger&lt;/td&gt;
&lt;td&gt;Core-Triggers&lt;/td&gt;
&lt;td&gt;The ability to union multiple triggers together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Append Action&lt;/td&gt;
&lt;td&gt;Core-Actions&lt;/td&gt;
&lt;td&gt;Ability to add text to the game output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complete Action&lt;/td&gt;
&lt;td&gt;Core-Actions&lt;/td&gt;
&lt;td&gt;The ability to complete a game state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execute Action&lt;/td&gt;
&lt;td&gt;Core-Actions&lt;/td&gt;
&lt;td&gt;The ability to trigger a process on the users machine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modify Player Action&lt;/td&gt;
&lt;td&gt;Core-Actions&lt;/td&gt;
&lt;td&gt;The ability to change player state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Save action&lt;/td&gt;
&lt;td&gt;Core-Actions&lt;/td&gt;
&lt;td&gt;The ability to save the game&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Script action&lt;/td&gt;
&lt;td&gt;Core-Actions&lt;/td&gt;
&lt;td&gt;Any action that could be expressed in javascript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finish action&lt;/td&gt;
&lt;td&gt;Core-Actions&lt;/td&gt;
&lt;td&gt;The action that completed the game&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text and Input View&lt;/td&gt;
&lt;td&gt;Layout&lt;/td&gt;
&lt;td&gt;The base look and feel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text and Button View&lt;/td&gt;
&lt;td&gt;Layout&lt;/td&gt;
&lt;td&gt;A look and feel that replaces a text input with buttons&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content Only&lt;/td&gt;
&lt;td&gt;Layout&lt;/td&gt;
&lt;td&gt;A display only view for things like transition images or videos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom layout&lt;/td&gt;
&lt;td&gt;Layout&lt;/td&gt;
&lt;td&gt;A customizable grid layout of whatever controls you want for the game state, including custom styling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Libraries&lt;/td&gt;
&lt;td&gt;Libraries&lt;/td&gt;
&lt;td&gt;User defined exportable collections of players/actions/triggers or layouts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugger&lt;/td&gt;
&lt;td&gt;DevTools&lt;/td&gt;
&lt;td&gt;A crude debugger to see how playing the game changes the state in the IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language Packs&lt;/td&gt;
&lt;td&gt;Localization&lt;/td&gt;
&lt;td&gt;The ability for users to define their own localization to be used in the IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mods&lt;/td&gt;
&lt;td&gt;DevTools&lt;/td&gt;
&lt;td&gt;The ability for a developer to add a runtime loaded mod into the IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Lessons learned at the project level&lt;/h2&gt;
&lt;p&gt;A warning to the reader. Many of these lessons are based on the constraints and end state of this project. If this project had been worked on by a team of engineers, my perspectives would have been different. Remember that the end state of this project is that a solo developer built something that was unused but is now in the public domain.&lt;/p&gt;
&lt;h3&gt;Just because it&apos;s on GitHub doesn&apos;t mean anyone will notice&lt;/h3&gt;
&lt;p&gt;I think this is one lesson that I wish I had learned early on. There was a fair amount of time I spent scrambling to get the code &quot;ready for the public to view&quot;. I was concerned that once you put something on GitHub, everyone would see it. In reality, I think a handful of people have glanced at the landing page, then saw a sparse readme and moved on. The largest reader of my code may be some AI model trained on all public GitHub data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The most important lesson for me around this is that you can waste an immense amount of time expanding code coverage and documentation on a project.&lt;/strong&gt; If you are not working on a team and do not plan to market your work, the returns for high test coverage and documentation are questionable. The few exceptions to this would be critical or regression-prone code paths. Now, in modern times, this may be less of an investment because you could offload most of this work to an AI agent or otherwise. However, if you are going to do that, you should really scrutinize the output because it might not be documenting things correctly or testing things effectively. It is unclear to me if it is even worth the tokens or time to review to autogenerate these sorts of things for solo side projects. What is clear to me is that incorrect documentation or tests are worse than having no documentation or tests.&lt;/p&gt;
&lt;p&gt;As far as visibility goes, what I have come to assume is that if people are going to look at your project, they will have to be led to it via some sort of marketing on social media. If you want to capture your audience, you will want a strong README with flashy images to draw their attention. I have never taken the effort to market my work, so these assumptions may be incorrect.&lt;/p&gt;
&lt;h3&gt;Industry standards are highly contextual&lt;/h3&gt;
&lt;p&gt;In this case, I made a classic junior to mid-level engineering mistake. That is adopting the mindset that the industry standard is the best practice for all use cases. Since then, I have learned that industry standards are guidelines contextualized for engineering with many active engineers working on the same project, or for domain-specific reasons.&lt;/p&gt;
&lt;p&gt;Take, for instance, this project. I intentionally broke apart a monorepo into a series of small, targeted repositories without considering the tradeoff. In this case, I lost valuable time breaking apart a monorepo and incurred the cost of managing dependencies without getting observable benefits. Here are some cases that could have made the investment valuable, and why it remains a sunken cost.&lt;/p&gt;
&lt;h4&gt;Community involvement&lt;/h4&gt;
&lt;p&gt;I could have built a community around something like iroshell. This would have the benefit of many engineers helping me with my framework. This did not happen because I did not take an active effort to build a community. In a single instance, a developer reached out with an interest in a single part of the framework, and I chose not to engage with that engineer. If I had been truly interested in a community, I would have missed a real opportunity there.&lt;/p&gt;
&lt;h4&gt;Code Reuse&lt;/h4&gt;
&lt;p&gt;Another possible benefit I could have gotten was reuse. However, this reuse benefit would have depended on doing more Java projects that are built on iroshell, java-core, or logrunner. Instead, I have not started another Java project since this project&apos;s completion. This means I missed out on all of the hard work I put into making iroshell reusable for other possible applications.&lt;/p&gt;
&lt;h3&gt;Observing the problem space has its benefits&lt;/h3&gt;
&lt;p&gt;At no point during this work did I ever stop to look around at what other people had been doing. Had I done so, I would have found that there was already a pretty big community around tools very similar to the one I created. For instance, &lt;a href=&quot;https://twinery.org/&quot;&gt;Twine&lt;/a&gt; is a rather powerful tool that can do something very similar to what I created. I do not know that this would have deterred me from taking on this project. However, taking the time to read about the project could have given me a chance to see what features others like and some of the pain points. If I wanted to create a product that got traction, that was a missed opportunity to build for the community.&lt;/p&gt;
&lt;h3&gt;Not all features are worth the investment&lt;/h3&gt;
&lt;p&gt;There are a handful of features that were either premature or questionable. In particular, the “execute action” in the game engine itself is a feature that didn’t need to be made. I am still not sure what I thought the benefit would be. As it stands, its biggest purpose is a security risk. On the premature side, features like modding and libraries had been way too early. Without a community using the tool, there was no reason to create community tools like modding.&lt;/p&gt;
&lt;h2&gt;The highlights&lt;/h2&gt;
&lt;p&gt;So far, I have been very critical of all the work I have done. However, I would be remiss if I didn&apos;t point out the benefits. On the off chance a junior to mid-level developer finds the blog and reads it, I wouldn&apos;t want to give the impression that this was a completely wasted effort. While I may have some regrets about the features I chose to work on or the way I assumed the project would be received, it was a very valuable learning lesson, even from a techinical level.&lt;/p&gt;
&lt;h3&gt;Learning JavaFX&lt;/h3&gt;
&lt;p&gt;At the start of this project, my experience with Java UIs was small college projects using &lt;a href=&quot;https://en.wikipedia.org/wiki/Swing_(Java)&quot;&gt;Swing&lt;/a&gt;. At work, I was learning about C# and WPF, but those lessons had not been fully transferable. In this case, I learned how to build a framework, a UI, and auto-generated games all on top of JavaFX. I really enjoyed learning about JavaFX&apos;s use of CSS and using tools like &lt;a href=&quot;https://github.com/JonathanGiles/scenic-view&quot;&gt;ScenicView&lt;/a&gt;. While I have yet to use this knowledge in a professional setting, it was great fun to learn.&lt;/p&gt;
&lt;h3&gt;Installers&lt;/h3&gt;
&lt;p&gt;While I do not think I nailed the implementation, I did get to learn the basics of installers and the pain points of creating one. Up until this point, the software I wrote either had a team working on an installer or was just a jar/exe that someone else had to figure out how to run for themselves. In the modern era, with web-first and electron apps, this may be an irrelevant skill, but it helped remind me that different users have different machines, which may or may not have some of your prerequisites for your software to run.&lt;/p&gt;
&lt;h3&gt;It still works&lt;/h3&gt;
&lt;p&gt;With fairly minimal effort, I was able to come back to this years later and get the thing running again. The biggest pain points I had were the kinds that I expected. Mostly setting up my machine to build Java again by installing OpenJDK and Maven, as well as configuring Maven to install from GitHub.&lt;/p&gt;
&lt;h3&gt;Project completion&lt;/h3&gt;
&lt;p&gt;This was the first project I really got to play every possible role. I had the idea, oversaw all the technical decisions, implemented the entire project, designed the UX, and even did some terrible icon artwork to top it all off. I got to see this thing from a silly drawing in a notebook to a completed project that can still be used today.&lt;/p&gt;
&lt;p&gt;In this, I learned how to stick with something even when it gets hard or boring. There were days when I would get stuck on a technical issue that I couldn&apos;t find any great documentation online. On other days, I mind-numbingly drudged through just one more Javadoc comment.&lt;/p&gt;
&lt;p&gt;I cannot overstate how valuable that was to me. I find that when working at a company with a clear goal in mind, there are  trade-offs that must be made. As an engineer, those are not always to the benefit of your technical growth. You may want to spend time optimizing a routine or playing around with a new technology/framework/language. In many cases, doing this on the job is borderline negligent and not in the interest of the company you are working for. However, when you are working on a project that is yours without direct financial incentives, you are free to make whatever choices you want. The cost incurred, in money or in time, is on you, and you do not have to consider the cost to some company.&lt;/p&gt;
&lt;p&gt;In the modern era of AI, I am not sure if you could recreate this experience. For example, a new developer who needed an icon in a specific way might not try to draw it themselves. Instead, they might just ask an AI to generate it for them. AI can provide some excellent rubber ducking, which was just not possible when I attempted this project.&lt;/p&gt;
&lt;h2&gt;Digging deeper&lt;/h2&gt;
&lt;p&gt;By now, I have covered an exhaustive history of this application, with topics across the board. Now I want to dive deeper into the technical design choices. I will have some follow-up blogs about specific libraries and some of the technical design choices I made. This will focus on how I see those decisions now.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Evaluating past projects]]></title><description><![CDATA[Growth through reflection Lately, I have been busy with my day job, and the work I am doing on the side is not something I am ready to share…]]></description><link>https://ilusr.com/project-review/</link><guid isPermaLink="false">https://ilusr.com/project-review/</guid><pubDate>Fri, 02 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Growth through reflection&lt;/h1&gt;
&lt;p&gt;Lately, I have been busy with my day job, and the work I am doing on the side is not something I am ready to share publicly. This has left me wanting to share something, but unsure of what to share. After some consideration, I found that there is something I can write about without requiring the focus of a full public project.&lt;/p&gt;
&lt;p&gt;Spending some time looking at the work I have done in my spare time, I realized I am missing a key part of learning. In much of my work, I focus on generating a product or prototype to learn something new. Throughout this process, I have learned a fair amount through repeated efforts and failures along the way. However, I rarely go back and look at what I have done years later to reflect on what I did right or wrong. As of writing, I now have 51 source repositories on GitHub, and I think it’s about time to start reflecting.&lt;/p&gt;
&lt;h2&gt;Upcoming content&lt;/h2&gt;
&lt;p&gt;I intend to create a collection of blog posts about my past public projects on GitHub. In these blog posts, I intend to cover the following topics.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Loosely, why I started the project.&lt;/li&gt;
&lt;li&gt;The constraints I had on the project.&lt;/li&gt;
&lt;li&gt;An overview of using the project in its current state.&lt;/li&gt;
&lt;li&gt;A dive into how the project exists now. This would include topics such as code structure, architectural patterns, and other considerations.&lt;/li&gt;
&lt;li&gt;A reflection on what I like and dislike about the state of the project.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of these projects are big and will need to be split across several posts. I also do not intend to post regularly about this, and expect that there may be some blog posts focused on what I am learning with the other project I am not currently sharing publicly.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Web visualization]]></title><description><![CDATA[Visualizing the web So now we come to the end of our planned journey. If you have been following along so far, here is a quick recap. What…]]></description><link>https://ilusr.com/web-visualization/</link><guid isPermaLink="false">https://ilusr.com/web-visualization/</guid><pubDate>Sat, 27 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Visualizing the web&lt;/h1&gt;
&lt;p&gt;So now we come to the end of our planned journey. If you have been following along so far, here is a quick recap. What started off as a plan to work on a small project in Neovim ended with me doing all sorts of extra work. I have covered how I built a web crawler, an administrative application, and a PageRank implementation. With this done, we can explore the final visualization work I did.&lt;/p&gt;
&lt;p&gt;For this final stage, I created a standard search-based UI and another that was more interactive with visualizations.&lt;/p&gt;
&lt;h2&gt;Basic search&lt;/h2&gt;
&lt;p&gt;As a test, I pulled back out Rust and HTMX to build out a basic search page. This is a very simplified version of what you might have seen from Google, Yahoo!, or Bing. However, I decided to do one thing a bit differently. In this search page, I added some extra details.&lt;/p&gt;
&lt;h3&gt;With an inspection twist&lt;/h3&gt;
&lt;p&gt;While working with a crawler, I found that how pages connect to other pages and assets became an interest of mine. Due to this, I added a feature to see all links in a sidebar for a given page.&lt;/p&gt;
&lt;p&gt;Another feature that I decided to create was an inspection of the page. I was already downloading all the HTML, JavaScript, and CSS, so I figured it would be neat to see what I could get from those assets.&lt;/p&gt;
&lt;p&gt;For CSS, I got all the links I could find in the documents. Then I decided to list all of the classes, ids, and selectors used. I also decided to find all CSS functions that had been used.&lt;/p&gt;
&lt;p&gt;In the case of JavaScript, I decided to look for all properties and functions that had been used on the window and document. I also decided to gather every string that was defined because those strings can contain URLs.&lt;/p&gt;
&lt;p&gt;For HTML files, I started by grabbing all links. Then I pulled in all node types, attributes, ids, and classes used. Finally, I processed all inline JavaScript and CSS using the rules above.&lt;/p&gt;
&lt;p&gt;This work did require a bit of additional parsing in Rust. My prior experience with &lt;a href=&quot;https://en.wikipedia.org/wiki/Abstract_syntax_tree&quot;&gt;ASTs&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Visitor_pattern&quot;&gt;visitor patterns&lt;/a&gt; made this relatively easy to pick up on.&lt;/p&gt;
&lt;h2&gt;Interactive search&lt;/h2&gt;
&lt;p&gt;For the interactive search feature, I decided I would try something rather different. Originally, I wanted to create a large graph of all of the pages and their connections. However, I also really wanted to show how PageRank impacts the importance of pages. I didn&apos;t really think that would highlight the importance as much as I wanted. After some consideration, I landed on a visualization that was a collection of stars. Each star was the result of a search, and each star would have a size relative to its page rank.&lt;/p&gt;
&lt;p&gt;Soon after I got that working, I decided to do a couple of screen transitions. When you clicked on a star, you could explore the star. Exploring the star would switch to a different view. This exploration would show the search result as the center of a solar system. This solar system would contain all of the pages it linked to. On that page, you could either follow a planet and see its links, or you could explore the planet. If you explored the planet, you would see all of the assets the page used and the relative footprint of the asset on the page. For example, if a page had 10 images, each 10KB in size, and one JavaScript file 1MB in size, you would see 11 elements with the JavaScript one being larger than the others.&lt;/p&gt;
&lt;h3&gt;Tooling for visualization&lt;/h3&gt;
&lt;p&gt;While I kept the Rust backend, I completely dropped HTMX from the equation. Instead, I did all of this visualization by drawing on a 2d canvas. Now, when I say I drew to a 2d canvas, I mean I did this only using the native browser API with no library on top of it. I decided to forego the use of any build step for this page. Instead, I just used the ESM import style of the document. I found it very nice to have the benefit of multiple JavaScript files and ESM import styles without needing a build step or any JavaScript libraries.&lt;/p&gt;
&lt;h3&gt;Building on canvas is different&lt;/h3&gt;
&lt;p&gt;When you start drawing directly on a canvas and building interactive features manually after doing typical web development, you start to see things other developers already know. I am sure most developers working on games, browsers, or operating systems already know everything I found in far better than I do.&lt;/p&gt;
&lt;h4&gt;Elements and Controls are an abstraction&lt;/h4&gt;
&lt;p&gt;You don&apos;t need HTML elements or common controls for interactivity. While you get benefits like accessibility for using the DOM correctly, you don&apos;t actually need a button element to make a button. Instead, you could draw a rectangle and put some text in the center. Then you can watch the mouse events and determine if the mouse is hovering over an element or pressing an element. In these cases, you can just draw a different state in the button.&lt;/p&gt;
&lt;h4&gt;Behaviors require consideration&lt;/h4&gt;
&lt;p&gt;I alluded to this before, but handling a hover or a click requires careful consideration of the current mouse position and state. The more complex the shape gets, the harder it is to determine if the mouse is within the element. Concepts that seem simple, like word wrapping or truncation, require careful measuring of the text and the size of its container. Most web developers take all of this for granted. You can easily apply CSS rules and not even think twice about what needs to be done to make a hover event trigger correctly on both a square and circular button.&lt;/p&gt;
&lt;h4&gt;Trigonometry is everywhere&lt;/h4&gt;
&lt;p&gt;While it could have been my application of the canvas, I found that I was constantly having to write code that required trigonometry. I kept finding cases where I would have to plot some visualization along some arc. I would constantly find myself pulling out trigonometry to create certain visualization effects.&lt;/p&gt;
&lt;p&gt;After spending so much time doing traditional web development, it is easy to forget just how much math is done in the layers of abstraction you are building on.&lt;/p&gt;
&lt;h3&gt;Reflecting on the process&lt;/h3&gt;
&lt;p&gt;I found this to be radically different from what I had been doing for so long and had a blast doing it. However, I never quite accomplished the effect I was after. One aspect of this was that I didn&apos;t really have good images for the stars or the planets. I think with some better images or spritesheets I could produce a much better effect. I also didn&apos;t really consider adding the aspect of a camera with a viewpoint. I think adding this element would have allowed for some more interesting searching experiences when looking at some of the scenes.&lt;/p&gt;
&lt;p&gt;That being said, while I had a lot of fun doing it, I doubt I would ever use a canvas for a commercial-grade project. While I learned a lot, using semantic HTML has benefits. The most notable being accessibility. I do not even begin to pretend to know how you could make a site that only uses a canvas usable for someone who couldn&apos;t see.&lt;/p&gt;
&lt;h2&gt;And so it ends&lt;/h2&gt;
&lt;p&gt;If you have read this blog and all the blogs before it, thank you. While I doubt I have provided any additional insights for anyone who may have read this, I found that some of what I was doing was a touch out of the norm. I had a lot of fun doing this, but there are other interests I have wanted to explore for some time now.&lt;/p&gt;
&lt;p&gt;Forgive me for a moment while I get on my soapbox. I have not explicitly stated this up to now, but I would like to emphasize a choice I made during this project. During this project, I limited my use of AI to general research and as a springboard to more official documentation. I find that while using AI for your day job is a great idea, to truly learn new things it is beneficial to go back to the basics and avoid letting AI do everything for you. I would definitely encourage others who are writing code to learn new concepts  to be diserning about how they are incorporating AI.&lt;/p&gt;
&lt;p&gt;I do not know how long this project will be hosted; as such, I will finish by providing some images in case I take down the site due to cost, lack of interest, or something else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Basic Search&lt;/strong&gt;
&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/web-visualization/standard-search.png&quot; alt=&quot;Basic Search View&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interactive Search&lt;/strong&gt;
&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/web-visualization/graph-view.gif&quot; alt=&quot;Interactive Search View&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Figuring out Page Rank]]></title><description><![CDATA[Figuring out what is important By now, we have built a functioning web crawler and even generated some administrative tooling to make…]]></description><link>https://ilusr.com/page-rank/</link><guid isPermaLink="false">https://ilusr.com/page-rank/</guid><pubDate>Sun, 21 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Figuring out what is important&lt;/h1&gt;
&lt;p&gt;By now, we have built a functioning web crawler and even generated some administrative tooling to make crawling easier. Now the problem is we don&apos;t really know what data is important. This is not a new problem, and research has been conducted on this. The most notable research in this field would be &lt;a href=&quot;http://ilpubs.stanford.edu:8090/422/1/1999-66.pdf&quot;&gt;Bringing Order to the Web&lt;/a&gt;. In this paper, the concept of a page ranking system was proposed. This is where my curiosity took me next, so I began to fumble through figuring it out.&lt;/p&gt;
&lt;h2&gt;A brief aside&lt;/h2&gt;
&lt;p&gt;This is the part where I am glad I am writing a series of blog posts despite the fact that I will likely be the only one to read them. Going into this blog entry, I assumed I had taken notes on implementing page rank. I also assumed I had implemented it correctly. Over the past few days, I found that I was very wrong on this, and I only found that out because I wanted to create this entry.&lt;/p&gt;
&lt;h2&gt;Bringing Order to the Web&lt;/h2&gt;
&lt;p&gt;Back in 1998, Sergey Brin and Larry Page wrote a paper on how to address this issue. Why I didn&apos;t read this on my first attempt to implement, I have no idea. This paper not only explains how to determine which pages are important, but it also covers some of the challenges of crawling the web, many of which I encountered. In this paper, they discuss how to approach the problem and elaborate on some applications of the algorithm in two different search engines.&lt;/p&gt;
&lt;p&gt;The key insight behind the PageRank algorithm is that any given pages importance can be derived from the importance of all page&apos;s that link to it.&lt;/p&gt;
&lt;h3&gt;The difficulty with links&lt;/h3&gt;
&lt;p&gt;The primary focus of the algorithm is on so-called backlinks. The problem with backlinks is that it&apos;s impossible to know if you have all the backlinks to a page. Instead, you can only tell the forward links for a page. If you could effectively gather every page, then you could produce a proper graph with the correct backlinks. However, since the content on the internet is constantly changing, you can only ever work on a partial subset of the internet. Because of this, certain considerations had been made that could make the algorithm more effective.&lt;/p&gt;
&lt;h3&gt;The algorithm&lt;/h3&gt;
&lt;p&gt;I will spare you the formal notation of the algorithm; if you are interested in that, I suggest you read the paper. Let&apos;s walk through the algorithm. The first step is to build an adjacency matrix of all pages and their edges. In this paper, they suggested building an N by N matrix where all values are either 0 or 1. This bit would correlate to the existence of an edge. Also, in this matrix, the N value is all of the known pages on the internet. After this is done, we need to normalize the matrix such that each page is sending an equal weight to all of its links. Once this is done, we generate a random vector of size N as our starting point. We then repeatedly multiply the vector by the normalized adjacency matrix until it converges.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/page-rank/page_rank_algo.gif&quot; alt=&quot;Page Rank Algorithm&quot;&gt;&lt;/p&gt;
&lt;p&gt;The property of convergence comes from the fact that this is an eigenvector problem. If you are more interested in the mathematics of this problem, I suggest reading more about &lt;a href=&quot;https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors&quot;&gt;eigenvectors&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Markov_chain&quot;&gt;Markov chains&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Additional considerations&lt;/h3&gt;
&lt;p&gt;This paper explores additional considerations for this algorithm. The most notable ones are dangling references and the personalization vector.&lt;/p&gt;
&lt;h4&gt;Dangling references&lt;/h4&gt;
&lt;p&gt;One problem with this algorithm appears when a page has no outbound links. In this case, the page ends up being a bit of a rank sink. Generally, when this happens, it&apos;s not because the page doesn&apos;t link to anything, but rather that the page has not been processed yet. To manage this, the suggestion is to remove dangling references from the original calculation and then add them back in later with some initial value.&lt;/p&gt;
&lt;h4&gt;Personalization Vector&lt;/h4&gt;
&lt;p&gt;Another issue with search is contextualization. The example given in this paper is someone searching for &quot;wolverine&quot;. The additional context here is that wolverine is or maybe was an administrative tool used by students at Michigan University. When the typical person searches for wolverine, they would expect to find more details about the animal. However, when a student at Michigan University does the same search, they might be interested in the tool. The suggestion proposed in this paper is that we could create personalization vectors that get added to the equation to make one of the search contexts more likely for the given person.&lt;/p&gt;
&lt;h2&gt;Looking at an example&lt;/h2&gt;
&lt;p&gt;Now that I have covered the algorithm, I find it&apos;s best to see it applied on a smaller scale. Below is an animation that shows how a small internet with 4 pages and 5 links would propagate rank. This only shows one transformation, and many more of the same operation would happen in practice.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/page-rank/graph_example.gif&quot; alt=&quot;Page Rank Example&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Examining some implementations&lt;/h2&gt;
&lt;p&gt;I also find it helpful to see how others have implemented the solution. The following are a couple of implementations publicly shared on Github that I used to better understand how others have implemented this algorithm.&lt;/p&gt;
&lt;h3&gt;Memgraph&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://memgraph.com/&quot;&gt;Memgraph&lt;/a&gt; is a graph-based database written in C++. It is common for graph databases to provide functionality like PageRank out of the box because it is a clear graph algorithm. While I will not cover its implementation, another popular graph database that provides this functionality would be &lt;a href=&quot;https://neo4j.com/&quot;&gt;Neo4j&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The majority of the interesting parts of the code can be found &lt;a href=&quot;https://github.com/memgraph/mage/blob/main/cpp/pagerank_module/algorithm/pagerank.cpp&quot;&gt;here&lt;/a&gt;. In this implementation, a few optimizations are added to the original algorithm. The first optimization is building a coordinate list instead of a square matrix of all nodes. So instead of having a data structure like this&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;we could instead have this&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The second optimization that was applied was the use of parallel execution. In the Memgraph implementation, each cycle of the vector by matrix multiplication step is broken up amongst the cores available for execution. Meaning the multiplication is split into batches. Those batches are executed in parallel and then finally merged back together in a final pass.&lt;/p&gt;
&lt;h3&gt;NetworkX&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://networkx.org/documentation/stable/index.html&quot;&gt;NetworkX&lt;/a&gt; is a Python library for handling network-related algorithms. This appears to align a bit more with the academic side of this topic. The implementation of the algorithm can be found &lt;a href=&quot;https://github.com/networkx/networkx/blob/main/networkx/algorithms/link_analysis/pagerank_alg.py&quot;&gt;here&lt;/a&gt;. This algorithm can run on &lt;a href=&quot;https://scipy.org/&quot;&gt;SciPy&lt;/a&gt; or &lt;a href=&quot;https://numpy.org/&quot;&gt;NumPy&lt;/a&gt;. My research mainly focused on the SciPy implementation. For the most part, this was very similar to the Memgraph implementation with some notable differences. One of the differences was that there was no explicit multithreading. All operations were done using matrix operations on SciPy classes. Since I have not investigated how SciPy handles aspects like the &lt;code&gt;@&lt;/code&gt; operator, it is entirely possible that under the covers, these matrix operations happen in parallel.&lt;/p&gt;
&lt;p&gt;One thing I found interesting was how true to the paper this algorithm was in how it was expressed. It worked on matrix multiplication of adjacency graphs. The bulk of the operation can be summed up in this line of Python.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; alpha &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x @ A &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;is_dangling&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; dangling_weights&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; alpha&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; p&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case, A is the adjacency matrix, but it is actually a coordinate graph in its storage. We will also notice that in this implementation, dangling nodes are handled, and they introduce the personalization vector &lt;code&gt;p&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Trying it out myself&lt;/h2&gt;
&lt;p&gt;Even though modern search engines have moved far beyond just using a page rank algorithm, it was a lot of fun for me to explore this. This was one of a few times when I actually got to read a white paper. Since so much of this for me had been for learning, I actually created my own implementation of PageRank. My goal was not to be efficient but to fully understand it, so I even hand-rolled the matrix multiplication logic. I have been timing my implementation, and at the current scale I am testing with, the bottleneck is certainly the time to crawl all pages. Also, in my implementation, I do a crazy inefficient scan of pages to build the initial adjaceny matrix. I suspect I will optimize that as needed instead of reaching for one of these libraries to do the trick.&lt;/p&gt;
&lt;p&gt;By now, we have covered basically all of the back-end processing and collection I planned on covering. Going forward, I will take some time to talk about some of the searching UI&apos;s and visualizations I put on top of this data.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Build admin site for crawler]]></title><description><![CDATA[So you want an intro? If you have been following along by now, you know that I have been working on a search project and have covered what…]]></description><link>https://ilusr.com/search-admin/</link><guid isPermaLink="false">https://ilusr.com/search-admin/</guid><pubDate>Sun, 24 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;So you want an intro?&lt;/h1&gt;
&lt;p&gt;If you have been following along by now, you know that I have been working on a search project and have covered what it took to make a crawler. If you are interested, stop now and read the &quot;Indexing the web&quot; blog post.&lt;/p&gt;
&lt;h1&gt;Building an admin app&lt;/h1&gt;
&lt;p&gt;By now, I had built a Python script that would crawl the web and put some data into a SQLite database. The problem was that the amount of command line arguments was growing. Also, I was often modifying the database directly between runs.&lt;/p&gt;
&lt;p&gt;To deal with this, I setteled on creating a very basic administrative style application. This application would handle setting the domain policy, setting the download policy, and would show some insights on the data crawled so far. Eventually, this was extended to trigger runs of the crawling script. Since I have no plans of writing much about that, what ended up happening there was a minor refactor to the Python script to also run as a &lt;a href=&quot;https://flask.palletsprojects.com/en/stable/&quot;&gt;flask&lt;/a&gt; application which allowed you to trigger and view pervious runs of the crawler.&lt;/p&gt;
&lt;p&gt;As was the theme with this project, I wanted to learn something new. I could have done something comfortable and built this web application in a front-end framework I use often, like React or Angular. However, instead of doing that, I decided it was time to give HTMX a go. Also on the back-end, I could have done the same using something like Node.js, Java, or .Net core, but instead I decided to pick up Rust again.&lt;/p&gt;
&lt;h1&gt;Picking a front-end framework&lt;/h1&gt;
&lt;p&gt;One thing I was paying close attention to while working on this project was the amount of JavaScript that was on the web. I knew that for a very boring administrative app with no major features, there would be no reason to have a lot of JavaScript, as the amount of interactive features would be low. I also have noticed that even &quot;libraries&quot;, because some might get angry if I call it a framework, like React, seem to be growing in bundle size without end.&lt;/p&gt;
&lt;h2&gt;The sales pitch&lt;/h2&gt;
&lt;p&gt;I had heard the pitch for HTMX in the past. The following is a quick summary, as best as I could remember it. Back before AJAX and Web 2.0, we got along just fine. There was just one problem: fetching net new data required a full page load. To deal with this, a lot of work was done to optimize performance by effectively mangaging DNS, HTTP headers, and document size. After Web 2.0, we had a new shiny tool for handling this, and we used it for everything. Along the way, we lost sight of what hypertext media should have been. Basically, we started off strong with the anchor and form tags, but hypertext media failed to deliver more features. The web didn&apos;t have to be this way, so the creators of HTMX set out to make hypertext media what it should have been. Somewhat paradoxically, they did this by creating a JavaScript library. One might hope that if their project is successful that the hypertext media primatives that HTMX attempts to establish just become part of the browser implementation.&lt;/p&gt;
&lt;h2&gt;But what the heck does that even mean?&lt;/h2&gt;
&lt;p&gt;So, apparently, Web 1.0 and hypertext media are a good thing, but what does it mean to expand that feature set? I would summarize it as making better use of DOM attributes to control document behavior. Outside of loading a JavaScript file, most of what HTMX does is add new special attributes to DOM nodes. All of these attributes are prefixed with &lt;code&gt;hx-&lt;/code&gt;. The types of things that these new attributes allow you to do are attach behaviors to DOM nodes. For example, you might want to say, when a user clicks a button, make a GET request and put the body in some other area. In a framework like Angular, this might look something like this&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;@&lt;span class=&quot;token function&quot;&gt;&lt;span class=&quot;token maybe-class-name&quot;&gt;Component&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token string-property property&quot;&gt;&apos;selector&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;my-super-cool-search&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token string-property property&quot;&gt;&apos;template&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
       &amp;lt;input type=&quot;text&quot; [(ngModel])=&quot;searchText&quot; [keyup.enter]=&quot;doSearch()&quot; /&gt;
       &amp;lt;div&gt;
         Resulting data: {{randomData()}}
       &amp;lt;/div&gt;
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword module&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MySuperCoolComponent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;httpClient&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token maybe-class-name&quot;&gt;HttpClient&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token maybe-class-name&quot;&gt;HttpClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; randomData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; signal&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; searchText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; signal&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doSearch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;httpClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/api/so-cool/search?q={this.searchText()}&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;randomData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What we will notice is that it is just a small subset of the total code required to make this happen. There is a whole lot of setup and other components that may be required just to be able to use this component. Also, a compile step is required to do this very simple task. In the realm of HTMX, this might instead look something like this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;hx-get&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;q&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;hx-trigger&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;keyup[key==&apos;Enter&apos;]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;hx-target&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#result-area&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;hx-swap&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;innerHtml&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;result-area&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;path/to/htmx.min.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, using HTMX basically makes all the JavaScript disappear and gets rid of a build setup. The downside is that it comes with the requirement that you learn a new set of attributes and their behavior. The one thing here that took me a while to fully come to terms with was the target and swap. The target is the DOM node that will be impacted by some action, and the swap is what will change. So, in this case, when you press enter you set the innerHtml of the result-area div with the contents from the API call.&lt;/p&gt;
&lt;h2&gt;But doesn&apos;t that change my back-end?&lt;/h2&gt;
&lt;p&gt;It is true that a front-end that uses HTMX is not a rip-and-replace framework. HTMX works a lot like how JSP and Ruby on Rails work. JSON is dead, and HTML is back. This means that in order to effectively use HTMX, you will either have to write your application with this in mind or create some sort of proxy API server or translation layer on your existing back-end.&lt;/p&gt;
&lt;p&gt;I would argue that this comes with some benefits and some drawbacks. The benefit is in some ways, debugging the DOM gets a bit easier. No longer will you have to look at how the mess of JavaScript you have created to understand how it converts JSON into DOM nodes. On top of this, HTTP headers around cache control can be even more impactful. On the drawback side, one thing that JSON did was make it easier to have multiple clients for the same API. Going all in on HTML as a transport can impact non-web clients, for example, a mobile application that uses native rendering.&lt;/p&gt;
&lt;h2&gt;There are some weird things in the browser specification&lt;/h2&gt;
&lt;p&gt;One of HTMX&apos;s greatest strengths is also one of its weaknesses. One thing modern frameworks do very well is paper over some of the rough edges of the browser specification. While the browser specification is getting better, there are still some rough areas in there. In my case, the one that threw me for a loop was posting a form with a checkbox in it. As it turns out, I am not the only person who encountered this issue, and there is an issue that documents it well in HTMX &lt;a href=&quot;https://github.com/bigskysoftware/htmx/issues/894&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Jumping over to the back-end&lt;/h1&gt;
&lt;p&gt;I have used Rust in the past for a couple of things, but I have never used it for a web server. While I know it is often considered the &quot;systems programming language,&quot; I figured there had to be a few more people out there who wanted to use it for a web server. After doing a bit of research,I stumbled on &lt;a href=&quot;https://actix.rs/&quot;&gt;Actix&lt;/a&gt;, which appears to be a popular Rust framework for doing web development.&lt;/p&gt;
&lt;h2&gt;But why Rust?&lt;/h2&gt;
&lt;p&gt;As will always be the theme with this project, it was to learn more. While it is true I had used Rust in the past, it was never for anything of substantial scale. Since all of the previous uses I had for it had been so small, I hadn&apos;t had the opportunity to learn as much about it as I wanted. Also, strangely, while it can be a rather infuriating language to work with, I do quite enjoy using it.&lt;/p&gt;
&lt;h2&gt;Doubling up on front-end frameworks&lt;/h2&gt;
&lt;p&gt;To say I was just using HTMX is a bit of a lie. On the back-end I was also using the rendering framework &lt;a href=&quot;https://keats.github.io/tera/docs/&quot;&gt;tera&lt;/a&gt; to do some basic HTML templating before sending the HTML off to the client. Tera is a Jinja2 and Django-compliant templating framework. In hindsight, I am not sure that I really needed this framework as my template substitutions had been so small.&lt;/p&gt;
&lt;p&gt;One issue I ran into pretty early on was that my &lt;a href=&quot;https://github.com/rwf2/Rocket/issues/163&quot;&gt;templates had been cached&lt;/a&gt;. Turns out, when using tera you have to restart your server every time you make a change to any HTML template. This caused the turn around time to debug issues to be longer than I am accustom to. Also, since I had never really used Django, I found myself struggling with some of the syntax and concepts. For example, checking the length of an array being &lt;code&gt;| length&lt;/code&gt; was something that took me some time to figure out.&lt;/p&gt;
&lt;h2&gt;Crates, crates everywhere&lt;/h2&gt;
&lt;p&gt;Package managers are a blessing and a curse. What I found is that Rust, in some ways, has the same issue as Node.js. Since there is a module system and it&apos;s very easy to use, there are a ton of modules of varying degrees of quality. Also, because there are so many modules you can kind of cheat on learning the language by cobbling together a ton of modules that solve the hard problems. I used quite a few modules on this project, and I don&apos;t think I could have done it all without some of them. That being said, I do think I would learn even more about the language if I would try to further limit my crate usage in the future.&lt;/p&gt;
&lt;h2&gt;Documentation is hard&lt;/h2&gt;
&lt;p&gt;I am not sure if this is a personal issue or if this is a general issue in Rust. In other languages, I have been pretty easily able to understand a majority of the concepts a package provides just by reading the documentation. Yes, I would inevitably pull open the source to understand a few things, but that was rare. However, in Rust, I constantly found myself looking at the documentation, getting confused, trying something out, reading the documentation again, just to ultimately end up looking at the source code to figure out what the heck is going on.&lt;/p&gt;
&lt;p&gt;I am not sure if others in Rust have found the same thing or if I just haven&apos;t figured out the art of reading the Rust documentation sites. An alternative possibility is that I do not have enough experience in the ecosystem to know that I am choosing some questionable crates. Regardless of the reason this was, this was the single thing that I found to be the hardest about working in Rust.&lt;/p&gt;
&lt;h2&gt;Now what about Docker?&lt;/h2&gt;
&lt;p&gt;Towards the later stages of what I was working on, I found it a bit annoying to have to start three apps and maintain them locally. Because of this, I switched over to using docker-compose to run my applications. However, in order to use docker-compose, you have to put your applications in a docker container. Doing this took a bit more time than I was used to. In many cases, I would just extend from some base language specific image like Go or Python and layer on the stuff I needed. In the case of Rust, I found this harder to do. In the end, I had to use two FROM statements, which I didn&apos;t even realize was an option. The first FROM would pull a Rust builder and build the asset. In the second FROM it would actually create the final image with the runtime and the program.&lt;/p&gt;
&lt;h1&gt;Looking forward&lt;/h1&gt;
&lt;p&gt;By this point, we have created a functional crawler in Python and an app to administer it using HTMX and Actix. This is a good start, but at this point, there is nothing to really play with. All of the data is in tables on a database, and there are no searching or visualization methods for this data. While we could talk about that next, we are going to take a breif detour to talk about page rank in the next post.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Indexing the web]]></title><description><![CDATA[Taking stock If you are just jumping into this blog post, I would highly recommend reading the "Journey into search" blog I posted before…]]></description><link>https://ilusr.com/search-indexing/</link><guid isPermaLink="false">https://ilusr.com/search-indexing/</guid><pubDate>Fri, 22 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Taking stock&lt;/h1&gt;
&lt;p&gt;If you are just jumping into this blog post, I would highly recommend reading the &quot;Journey into search&quot; blog I posted before this one. This helps set the tone for what I am talking about here. If you don&apos;t have time for that and want a quick recap, here it is. Basically, I ended up starting a &quot;little&quot; side project to get used to using a terminal-based editor and fell down the deep rabbit hole that is search. Moving forward, I am digging into the first topic, indexing the web.&lt;/p&gt;
&lt;h1&gt;Indexing the web&lt;/h1&gt;
&lt;p&gt;The internet is full of interesting data; you just have to go out and find it. Now, Most of us don&apos;t think much about that because we let companies with lots of money find the interesting data for us. This turns into companies like Microsoft, Google, Meta, and at one point in time, Yahoo and AltaVista having a lot of indexed data. Now, I am sure most are probably aware of that, but what does it actually take to build and maintain these indexes?&lt;/p&gt;
&lt;p&gt;This became a decent part of what I spent my time doing when working on my little search project.&lt;/p&gt;
&lt;h1&gt;Compiling assumptions&lt;/h1&gt;
&lt;p&gt;Often, when going after projects like this one, I start by setting up some assumptions. I like to see how far off my assumptions are from the ground truth.&lt;/p&gt;
&lt;h2&gt;Setting the scope&lt;/h2&gt;
&lt;p&gt;Before listing the assumptions, the following are some basic plans going into this project. I was going to write a web crawler. This web crawler was going to be written in Python. I chose Python because I had used beautifulsoup4 in the past and found it rather effective for parsing html documents. Then I would use SQLite to store the data because that would be the fastest option to bootstrap this.&lt;/p&gt;
&lt;h2&gt;Assumptions going in&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;SQLite will be insufficient for the volume and scale of data.&lt;/li&gt;
&lt;li&gt;Most time will be spent waiting on HTTP responses.&lt;/li&gt;
&lt;li&gt;5% or less of the traffic I will encounter will be SPAs.&lt;/li&gt;
&lt;li&gt;The Average main asset (HTML file) will be between 15 and 50kb.&lt;/li&gt;
&lt;li&gt;The initial attempt will miss many links because other linking strategies than anchor tags will be used.&lt;/li&gt;
&lt;li&gt;99% of sites will have more than 1kb of Javascript.&lt;/li&gt;
&lt;li&gt;The Average size of css will exceed 3kb.&lt;/li&gt;
&lt;li&gt;The total execution time will be less than a day to start.&lt;/li&gt;
&lt;li&gt;The total db size will be over 1gb on disk (.db file).&lt;/li&gt;
&lt;li&gt;The total number of unique domains will be between 100 and 500.&lt;/li&gt;
&lt;li&gt;The most linked site will be Wikipedia.&lt;/li&gt;
&lt;li&gt;90% of all pages will use compression.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Constraining the problem&lt;/h1&gt;
&lt;p&gt;Now I knew going into this that I was just going to run a Python program on my local computer. I also knew there was way too much data on the internet to possibly get a program to complete. Because of this, I had to constrain the problem a bit. What I landed on was that I would point my crawler at a domain and then restrict the crawler activity to only that domain.&lt;/p&gt;
&lt;p&gt;Since many of my assumptions had not been limited to HTML, I also knew that I would have to consider all types of assets, not just HTML pages.&lt;/p&gt;
&lt;p&gt;To deal with this, I landed on using different policies for different domains. Since these metrics by themselves are only interesting if you can get a couple of different domains involved, the domains would either be crawled, read, or blocked.&lt;/p&gt;
&lt;h1&gt;Site selection&lt;/h1&gt;
&lt;p&gt;Now it was time to start writing some code and running some tests. The problem was I wasn&apos;t really sure what to crawl. I knew if I wanted diverse content, I would want to crawl Wikipedia, but there was no way I was going to be able to crawl all of Wikipedia. Since I lack originality and spend a good amount of my time listening to podcasts about software, I figured that would be a good place to start.&lt;/p&gt;
&lt;p&gt;A majority of the podcasts I listen to often have their own websites, and I figured that would be a relatively smaller dataset. I eventually came to find out that not all podcasts are treated equally, and some have a shocking amount of content. While I indexed a handful of sites in my testing, I will primarily focus on my findings when indexing &lt;a href=&quot;https://changelog.com/&quot;&gt;the changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;And so the learning begins&lt;/h1&gt;
&lt;p&gt;To get started, I figured I would focus on crawling the changelog; this ended up being a mistake. Going into this, I didn&apos;t realize just how much content was on the changelog. I also didn&apos;t realize just how many different linking strategies they used and just how many domains they owned. Let&apos;s take a journey through all the dumb mistakes and self-inflicted challenges I had during this time.&lt;/p&gt;
&lt;h2&gt;Href be crazy&lt;/h2&gt;
&lt;p&gt;Even if you just constrain links to href attributes on an anchor tag, it turns out that one string has a ton of possibilities. If you get this wrong, you might hit a bunch of dead links because you forgot that hrefs can be relative or absolute. Also, you may forget that you can link to a different part of a page using a &lt;code&gt;#&lt;/code&gt; in the link and either fail to process that page, or even worse, process the same page a ton of times.&lt;/p&gt;
&lt;h2&gt;Assets are hiding everywhere&lt;/h2&gt;
&lt;p&gt;Given the original assumptions, I needed to figure out things like the total JavaScript used. One way to measure this would be to just look at the script tags with a source and measure those. However, that wouldn&apos;t be very accurate because JavaScript on a page might be coming from an external source or embedded in the document itself. For example, you could have a script tag with a body or with a src attribute. Likewise, you have similar problems with CSS.&lt;/p&gt;
&lt;p&gt;To deal with this, you end up having to consider all sorts of fun ways that JavaScript and CSS can get loaded and used on a page.&lt;/p&gt;
&lt;p&gt;Now this could have been the end but instead I started to think about the other supporting assets. What about the images, JSON files, XML files, and audio files? I might as well download and inspect those too, right? In the end, I think the only file types I didn&apos;t actively look for were video files. To support all of this content type, I ended up having to do massive refactors to my program, but it was worth it or at least that is what I kept telling myself.&lt;/p&gt;
&lt;h2&gt;You wanted that data compressed?&lt;/h2&gt;
&lt;p&gt;Just because a site supports compression doesn&apos;t mean you are going to get compressed content. One of the things I was noticing while looking at my data was that the bytes just didn&apos;t add up. I would go to a site in a browser and use the network inspector, and come up with a completely different number than my crawler. For some reason, my crawler had always downloaded more bytes. How could that be? Turns out that those HTTP headers you often forgot about are very important. Also, Python&apos;s default HTTP client doesn&apos;t help you fall into the pit of success. It is on you to make sure you set that &lt;code&gt;Accept-Encoding&lt;/code&gt; header and also handle any encodings you claim to handle. From what I have seen, the most popular types of encoding are &lt;code&gt;brotli&lt;/code&gt; and &lt;code&gt;gzip&lt;/code&gt;, so I added support for those, and the numbers started tying out.&lt;/p&gt;
&lt;h1&gt;Did I forget to mention performance?&lt;/h1&gt;
&lt;p&gt;What I have neglected to tell you is that through all of these learnings, my crawler was crashing after very long runs. You know how I mentioned the dataset was large, well, that large dataset was causing me to crash a lot, but very slowly. I would start up a run, do something else, and come back to a crashed app hours later. Then I would have to play detective to see what went wrong. Most of the time, it was silly design decisions I made.&lt;/p&gt;
&lt;h2&gt;You don&apos;t always have to query small data&lt;/h2&gt;
&lt;p&gt;While this did not end up being a substantial issue, I quickly found out that I was constantly reading the same data from the SQLite database. This data was largely asking the question &quot;Have I seen this URL yet?&quot;. In these sorts of crawl patterns, you will often end up finding links back to sites you have already processed. Because of this, I ended up adding a little cache of previously processed URLs and saw a small speed boost.&lt;/p&gt;
&lt;h2&gt;Massive columns are bad&lt;/h2&gt;
&lt;p&gt;I knew this was a bad idea going into the first database design; I just didn&apos;t know how bad. In the first version of the database schema, I dumped the entire site HTML into a single column as a raw string. No compression, no special treatment. This was causing me to get databases as big as 3GB before crashing. Doing the sensible thing and saving that content to a file and having a column that stored the file path made a massive diffrence.&lt;/p&gt;
&lt;h2&gt;Writes don&apos;t always have to be small&lt;/h2&gt;
&lt;p&gt;By this point, I had made some notable improvements to the performance, but things had still been way slower than I wanted them to be. One thing I was not paying attention to initially was just how often I was writing the database. Turns out that when you are constantly writing to the database as you process each page, you have a lot of small writes. Doing some batching of these writes made the process much quicker.&lt;/p&gt;
&lt;h2&gt;Absurd memory usage&lt;/h2&gt;
&lt;p&gt;By this point, I had solved many of the obvious database issues, but now a new issue was starting to crop up. After running for a while, the process would start to slow down a lot, and the memory was growing. At one point, I got the process up to 30GB of RAM in use before the program crashed. At first, I noticed that I wasn&apos;t quite using the http client correctly, but even addressing that was still causing an absurd amount of memory to be used. After figuring out how to profile in Python, I found that almost all of the memory was being used up by beautifulsoup4.&lt;/p&gt;
&lt;p&gt;The process I had been using up to this point was a very naive approach. First, I would get a page and process it. Then I would find all of its links. Then I would repeat the process on the newly found pages that had not already been processed. These pages would be classes that had a property for the beautifulsoup4 content. You could imagine the code as something like the following&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;crawl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pending_links&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    new_links &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; link &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; pending_links
        &lt;span class=&quot;token comment&quot;&gt;# Process link&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Add to new_links&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;new_links&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        crawl&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;new_links&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you may be able to imagine, after a certain point, you get very large lists of pages to process that all have to be completed before getting reclaimed. What I ended up doing to address this was as simple as doing an iteration by popping off a list instead of doing a foreach style enumeration. Creating something closer to this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;crawl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pending_links&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    new_links &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pending_links&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        link &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pending_links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pop&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Process link&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Add to new_links&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;new_links&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        crawl&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;new_links&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Python has threads&lt;/h2&gt;
&lt;p&gt;By this point, I had finally had a successful run, but processing one of the sites I wanted to ended up taking 4 days to complete. This was not optimal. Up until this point, I was doing everything in a single thread on a single process. As you can imagine, reading all of this data this way takes a very long time. In order to speed this process up, I started using Python&apos;s thread pool feature. This made things much faster, but I found Pythons memory management cross-thread/process to be quite frustrating to deal with.&lt;/p&gt;
&lt;h1&gt;Evaluating the results&lt;/h1&gt;
&lt;p&gt;At this point, I had crawled a handful of sites and had enough data to do some evaluations based on my original considerations.&lt;/p&gt;
&lt;h2&gt;SQLite is solid&lt;/h2&gt;
&lt;p&gt;Outside of mistakes of my own making with the database, I never really ran into a case where SQLite was an insufficient choice. Eventually, I added support for Postgres as well, but that was mostly for hosting reasons later on. By the end, with the largest amount of data I had crawled, the biggest my database size got to was 260mb.&lt;/p&gt;
&lt;h2&gt;This is a network-bound problem&lt;/h2&gt;
&lt;p&gt;Not so surprisingly, the biggest bottleneck in the end was network time. The amount of time spent waiting for HTTP responses was overwhelmingly larger than any processing time or database time.&lt;/p&gt;
&lt;h2&gt;There might not have been enough variance in my testing&lt;/h2&gt;
&lt;p&gt;Most, if not all, of my crawling was on podcast websites. The limit diversity even more, almost all of these had been tech podcasts. As such, I found that the data was pretty similar. During this time, I didn&apos;t encounter a single SPA. I also did not find a single site that didn&apos;t support some form of compression.&lt;/p&gt;
&lt;h2&gt;I was way off on the domains&lt;/h2&gt;
&lt;p&gt;Throughout my attempts, I encountered thousands of domains, not just hundreds of domains. That being said, Wikipedia was linked quite a few times, so maybe I get partial credit.&lt;/p&gt;
&lt;h2&gt;Asset sizes&lt;/h2&gt;
&lt;p&gt;I had assumed that most sites, especially sites that are not SPAs, would try to limit the amount of JavaScript, HTML, and CSS used. What I ended up finding was what appeared to be quite the opposite to me. The average JavaScript used on the pages I crawled was nearly 1mb, and the average CSS was 150kb. Compare this with the average HTML size, which was only 12Kb. It really does seem like JavaScript has eaten the world and a large chunk of compute on consumer devices.&lt;/p&gt;
&lt;h1&gt;Additional considerations&lt;/h1&gt;
&lt;p&gt;As I was going through this and expanding my crawls, I started to run into quite a few sites that have made crawling much harder. I assume this is largely due to AI crawlers. Also, much of the time, I couldn&apos;t help but notice that people are constantly visiting websites and processing this same data on their local hardware. This made me realize that if I were a browser vendor like Google with Chrome, I might be tempted to send &quot;telemetry&quot; data to help me build my index on someone else&apos;s hardware. Hopefully, none of the browsers do that, but I can understand the temptation.&lt;/p&gt;
&lt;h1&gt;Moving on&lt;/h1&gt;
&lt;p&gt;If you made it this far, maybe you are invested enough to read more about my silly little project. The next topic I plan on writing about would be the admin app that I created using &lt;a href=&quot;https://actix.rs/&quot;&gt;Actix&lt;/a&gt; and &lt;a href=&quot;https://htmx.org/&quot;&gt;htmx&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Journey into search]]></title><description><![CDATA[Falling down the rabbit hole When I started all of this madness, I had two very simple goals in mind. First, I was going to start using a…]]></description><link>https://ilusr.com/search-intro/</link><guid isPermaLink="false">https://ilusr.com/search-intro/</guid><pubDate>Thu, 14 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Falling down the rabbit hole&lt;/h1&gt;
&lt;p&gt;When I started all of this madness, I had two very simple goals in mind. First, I was going to start using a terminal-based editor. The second was that I was going to crawl a couple of pages and measure the time it took. Now, some two years later, I have a small three service system that can be run locally or in AWS. It turns out that once you start crawling the web, you are reminded that the &lt;a href=&quot;https://en.wikipedia.org/wiki/Memex&quot;&gt;Memex&lt;/a&gt; is vast and there are links in every content type imaginable. Also, you start to realize that you end up with a fair amount of semi-structured data that can be fun to play around with.&lt;/p&gt;
&lt;h1&gt;A warning to the reader&lt;/h1&gt;
&lt;p&gt;At this point, I find it relevant to warn the reader that I am not an expert in search engines or crawlers. I am just some dude playing around, having a good time, and sharing my findings.&lt;/p&gt;
&lt;h1&gt;Original scope&lt;/h1&gt;
&lt;p&gt;As I mentioned before, my original scope for this &quot;little&quot; project was to create a web crawler. This crawler was going to take an entry point and restrict its crawling to a single domain. While doing that, I would collect the time it took to load the assets from the network and parse those assets using &lt;a href=&quot;https://pypi.org/project/beautifulsoup4/&quot;&gt;beautifulsoup4&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also, since I don&apos;t use Python a whole lot, it was going to be a chance to dig a little deeper on something I touch every once in a while.&lt;/p&gt;
&lt;p&gt;Since I knew what I was going to collect, I took a bit of time before writing any code and made some assumptions about what I might find. I will go over these assumptions and how the crawler evolved in a later blog post.&lt;/p&gt;
&lt;h1&gt;And so the scope expands&lt;/h1&gt;
&lt;p&gt;Once I had run a couple of tests and built up a small index or two of the websites I was interested in, I hit my first scope expansion. I decided it would be nice to save a couple of the queries I was running into an admin style web app that would show a handful of specific performance metrics I cared about.&lt;/p&gt;
&lt;p&gt;Now I could have done something sensible and written this application in something I was familiar with, but instead I decided to do something completely different. There was this semi-new quasi-front-end framework that had recently hit the spotlight, and I wanted to check it out. Apparently, picking up htmx wasn&apos;t enough; no, I had to go all out and write my backend in Rust.&lt;/p&gt;
&lt;p&gt;Now with this new found admin app in hand, I started to find other things I wanted. I started to consider things like, &quot;wouldn&apos;t it be nice if I controlled what kinds of assets get downloaded?&quot;, and &quot;I really should be able to crawl and manage multiple domains&quot;. This led to a slew of features to control the crawler.&lt;/p&gt;
&lt;h1&gt;But hold on, what about UX?&lt;/h1&gt;
&lt;p&gt;Armed with data and hours of playing around with crawlers, I decided it was time to do something else. Those more inclined by profits might suggest figuring out how to train a neural network, but apparently, that is not for me. You see, I prefer the simpler things in life. Things like visualizing data into a planetary map.&lt;/p&gt;
&lt;p&gt;I was about to set out to build an interactive canvas that would visualize a search as a collection of solar entities and make those different sizes based on the entities&apos; perceived importance. This led me to realize that I needed to change my crawler again. I ended up taking another detour back into the crawler to build some edges between URLs and stored those in an edge table. Then, since the new goal was to compare the importance of the URLs, I took another side quest to learn how to implement a crude version of PageRank.&lt;/p&gt;
&lt;p&gt;Now that my crawler and database finally matched my aspirations, I could finally set out on building this interactive canvas. In this process, I was reminded that there are a lot of things you learn to take for granted when doing UI in a framework of any kind. All of this I hope to cover in yet another blog post.&lt;/p&gt;
&lt;h1&gt;Why not just try a typical search page?&lt;/h1&gt;
&lt;p&gt;Around this time, I started to think, why not just build a typical search page? I have some data, and there is no way it will be as hard as building an interactive canvas. So I pulled back out my htmx and rust and got back to work.&lt;/p&gt;
&lt;p&gt;As is the theme with this whole adventure, I decide well, that is good and fine, but maybe I should add a twist. Since the fascination I was finding was with how data was connected and general metadata, I decided it would be neat to interpret some of this data. In this search page, I would have additional options to see what the page links to and general information about the web primitives the page used without visting it.&lt;/p&gt;
&lt;p&gt;This, of course, lead to figuring out how to parse html, javascript, and css in rust. Which, as you can imagine, was another adventure.&lt;/p&gt;
&lt;h1&gt;What more could you possibly want to do?&lt;/h1&gt;
&lt;p&gt;Now with three services and two different UI&apos;s it was time to make the finishing touch, deploying the thing. Once again, this came with its own set of challenges, most of which came from my choice to use rust.&lt;/p&gt;
&lt;p&gt;After cutting my teeth for a while, mucking with cdk and rewriting parts of my service to optionally use s3 as a storage layer, I finally had something that could be deployed by anyone brave enough to take a stranger&apos;s CDK project and deploy it into their own AWS account.&lt;/p&gt;
&lt;h1&gt;Still ideas persist&lt;/h1&gt;
&lt;p&gt;Admittedly, I do not know what it was about this project that became so consuming. Many times, while I was working on this, I would think of something new I wanted to learn about, but I wouldn&apos;t be able to pull myself to do that until I &quot;finished&quot; whatever this was becoming.&lt;/p&gt;
&lt;p&gt;What is maybe even more shocking for me is that I still have a long list of things I didn&apos;t yet do that I would potentially like to one day do. These are some of the things I have still been fighting the urge to act on.&lt;/p&gt;
&lt;h2&gt;Vector search&lt;/h2&gt;
&lt;p&gt;Currently, the search behavior of my site is pretty primitive and rather crappy. While apparently no one uses search anymore, those who do expect a certain amount of flexibility in their textual query. As I understand, most deal with this by using a vector search approach. This being done by generating embeddings on the content and the user input, then you follow that up with some sweet cosine similarity magic and use that to pop out better results.&lt;/p&gt;
&lt;h2&gt;Robots.txt&lt;/h2&gt;
&lt;p&gt;I suspect I should feel some shame that my crawler does not respect robots.txt. However, I take solice in the fact that I am not running an entire datacenter of crawl compute and network IO. That being said, it would be nice for my crawler to be a better actor in the crawling space.&lt;/p&gt;
&lt;h2&gt;Why not a shared library?&lt;/h2&gt;
&lt;p&gt;While I have no good reason to do it, I have considered making parts of my crawler a shareable Python module. I don&apos;t really think the world needs yet another crawler, but it would be a nice opportunity to refactor some of my code.&lt;/p&gt;
&lt;h2&gt;Sub Indexes&lt;/h2&gt;
&lt;p&gt;One concept I had considered was the idea of being able to have sub-indices of the main index. Since I have no interest in gathering user data to create more relevant queries, the use of different indexes could fill that void. These indexes would be a way for users of the system to define a more constrained index, so they would just be searching the things they care about. This would be done by having the user choose to either blacklist or whitelist domains of interest to them. These indices could then be shared between users of the system.&lt;/p&gt;
&lt;h2&gt;Snow Crash Librarian&lt;/h2&gt;
&lt;p&gt;In the novel &lt;a href=&quot;https://en.wikipedia.org/wiki/Snow_Crash&quot;&gt;Snow Crash&lt;/a&gt;, there was an interesting bit in which the main protagonist started working with a piece of software called the librarian. This software would find information for the protagonist and summarize the information he has gathered. While not a profound realization, I realize that now with modern LLMs, you could create something quite similar. This would be done by first doing a search query to &quot;gather pages&quot;. Then you could present this in a UI and have an interface with an LLM summarize the search results in an interactive dialog.&lt;/p&gt;
&lt;h1&gt;What&apos;s next?&lt;/h1&gt;
&lt;p&gt;While I am not sure if I will continue to let this project take up my free time, I do plan on at least wrapping up part of what I set out to do. That being write a series of blog posts about the lessons I have learned along the way. This will start with a blog about crawling the web and building an index. After that, I am considering writing about the following topics&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;htmx and actix&lt;/li&gt;
&lt;li&gt;page rank&lt;/li&gt;
&lt;li&gt;using a 2d canvas&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any of the additional ideas end up getting done, I may very well write about those topics as well. If any of this work sounds interesting, feel free to &lt;a href=&quot;https://github.com/JeffreyRiggle/caribou&quot;&gt;check out the code on Github&lt;/a&gt;. Alternatively, if you just want to see what I have built for the time being, I am &lt;a href=&quot;http://caribou.ilusr.com/&quot;&gt;hosting it here&lt;/a&gt;. I make no guarantees for how long I will keep it up. Also, the index will mostly be based on random software engineering podcasts and other similar resources.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[IDE shake-up]]></title><description><![CDATA[What's Old is New (to me) It’s been a while since I’ve altered my development workflow, but I decided it was time for a change. Latetly I…]]></description><link>https://ilusr.com/neovim/</link><guid isPermaLink="false">https://ilusr.com/neovim/</guid><pubDate>Mon, 17 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;What&apos;s Old is New (to me)&lt;/h1&gt;
&lt;p&gt;It’s been a while since I’ve altered my development workflow, but I decided it was time for a change. Latetly I have noticed constant switching between keyboard and mouse can cause me some wrist pain. To try and reduce the possibility of future issues I decided it was time to give some other setup a try.&lt;/p&gt;
&lt;h2&gt;My Usual Workflow&lt;/h2&gt;
&lt;p&gt;My journey with coding environments has evolved over the years. I started with &lt;a href=&quot;(https://en.wikipedia.org/wiki/Windows_Notepad)&quot;&gt;Windows Notepad&lt;/a&gt; and the default terminal for compiling. Then, I discovered &lt;a href=&quot;https://notepad-plus-plus.org/&quot;&gt;Notepad++&lt;/a&gt; in high school, which I used until college. In college, we primarily used Java, and it was time to upgrade to a fully-fleged IDE. In the war of &lt;a href=&quot;https://netbeans.apache.org/front/main/index.html&quot;&gt;Netbeans&lt;/a&gt; vs &lt;a href=&quot;https://eclipseide.org/&quot;&gt;Eclipse&lt;/a&gt;, I landed in the Eclipse camp.&lt;/p&gt;
&lt;p&gt;After college, I joined a .NET shop and switched to &lt;a href=&quot;https://visualstudio.microsoft.com/&quot;&gt;Visual Studio&lt;/a&gt;, incorporating &lt;a href=&quot;https://en.wikipedia.org/wiki/PowerShell&quot;&gt;PowerShell&lt;/a&gt; into my toolkit. Later, when I moved into web development, I found Visual Studio and Eclipse lacking for JavaScript, HTML, and CSS, so I tried &lt;a href=&quot;(https://www.sublimetext.com/)&quot;&gt;Sublime Text&lt;/a&gt;. It didn’t fully click, leading me to &lt;a href=&quot;https://atom-editor.cc/&quot;&gt;Atom&lt;/a&gt;, which I enjoyed until I discovered &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;VSCode&lt;/a&gt;. Despite initial skepticism, I’ve been hooked on VSCode for years.&lt;/p&gt;
&lt;h2&gt;Choosing right editor&lt;/h2&gt;
&lt;p&gt;Armed with a &quot;simple&quot; program idea, I set out to find a terminal-based editor. From experience, I knew &lt;a href=&quot;https://en.wikipedia.org/wiki/GNU_nano&quot;&gt;Nano&lt;/a&gt; was not going to work. This left either &lt;a href=&quot;https://en.wikipedia.org/wiki/Emacs&quot;&gt;emacs&lt;/a&gt; or some variant of &lt;a href=&quot;https://en.wikipedia.org/wiki/Vi_(text_editor)&quot;&gt;vi&lt;/a&gt;. Since I have seen more community representation in vi-based editors I decided this was the route to go down given my experience with poor community support (Aurelia). Immediately I knew that vi would probably not be the right choice because it was not as rich of an environment as &lt;a href=&quot;https://www.vim.org/&quot;&gt;vim&lt;/a&gt; and &lt;a href=&quot;https://neovim.io/&quot;&gt;Neovim&lt;/a&gt;. Ultimately, I landed on Neovim because it appears to be the latest incarnation of vi.&lt;/p&gt;
&lt;h2&gt;Setting Expectations&lt;/h2&gt;
&lt;p&gt;As I set out on my journey to use a new editor I did what I usually do in these situations, and laid out some expectations. In this, I assumed it would be slower at first to edit in neovim than just using the tools I had been using. I also assumed that figuring out the keybindings would take a while. Another thing I assumed was that pretty early on I would have to add plugins and might even have to use tmux. In the end, I assumed I would enjoy the result and might even use it full-time.&lt;/p&gt;
&lt;h2&gt;Getting started&lt;/h2&gt;
&lt;p&gt;I began on an Ubuntu machine and installed Neovim with apt-get. The default settings weren’t suitable, so I adjusted the numbering scheme and color settings. Then it came time for the hard part, sifting through all too many resources to figure out what plugins I needed and how to set them up.&lt;/p&gt;
&lt;h3&gt;Configuring Neovim&lt;/h3&gt;
&lt;p&gt;The first thing I found was that I just wanted to set some editor properties and move on with my coding; However, it appeared there were two ways to set configuration. You can either use a &lt;code&gt;vim.init&lt;/code&gt; file in your config space or write some Lua code to configure your editor. Most online tutorials had been all in on Lua but I just wanted something quick, simple, and easy for me to understand. For this, I decided to proceed with the &lt;code&gt;vim.init&lt;/code&gt; pattern.&lt;/p&gt;
&lt;h3&gt;First Round of Plugins&lt;/h3&gt;
&lt;p&gt;After getting Neovim set up the way I wanted, I installed my first plugins: &lt;a href=&quot;https://github.com/vim-airline/vim-airline&quot;&gt;airline&lt;/a&gt; and &lt;a href=&quot;https://github.com/preservim/nerdtree&quot;&gt;nerdtree&lt;/a&gt;. I installed Airline because it helped me distinguish between edit and view modes. As for NerdTree, I figured all IDEs have a project tree so of course I would need that right?&lt;/p&gt;
&lt;h2&gt;Keybindings don&apos;t have to have a modifier?&lt;/h2&gt;
&lt;p&gt;Understanding Neovim’s keybindings took time. Unlike traditional editors, Neovim’s different modes eliminate the need for complex keybindings. For instance, jumping to the next word or end of the line doesn’t require a modifier key. This approach reduced finger strain and improved my workflow. The &lt;a href=&quot;https://vim.rtorr.com&quot;&gt;Vim Cheat Sheet&lt;/a&gt; was invaluable during this period.&lt;/p&gt;
&lt;p&gt;The hardest part was memorizing the cut command. While copying (yank) was intuitive, using d for cut/delete took some getting used to.&lt;/p&gt;
&lt;h2&gt;Spoiled by Sensible Defaults&lt;/h2&gt;
&lt;p&gt;Through this experience I learned having sensible formatting etc defaults baked into the editor is something I take for granted. In the past I had seen defaults break down a bit when writing javascript in Visual Studio, at least circa 2015, or Eclipse. However, normally these standard IDEs handled the default formatting for the language they were designed for very well. VSCode took that to the next level by having different default formats for different languages and even detecting different tools that you should install based on the language you are writing in.&lt;/p&gt;
&lt;p&gt;The behavior of VSCode reduces the cognitive load for developers who just want sensible defaults and don&apos;t want to spend a lot of time picking out their tools. At times this was something I missed. As it turns out, I do not always enjoy going down a rabbit hole to find a suitable option for the task I am working on.&lt;/p&gt;
&lt;h2&gt;Finding the Right Plugins&lt;/h2&gt;
&lt;p&gt;Pretty early on it was clear to me that the original set of plugins I installed wasn&apos;t cutting it. Neovim is great but at its core, it is a text editor that gets better with plugins. By default, Neovim had limited or no autocomplete, but with many modern IDEs, it is something you expect. After looking around a bit I found &lt;a href=&quot;https://github.com/neoclide/coc.nvim&quot;&gt;CoC (Conquerer of Completion)&lt;/a&gt;. This tool worked fine but I never fully enjoyed using it. It was a bit weird to have to deal with a plugin system in one of my plugins. Also, it was a bit strange that one of my plugins was built on Nodejs requiring specific node versions to be present. In the end, this ended up being the right tool to unblock me but I still cannot help but wonder if there is a better way to handle this problem.&lt;/p&gt;
&lt;p&gt;As it turns out I like to be able to fuzzy search, specifically for files. I realized that I never interact with my tree structure and  exclusively navigate around by fuzzy finding the files. While there might have been a way to get this with CoC I was not finding it. I ended up finding &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope&lt;/a&gt; but it didn&apos;t seem like it was able to be used on the stable version of Neovim. After some fussing around with versions I ended up dropping that attempt and landed on &lt;a href=&quot;https://github.com/junegunn/fzf.vim&quot;&gt;fzf&lt;/a&gt;. This is hands down my favorite plugin I ended up installing. It did exactly what I wanted and didn&apos;t involve any special setup on my end.&lt;/p&gt;
&lt;h2&gt;Now do it again&lt;/h2&gt;
&lt;p&gt;During this experiment, I ended up getting a new laptop. This put me at having to recreate all of this configuration on a new machine with another operating system. The initial setup was pretty easy but getting all the plugins and &lt;code&gt;init.vim&lt;/code&gt; setup correctly was a bit of a pain. Some of this was a difference in reserved keys between operating systems, but a majority of it was recreating the config by hand. I can see the reason why many devs who run with this setup full-time end up putting all of their dotfiles or lua code in a Github repository. While this didn&apos;t take an insane amount of time, I could see that repository saving a couple of hours for every new setup.&lt;/p&gt;
&lt;h2&gt;Enter tmux&lt;/h2&gt;
&lt;p&gt;As I predicted eventually the time came when I needed to use &lt;a href=&quot;https://github.com/tmux/tmux/wiki&quot;&gt;tmux&lt;/a&gt;. For the longest time, I was just working on a Python process that had a slow feedback loop. In these cases opening Neovim, putting it in the background, running the process, waiting for the result, and switching back was not that big of a pain point. However, once I layered in a web interface it became clear that rapid iteration in this fashion was just not fast enough. The ceremony of control/alt+z, run process, control/alt+c, and fg repeat became too much. I was just altering static assets so the run process didn&apos;t need to keep being kicked off. Switching to tmux and having both the process run and editor visible at the same time was a big productivity win for me.&lt;/p&gt;
&lt;h2&gt;What I learned&lt;/h2&gt;
&lt;p&gt;While I enjoyed working in this way I do not see myself making this my full-time setup. Having to keep on top of what plugins I want for commonly supported IDE workflows does not seem to be how I enjoy spending my time. During this process, I found out which editor features are important to me, if my IDE has decent autocomplete, inline signature help, and fuzzy file finding I am pretty happy. I was a bit surprised to find that I do not use the file tree view much if at all.&lt;/p&gt;
&lt;p&gt;Turns out that working on a laptop without access to a mouse is far more enjoyable in Neovim. When working on a laptop in another IDE I am reminded how much I struggle to use a touchpad effectively, working in Neovim gets rid of this classification of issue for me.&lt;/p&gt;
&lt;p&gt;As is often the case with my side projects I found that my &quot;simple&quot; program expanded into something far more complicated. This program ended up loosely resembling a search engine. This also ended up using Python, Rust, and standard web primitives (Javascript, CSS, HTML) which led to more and more autocompletion flows I needed to consider. Since I ended up enjoying the semi search engine project I will probably add some additional blog entries about that in the future.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[LLMs and TDD]]></title><description><![CDATA[LLMs and TDD With all the undeniable hype around LLMs and more specifically ChatGPT I decided it was time to give it a fair shot. For the…]]></description><link>https://ilusr.com/ai-tdd/</link><guid isPermaLink="false">https://ilusr.com/ai-tdd/</guid><pubDate>Sat, 04 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;LLMs and TDD&lt;/h1&gt;
&lt;p&gt;With all the undeniable hype around LLMs and more specifically &lt;a href=&quot;https://chat.openai.com/&quot;&gt;ChatGPT&lt;/a&gt; I decided it was time to give it a fair shot. For the last year or so almost everyone has been talking about how it is going to revolutionize how many of us do our jobs and completely change how software engineers write software. It has also been suggested that those of us who choose not to use the technology will be left in the dust by those who choose to use it.&lt;/p&gt;
&lt;p&gt;This sort of hype is so common in our industry that I decided to give it a while before even attempting to use it. When I finally got around to using it at first I was impressed. Visually its presentation style is quite stunning and it provides very promising-looking results to the questions you give it. However, on further inspection, my initial take was it constantly makes mistakes and presents them in a way that sounds factual. Most of my common use cases for a tool like this would be to replace searching documentation on a third-party library I depend on, but alas it would often make up interfaces and function calls for the tool that didn&apos;t exist. After this first exposure, I decided to put the tool down and move on.&lt;/p&gt;
&lt;p&gt;Over the past several months people in the industry kept singing its praises. This got me thinking maybe I wasn&apos;t using the tool the right way and if I could just find the right way to work with it I would become even more productive and might be able to accomplish things I would otherwise pass on due to difficulty.&lt;/p&gt;
&lt;h2&gt;Understanding how others use it&lt;/h2&gt;
&lt;p&gt;The first step I figured was to see how other people had been using it and where they seemed to find value with the tool. Through this, I found that the most common use cases had been the following themes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Document this code for me because it&apos;s hard to understand.&lt;/li&gt;
&lt;li&gt;Write tests for the code I have already authored.&lt;/li&gt;
&lt;li&gt;Write my code for me as I describe what it should do.&lt;/li&gt;
&lt;li&gt;Refactor some existing code to make it more readable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of these cases, the one case I found fascinating was the &lt;code&gt;Write my code for me as I describe what it should do&lt;/code&gt;. This seems like an interesting replacement for pair programming in an industry where that sort of activity is becoming a bit rarer. However, most of the other cases just didn&apos;t work for me. I suspect it might just be me being stubborn or maybe I have subscribed too much to the dogma of people like &lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_C._Martin&quot;&gt;Robert C. Martin&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt; but some of these cases seemed a bit irresponsible. I understand documentation is hard to write and tests can be tedious but these seem like part of the rigor that comes along with any Job containing the title &quot;Engineer&quot;.&lt;/p&gt;
&lt;h2&gt;Thinking about how I would want to apply it&lt;/h2&gt;
&lt;p&gt;At this point, I decided to take some time and reflect. If I was going to use a tool like this how would I want to use it? Upon a fair amount of thinking I landed on the best way to use the tool and get the desired outcomes would be some sort of TDD loop. In this loop, I decided that the human would be in control of the inputs and outputs by writing the tests. This would in turn leave the implementation up to the AI.&lt;/p&gt;
&lt;p&gt;At this point, I was starting to get excited and even thought a bit more about how transformative this kind of workflow could be. I even started to consider how it might start to draw parallels between other industries. For example, it&apos;s interesting that we design and build code as programmers but other industries like housing have architects that design the house but never have to do the construction.&lt;/p&gt;
&lt;h2&gt;Starting off simple&lt;/h2&gt;
&lt;p&gt;At first, I decided to start off simple. In this case, I was going to use a language I use a lot and try something rather trivial. In this case, I decided something trivial would be a simple partitioned log that is backed by localStorage. Going into this I had already built up a few assumptions&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ChatGPT would not produce a working result faster&lt;/li&gt;
&lt;li&gt;ChatGPT would not write documentation by default&lt;/li&gt;
&lt;li&gt;ChatGPT would default to writing typescript when given a test with no types&lt;/li&gt;
&lt;li&gt;ChatGPT would write more code than was required.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After this test was completed I found the following. Much to my surprise, ChatGPT did not assume typescript by default. Also since I was in such a rush to set a time record to beat I made a mistake that assumed you would always append a log before reading the log. I also found that ChatGPT did produce a result faster however I had already written the tests in advance so that might account for the time difference.&lt;/p&gt;
&lt;h3&gt;Expectation breakdowns&lt;/h3&gt;
&lt;p&gt;One thing I found rather quickly was that ChatGPT was not picking up on the expectations that my tests had been subtly implying. For example, in my test code, I was mocking out &lt;code&gt;getItem&lt;/code&gt; and &lt;code&gt;setItem&lt;/code&gt; in local storage. However, ChatGPT really wanted to index all items directly from local storage. For example instead of writing some code like this&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token dom variable&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;it really wanted to do this&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token dom variable&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another assumption I had built up was that if I just fed it the errors from execution it would be able to deduce what was wrong and at least attempt a change that would fix the failure. What I found instead was that often the change it made would actually produce more failures and might not even fix the originally failing test. In the end, I found that I had to directly state my expectations around why I thought its implementation was failing tests.&lt;/p&gt;
&lt;h3&gt;Result&lt;/h3&gt;
&lt;p&gt;In the end, we worked out a solution that got all tests passing but still wasn&apos;t quite what I wanted. Ideally, I wanted it to use generics for values on a log but due to how I wrote the tests &lt;code&gt;string&lt;/code&gt; was sufficient. A bit tired from the conversation I gave up and accepted the result.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LocalStorageLog&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;logs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token maybe-class-name&quot;&gt;Record&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getLogFromLocalStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logJSON &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token dom variable&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;logJSON&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token known-class-name class-name&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;logJSON&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;updateLocalStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;logs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;logArray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logJSON &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token known-class-name class-name&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;logArray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token dom variable&quot;&gt;localStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logJSON&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;readLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;logs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;logs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;getLogFromLocalStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;logs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;appendLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword control-flow&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;logs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;logs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;getLogFromLocalStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token property-access&quot;&gt;logs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token method function property-access&quot;&gt;updateLocalStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword module&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token exports&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token maybe-class-name&quot;&gt;LocalStorageLog&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The result of this test can be found &lt;a href=&quot;https://github.com/JeffreyRiggle/ai-tdd-test/tree/master/robot/simple&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At this point, I was feeling a bit defeated. I had hoped for so much and found that the result was not what I envisioned. However, I had come up with a plan that involved multiple tests and I was determined to keep on trying.&lt;/p&gt;
&lt;h2&gt;Trying something a bit less comfortable&lt;/h2&gt;
&lt;p&gt;Moving on another test I really wanted to try was using a language I was less comfortable with. I suspected in this case maybe I would have fewer opinions and might even be able to learn something about the language I had not picked up on before. In this case, I decided to use rust and write a very similar bit of code. The twist was this time I would be using files to store data.&lt;/p&gt;
&lt;h3&gt;Observations about my own coding experience&lt;/h3&gt;
&lt;p&gt;What I found while trying to implement this first by myself was that it took me a significantly longer time to execute than the previous example. Another observation I made was that I ended up doing a lot of context-switching between my IDE and the standard library. In the end, I got a working result.&lt;/p&gt;
&lt;h3&gt;Handing it over to ChatGPT&lt;/h3&gt;
&lt;p&gt;Much in the same fashion as before I decided to then take my tests and hand them off to ChatGPT and see what I could do. In this case, I found some familiar issues but to my surprise in the end it produced working code without me having to explain directly how to fix the code. There however two new issues I did not encounter before. The first one was quite minor originally it failed to import something that was needed. The second issue for whatever reason struck a nerve with me. In this case, I was writing tests and wanted only the implementation written however ChatGPT took it upon itself to rewrite my tests. In this case, it was minor it decided that rust should be written in &lt;code&gt;snake_case&lt;/code&gt; instead of &lt;code&gt;camelCase&lt;/code&gt;, but I didn&apos;t like the idea of changing the tests this was supposed to be the human part of the job.&lt;/p&gt;
&lt;p&gt;In the end, I will say it did produce a more correct result and even added some documentation I was not expecting.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;rust&quot;&gt;&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Non GPT comment had to manually add File import&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;OpenOptions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;io&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Read&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token type-definition class-name&quot;&gt;LogManager&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    log_dir&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LogManager&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;log_dir&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Create the log directory if it doesn&apos;t exist&lt;/span&gt;
        &lt;span class=&quot;token namespace&quot;&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create_dir_all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;log_dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Failed to create log directory&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;LogManager&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; log_dir&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; log_dir&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;to_string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;appendLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log_name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; log_path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token macro property&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{}/{}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;log_dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log_name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;mut&lt;/span&gt; file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OpenOptions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;log_path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Failed to open log file for appending&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// Append the message to the log file&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;writeln!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Failed to write to log file&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;readLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log_name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; log_path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token macro property&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{}/{}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;log_dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log_name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;mut&lt;/span&gt; file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;log_path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;mut&lt;/span&gt; contents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;read_to_string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;mut&lt;/span&gt; contents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Failed to read log file&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            contents&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;from&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token macro property&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token attribute attr-name&quot;&gt;#[cfg(test)]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;token module-declaration namespace&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token attribute attr-name&quot;&gt;#[test]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;test_empty_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; manager &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LogManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./unittestdir&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;empty&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Gave up and changed test&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token attribute attr-name&quot;&gt;#[test]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;test_append_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; manager &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LogManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./unittestdir&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;append&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;My new Message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;append&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token macro property&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;My new Message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Gave up and changed test&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token attribute attr-name&quot;&gt;#[test]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;test_append_many_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; manager &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LogManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./unittestdir&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;appendMany&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;My new Message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;appendMany&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;My Message 2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;appendMany&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token macro property&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;My new Message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;My Message 2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Gave up and changed test&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token attribute attr-name&quot;&gt;#[test]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;test_file_creation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; manager &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LogManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./unittestdir&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;creation&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;My creation message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./unittestdir/creation&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token macro property&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;read_to_string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./unittestdir/creation&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;My creation message\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The result of this test can be found &lt;a href=&quot;https://github.com/JeffreyRiggle/ai-tdd-test/tree/master/robot/less-used&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Trying something a bit more complicated&lt;/h2&gt;
&lt;p&gt;With the previous tests out of the way, it was time to attempt my final test. In this case, I was going to give it something a bit more complex that would require implementing multiple files and a common type. This expanded on my first test but added an eventing system in front of the log on top of this we would also have both a local storage and filesystem backed option for this eventing system.&lt;/p&gt;
&lt;p&gt;In this case, I had learned from my past experiences and was ready to do a couple of things differently. First I was not going to try to time myself on the initial implementation. I wanted to take it slow and write what I would have wanted to produce. Second, at this point, I was ready to have to be a bit more interactive with ChatGPT. Instead of just throwing failures at it I was ready to give it subtle hints to get to the end goal with my sanity intact.&lt;/p&gt;
&lt;p&gt;What I found in this case was that again it took ChatGPT a lot longer than I had anticipated to complete this task and again it did in fact require a lot of direct suggestions to get a working result. In this case, since there were multiple files there was an opportunity to produce more typescript errors and it certainly did produce a fair amount of those which required me to debug the code and make suggestions on a type that would work. Most of the time during this exercise it felt like I was pair programming with a junior developer. That is not to say there is anything wrong with working with junior developers just I would rather use those opportunities to teach another engineer instead of fighting with a machine to just have to do it all over again in the future.&lt;/p&gt;
&lt;p&gt;In the end, there were a couple of positives to this experience. Firstly I found that it exposed some assumptions I had about my filesystem-backed implementation that could have been better. I also found that the more files we worked on the better it got at producing what I wanted. For example, it produced the final file with no issue the first time.&lt;/p&gt;
&lt;p&gt;The result of this test can be found &lt;a href=&quot;https://github.com/JeffreyRiggle/ai-tdd-test/tree/master/robot/event-log&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Unexpected surprise&lt;/h2&gt;
&lt;p&gt;In between these tests, I decided to play around with ChatGPT a bit and decided to flip this problem on its head. Instead, I would have ChatGPT write some tests and I would write the implementation for those tests. In the end, I found this to be a lot more enjoyable and saw this as a good opportunity to use the tool as more of a generalized hone-your-skills type tool similar to Robert C. Martin&apos;s idea of a code kata.&lt;/p&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;I understand that this is not the most conclusive test and that there are other tools I could have explored. I am sure I would have seen slightly different results using something like GPT-4 from &lt;a href=&quot;https://openai.com/&quot;&gt;openai&lt;/a&gt; or &lt;a href=&quot;https://github.com/features/copilot&quot;&gt;copilot&lt;/a&gt; from GitHub. However, after this experience, I was not really willing to invest money to see if I would get a better result.&lt;/p&gt;
&lt;p&gt;In the end, many of the assumptions I had about the tool had been wrong in ways I didn&apos;t expect. However, instead of being completely disappointed I did find one workflow I quite enjoyed with this tool and it did not end up being a complete waste of time. ChatGPT may be useful for many but for the way I like to work with my tools, it doesn&apos;t quite cut it for me.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Book Note - The Mythical Man-Month]]></title><description><![CDATA[The Mythical Man-Month The Mythical Man-Month is a book authored by Frederick Brooks. High level overview This book is a series of essays…]]></description><link>https://ilusr.com/mythical-man-month/</link><guid isPermaLink="false">https://ilusr.com/mythical-man-month/</guid><pubDate>Wed, 09 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;The Mythical Man-Month&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.com/Mythical-Man-Month-Software-Engineering-Anniversary/dp/0201835959&quot;&gt;The Mythical Man-Month&lt;/a&gt; is a book authored by &lt;a href=&quot;https://en.wikipedia.org/wiki/Fred_Brooks&quot;&gt;Frederick Brooks&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;High level overview&lt;/h2&gt;
&lt;p&gt;This book is a series of essays from Frederick Brooks. In these essays the problems of software engineering and management are explored. Much of this book is polled from Fredricks own experiences while working on &lt;a href=&quot;https://en.wikipedia.org/wiki/IBM_System/360&quot;&gt;IBM System/360&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Notes&lt;/h2&gt;
&lt;h3&gt;The Tar Pit&lt;/h3&gt;
&lt;p&gt;This is a good introduction essay. In this chapter, Frederick does a great job distinguishing between software that works and production-grade software. The fact that you can get something that works together quickly often gives false hope for moving that to production. In this move, there is a lot of work to make the application stable for many users on many machines with few bugs in new features.&lt;/p&gt;
&lt;p&gt;Another aspect of this chapter I found quite interesting was the description of why so many people enjoy building software and how that can become a trap. The comparison of programming and programming projects to a tar pit is a very interesting metaphor that I think often fits.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A &lt;br&gt; Program&lt;/td&gt;
&lt;td&gt;A &lt;br&gt; Programming &lt;br&gt; System&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A &lt;br&gt; Programming &lt;br&gt; Product&lt;/td&gt;
&lt;td&gt;A &lt;br&gt; Programming &lt;br&gt; Systems &lt;br&gt; Product&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Large system programming is a tar pit and many powerful beasts have thrashed in it.
&lt;ul&gt;
&lt;li&gt;many have made it out with running systems.&lt;/li&gt;
&lt;li&gt;less have met goals, schedules, and budgets.&lt;/li&gt;
&lt;li&gt;No one can escape this problem no matter how big or small the team is.&lt;/li&gt;
&lt;li&gt;Most are surprised how sticky it is&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If this is such an issue why do small teams working in garages seem to be able to pull it off?
&lt;ul&gt;
&lt;li&gt;A functioning product is easy to build but a hardened tested product is much harder.&lt;/li&gt;
&lt;li&gt;See chart above for next points.&lt;/li&gt;
&lt;li&gt;Generally speaking, these teams create something in the top left quadrant.&lt;/li&gt;
&lt;li&gt;To make a program more useful but more costly moving down or to the right adds 3 times the effort and expense&lt;/li&gt;
&lt;li&gt;A programming product
&lt;ul&gt;
&lt;li&gt;Has Generalization&lt;/li&gt;
&lt;li&gt;Has Testing&lt;/li&gt;
&lt;li&gt;Has Documentation&lt;/li&gt;
&lt;li&gt;Is Maintained&lt;/li&gt;
&lt;li&gt;can be run, tested, and extended by anybody.&lt;/li&gt;
&lt;li&gt;Is usable in many different operating systems.&lt;/li&gt;
&lt;li&gt;This means a ton of testing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A programming system
&lt;ul&gt;
&lt;li&gt;Collection of interacting components.&lt;/li&gt;
&lt;li&gt;coordinated in function and disciplined in format.&lt;/li&gt;
&lt;li&gt;every input and output must conform to syntax and semantics with precisely defined interfaces.&lt;/li&gt;
&lt;li&gt;must only use the prescribed amount of resources (RAM, CPU, etc)&lt;/li&gt;
&lt;li&gt;must be tested with other components&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A Programming Systems Product
&lt;ul&gt;
&lt;li&gt;cost 9 times as much as a simple program&lt;/li&gt;
&lt;li&gt;Is a mix of a programming product and a programming system.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Programming is fun
&lt;ul&gt;
&lt;li&gt;This is partly due to the joy of making things in general.&lt;/li&gt;
&lt;li&gt;It is pleasurable to make something that works for other people.&lt;/li&gt;
&lt;li&gt;It is puzzle-like which can be quite fun.&lt;/li&gt;
&lt;li&gt;There is a joy to learning and programming is all about learning.&lt;/li&gt;
&lt;li&gt;Programming is not generally bound by physical mediums. It is pure thought. Very few forms of media are as flexible when it comes to creation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Woes
&lt;ul&gt;
&lt;li&gt;The implementation must be perfect. Computers are quite dumb and only handle simple instructions. As humans, we often lack the discipline to define something perfectly.&lt;/li&gt;
&lt;li&gt;The programmer rarely controls what they are working on. This often comes under the direction of a customer or third party.&lt;/li&gt;
&lt;li&gt;Depending on others programs can be painful. It is very annoying to find a system you depend on has a bug in it and its not meeting it&apos;s required specifications.&lt;/li&gt;
&lt;li&gt;Designing is fun but fixing bugs painstaking laborious work&lt;/li&gt;
&lt;li&gt;Debugging gets harder as more bugs are solved.&lt;/li&gt;
&lt;li&gt;In many cases, the product you have been laboring over is obsolete by the time you are ready to release it. This can lead to massive frustration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Mythical Man-Month&lt;/h3&gt;
&lt;p&gt;In this essay, Fredrick explores the complexity of getting a software project done on time and correctly. One major theme is it is very hard to estimate a software task. Currently, any estimation techniques we have are somewhat poor and these poor estimations make it hard for managers to give good timelines. One interesting concept that is brought up is that developer estimates are often optimistic. It is argued that software engineers are eternal optimists and this can lead to estimates being very off. Another issue with estimations is they are often ignored or pressured to meet a customer&apos;s demand. There is a call for managers with stronger backbones to avoid this sort of temptation.&lt;/p&gt;
&lt;p&gt;Another topic that is talked about a lot is the trade-off between men and months. In many other industries if you add more people to a project it will get done faster. Software is a bit of an exception. In the case of software often adding more people will have no effect or a negative impact on timelines. Bringing more people onboard requires more communication from already productive developers.&lt;/p&gt;
&lt;p&gt;As far as getting the product out the door there is a surprising amount of time spent doing things other than writing the code. It is argued that really coding is only one-sixth of the total effort. The rest of the effort is spent planning and testing.&lt;/p&gt;
&lt;p&gt;In the last section of this chapter, there is some guidance provided on what you can try to do if a project is falling behind. Some advice includes push the task out, drop scope on the task, and if all else fails you can try to add heads but smartly. Adding more developers is a serious risk and should be done early in the process.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Techniques of estimating are poorly developed&lt;/li&gt;
&lt;li&gt;estimating techniques confuse effort with progress. (This hides the assumption that people and months are interchangeable)&lt;/li&gt;
&lt;li&gt;since we are unsure of our estimates it makes software managers lives difficult&lt;/li&gt;
&lt;li&gt;progress is poorly monitored.&lt;/li&gt;
&lt;li&gt;when slipage is seen often the idea of adding more manpower is assumed to be a solution.&lt;/li&gt;
&lt;li&gt;All programmers are optimists
&lt;ul&gt;
&lt;li&gt;Often we assume things like &quot;The time time this will surely run&quot;&lt;/li&gt;
&lt;li&gt;Often we assume all will go well.&lt;/li&gt;
&lt;li&gt;Reference to The &lt;a href=&quot;https://www.amazon.com/Mind-Maker-Dorothy-L-Sayers/dp/1520215185&quot;&gt;Mind of the Maker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;In many creative activities (not programming) there are physical limitations that can be expressed. The difficulty in these cases is often implementation&lt;/li&gt;
&lt;li&gt;Since programming is pure thought we expect very few issues in implementation because it is all thought matter.&lt;/li&gt;
&lt;li&gt;Since our ideas are faulty we end up with bugs. This invalidates our optimism.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Man-Month
&lt;ul&gt;
&lt;li&gt;Cost varies as the number of men or months are tweaked. However, progress does not.&lt;/li&gt;
&lt;li&gt;A man-month is a bad unit for measuring the size of a job.&lt;/li&gt;
&lt;li&gt;Men and months are only interchangeable in tasks that do not require communication. Programming is not one of these tasks.&lt;/li&gt;
&lt;li&gt;If a task cannot be partitioned due to sequential blockers more effort will have no effect on the schedule.&lt;/li&gt;
&lt;li&gt;In the case that a task can be partitioned it often still requires a lot of communication. This adds to the amount of time required to complete the task.&lt;/li&gt;
&lt;li&gt;There is a burden to adding more developers
&lt;ul&gt;
&lt;li&gt;training, every new member must be brought up to speed and trained accordingly.&lt;/li&gt;
&lt;li&gt;intercommunication, as you add more people there is even more communication that needs to happen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Often adding more developers lengthens instead of shortens a project.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;System test
&lt;ul&gt;
&lt;li&gt;Debugging of a component and testing of a system are very dependant on sequential constraints.&lt;/li&gt;
&lt;li&gt;Time required is dependant on the subtlety and number of errors found.&lt;/li&gt;
&lt;li&gt;Breakdown of a software task
&lt;ul&gt;
&lt;li&gt;1/3 Planning&lt;/li&gt;
&lt;li&gt;1/6 coding&lt;/li&gt;
&lt;li&gt;1/4 component test and early systems test&lt;/li&gt;
&lt;li&gt;1/4 system test&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The time devoted to planning is larger than normal&lt;/li&gt;
&lt;li&gt;half of time schedule is debugging&lt;/li&gt;
&lt;li&gt;the easy part to estimate only makes up for 1/6th of the work.&lt;/li&gt;
&lt;li&gt;Failure to plan enough time for a system test is dangerous. This is often found out later into the project and the impact is usually severe.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Estimating
&lt;ul&gt;
&lt;li&gt;It is easy to promise something that cannot be delivered. I can promise you an omelet in two minutes but when that time is up the customer must choose to wait or eat it raw.&lt;/li&gt;
&lt;li&gt;False scheduling to meet customer demands is far more common in this industry.&lt;/li&gt;
&lt;li&gt;We need to publicize productivity, bug incidents figures. The whole industry would benefit from this. (Maybe open source and github has helped with this)&lt;/li&gt;
&lt;li&gt;Managers need stronger backbones until our estimation techniques get better.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What to do when a task is falling behind
&lt;ul&gt;
&lt;li&gt;You can add more heads but do it smartly. There are limits to how much and to what effect adding more heads will do.&lt;/li&gt;
&lt;li&gt;reschedule, push the task out.&lt;/li&gt;
&lt;li&gt;Trim the task, drop scope.&lt;/li&gt;
&lt;li&gt;Brooks Law simplified &quot;Adding manpower to a late software project makes it later&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Surgical Team&lt;/h3&gt;
&lt;p&gt;In this essay, an examination of how to structure software teams is done. In general, it seems that small teams work better. However, small teams cannot produce the large systems that are often required. To deal with this a collection of surgical teams can be created to have small effective teams while still producing large systems.&lt;/p&gt;
&lt;p&gt;These surgical teams are made of surgeons, copilots, administrators, editors, secretaries, program clerks toolsmiths, testers, and language lawyers.&lt;/p&gt;
&lt;p&gt;A surgeon in this context is your lead developer. The surgeon is responsible for designing code, writing documentation, and testing code. Generally, this person should have 10 years of experience. In a lot of ways, this role is similar to the master described in the clean coder book.&lt;/p&gt;
&lt;p&gt;A copilot can do everything a surgeon can but does not quite have the same experience as the surgeon. The biggest part of this role is to work with the surgeon. In this role, the copilot can question the surgeon&apos;s choices but the surgeon always gets the final say in the end design. In many ways, this is like clean coders journeyman.&lt;/p&gt;
&lt;p&gt;The administrator is the surgeon&apos;s boss and tends to handle non-technical aspects of work. These might include things like raises.&lt;/p&gt;
&lt;p&gt;The editor primarily works on documentation. The editor will review and edit documentation as needed.&lt;/p&gt;
&lt;p&gt;Secretaries in this context handle correspondence for the editor and the administrator.&lt;/p&gt;
&lt;p&gt;The program clerk manages all records. This includes both human and machine-generated records. This role would have to aggregate things like developer documentation and build output information.&lt;/p&gt;
&lt;p&gt;The toolsmith creates and maintains any specialized tools the surgeon may need.&lt;/p&gt;
&lt;p&gt;The tester creates system tests and plans testing sequences.&lt;/p&gt;
&lt;p&gt;Lastly, the language lawyer is a programming language expert. In this role, the language expert can help surgeons find ways to do things that might be difficult to accomplish in the language of choice.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;People favor small teams but small teams cannot produce large systems.&lt;/li&gt;
&lt;li&gt;There are wide productivity differences between good and bad programmers. (I assume this is about the controversial 10x programmer)&lt;/li&gt;
&lt;li&gt;There is no correlation between years of experience and productivity.&lt;/li&gt;
&lt;li&gt;a small team should not exceed 10 people&lt;/li&gt;
&lt;li&gt;Harlan Mills has a solution
&lt;ul&gt;
&lt;li&gt;A segment of a large job should be tackled by a team.&lt;/li&gt;
&lt;li&gt;This team should be organized like a surgical team.&lt;/li&gt;
&lt;li&gt;In this model, each team member has a specific role to play.&lt;/li&gt;
&lt;li&gt;The Surgeon
&lt;ul&gt;
&lt;li&gt;Also known as the chief programmer.&lt;/li&gt;
&lt;li&gt;defines functional and performance specifications.&lt;/li&gt;
&lt;li&gt;designs code&lt;/li&gt;
&lt;li&gt;tests code&lt;/li&gt;
&lt;li&gt;writes documentation&lt;/li&gt;
&lt;li&gt;should have 10 years experience (reminds me of clean coders master role)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The copilot
&lt;ul&gt;
&lt;li&gt;able to do anything the surgeon can.&lt;/li&gt;
&lt;li&gt;is less experienced than the surgeon.&lt;/li&gt;
&lt;li&gt;main role in design is as a thinker, discussant, and evaluator.&lt;/li&gt;
&lt;li&gt;the surgeon works with them to form ideas but is not bound to their suggestions.&lt;/li&gt;
&lt;li&gt;They may write code but are not responsible for the code.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The administrator
&lt;ul&gt;
&lt;li&gt;This is the surgeon&apos;s boss.&lt;/li&gt;
&lt;li&gt;manages personal raises etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The editor
&lt;ul&gt;
&lt;li&gt;This role reviews the documentation generated by the surgeon.&lt;/li&gt;
&lt;li&gt;Provides references in documentation&lt;/li&gt;
&lt;li&gt;criticizes and reworks the documentation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The secretaries
&lt;ul&gt;
&lt;li&gt;handle correspondence for the administrator and editor.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The program clerk
&lt;ul&gt;
&lt;li&gt;Maintains all records of the team in a programming-product library&lt;/li&gt;
&lt;li&gt;Is a secretary for but machine and human-readable files.&lt;/li&gt;
&lt;li&gt;Makes all computer runs visible&lt;/li&gt;
&lt;li&gt;aggregates program output/build information. (I suspect this role is largely un-needed now with advanced CI pipelines)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The toolsmith
&lt;ul&gt;
&lt;li&gt;Creates and maintains special tools for the surgeon&lt;/li&gt;
&lt;li&gt;each team has their own toolsmith&lt;/li&gt;
&lt;li&gt;only produces tools wanted or needed by their surgeon.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The tester
&lt;ul&gt;
&lt;li&gt;creates system tests from functional specs&lt;/li&gt;
&lt;li&gt;Plans testing sequences&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The language lawyer
&lt;ul&gt;
&lt;li&gt;Understand the programming language in use very well.&lt;/li&gt;
&lt;li&gt;Helps find ways to do things that are difficult in the language of choice.&lt;/li&gt;
&lt;li&gt;Can aid many surgeons&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Aristocracy, Democracy, and System Design&lt;/h3&gt;
&lt;p&gt;This chapter focused a lot on architecture implementation and consistent design. It is important to have consistency in design. To make design consistent sometimes it is important to know what features to omit to keep the design consistent. A large portion of this chapter focuses on the difference between architecture and implementation.&lt;/p&gt;
&lt;p&gt;It is important to have architecture and implementation be separate concerns. Only by doing this can you make your system consistent. It is important to note that neither responsibility is any more creative than the other. Creativity is just on different dimensions.&lt;/p&gt;
&lt;p&gt;An architect&apos;s primary responsibility is to define what happens. Architects are focused on the end-user and know how to make the system feel the same. To help keep the system consistent there should be few architects.&lt;/p&gt;
&lt;p&gt;On the other hand, an implementor defines how it happens. While this might not sound like a creative process the creativity here lies in cost and performance optimizations. Sometimes implementors have good ideas, sadly if it is not consistent with the system it really should not be done.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Conceptual integrity is the most important consideration in system design.&lt;/li&gt;
&lt;li&gt;it&apos;s better to omit some features if it makes design ideas consistent.&lt;/li&gt;
&lt;li&gt;Programming systems are intended to make a computer easy to use.&lt;/li&gt;
&lt;li&gt;Ease of use is only enhanced if time gained in functional specification exceeds time lost in learning, remembering, and searching manuals.&lt;/li&gt;
&lt;li&gt;Every part of a system should reflect the same philosophies and use the same techniques in syntax.&lt;/li&gt;
&lt;li&gt;There are two ways to keep the design consistent with multiple people working on a project
&lt;ul&gt;
&lt;li&gt;Careful division of labor between architecture and implementation.&lt;/li&gt;
&lt;li&gt;Structured teams discussed in the surgical team&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Separation of architecture and implementation is a powerful tool for conceptual integrity.&lt;/li&gt;
&lt;li&gt;Architect of the system
&lt;ul&gt;
&lt;li&gt;job is to bring professional and technical knowledge to bear in the interest of the user. This is as opposed to the interested of the salesman&lt;/li&gt;
&lt;li&gt;must carefully be distinguished from implementation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Architecture is what happens implementation is how it happens.&lt;/li&gt;
&lt;li&gt;Just because implementers or users have good ideas does not mean they are the right ideas. It is more important to keep the system consistent and that is the job of the architect.&lt;/li&gt;
&lt;li&gt;There should be few architects&lt;/li&gt;
&lt;li&gt;Architecture work is not more creative than implementation. Just because you are setting the external boundaries does not mean you have made all the creative choices.&lt;/li&gt;
&lt;li&gt;The cost-performance ratio is often where the implementors creativity lies.&lt;/li&gt;
&lt;li&gt;Form can be liberating. Sometimes having additional constraints makes your work more creative. this is not just seen in software as it has been seen in other practices like art.&lt;/li&gt;
&lt;li&gt;Common concerns for implementors that can have from an architecture team.
&lt;ul&gt;
&lt;li&gt;Specifications can be too rich in function and not reflect practical cost considerations. This concern is valid.&lt;/li&gt;
&lt;li&gt;Architects will get all the creative fun. This is argued to not be true.&lt;/li&gt;
&lt;li&gt;They will have to sit by idly while waiting on specifications to arrive. Don&apos;t hire implementors until you have the specs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Implementors can start as soon as a vague idea of the specification exists.&lt;/li&gt;
&lt;li&gt;The Implementor has tons of work to do even before the specification exists.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Second-System Effect&lt;/h3&gt;
&lt;p&gt;At some point in every software project comes a time in which a second system must be considered. In these cases, extreme caution must be made. Oftentimes additional function, extrapolation of function, and over-design are the issues the architect must battle. Another common issue is matching functionality correctly. It often happens that the second system omits some functionality that the first system had.&lt;/p&gt;
&lt;p&gt;On top of these factors friction between the architect and the implementors can come up. The architect needs to remember that it is the implementor&apos;s job to deal with implementation. While this is true for some cases the architect must be ready to suggest a way to implement his design.&lt;/p&gt;
&lt;p&gt;In general, the best practice is to have an architect who is experienced with second systems working on the second system. These architects should be able to spot the pitfalls before it is too late.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;When a cost is too high the software architect has two options
&lt;ol&gt;
&lt;li&gt;Cut the design&lt;/li&gt;
&lt;li&gt;challenge the estimate by suggesting cheaper impelementations.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;The second option gets in the way of the implementer doing their job correctly.&lt;/li&gt;
&lt;li&gt;To do this right the architect must
&lt;ul&gt;
&lt;li&gt;remember that the implementor has inventive and creative control over implementation.&lt;/li&gt;
&lt;li&gt;always be prepared to suggest a way of implementing what he specifies.&lt;/li&gt;
&lt;li&gt;deal with these suggestions&lt;/li&gt;
&lt;li&gt;be ready to forego credit for suggested improvements.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When an architect designs a system they often keep track of embellishments that could be used in a second system.&lt;/li&gt;
&lt;li&gt;second systems are dangerous
&lt;ul&gt;
&lt;li&gt;tendency to over-design the second system&lt;/li&gt;
&lt;li&gt;tends to change the system a bit. Fundamental aspects of the first system might be lost&lt;/li&gt;
&lt;li&gt;aspects of the old system can become obsolete.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;when starting on a second system
&lt;ul&gt;
&lt;li&gt;avoid functional ornamentation&lt;/li&gt;
&lt;li&gt;avoid extrapolation of functions&lt;/li&gt;
&lt;li&gt;discipline is key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If a second system is required consider having an architect who has already done two systems take on the job of the lead architect as they will have learned from their mistakes in their second system.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Passing the Word&lt;/h3&gt;
&lt;p&gt;Keeping a manual or good documentation is key to keeping everyone working on a software project in sync. Manuals should be consistent in style and they should have an appropriate level of precision.&lt;/p&gt;
&lt;p&gt;Using implementation as a formal definition can be a useful tool. When this is done questions are answered unambiguously, a debate is never needed and the precision is always appropriate.&lt;/p&gt;
&lt;p&gt;Another helpful tool for keeping everyone in sync is consistent meetings where changes get discussed and impacts to other components can be identified or known.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;a manual is a necessary tool&lt;/li&gt;
&lt;li&gt;a manual is an external specification of the product.&lt;/li&gt;
&lt;li&gt;manuals should not only include what a user sees but it should also refrain from describing everything a user does not see.&lt;/li&gt;
&lt;li&gt;The style of a manual should be precise.&lt;/li&gt;
&lt;li&gt;Writers of manuals must strain the language they use to create the level of precision required for a manual.&lt;/li&gt;
&lt;li&gt;Merits of formal definitions
&lt;ul&gt;
&lt;li&gt;They are precise&lt;/li&gt;
&lt;li&gt;They tend to be complete&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Problems with formal definitions
&lt;ul&gt;
&lt;li&gt;They lack comprehensibility&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;many tools exist for formal definitions&lt;/li&gt;
&lt;li&gt;care should be made in distinguishing externals in a formal definition&lt;/li&gt;
&lt;li&gt;formal definition is an implementation.&lt;/li&gt;
&lt;li&gt;implementation can also serve as a formal definition&lt;/li&gt;
&lt;li&gt;using implementation as a definition has these advantages
&lt;ul&gt;
&lt;li&gt;All questions can be answered unambiguously with experimentation.&lt;/li&gt;
&lt;li&gt;debate is never needed&lt;/li&gt;
&lt;li&gt;answers are always a precise as one needs and are always correct&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;implementation may over-prescribe&lt;/li&gt;
&lt;li&gt;In an unpoliced system side effects can occur.&lt;/li&gt;
&lt;li&gt;implementation as formal definition can lead to confusion on if it is in fact standard.&lt;/li&gt;
&lt;li&gt;meetings help keep everyone on board. This can prevent hardware and software specifications from drifting&lt;/li&gt;
&lt;li&gt;telephone logs should be kept by architects.
&lt;ul&gt;
&lt;li&gt;These logs record all questions and answers.&lt;/li&gt;
&lt;li&gt;each week this log is concatenated amongst all architects and sent out to implementors.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Why Did the Tower of Babel Fail?&lt;/h3&gt;
&lt;p&gt;Most of the time project failures are the result of people not communicating. This is especially easy to end up happening in larger organizations. What tends to happen in these cases is teams build up assumptions about other teams. These assumptions are not always true and can lead to failures to integrate.&lt;/p&gt;
&lt;p&gt;There are some key tools to dealing with this. The first is identifying and informing teams of their intergroup dependencies. The second is using project meetings. Finally the third is to use a project workbook.&lt;/p&gt;
&lt;p&gt;A project workbook is an imposed standard on documents. In this workbook things like objectives, external specifications, interface specifications, technical standards, internal specifications, and administrative memoranda should be included.&lt;/p&gt;
&lt;p&gt;One last issue that tends to get in the way with large projects is tree organization structures. While these might be good for organizations they are terrible for communication. To work around this you can assign people roles to help with this cross tree issue.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Many project failures occur because two groups of people in a large organization are not talking
&lt;ul&gt;
&lt;li&gt;Each team often has assumptions that have not been verified about the other team.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How to communicate cross team
&lt;ul&gt;
&lt;li&gt;Informally. Keeping everyone informed and having a clear understanding of intergroup dependencies helps.&lt;/li&gt;
&lt;li&gt;Meetings. Have project meetings in which team after team gives a technical briefing.&lt;/li&gt;
&lt;li&gt;Workbook. Create a formal workbook.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Project workbook
&lt;ul&gt;
&lt;li&gt;It is a structure imposed on documents.&lt;/li&gt;
&lt;li&gt;All documents of a project should follow this structure&lt;/li&gt;
&lt;li&gt;Things that should be included: objectives, external specifications, interface specifications, technical standards, internal specifications, and administrative memoranda.&lt;/li&gt;
&lt;li&gt;This is important because technical prose lasts a long time.&lt;/li&gt;
&lt;li&gt;It is important to get the structure right so that memos can be turned into product-quality manuals.&lt;/li&gt;
&lt;li&gt;This also serves to control the distribution of information. This is to not restrict information but instead to get it into all the hands that need it.&lt;/li&gt;
&lt;li&gt;To keep every programmer in the loop every programmer should have a workbook and that workbook should be current.&lt;/li&gt;
&lt;li&gt;Maintenance of a physical workbook can get very difficult over a long period with many contributors.
&lt;ul&gt;
&lt;li&gt;In this example, they solved the problem with microfiche&lt;/li&gt;
&lt;li&gt;Later goes on to reflect on how it might be done today (when the book was published several decades ago). In this, we imagine a direct access file that is LIFO and everyone can see it. No one could directly change the document but they could provide updates that later get aggregated and put back into this read-only LIFO document.&lt;/li&gt;
&lt;li&gt;I imagine today something like wikis or confluence is serving a similar purpose.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Organization in a large programming project
&lt;ul&gt;
&lt;li&gt;Tree-like structures are good for authority and responsibility but are terrible for communication.&lt;/li&gt;
&lt;li&gt;A tree-like programming organization must have these roles to be successful
&lt;ul&gt;
&lt;li&gt;a mission&lt;/li&gt;
&lt;li&gt;a producer&lt;/li&gt;
&lt;li&gt;a technical director or architect&lt;/li&gt;
&lt;li&gt;a schedule&lt;/li&gt;
&lt;li&gt;a division of labor&lt;/li&gt;
&lt;li&gt;interface definitions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What is a producer?
&lt;ul&gt;
&lt;li&gt;The produce assembles a team, divides work, and creates a schedule.&lt;/li&gt;
&lt;li&gt;They require the necessary resources for the team.&lt;/li&gt;
&lt;li&gt;A major role is communication outside of the team.&lt;/li&gt;
&lt;li&gt;ensures the schedule is met.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What is a technical director?
&lt;ul&gt;
&lt;li&gt;thinks up the design to be built&lt;/li&gt;
&lt;li&gt;identifies parts of the design&lt;/li&gt;
&lt;li&gt;specifies how things will look from the outside.&lt;/li&gt;
&lt;li&gt;sketches the internal structure.&lt;/li&gt;
&lt;li&gt;brings unity and conceptual integrity to the design.&lt;/li&gt;
&lt;li&gt;limits technical complexity.&lt;/li&gt;
&lt;li&gt;invents solutions or redesigns the system as problems arise.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The producer and the technical director can be the same person.
&lt;ul&gt;
&lt;li&gt;Can often work on small teams but gets harder to maintain on larger teams.&lt;/li&gt;
&lt;li&gt;A person with strong management and technical skills is super rare.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;In some cases, the producer can be the boss and the technical direction his right-hand man.
&lt;ul&gt;
&lt;li&gt;the producer can do subtle things to help the technical director to avoid power struggles. Examples include office size, carpet, furnishing, carbon copies, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Just like the producer can be the boss the roles could be inverted. In some cases, the technical director is the boss and the producer is the right-hand man.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Calling the Shot&lt;/h3&gt;
&lt;p&gt;This essay is mostly the evaluation of a lot of studies around estimation and effort of different programming tasks.&lt;/p&gt;
&lt;p&gt;One of the key arguments here is that not all programming tasks are equal. Inevitably some programming is harder to do than other types of programming.&lt;/p&gt;
&lt;p&gt;The other key argument is there is more than coding that goes into software development. This means that estimates should not only account for coding time but should consider other tasks such as debugging time.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Estimations should not be based on coding alone since that is only 1/6th the effort&lt;/li&gt;
&lt;li&gt;Charles Portman conducted a study on productivity.
&lt;ul&gt;
&lt;li&gt;Found that tasks had been taking twice as long as estimated.&lt;/li&gt;
&lt;li&gt;50% of the time was found to be debugging time and programming time&lt;/li&gt;
&lt;li&gt;The remaining time was split between unrelated jobs, meetings, paperwork, company business, sickness, personal time, etc.&lt;/li&gt;
&lt;li&gt;Data suggested that there are unrealistic assumptions around technical work hours in a man-year.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Joel Anon studied programmer productivity.
&lt;ul&gt;
&lt;li&gt;In this study, the relationship of interactions amongst developers and instructions written per year had been used.&lt;/li&gt;
&lt;li&gt;With few interactions, 10,000 instructions should be able to be completed in a man-year&lt;/li&gt;
&lt;li&gt;With some interactions, 5,000 instructions should be able to be completed in a man-year&lt;/li&gt;
&lt;li&gt;With many interactions, 1,500 instructions should be able to be completed in a man-year&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;John Harr did another study on this topic
&lt;ul&gt;
&lt;li&gt;productivity was measured in debugged words per man-year&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Prog units&lt;/th&gt;
&lt;th&gt;Number of programs&lt;/th&gt;
&lt;th&gt;Years&lt;/th&gt;
&lt;th&gt;Man-years&lt;/th&gt;
&lt;th&gt;Program words&lt;/th&gt;
&lt;th&gt;Words/man-year&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Operational&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;83&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;52,000&lt;/td&gt;
&lt;td&gt;515&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;81&lt;/td&gt;
&lt;td&gt;51,00&lt;/td&gt;
&lt;td&gt;630&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compiler&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;2.25&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;38,000&lt;/td&gt;
&lt;td&gt;2230&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Translator&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;25,000&lt;/td&gt;
&lt;td&gt;2270&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Data from IBM OS/360 experience, Aron and Harr confirm that productivity is related to the complexity and difficulty of a task.&lt;/li&gt;
&lt;li&gt;According to this data, compilers are three times as bad as batch application programs, and operating systems are three times as bad as compilers.&lt;/li&gt;
&lt;li&gt;Corbto data looks at lines of PL/I per man-year instead of words per man-year. In this study, the lines of debugged PL/I code was found to be 1,200.
&lt;ul&gt;
&lt;li&gt;According to this data, productivity is constant in terms of statements&lt;/li&gt;
&lt;li&gt;According to this data, productivity may increase as much as five times with a high-level programming language.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Ten Pounds in a Five-Pound Sack&lt;/h3&gt;
&lt;p&gt;Most of this chapter focuses on size constraints. This focuses a lot on the cost of resources on older machines. While most of the lessons seem a bit out of date there is likely some equivalent that can be made in modern web and mobile development. Some of the key lessons to take away are the following. If you give users fine-grain control over options more space will be required. Breaking functionality into smaller modules can have an impact on performance and space. This might have been true for native binaries but I am not fully convinced it applies to web development. That is assuming you are not shipping duplicated code in your bundles. The last piece of information we are left with is to think about your data structure. In many cases, space optimization can happen at the data structure level.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Much of this is based on the memory consumption of applications on hardware. At the time this was authored renting even 1KB of data a month was not cheap.&lt;/li&gt;
&lt;li&gt;builder of software must set size targets, control size and devise size-reduction techniques.&lt;/li&gt;
&lt;li&gt;hardware builder sets component-count targets, controls component count, and devises count-reduction techniques.&lt;/li&gt;
&lt;li&gt;Size is not a bad thing but unnecessary size is&lt;/li&gt;
&lt;li&gt;Size control
&lt;ul&gt;
&lt;li&gt;This is partially a technical job and partly a managerial one for a product manager.&lt;/li&gt;
&lt;li&gt;users and applications need to be studied to get sizes right&lt;/li&gt;
&lt;li&gt;Setting targets is not all that needs to be done. In addition, all aspects of size must be budgeted.&lt;/li&gt;
&lt;li&gt;disk access is slow. At this time magnetic tape was common and round trips to the disk had been very expensive.&lt;/li&gt;
&lt;li&gt;A good way to help avoid issues around this kind of thing is to define exactly what a module must do.&lt;/li&gt;
&lt;li&gt;During implementation, architects must be vigilant in ensuring system integrity.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Space techniques
&lt;ul&gt;
&lt;li&gt;Making a program small requires invention and craftsmanship.&lt;/li&gt;
&lt;li&gt;More function means more space.&lt;/li&gt;
&lt;li&gt;The first area of craftmanship is trading function for size.
&lt;ul&gt;
&lt;li&gt;The more fine-grained the user&apos;s options are the more space the program will take up.&lt;/li&gt;
&lt;li&gt;Breaking functions into small modules costs performance and space.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The second area of craftmanship is space-time trade-offs.
&lt;ul&gt;
&lt;li&gt;To do this make sure your team is trained in programming techniques and not just reliant on previous experience.&lt;/li&gt;
&lt;li&gt;Each program should have access to two different library sets for the common functionality. The quick one and the squeezed one.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Often time gains are made via strategic breakthrough instead of tactical cleverness.&lt;/li&gt;
&lt;li&gt;Most breakthroughs will come from redoing the representation of data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Documentary Hypothesis&lt;/h3&gt;
&lt;p&gt;This chapter talks a lot about documentation requirements and how different jobs need different documents. Some recommended documentation for a manager would include documentation around objectives, goals, specifications, schedule, budget, and organization. Managers also need appropriate documentation to handle the forecasting and pricing of their products. Software projects require very similar documentation to that of managers.&lt;/p&gt;
&lt;p&gt;One of the bigger takeaways from this chapter is the need for formal documents. We need formal documents without these documents we cannot check our assumptions. Many times gaps in understanding and knowledge can only be found when documentation is created.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;What are the critical documents for managers?
&lt;ul&gt;
&lt;li&gt;Objectives define the need to be met and the goals.&lt;/li&gt;
&lt;li&gt;Specifications are the computer manual plus performance specifications.&lt;/li&gt;
&lt;li&gt;Schedule&lt;/li&gt;
&lt;li&gt;Budget is a very useful document for managers.&lt;/li&gt;
&lt;li&gt;Organization chart&lt;/li&gt;
&lt;li&gt;Space allocations&lt;/li&gt;
&lt;li&gt;Estimate, forecast, and prices.
&lt;ul&gt;
&lt;li&gt;determine the success or failure of a project&lt;/li&gt;
&lt;li&gt;To generate a forecast you need performance specifications and postulated prices.&lt;/li&gt;
&lt;li&gt;Forecasts determine a per-unit share of development and fixed costs.&lt;/li&gt;
&lt;li&gt;Forecasts allow you to determine prices.&lt;/li&gt;
&lt;li&gt;If prices are below the postulated value then a success spiral occurs.
&lt;ul&gt;
&lt;li&gt;unit costs can drop&lt;/li&gt;
&lt;li&gt;prices can drop&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If prices are above the postulated value then a disastrous spiral begins
&lt;ul&gt;
&lt;li&gt;Performance must be squeezed&lt;/li&gt;
&lt;li&gt;costs must be squeezed down.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Documents for University departments
&lt;ul&gt;
&lt;li&gt;Objectives&lt;/li&gt;
&lt;li&gt;Course descriptions&lt;/li&gt;
&lt;li&gt;Degree requirements&lt;/li&gt;
&lt;li&gt;Research proposals&lt;/li&gt;
&lt;li&gt;Class schedule and teaching assignments&lt;/li&gt;
&lt;li&gt;Budget&lt;/li&gt;
&lt;li&gt;Space allocation&lt;/li&gt;
&lt;li&gt;Assignment of staff and graduate students.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Documents for a Software Project
&lt;ul&gt;
&lt;li&gt;What: Objectives. These define the needs, goals, desiderata, constraints, and priorities&lt;/li&gt;
&lt;li&gt;What: Product specifications. Starts as a proposal but ends up a manual/internal document.&lt;/li&gt;
&lt;li&gt;When: schedule&lt;/li&gt;
&lt;li&gt;How much: budget&lt;/li&gt;
&lt;li&gt;Where: space allocation&lt;/li&gt;
&lt;li&gt;Who: organization chart
&lt;ul&gt;
&lt;li&gt;If the system is free to change the organization must be prepared to change as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Need for formal documents
&lt;ul&gt;
&lt;li&gt;Gaps can only be found once inconsistencies arise in written documents.&lt;/li&gt;
&lt;li&gt;They communicate decisions to others.&lt;/li&gt;
&lt;li&gt;Provides a database and checklist to help managers figure out where to put their efforts.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The task of a manager is to develop a plan and then to realize it. A written plan is precise and communicable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Plan to Throw One Away&lt;/h3&gt;
&lt;p&gt;A common issue in software development is the first thing you build is what will be used. This is not common in other industries and appears to be an issue in the software industry in general. No matter how good your planning is it will never be good enough hence the need for a first throw-away system.&lt;/p&gt;
&lt;p&gt;Since you are planning to throw away you need to accept the fact that change is inevitable. Since change is inevitable there are things you can do to help your system change over time. Some things that help with change over time are the following.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use careful modularization&lt;/li&gt;
&lt;li&gt;Have a complete and precise definition of inter-module interfaces.&lt;/li&gt;
&lt;li&gt;Have complete documentation for modules&lt;/li&gt;
&lt;li&gt;Use a high-level language.&lt;/li&gt;
&lt;li&gt;Use self-documenting techniques.&lt;/li&gt;
&lt;li&gt;Use compile-time operations to enforce standard declarations.&lt;/li&gt;
&lt;li&gt;Use module versioning&lt;/li&gt;
&lt;li&gt;Have good version releasing practices.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another form of change you need to be ready for is organizational change. The best way to handle this is to make sure that your senior management and engineers are technically and emotionally stable. Another key aspect is to generate sound documentation.&lt;/p&gt;
&lt;p&gt;There is a long tail end of software. Even after the product is released there is a maintenance cycle that continues to change the software over time. This maintenance generally costs 40% more than the software had cost to produce. Also with every defect that is fixed in this phase, there is a 20-50% chance a new one will come up as a result of the change. Because of this, it is important to have appropriate regression testing.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Chemical engineers build a pilot plant before making a fully operational factory since what works in a lab does not necessarily work in a factory.&lt;/li&gt;
&lt;li&gt;Programmers do not seem to have this process and this is a constantly repeated mistake.&lt;/li&gt;
&lt;li&gt;In many projects, the first version is barely usable.&lt;/li&gt;
&lt;li&gt;Even the best planning will not be sufficient and eventually, all code gets rewritten.&lt;/li&gt;
&lt;li&gt;This is an interesting dilemma for managers. Do you plan to build a pilot to throw away?
&lt;ul&gt;
&lt;li&gt;You should because you are going to do it anyway&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You need to accept change is an inevitable fact of life.
&lt;ul&gt;
&lt;li&gt;It&apos;s better to be prepared for it than have to comes to terms with it later.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Planning a system for change
&lt;ul&gt;
&lt;li&gt;Use careful modularization&lt;/li&gt;
&lt;li&gt;Have a complete and precise definition of inter-module interfaces.&lt;/li&gt;
&lt;li&gt;Have complete documentation for modules&lt;/li&gt;
&lt;li&gt;Use a high-level language.&lt;/li&gt;
&lt;li&gt;Use self-documenting techniques.&lt;/li&gt;
&lt;li&gt;Use compile-time operations to enforce standard declarations.&lt;/li&gt;
&lt;li&gt;Use module versioning&lt;/li&gt;
&lt;li&gt;Have good version releasing practices.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Planning for Organizational changes.
&lt;ul&gt;
&lt;li&gt;All plans should be treated as tentative.&lt;/li&gt;
&lt;li&gt;reluctance to generate documentation does not come from laziness. Instead, it comes from a designer&apos;s unwillingness to commit themselves to the defense of decisions known to be tentative.
&lt;ul&gt;
&lt;li&gt;&quot;By documenting a design, the designer exposes himself to the criticisms of everyone, and he must be able to defend everything he writes.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Structuring an organization for change is harder than designing a system for change.
&lt;ul&gt;
&lt;li&gt;Every developer must be given tasks to broaden their skill set.&lt;/li&gt;
&lt;li&gt;The manager needs to keep two or three top programmers to jump in on the toughest issues.&lt;/li&gt;
&lt;li&gt;Managers and technical people need to be interchangeable as talents allow.&lt;/li&gt;
&lt;li&gt;Often has sociological barriers&lt;/li&gt;
&lt;li&gt;A common trap is for managers to think of senior people as &quot;too valuable&quot; to use for actual programming.
&lt;ul&gt;
&lt;li&gt;Bell labs overcame this issue by getting rid of job titles.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It&apos;s easy to increase salary with job tiers, it&apos;s harder to give higher job tiers more prestige.&lt;/li&gt;
&lt;li&gt;Switching from a technical path to a manager path should never result in a raise.
&lt;ul&gt;
&lt;li&gt;This is a reassignment, not a promotion.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A manager should have technical refresher courses.&lt;/li&gt;
&lt;li&gt;Senior developers should have management training.&lt;/li&gt;
&lt;li&gt;Senior people must be kept technically and emotionally ready to manage groups or to build programs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Programs do not stop changing once they are delivered to a customer.&lt;/li&gt;
&lt;li&gt;Hardware and Software have very different maintenance requirements.&lt;/li&gt;
&lt;li&gt;Software Maintenance
&lt;ul&gt;
&lt;li&gt;Requires constant fixing of defects.&lt;/li&gt;
&lt;li&gt;The cost of maintenance is typically 40% more than developing it in the first place.&lt;/li&gt;
&lt;li&gt;The more users you have the more bugs that are found.&lt;/li&gt;
&lt;li&gt;Old bugs found and solved strangely seem to come back in future releases.&lt;/li&gt;
&lt;li&gt;New functions of a new release often have defects.&lt;/li&gt;
&lt;li&gt;Bugs begin to plateau over time but some of this might be customers becoming complacent with the bugs that are in the system.&lt;/li&gt;
&lt;li&gt;Fixing a defect has a 20-50% chance of introducing another.
&lt;ul&gt;
&lt;li&gt;Unless the program is well documented it is too easy to make a local change at a minimum effort instead of looking at the wider-reaching impact of the change.&lt;/li&gt;
&lt;li&gt;The repairer is often not the developer that wrote the code. This is often done by a junior programmer or trainee.&lt;/li&gt;
&lt;li&gt;Results in far more system testing&lt;/li&gt;
&lt;li&gt;Regression testing must be done but it can be very costly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The total number of modules increases linearly with each release number. Repairs often destroy the structure and cause disorder to the system.&lt;/li&gt;
&lt;li&gt;Over time less effort is spent on fixing the original design flaws and more time is spent fixing flaws introduced by earlier fixes.&lt;/li&gt;
&lt;li&gt;Things are always best at their beginning from a statistical model.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Sharp Tools&lt;/h3&gt;
&lt;p&gt;Most of this chapter feels a bit outdated. Much of the discussion in this chapter is centered around tooling and environments.&lt;/p&gt;
&lt;p&gt;In this chapter, there is an argument that tools are secrets held close by developers and not shared. Thankfully the proliferation of open source over the years has almost turned this around completely. At this point, it feels like there are too many tools to choose from. There are also big players in the game backing important tooling projects with real money. There is a lot more that could be said about open source and the pros and cons but that is not related to this chapter.&lt;/p&gt;
&lt;p&gt;Another topic that is discussed a ton is environments. This is another thing I think has changed over time. Anymore much of consumer software runs in virtual machines. Often higher-level languages like Java, C#, Javascript, Go, etc are running in virtual machines and do not have to worry much if at all about the target machine.&lt;/p&gt;
&lt;p&gt;The last thing is a call for better debugging and tooling. I think there is always room for improvement here but it seems we have come a long way from having to evaluate heaps. Anymore it is not uncommon to be able to have a fully debuggable environment with near real-time feedback to the developer.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Many programmers have their own personal set of tools that they acquire over time and do not share
&lt;ul&gt;
&lt;li&gt;I do not think this is true anymore, if anything we have too many shared tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Individualized tools hamper instead of aiding communication&lt;/li&gt;
&lt;li&gt;There are not enough general-purpose tools
&lt;ul&gt;
&lt;li&gt;Again not sure I agree with this in modern times.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Target machines
&lt;ul&gt;
&lt;li&gt;machine support can be broken down into target machine and vehicle machines
&lt;ul&gt;
&lt;li&gt;The target machine is the one that the software is being written for.&lt;/li&gt;
&lt;li&gt;The vehicle machines are the ones that provide the services used in the build system.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Teams building new supervisors or core system software need machines of their own.
&lt;ul&gt;
&lt;li&gt;This comes with the overhead of operators and a system programmer or two to make sure the machines in use are serviceable.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Debugging machines need to be instrumented so that counts and measurements can be made on all kinds of program parameters.&lt;/li&gt;
&lt;li&gt;Scheduling can be a real issue when there is a limited supply of the target machine.
&lt;ul&gt;
&lt;li&gt;Generally speaking, usage starts low but as teams start to get ready to debug their features demand for time on the system is very high. Generally, all teams hit this point at the same time.&lt;/li&gt;
&lt;li&gt;In the S/360 project no matter how they tried to divvy up the time it was always an issue and in the end, they need to allocate large segments of time to teams for debugging.&lt;/li&gt;
&lt;li&gt;Giving large chunks of time on a target machine tends to work out better for productivity.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Vehicle Machines and Data Services
&lt;ul&gt;
&lt;li&gt;If the target computer is new you need a simulator.
&lt;ul&gt;
&lt;li&gt;Needs to exist long before the target does.&lt;/li&gt;
&lt;li&gt;Gives access to dependable debugging. This is not to be confused with accurate debugging as only the target machine will give that to you.&lt;/li&gt;
&lt;li&gt;Anymore hardware works correctly. This means if you have a bug it would be wise to start looking at the software first.
&lt;ul&gt;
&lt;li&gt;This is not true for new machines. In the case of new machines often there are hardware issues.&lt;/li&gt;
&lt;li&gt;Simulators help when these hardware issues do crop up.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Compiler and assemblers
&lt;ul&gt;
&lt;li&gt;Compilers and assemblers should work on vehicle machines but compile down to the target machine.&lt;/li&gt;
&lt;li&gt;With high-level languages, a lot more testing can be done on the vehicle machine before moving to the target machine.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Program Libraries
&lt;ul&gt;
&lt;li&gt;OS/360 used vehicle machines to maintenance program libraries.
&lt;ul&gt;
&lt;li&gt;All code tested was kept in the library&lt;/li&gt;
&lt;li&gt;Libraries were sub-libraries with different access rules.&lt;/li&gt;
&lt;li&gt;Programmers had playpen areas with no restrictions. These had been used for test cases and component scaffolding.&lt;/li&gt;
&lt;li&gt;When a program was ready for integration, this code was passed off to a manager that put the code into a system integration sub-library.
&lt;ul&gt;
&lt;li&gt;At this point, the programmer could no longer change the code with permission from the integration manager.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When the system version was ready for larger use it would be promoted to the current version sub-library.
&lt;ul&gt;
&lt;li&gt;This version never changes unless there are crippling bugs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What this did right were control and formal separation. In this case, changes went through different stages.
&lt;ul&gt;
&lt;li&gt;This reminds me a bit of dev, test stage, prod cycles that are common in the industry now.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Program tools
&lt;ul&gt;
&lt;li&gt;Developers need dumps, source-file editors, snapshot dumps, and traces.&lt;/li&gt;
&lt;li&gt;Developers also need utilities for putting decks on disks, making tape copies, printing files, and changing catalogs.
&lt;ul&gt;
&lt;li&gt;Not sure I believe this is relevant anymore.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Documentation system
&lt;ul&gt;
&lt;li&gt;It is better to over document than to under document a system.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Performance simulators are a must-have.&lt;/li&gt;
&lt;li&gt;High-Level Language and Interactive Programming
&lt;ul&gt;
&lt;li&gt;These are powerful tools that had not gotten enough inertia at the time. I think this has changed over time. Anymore I suspect it is harder to find a developer that will work in anything other than a high level-language (assuming you consider c++, rust, etc high level)&lt;/li&gt;
&lt;li&gt;High-Level languages
&lt;ul&gt;
&lt;li&gt;Are far more productive&lt;/li&gt;
&lt;li&gt;Have better debugging speeds.&lt;/li&gt;
&lt;li&gt;There tend to be fewer bugs.
&lt;ul&gt;
&lt;li&gt;This is because many semantic bugs are no longer possible. An example would be misusing registers.&lt;/li&gt;
&lt;li&gt;The compiler often finds your bugs for you at compile time.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Common objections to high-level languages
&lt;ul&gt;
&lt;li&gt;It doesn&apos;t let me do what I want&lt;/li&gt;
&lt;li&gt;Object code is too big&lt;/li&gt;
&lt;li&gt;Object code is too slow&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Objections are no longer valid. Compilers are doing a much better job at optimization.&lt;/li&gt;
&lt;li&gt;At the time of authoring the recommended high level-language was &lt;a href=&quot;https://en.wikipedia.org/wiki/PL/I&quot;&gt;PL/I&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Interactive programming
&lt;ul&gt;
&lt;li&gt;The author believes interactive programming will never replace batch systems for more applications.&lt;/li&gt;
&lt;li&gt;There is no evidence to prove these tools are useful.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Whole and the Parts&lt;/h3&gt;
&lt;p&gt;In this chapter reducing bugs, testing applications, and debugging are discussed.&lt;/p&gt;
&lt;p&gt;For the most part, bugs are the result of mismatched expectations between component authors. To avoid this it is important to have detailed specifications on the component boundaries. The better the documentation is on the components the less likely there are the be bugs.&lt;/p&gt;
&lt;p&gt;When it comes to testing developers mustn&apos;t be the ones testing their code. It is too easy for developers to invent ways to fix the problem in testing instead of fixing their code.&lt;/p&gt;
&lt;p&gt;The top-down design methodology is proposed as a solution to avoid bugs. In this case system building is broken down into architecture, implementation, and realization. At each stage in this process, refinement can happen to make sure the scope is appropriate and those modules are defined well. This process avoids bugs by having a clear structure and representation. This process also produces smaller modules.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Designing the bugs out
&lt;ul&gt;
&lt;li&gt;Bug proof definitions
&lt;ul&gt;
&lt;li&gt;Most subtle bugs come from mismatched assumptions between component authors.&lt;/li&gt;
&lt;li&gt;The crucial task is to get the product defined.&lt;/li&gt;
&lt;li&gt;Most failures happen around things not specified.&lt;/li&gt;
&lt;li&gt;Bugs can be reduced by careful function definition, careful specification, and disciplined exorcism of frills of function.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Testing application
&lt;ul&gt;
&lt;li&gt;Before code exists specification should be handled to an outside testing group.&lt;/li&gt;
&lt;li&gt;developers invent ways around gaps&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Top-down design
&lt;ul&gt;
&lt;li&gt;System building can be divided into architecture, implementation, and realization.&lt;/li&gt;
&lt;li&gt;This can be done by top-down methods&lt;/li&gt;
&lt;li&gt;refinement steps
&lt;ul&gt;
&lt;li&gt;sketch rough task definition and solution.&lt;/li&gt;
&lt;li&gt;example the definition more closely to see how results differ from what is desired.&lt;/li&gt;
&lt;li&gt;take large steps and break them down into smaller steps.&lt;/li&gt;
&lt;li&gt;In this process identification of modules of solution or data that can be refined independently are found.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This process avoids bugs by
&lt;ul&gt;
&lt;li&gt;having clarify of structure and representation.&lt;/li&gt;
&lt;li&gt;partitioning modules&lt;/li&gt;
&lt;li&gt;suppression of detail makes flaws more apparent.&lt;/li&gt;
&lt;li&gt;design can be tested in refinement steps&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;reduces the temptation to patch over bad design.&lt;/li&gt;
&lt;li&gt;Argued to be the most important new programming formalization of the decade.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Structured Programming
&lt;ul&gt;
&lt;li&gt;Design programs whose control structures consist only of loops and conditionals.&lt;/li&gt;
&lt;li&gt;This is an alternative to using GO TO which leads to many logical errors&lt;/li&gt;
&lt;li&gt;We should think of the control structures of a system as control structures not as branch statements.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Component Debugging
&lt;ul&gt;
&lt;li&gt;When debugging on a machine, it is a bad idea to start without planning what you want to test.&lt;/li&gt;
&lt;li&gt;Memory dumps
&lt;ul&gt;
&lt;li&gt;Sometimes access to a machine is scarce and taking up two-plus hour segments to debug is not always a good option.&lt;/li&gt;
&lt;li&gt;Allows for postmortem debugging.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Snapshots allowed for insertion into a program without reassembly or recompilation&lt;/li&gt;
&lt;li&gt;Interactive debugging
&lt;ul&gt;
&lt;li&gt;Efficient editing facilities make snapshots easy&lt;/li&gt;
&lt;li&gt;provides instant turnaround capability.&lt;/li&gt;
&lt;li&gt;preplanning is not as necessary.&lt;/li&gt;
&lt;li&gt;The author suggests two hours of desk time for every two hours in the terminal.
&lt;ul&gt;
&lt;li&gt;Forces you to stop and plan.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Test cases are important.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;System Debugging
&lt;ul&gt;
&lt;li&gt;System Debugging will take longer than one expects.&lt;/li&gt;
&lt;li&gt;Only debug after pieces seem to work.&lt;/li&gt;
&lt;li&gt;The sooner pieces are put together the sooner bugs will emerge.&lt;/li&gt;
&lt;li&gt;Less scaffolding is required when pieces test each other.
&lt;ul&gt;
&lt;li&gt;This is a bit of a trap and the time spent scaffolding is often worth it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The &quot;documented bug&quot; approach promotes finding bugs before fixing them.
&lt;ul&gt;
&lt;li&gt;This is a wishful thinking approach used to rationalize away slipped schedules.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Build scaffolding
&lt;ul&gt;
&lt;li&gt;It is not unreasonable to have half as much code in scaffolding as in the product.&lt;/li&gt;
&lt;li&gt;A form of scaffolding can be the dummy component. This component exists only of interfaces and fake data.&lt;/li&gt;
&lt;li&gt;miniature files can be used to make sure formats are correct.&lt;/li&gt;
&lt;li&gt;auxiliary programs include
&lt;ul&gt;
&lt;li&gt;generators for test data.&lt;/li&gt;
&lt;li&gt;analysis printouts.&lt;/li&gt;
&lt;li&gt;cross-reference table analyzers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Tight control should happen.&lt;/li&gt;
&lt;li&gt;All changes should be logged.&lt;/li&gt;
&lt;li&gt;Only add one component at a time.&lt;/li&gt;
&lt;li&gt;Though test cases are needed.&lt;/li&gt;
&lt;li&gt;Tests should be run after each component is added.&lt;/li&gt;
&lt;li&gt;Systematic testing procedures should happen for all updates to existing components.&lt;/li&gt;
&lt;li&gt;Be careful about release time, changes can disrupt others who are expecting a stable testbed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Hatching a Catastrope&lt;/h3&gt;
&lt;p&gt;In this chapter projects and deadlines are discussed in depth. A large focus of this chapter is how to detect when a project is falling behind. In many cases, a project does not fall behind over one major thing. Instead, over time a lot of little things add up and cause major deadline issues.&lt;/p&gt;
&lt;p&gt;To help mitigate this a schedule is needed with concrete, specific, measurable, and well-defined milestones. The more specific the milestone is the harder it is for anyone to deceive themselves into believing that an unfinished project could be counted as a complete milestone.&lt;/p&gt;
&lt;p&gt;In some cases, developers will need to try harder than necessary to cope with mishaps. This is a talent that should be used sparingly but is a talent that needs to be able to be utilized. Since this should be used sparingly a PERT chart should be used to identify when this is required.&lt;/p&gt;
&lt;p&gt;Sometimes slippages get hidden from managers. This is often not a deliberate act but instead a shield to not burden upper management with too much information. To avoid this becoming a real issue there are a couple of suggestions made in this chapter for appropriate information transfer in these cases. In many cases, it is an issue of providing the boss with the correct amount of actionable and status information. As a boss, it is your job not to act not status information. In some cases, a boss just needs more information in these cases a PERT chart acts as a perfect document to get them the scheduling information they need.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Disaster in projects is often a bunch of little things instead of one big thing&lt;/li&gt;
&lt;li&gt;slippages are hard to recognize, harder to prevent, and even harder to make up.&lt;/li&gt;
&lt;li&gt;You need a schedule
&lt;ul&gt;
&lt;li&gt;Broken down into milestones with fixed dates
&lt;ul&gt;
&lt;li&gt;picking the right date is an estimation problem&lt;/li&gt;
&lt;li&gt;milestones must be concrete, specific, measurable, and defined with knife-edge sharpness.
&lt;ul&gt;
&lt;li&gt;This is a departure from coding which is usually 90% complete and debugging which is usually 99% complete.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;milestones must also be unambiguous in the sense that they should be easily verifiable by a boss.&lt;/li&gt;
&lt;li&gt;If the milestone is defined well enough it is hard for someone to deceive themselves into believing an effort is complete.&lt;/li&gt;
&lt;li&gt;Sharp milestones are to the benefit of the team.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;hustle is a talent that is used in sports and good programming teams. In this case, hustle means trying harder than necessary to cope with routine mishaps.&lt;/li&gt;
&lt;li&gt;You need to pay attention to a one-day slip it is a big deal.&lt;/li&gt;
&lt;li&gt;PERT technique acts as a guide for when to apply hustle.
&lt;ul&gt;
&lt;li&gt;A PERT chart is an elaboration of critical-path scheduling in which one estimates three times for every event. This was covered in an earlier chapter.&lt;/li&gt;
&lt;li&gt;The most valuable use is the preparation of the PERT chart. This helps identify dependencies, lays out the network, and estimates all legs of a project.&lt;/li&gt;
&lt;li&gt;The first chart is always terrible.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It is common for slippages to accidentally get swept under the rug
&lt;ul&gt;
&lt;li&gt;All bosses need two kinds of information
&lt;ul&gt;
&lt;li&gt;Exceptions to the plan that requires action.&lt;/li&gt;
&lt;li&gt;Status picture&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This can cause issues between first-line managers and bosses. The first line manager might want to warn of slippage but there may be no action required.&lt;/li&gt;
&lt;li&gt;To help address this
&lt;ul&gt;
&lt;li&gt;Role conflict must be reduced.
&lt;ul&gt;
&lt;li&gt;The boss needs to be able to distinguish between action and status information.&lt;/li&gt;
&lt;li&gt;The boss must not act on problems the manager can solve.&lt;/li&gt;
&lt;li&gt;The boss must never explicitly act on problems when reviewing status.&lt;/li&gt;
&lt;li&gt;The boss should label meetings as status review or problem action meetings.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A boss should occasionally yank the rug back.
&lt;ul&gt;
&lt;li&gt;There need to be review techniques in which true status is known.&lt;/li&gt;
&lt;li&gt;PERT charts are often the answer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Preparation of PERT chart is a function of the boss and managers reporting to them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Other Face&lt;/h3&gt;
&lt;p&gt;This is another chapter that talks about the importance of good documentation. This chapter focuses on a couple of different types of documentation.&lt;/p&gt;
&lt;p&gt;The first type of documentation that is mentioned is the documentation required to use a program. The common issue with this kind of documentation is it often lacks sufficient explanation. In many cases, the big picture is documented but the finer details are omitted from the documentation. Good usage documentation addresses the following.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Purpose. What is the main function and reason for the program?&lt;/li&gt;
&lt;li&gt;Environment. What machines, hardware, and operating systems does it run on?&lt;/li&gt;
&lt;li&gt;Domain and Range. What is the type of input? What kinds of output can you expect?&lt;/li&gt;
&lt;li&gt;Algorithms used. What does the program do?&lt;/li&gt;
&lt;li&gt;Input-Output formats. Complete and precise details on these formats.&lt;/li&gt;
&lt;li&gt;Operating Instructions. What are the normal and abnormal end operations?&lt;/li&gt;
&lt;li&gt;Options. What choices does the user have? How can the user specify those?&lt;/li&gt;
&lt;li&gt;Running time. How long should the program take to run?&lt;/li&gt;
&lt;li&gt;Accuracy. How precise are the answers intended to be?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another type of documentation is the documentation required to believe a program works. In general, this documentation comes in the form of small tests a user can perform against the program to verify it is working as documented.&lt;/p&gt;
&lt;p&gt;The last type of documentation covered in this chapter is documentation to modify a program. This documentation gives a clear overview of the internal structure of the product. In this documentation, you might expect to find flow charts, descriptions of algorithms used, explanations of file layouts, and discussions around modifications that had been considered but not implemented.&lt;/p&gt;
&lt;p&gt;The last section of this chapter discussed self-documenting programs. In this case, the idea is the source code acts as documentation. In the form proposed in this essay code comments are used but it does mention having descriptive variable names. This call to action is a little bit less strict than the self-documenting approach mentioned in clean code.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;There are two faces to software
&lt;ul&gt;
&lt;li&gt;One is it is a message from man to machine.&lt;/li&gt;
&lt;li&gt;The other is human to human. Memory fades ownership changes and we still need to understand what a program does&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Documentation becomes even more important if the user does not have direct access to the author&lt;/li&gt;
&lt;li&gt;Documentation and the practices around it are wrong despite efforts to make it better.&lt;/li&gt;
&lt;li&gt;The most important aspect is the &quot;how&quot; of documentation.&lt;/li&gt;
&lt;li&gt;What documentation is required?
&lt;ul&gt;
&lt;li&gt;Different levels of documentation are required for different users.&lt;/li&gt;
&lt;li&gt;Documentation to use a program.
&lt;ul&gt;
&lt;li&gt;Most documentation fails to give a sufficient overview. Big picture stuff is not covered but all the little details are.&lt;/li&gt;
&lt;li&gt;This documentation should have the following
&lt;ul&gt;
&lt;li&gt;Purpose. What is the main function and reason for the program?&lt;/li&gt;
&lt;li&gt;Environment. What machines, hardware, and operating systems does it run on?&lt;/li&gt;
&lt;li&gt;Domain and Range. What is the type of input? What kinds of output can you expect?&lt;/li&gt;
&lt;li&gt;Algorithms used. What does the program do?&lt;/li&gt;
&lt;li&gt;Input-Output formats. Complete and precise details on these formats.&lt;/li&gt;
&lt;li&gt;Operating Instructions. What are the normal and abnormal end operations?&lt;/li&gt;
&lt;li&gt;Options. What choices does the user have? How can the user specify those?&lt;/li&gt;
&lt;li&gt;Running time. How long should the program take to run?&lt;/li&gt;
&lt;li&gt;Accuracy. How precise are the answers intended to be?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;In general, this documentation should fit into 3 or 4 pages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Documentation to believe a program
&lt;ul&gt;
&lt;li&gt;To believe it works you need proof. Proof comes in the form of test cases.&lt;/li&gt;
&lt;li&gt;Every copy of a program should include some small test cases the user can use to verify the program is correctly loaded on their machine.&lt;/li&gt;
&lt;li&gt;Types of tests
&lt;ul&gt;
&lt;li&gt;Mainline cases that test key functionality for commonly encountered data.&lt;/li&gt;
&lt;li&gt;Barely legitimate cases that test the edge cases in input data.&lt;/li&gt;
&lt;li&gt;Barely illegitimate cases that test inputs that raise diagnostic messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Documentation to modify a program.
&lt;ul&gt;
&lt;li&gt;Adapting or fixing a program requires more information.&lt;/li&gt;
&lt;li&gt;Needs to have a clear and sharp overview of the internal structure.&lt;/li&gt;
&lt;li&gt;Components of the overview.
&lt;ul&gt;
&lt;li&gt;A flow chart or subprogram structure graph.&lt;/li&gt;
&lt;li&gt;Complete descriptions of algorithms used.&lt;/li&gt;
&lt;li&gt;Explanation of layout of files.&lt;/li&gt;
&lt;li&gt;Overview of how data is loaded from disk.&lt;/li&gt;
&lt;li&gt;Discussions of modifications considered but not implemented. These observations are critical.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Flow charts
&lt;ul&gt;
&lt;li&gt;Is the most oversold piece of program documentation.&lt;/li&gt;
&lt;li&gt;Many do not need flow charts.&lt;/li&gt;
&lt;li&gt;Only show one aspect of a program&apos;s structure.&lt;/li&gt;
&lt;li&gt;Break down when they span more than one page.&lt;/li&gt;
&lt;li&gt;blow-by-blow flow charts are an obsolete nuisance whose only purpose is to initiate beginners into algorithmic thinking.&lt;/li&gt;
&lt;li&gt;flowcharting is more preached than practiced.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Self-documenting programs
&lt;ul&gt;
&lt;li&gt;It&apos;s better to keep all data in one place instead of spreading it out across multiple locations&lt;/li&gt;
&lt;li&gt;We break this rule all the time trying to maintain a human and machine-readable version of the code.&lt;/li&gt;
&lt;li&gt;Program documentation is notoriously poor and its maintenance is even worse.&lt;/li&gt;
&lt;li&gt;Documentation should be in the source of the program.&lt;/li&gt;
&lt;li&gt;High-level languages make this more possible.&lt;/li&gt;
&lt;li&gt;Approach to minimizing the burden of documentation.
&lt;ul&gt;
&lt;li&gt;Use parts of the program that have to be there anyway. This would include labels, declaration statements, and symbolic names.&lt;/li&gt;
&lt;li&gt;Use space and format to your advantage.&lt;/li&gt;
&lt;li&gt;Insert necessary documentation into comments.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Why not do this?
&lt;ul&gt;
&lt;li&gt;Increased size of source code stored.&lt;/li&gt;
&lt;li&gt;Requires more keystrokes.&lt;/li&gt;
&lt;li&gt;In general the benefits out-weight the negatives.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;No Silver Bullet - Essence and Accident&lt;/h3&gt;
&lt;p&gt;This is the longest of the essays in the book and quite possibly the most quoted title in the industry. In this chapter, the silver bullet refers to some possible technique, technology, or management style that would radically improve the productivity of software projects.&lt;/p&gt;
&lt;p&gt;The argument posed is that it is very likely that developers would like to find some solution that could drastically improve productivity. This comes in part due to software&apos;s counterpart hardware. In the case of hardware, with the introduction of the transistor, we saw very large productivity gains. It is argued that no technology in the history of man has ever grown as fast or effectively as hardware. The issue here is software is built on hardware so there is the hope that we could find the transistor equivalent for software.&lt;/p&gt;
&lt;p&gt;In this chapter the argument is that no such technique can be found in software and instead we should strive for incremental improvement. This argument is made by evaluating essential and accidental complexity in software development. To give a loose definition accidental complexity is any complexity that does not need to exist to get the job of software development done. Some examples of accidental complexity would be compile times, machine access, and language. On the other hand, essential complexity is the complexity that must be handled and is the main purpose of software. Essential complexity is defining what it is we want the program to do. It is argued that the only real drastic gains that can be had in software ever is for the accidental complexity. It is also argued that most of the challenges with accidental complexity are mostly solved and there are only minor incremental gains that can be had at this point. Since all that is left is essential complexity there are no more major improvements to be had since all that is left is the main part of the job which is essentially difficult.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Software construction is made up of essential tasks and accidental tasks.
&lt;ul&gt;
&lt;li&gt;Essential tasks are the fashioning of complex conceptual structures.&lt;/li&gt;
&lt;li&gt;Accidental tasks are the representations of abstract entities in programming languages. This includes the management of space and speed constraints.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Most gains in software productivity have come from removing artificial barriers that have made accidental tasks harder. Examples include severe hardware constraints, awkward programming languages, and lack of machine time.&lt;/li&gt;
&lt;li&gt;Ways to address the essential complexity
&lt;ul&gt;
&lt;li&gt;Exploit mass market. Do not build what can be bought.&lt;/li&gt;
&lt;li&gt;Use rapid prototyping&lt;/li&gt;
&lt;li&gt;Grow software organically, add function over time as needed.&lt;/li&gt;
&lt;li&gt;Develop great conceptual designers in the next generation of software developers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Everyone wants to see software costs drop as fast as hardware costs did.&lt;/li&gt;
&lt;li&gt;No development or management technique offers even one order of magnitude improvement of productivity in software development.&lt;/li&gt;
&lt;li&gt;Progress must be made stepwise. It is time to stop expecting some magical solution to this problem.&lt;/li&gt;
&lt;li&gt;We should never expect the type of gains we have seen in hardware in any field. Hardware has progressed faster than any other technology.&lt;/li&gt;
&lt;li&gt;Essence includes the interlocking concepts: data sets, relationships among data items, algorithms, and invocations of functions.&lt;/li&gt;
&lt;li&gt;Essence is abstract but at the same time highly precise and richly detailed.&lt;/li&gt;
&lt;li&gt;The hard part of building software is the specification, design, and testing, not the labor of representing it.&lt;/li&gt;
&lt;li&gt;Building software will always be hard.&lt;/li&gt;
&lt;li&gt;Complexity
&lt;ul&gt;
&lt;li&gt;Software is more complex for its size than any other human construct.&lt;/li&gt;
&lt;li&gt;No two parts are alike and if they are we make them one (DRY).&lt;/li&gt;
&lt;li&gt;Digital computers have a very large number of states. This makes conceiving, describing, and testing hard.&lt;/li&gt;
&lt;li&gt;Software systems have orders of magnitude more states than computers.&lt;/li&gt;
&lt;li&gt;The complexity of the software system does not grow linearly.&lt;/li&gt;
&lt;li&gt;The complexity of software is essential, not accidental.&lt;/li&gt;
&lt;li&gt;This complexity leads to difficulty communicating between team members. This then leads to bugs, cost overruns, and schedule delays.&lt;/li&gt;
&lt;li&gt;The complexity of functions is invoking those functions.&lt;/li&gt;
&lt;li&gt;With the complexity of structure comes extending programs to use new functions without creating side effects.&lt;/li&gt;
&lt;li&gt;With the complexity of structure comes unvisualized states that become trapdoors.&lt;/li&gt;
&lt;li&gt;The complexity creates management burdens as well as learning, and understanding burdens.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conformity
&lt;ul&gt;
&lt;li&gt;Unlike in other fields, the complexity that software engineers must face is arbitrary.&lt;/li&gt;
&lt;li&gt;A lot of complexity comes from conformation to other interfaces which cannot be simplified out.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Changeability
&lt;ul&gt;
&lt;li&gt;Modifications in most manufactured goods are hard but software modifications are rather easy.&lt;/li&gt;
&lt;li&gt;Software can be changed more easily because it is &quot;pure thought-stuff&quot; and therefore infinitely malleable.&lt;/li&gt;
&lt;li&gt;All successful software gets changed.
&lt;ul&gt;
&lt;li&gt;As software becomes more popular more people use it and those people will continue to press the edge cases.&lt;/li&gt;
&lt;li&gt;All software survives beyond the normal life of the vehicle for which it was written.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Invisibility
&lt;ul&gt;
&lt;li&gt;Software is invisible and unvisualizable.&lt;/li&gt;
&lt;li&gt;Geometrics abstractions are a powerful tool other fields get to use but it does not quite work the same way for software. For instance, an architect can use a floor plan.&lt;/li&gt;
&lt;li&gt;Software does not exist in physical space.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Past Breakthroughs solved accidental difficulties.
&lt;ul&gt;
&lt;li&gt;High-level languages
&lt;ul&gt;
&lt;li&gt;Is believed to have created a productivity increase of at least 5 times.&lt;/li&gt;
&lt;li&gt;Also has gains in reliability, simplicity, and comprehensibility.&lt;/li&gt;
&lt;li&gt;Eliminates a whole level of complexity that was never inherent in programming.&lt;/li&gt;
&lt;li&gt;At some point, the elaboration of high-level languages becomes a burden and increases, not reduces, complexity.&lt;/li&gt;
&lt;li&gt;No additional gains can be found here.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Time-sharing
&lt;ul&gt;
&lt;li&gt;Had a large increase in productivity just not as much as high-level languages.&lt;/li&gt;
&lt;li&gt;This tackled a problem of immediacy.&lt;/li&gt;
&lt;li&gt;Slow turn-around is accidental instead of essential.&lt;/li&gt;
&lt;li&gt;Turn arounds are getting fast enough that they do not cause a cognitive disconnect.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Unified programming environments
&lt;ul&gt;
&lt;li&gt;Unix and Interlisp changed this space by having integrated libraries, unified file formats, and pipes and filters.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Hopes for silver
&lt;ul&gt;
&lt;li&gt;Ada and other high-level languages
&lt;ul&gt;
&lt;li&gt;Ada is a high-level language of the 1980s&lt;/li&gt;
&lt;li&gt;The philosophy might be more of an advance than the actual language.&lt;/li&gt;
&lt;li&gt;The philosophy is the modularization of abstract data types of hierarchical structuring.&lt;/li&gt;
&lt;li&gt;Ada will not be a silver bullet because it is just another high-level language.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Object-oriented programming.
&lt;ul&gt;
&lt;li&gt;Must be careful to distinguish between two separate ideas under the same name.
&lt;ul&gt;
&lt;li&gt;abstract data types.
&lt;ul&gt;
&lt;li&gt;object&apos;s type should be defined by a name, set of values, and a set of proper operations. This does not include its storage structure which should be hidden.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;hierarchical types also called classes.
&lt;ul&gt;
&lt;li&gt;Allow for the definition of interfaces.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This removes more accidental difficulties from the process by allowing the designer to express the essence of design.&lt;/li&gt;
&lt;li&gt;This does not solve any problems with essential complexity.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Artificial Intelligence
&lt;ul&gt;
&lt;li&gt;Many people believe this will be revolutionary and will produce orders of magnitude improvement the author does not agree.&lt;/li&gt;
&lt;li&gt;Common definitions for Artificial intelligence
&lt;ul&gt;
&lt;li&gt;The use of computers to solve problems that previously could only be solved by human intelligence.&lt;/li&gt;
&lt;li&gt;The use of a specific set of programming techniques known as heuristic or rule-based programming.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;There is not enough in common amongst problem domains. Problems solved with artificial intelligence in speech recognition have little to no overlap with image recognition.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Expert Systems
&lt;ul&gt;
&lt;li&gt;An expert system is a program containing a generalized inference engine and a rule base.&lt;/li&gt;
&lt;li&gt;These systems are designed to take input data and assumptions to explore logical consequences through the inferences derivable from the rule base.&lt;/li&gt;
&lt;li&gt;The ultimate outcome is conclusions and advice.&lt;/li&gt;
&lt;li&gt;Inference engines can deal with fuzzy probabilistic data and purely deterministic logic.&lt;/li&gt;
&lt;li&gt;Inference engine technology is developed in an application-agnostic way. This allows it to be applied to many uses.&lt;/li&gt;
&lt;li&gt;The changeable parts of the inference engine are encoded in the rule base.&lt;/li&gt;
&lt;li&gt;The most important advance is the separation of application complexity from the program.&lt;/li&gt;
&lt;li&gt;How can this be applied?
&lt;ul&gt;
&lt;li&gt;Interface rule suggestions&lt;/li&gt;
&lt;li&gt;Suggestions for testing strategies&lt;/li&gt;
&lt;li&gt;Remembering bug-type frequencies.&lt;/li&gt;
&lt;li&gt;Providing optimization hints&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;May be able to reduce the total effort involved in bringing up test cases.&lt;/li&gt;
&lt;li&gt;May help lifelong maintenance and modification testing.&lt;/li&gt;
&lt;li&gt;Problems with this approach
&lt;ul&gt;
&lt;li&gt;It&apos;s hard to generate rules.&lt;/li&gt;
&lt;li&gt;It&apos;s hard to find self-analytical experts that know why they do things. It&apos;s even harder to get these people to distill that into a rule base.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This pays off most for the inexperienced programmer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Automatic Programming
&lt;ul&gt;
&lt;li&gt;A program for solving a problem from a statement of the problem specifications.&lt;/li&gt;
&lt;li&gt;This has been talked about for a long time but never realized.&lt;/li&gt;
&lt;li&gt;In essence, it is the solution method that needs specification not the problem.&lt;/li&gt;
&lt;li&gt;There are some exceptions where this does work, but these are already being put to good use.&lt;/li&gt;
&lt;li&gt;These exceptions seem to have the following in common
&lt;ul&gt;
&lt;li&gt;Problems are characterized by few parameters.&lt;/li&gt;
&lt;li&gt;There are known methods of solution to provide a library of alternatives.&lt;/li&gt;
&lt;li&gt;Extensive analysis has lead to explicit rules for selecting solution techniques.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Graphical Programming
&lt;ul&gt;
&lt;li&gt;Nothing convincing has come out of this field and the author is convinced nothing ever will.&lt;/li&gt;
&lt;li&gt;The flow chart is a poor representation so why would this be any different?&lt;/li&gt;
&lt;li&gt;Screen resolution has not progressed far enough to display everything that is needed.&lt;/li&gt;
&lt;li&gt;Software is difficult to visualize.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Program Verification
&lt;ul&gt;
&lt;li&gt;There is no silver bullet for proving designs are correct.&lt;/li&gt;
&lt;li&gt;This is an important effort but it will not save labor.&lt;/li&gt;
&lt;li&gt;This does not mean error-proof. Even mathematical proofs can be faulty.&lt;/li&gt;
&lt;li&gt;Can only establish that the program meets its specification.&lt;/li&gt;
&lt;li&gt;In general, a lot of the problem with software is debugging the specification.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Environments and tools
&lt;ul&gt;
&lt;li&gt;Many problems have already been solved here
&lt;ul&gt;
&lt;li&gt;uniform file formats&lt;/li&gt;
&lt;li&gt;uniform program interfaces&lt;/li&gt;
&lt;li&gt;generalized tools&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IDEs look promising&lt;/li&gt;
&lt;li&gt;The biggest gain yet to be realized is the use of integrated database systems to keep track of details that must be recalled accurately by individual programmers.&lt;/li&gt;
&lt;li&gt;This will help but the gain will only be marginal.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Workstations
&lt;ul&gt;
&lt;li&gt;Enhancements are welcome but faster machines do not solve the fact that a lot of the problem is thinking time not compiling time. Often when you are compiling even if it is for a long time you are still thinking.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Promising Attacks on Conceptual Essence
&lt;ul&gt;
&lt;li&gt;Some of these look promising&lt;/li&gt;
&lt;li&gt;Buy versus build
&lt;ul&gt;
&lt;li&gt;There are more and more vendors so the option to buy is becoming more common.&lt;/li&gt;
&lt;li&gt;It is always cheaper to buy than to  build.&lt;/li&gt;
&lt;li&gt;A $100,000 purchased piece of software costs about as much as one programmer-year and its delivery is immediate.&lt;/li&gt;
&lt;li&gt;These products tend to be better documented.&lt;/li&gt;
&lt;li&gt;The hard part is applicability
&lt;ul&gt;
&lt;li&gt;Often the abstraction is not right or is too specialized. However, this is getting better due to standardized hardware.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Refinement and rapid prototyping.
&lt;ul&gt;
&lt;li&gt;The hardest part in building a software system is deciding what to build.&lt;/li&gt;
&lt;li&gt;The most important function of software builders is the iterative extraction and refinement of product requirements.&lt;/li&gt;
&lt;li&gt;Generally, customers have not thought of their problem in enough detail to form a valid specification.&lt;/li&gt;
&lt;li&gt;In planning any software activity it is necessary to allow for an extensive iteration between client and designer.&lt;/li&gt;
&lt;li&gt;Tools for rapid prototyping of systems as part of the iterative specification of requirements is a very promising effort.&lt;/li&gt;
&lt;li&gt;These prototypes simulate the important interfaces and performs main functions while not being bound to any speed, size, or cost constraints.&lt;/li&gt;
&lt;li&gt;Prototypes do not handle exceptions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Incremental development (grow software)
&lt;ul&gt;
&lt;li&gt;Building metaphor for software has outlived its usefulness instead it should be grown.
&lt;ul&gt;
&lt;li&gt;software overtime behaves more organically than a construct would. This is due to how it changes over time.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This calls for a top-down design.
&lt;ul&gt;
&lt;li&gt;It&apos;s very powerful to see something run and then see more features get added over time.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Great designers
&lt;ul&gt;
&lt;li&gt;Good design practices can be taught.&lt;/li&gt;
&lt;li&gt;New curricula, new literature, and new organizations need to come into being to help raise the bar.&lt;/li&gt;
&lt;li&gt;Software construction is a creative process.&lt;/li&gt;
&lt;li&gt;Great designers produce structures that are faster, smaller simpler, cleaner, and are produced with less effort.&lt;/li&gt;
&lt;li&gt;We need to grow great designers&lt;/li&gt;
&lt;li&gt;Great designers and great managers are both rare.&lt;/li&gt;
&lt;li&gt;Every software organization should proclaim that great designers are as important to its success as great managers.&lt;/li&gt;
&lt;li&gt;How to grow great designers
&lt;ul&gt;
&lt;li&gt;Identify top designers as early as possible, best are often not the most experienced.&lt;/li&gt;
&lt;li&gt;Assign a career mentor.&lt;/li&gt;
&lt;li&gt;Provide opportunities for growing designers to interact with one another.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&quot;No Silver Bullet&quot; Refined&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;For the most part, this is just minor clarifications on the previous chapter and defenses against papers that try to counter prove the author.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Insights&lt;/h2&gt;
&lt;p&gt;This might be one of the most referenced books of software I can think of. While this book was written quite some time ago, many of its concepts are still applicable today. It is also clear that a lot of the issues talked about have already been addressed and are somewhat obsolete since the authoring of this book. Some examples include machine access and machine speeds. We now live in a time where for the most part stable machines are a given. There is also very rarely software that is built for a specific machine. With these hardware changes, some of the tales and concerns become less relevant.&lt;/p&gt;
&lt;p&gt;One thing that was interesting to read about in this was the talk of high-level languages. It was clear that the author had considered high-level languages to be the future and the direction the industry needed to head in. In general, it would appear the author was right and high-level languages do dominate the space now. What is interesting however is that the languages considered are not used today and if they are they would now be considered lower-level languages.&lt;/p&gt;
&lt;p&gt;While reading this book I often wondered if there was going to be anything new talked about. What I have come to realize is that this book likely seemed so familiar because all of its teachings are indoctrinated into the industry&apos;s teachings. It appears to me that this book has been read by many and its suggestions have made it into industry.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Book Note - Clean Coder]]></title><description><![CDATA[The Clean Coder The clean coder is a book authored by Robert C. Martin. This is one book of many in Roberts clean series. High level…]]></description><link>https://ilusr.com/clean-coder/</link><guid isPermaLink="false">https://ilusr.com/clean-coder/</guid><pubDate>Wed, 14 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;The Clean Coder&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.com/Clean-Coder-Conduct-Professional-Programmers/dp/0137081073&quot;&gt;The clean coder&lt;/a&gt; is a book authored by &lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_C._Martin&quot;&gt;Robert C. Martin&lt;/a&gt;. This is one book of many in Roberts clean series.&lt;/p&gt;
&lt;h2&gt;High level overview&lt;/h2&gt;
&lt;p&gt;This book is about uncle bob&apos;s take on what it means to be a professional programmer. Some of the key skills this book tries to take on are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What it means to behave as a software craftsman.&lt;/li&gt;
&lt;li&gt;How to deal with tight schedules and demanding managers.&lt;/li&gt;
&lt;li&gt;How to get into good coding habits.&lt;/li&gt;
&lt;li&gt;How to avoid burnout.&lt;/li&gt;
&lt;li&gt;How to manage your time.&lt;/li&gt;
&lt;li&gt;How to foster an environment where programmers can thrive.&lt;/li&gt;
&lt;li&gt;How and when to say no.&lt;/li&gt;
&lt;li&gt;How and when to say yes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Notes&lt;/h2&gt;
&lt;h3&gt;Forward&lt;/h3&gt;
&lt;p&gt;This forward contains an interesting anecdote in which Robert worked with another manager. At this time he pushed the team hard to meet a deadline. By the description of pushing hard, it seemed like the conduct to his fellow developers was poor. When all was said and done the developers meet their goal but due to a legal team with a different priority structure, their efforts had been in vain. The interesting takeaway is that the legal team in this story was treated as professionals while the software engineers had not been treated the same way.&lt;/p&gt;
&lt;h3&gt;Preface&lt;/h3&gt;
&lt;p&gt;This preface while outlining the book&apos;s contents also contains another interesting anecdote. This anecdote is 3rd hand and is about the engineers and the failure of engineering and management on the challenger project. This failure ultimately leads to the death of seven individuals and the slowdown in space exploration in the United States.&lt;/p&gt;
&lt;h3&gt;Professionalism&lt;/h3&gt;
&lt;p&gt;Professionalism is all about acting as a professional might in any other industry. As with many industries being a professional is something to be proud of. A major part of being a professional is increased accountability. This means you are responsible for knowing your code works and knowing what you can and cannot do in a given time. It also means respecting your QA. It is not your QA engineer&apos;s job to find bugs you knew existed.&lt;/p&gt;
&lt;p&gt;A professional software engineer understands the code they are writing and follows good design practices when creating features.&lt;/p&gt;
&lt;p&gt;Another major aspect of being a professional is taking responsibility for your own career and career direction. It is not your employer&apos;s job to make sure you are keeping up to date in the world of software. This means they do not owe you trips to conferences or training materials. Software is an ever-changing industry and you must spend time outside of work to stay up to date and practiced in this field.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Being a professional is something to be proud of, but it means that you need to take on more accountability.&lt;/li&gt;
&lt;li&gt;Professionals do not cut corners to meet a deliverable target.&lt;/li&gt;
&lt;li&gt;Call for a hippocratic oath for software.&lt;/li&gt;
&lt;li&gt;Sending broken code to QA is unprofessional. QA should not be finding known bugs.&lt;/li&gt;
&lt;li&gt;professionals know code works. They know this because they use rigorous testing practices.&lt;/li&gt;
&lt;li&gt;professionals do not compromise structure to deliver a feature. Doing so sets future work up for failure.
&lt;ul&gt;
&lt;li&gt;mention of the boy scout rule and various other topics from clean code.&lt;/li&gt;
&lt;li&gt;code should always be changing (constantly refactored)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;it is not your employer&apos;s job to handle your future
&lt;ul&gt;
&lt;li&gt;employers should not have to pay for your training&lt;/li&gt;
&lt;li&gt;employers should not have to send you to conferences&lt;/li&gt;
&lt;li&gt;employers do not have to give you work time to learn something new&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The only thing you owe your employer is an amount of time and effort (40 hours a week)&lt;/li&gt;
&lt;li&gt;Professionals should spend 60 hours a week on programming (that&apos;s right 20 hours of personal time a week)
&lt;ul&gt;
&lt;li&gt;Uncle Bob argues that since you can focus on whatever topic you like this should not lead to burnout. In personal experience, I pretty much agree.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Professionals know their field.
&lt;ul&gt;
&lt;li&gt;You should be aware of what is happening in your field&lt;/li&gt;
&lt;li&gt;Just because a publication or idea is old does not mean that it is irrelevant now. (read old publications)&lt;/li&gt;
&lt;li&gt;Every software professional should know the following
&lt;ul&gt;
&lt;li&gt;Design patterns (&lt;a href=&quot;https://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional-ebook/dp/B000SEIBB8&quot;&gt;GOF&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Design principles (&lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID&quot;&gt;SOLID&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Methods (&lt;a href=&quot;https://en.wikipedia.org/wiki/Extreme_programming&quot;&gt;XP&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Scrum_(software_development)&quot;&gt;Scrum&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Waterfall_model&quot;&gt;Waterfall&lt;/a&gt;, etc)&lt;/li&gt;
&lt;li&gt;Disciplines (&lt;a href=&quot;https://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;TDD&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Object-oriented_programming&quot;&gt;OOP&lt;/a&gt;, etc)&lt;/li&gt;
&lt;li&gt;Artifacts (&lt;a href=&quot;https://en.wikipedia.org/wiki/Unified_Modeling_Language&quot;&gt;UML&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Data-flow_diagram&quot;&gt;DFD&lt;/a&gt;, etc)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This is a field of continuous learning.&lt;/li&gt;
&lt;li&gt;Professional practice often.&lt;/li&gt;
&lt;li&gt;Collaboration is a key skill&lt;/li&gt;
&lt;li&gt;Mentoring is a great way to learn.&lt;/li&gt;
&lt;li&gt;Know your domain. If you are entering a field you should read up on the domain you are going to be working in.&lt;/li&gt;
&lt;li&gt;Understand that the employer&apos;s problems are your problems.&lt;/li&gt;
&lt;li&gt;Professionals should be humble, not arrogant.&lt;/li&gt;
&lt;li&gt;Statement I am not sure I agree with. If you caused a bug that cost the company 10k you should be willing to pay for it out of your paycheck.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Saying No&lt;/h3&gt;
&lt;p&gt;A professional knows when and how to say no. Part of this is assessing a situation and making sure you can commit to something. If your boss asks you to mean a deadline and you agree to it knowing you cannot make the deadline you are acting unprofessionally.&lt;/p&gt;
&lt;p&gt;Often when something is at stake others might ask you to compromise your initial estimate, or to attempt to &quot;try harder&quot;. In these cases, you must stand your ground. Agreeing to &quot;try harder&quot; implies that you are not already giving it your all and that there is still some reserved effort you can exert.&lt;/p&gt;
&lt;p&gt;The cost of saying yes can lead to an utter mess. In these cases, we might think we are meeting deadlines and giving the employer what they want but ultimately what often ends up happening is we create an unmaintainable mess.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;starts with a tale of Bob being pressured to complete a project too quickly.
&lt;ul&gt;
&lt;li&gt;His manager would not budge on the date&lt;/li&gt;
&lt;li&gt;Bob and the team did not have the spine to stand up to the manager.&lt;/li&gt;
&lt;li&gt;the result was a disaster
&lt;ul&gt;
&lt;li&gt;an intermittent bug caused terminals to lock up at a rate of 1 time per hour.&lt;/li&gt;
&lt;li&gt;they could not roll back the change so the pressure to fix it faster was mounted (4 weeks was unacceptable)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Professionals know how to say no.&lt;/li&gt;
&lt;li&gt;Saying no to your boss is not unprofessional, agreeing and falling short is.&lt;/li&gt;
&lt;li&gt;Adversity is a good thing. Developers should stand their ground that is doing their job. Likewise, managers should pressure for quicker turnaround while understanding the developers. It is also their job to see things done on time.&lt;/li&gt;
&lt;li&gt;Never agree to try. That implies you can do more and you have been holding something in reserve.&lt;/li&gt;
&lt;li&gt;Do not compromise estimates, stand your ground. If timelines are an issue provide a reasonable feature expectation (we can have feature x but it will be missing y is that alright?)&lt;/li&gt;
&lt;li&gt;Be direct with your estimates.&lt;/li&gt;
&lt;li&gt;If you hit a snag that could compromise an estimate let management know as soon as possible.&lt;/li&gt;
&lt;li&gt;Be a team player.&lt;/li&gt;
&lt;li&gt;Do not be passive-aggressive. An example is keeping a log of memos to use against someone later instead of trying to resolve the issue.&lt;/li&gt;
&lt;li&gt;cost of saying yes. This is an interesting article about a developer that agreed to an unreasonable project with shifting requirements under a ridiculous time frame. In the end, this project died and the developer felt remorse about the terrible code they created.
&lt;ul&gt;
&lt;li&gt;Bob argues that the developer or his employer is at fault.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Saying Yes&lt;/h3&gt;
&lt;p&gt;To be a professional you need to know the right way to say yes to something. Language is everything in this case. There are several statements that you can make that sound non-committal. For example words like need, should, hope, wish and let&apos;s imply a lack of commitment. When you commit you need to&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;say you will do it in a way that sounds like you mean it&lt;/li&gt;
&lt;li&gt;mean that you will do it&lt;/li&gt;
&lt;li&gt;actually do it&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A strong commitment often sounds like this, &quot;I will ... by ...&quot;.&lt;/p&gt;
&lt;p&gt;There are cases in which life happens and a commitment cannot be made. In these cases, it is imperative to raise a red flag as soon as possible.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;starts with an interesting story about how bob had and lost a patent for voicemail and wanted to start a project around it not knowing the patent was not renewed.&lt;/li&gt;
&lt;li&gt;parts of a commitment: say you will do it, mean you will do it, actually do it.&lt;/li&gt;
&lt;li&gt;words that indicate a lack of commitment: need/should, hope/wish, let&apos;s. These imply a lack of concrete commitment.&lt;/li&gt;
&lt;li&gt;an example of a strong commitment sounds more like this: I will ... by ...&lt;/li&gt;
&lt;li&gt;Good commitments are binary (either you did it or you did not do it)&lt;/li&gt;
&lt;li&gt;You can only commit to things you have full control of, to help mitigate this some suggestions are offered.
&lt;ul&gt;
&lt;li&gt;work with external parties to understand your dependencies&lt;/li&gt;
&lt;li&gt;create an interface that mirrors the dependency.&lt;/li&gt;
&lt;li&gt;work with the build team to make sure your work will build.&lt;/li&gt;
&lt;li&gt;use integration tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Just because it cannot be done does not mean you cannot commit to things that move you in the right direction.&lt;/li&gt;
&lt;li&gt;life happens and sometimes commitments cannot be made. The responsible thing to do in these cases is raise a red flag as soon as possible.&lt;/li&gt;
&lt;li&gt;Don&apos;t use try also do not agree to try.&lt;/li&gt;
&lt;li&gt;professionals know how much overtime they can handle and require people to respect their time. For example at the end of this chapter overtime needs to be done. The programmer agrees to work the weekend with the pre-requisite that their family is alright with it and the understanding that they will take Tuesday off to make up for lost time on the weekend.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Coding&lt;/h3&gt;
&lt;p&gt;This is a topic Bob, has a lot to say on. He has written a different book on this very topic &lt;a href=&quot;https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882&quot;&gt;Clean Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A major part of coding is being in the right mindset. You should not code when you are tired or distracted. In some cases, life events can serve as a distraction to good code. In these cases, you should try to resolve your life events before coding. Failing to do this can lead to code you regret later on.&lt;/p&gt;
&lt;p&gt;One common topic that most developers talk about is getting into the zone. Often developers claim that being in the zone is a desirable thing because you feel more productive. In this book, Bob argues that the zone is a dangerous thing. The zone is a meditative state that lacks collaboration. In Bob&apos;s eyes, this is a problem is programming is a collaborative effort.&lt;/p&gt;
&lt;p&gt;When coding one should strive to reduce debugging time. To do this we should follow strong TDD practices. This should assure us the code works and only does exactly what it is specified to do.&lt;/p&gt;
&lt;p&gt;At some point, we all run into issues. In these cases, pairing is the best thing we can do. This is something that quite a few books echo. Although it may be comfortable to work solo, two heads are often better than one and coding is no exception.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;mentions the clean code book.&lt;/li&gt;
&lt;li&gt;talks about the unique challenge of code.
&lt;ul&gt;
&lt;li&gt;it must work&lt;/li&gt;
&lt;li&gt;it must solve a customer problem&lt;/li&gt;
&lt;li&gt;it has to fit well in an existing system.&lt;/li&gt;
&lt;li&gt;it has to be readable to other programmers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Don&apos;t write code while tired or distracted, it will end up having to be redone.
&lt;ul&gt;
&lt;li&gt;Bob tells a story about some 3 am code he regretted for a long time to come.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;life events can impact the quality of code since your focus is not on the code.
&lt;ul&gt;
&lt;li&gt;find a way to &quot;shut down the background process&quot; (life event)&lt;/li&gt;
&lt;li&gt;take time to deal with your personal issue but not at the expense of your employer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Bob comments on the &quot;flow state&quot; or the &quot;Zone&quot;.
&lt;ul&gt;
&lt;li&gt;coding in the zone is a bad thing.&lt;/li&gt;
&lt;li&gt;more of a form of meditation than a mechanism for good.&lt;/li&gt;
&lt;li&gt;the zone is only where you want to be when practicing.&lt;/li&gt;
&lt;li&gt;it is a non-communicative state.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Music while programming in Bob&apos;s opinion is bad and is just a tool to enter the &quot;zone&quot;.&lt;/li&gt;
&lt;li&gt;handling interruptions.
&lt;ul&gt;
&lt;li&gt;when in the zone the natural response might be to respond rudely.&lt;/li&gt;
&lt;li&gt;pair programming and TDD can help since the pair programmer or test can keep your context.&lt;/li&gt;
&lt;li&gt;remember to be professional next time you might be the one causing an interruption.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;To deal with writer&apos;s block consider pair programming.&lt;/li&gt;
&lt;li&gt;coding is a creative process so focusing on creativity is a good thing (just not while coding).
&lt;ul&gt;
&lt;li&gt;read books&lt;/li&gt;
&lt;li&gt;watch videos (unless you are bob)&lt;/li&gt;
&lt;li&gt;listen to music, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;contains an interesting story about bob debugging a terminal lockup problem he mentioned earlier in the book.&lt;/li&gt;
&lt;li&gt;Professional programmers should strive to spend less time debugging (use TDD to help with this).&lt;/li&gt;
&lt;li&gt;Debugging is part of programming.&lt;/li&gt;
&lt;li&gt;Software development is a marathon, not a sprint, pace yourself.&lt;/li&gt;
&lt;li&gt;When stuck on a problem disengage from it and come back to it later. You just might find yourself solving the problem in the shower, etc.&lt;/li&gt;
&lt;li&gt;Inevitably you will be late on some work, the goal is to be transparent about it. (I feel like this has been talked about before)&lt;/li&gt;
&lt;li&gt;Hope is not a strategy hope is a project killer. Do not hope you will get something done in 10 days.&lt;/li&gt;
&lt;li&gt;Do not rush, rushing never solves problems faster. Do not give in to pressure and rush through something&lt;/li&gt;
&lt;li&gt;Only take overtime if you can handle it. The following are recommended.
&lt;ul&gt;
&lt;li&gt;you can personally afford it.&lt;/li&gt;
&lt;li&gt;it is short-term.&lt;/li&gt;
&lt;li&gt;your boss has a fallback plan.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The most unprofessional behavior a programmer can engage in is changing the definition of &quot;done&quot;.
&lt;ul&gt;
&lt;li&gt;don&apos;t say something is done when it is not.&lt;/li&gt;
&lt;li&gt;This is an overt lie.&lt;/li&gt;
&lt;li&gt;It is too easy to rationalize.&lt;/li&gt;
&lt;li&gt;This practice is contagious, if someone sees you doing it they are likely to do it themselves.&lt;/li&gt;
&lt;li&gt;This leads to bad communication between managers and developers.&lt;/li&gt;
&lt;li&gt;Example calling a task done with a failing build.&lt;/li&gt;
&lt;li&gt;The best way to avoid this is to have business analysts and testers create automated acceptance tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;No matter how skilled you are you can and should still ask for help.
&lt;ul&gt;
&lt;li&gt;when being help accept the help do not &quot;protect your turf&quot;&lt;/li&gt;
&lt;li&gt;Do not push away help. Give it time.&lt;/li&gt;
&lt;li&gt;It is unprofessional to remain stuck on an issue when help is available.&lt;/li&gt;
&lt;li&gt;In general, programmers need to work on collaboration. Bob uses the example of the stereotype that often plays out in software (arrogant, self-absorbed introverts)&lt;/li&gt;
&lt;li&gt;More experienced programmers have the responsibility to mentor less experienced programmers.&lt;/li&gt;
&lt;li&gt;Mentoring is a good way to learn.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Test Driven Development&lt;/h3&gt;
&lt;p&gt;Test Driven Development or TDD is a way of writing code. In this methodology, one writes a test before any code is written. Only enough test code is written to cause a failure. Once this happens no more test code is to be written. After this production code must be written until the test is passing. Once the test is passing no more production code is to be written.&lt;/p&gt;
&lt;p&gt;TDD is the professional option. There are very few cases in which this is not the right thing to do.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;TDD was part of the XP (extreme programming wave)&lt;/li&gt;
&lt;li&gt;TDD helps reduce cycle time.&lt;/li&gt;
&lt;li&gt;TDD works and everyone should accept that.&lt;/li&gt;
&lt;li&gt;Interesting section from the chapter (I like this). &quot;How can you consider yourself to be a professional if you do not know that all your code works? How can you know all your code works if you don&apos;t test it every time you make a change? How can you test it every time you make a change if you don&apos;t have automated unit tests with very high coverage? How can you get automated unit tests with very high coverage without practicing TDD?&quot;&lt;/li&gt;
&lt;li&gt;Laws of TDD
&lt;ul&gt;
&lt;li&gt;you cannot write any production code until you have a failing test.&lt;/li&gt;
&lt;li&gt;you are not allowed to write more of a unit test than is sufficient to fail.&lt;/li&gt;
&lt;li&gt;you are not allowed to write more production code than is sufficient to pass the currently failing test.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Benefits
&lt;ul&gt;
&lt;li&gt;Certainty, you know the code works so you can release it at any time.&lt;/li&gt;
&lt;li&gt;The defect rate is very low.&lt;/li&gt;
&lt;li&gt;You have the courage to fix bugs because tests will let you know when you mess up another use case.&lt;/li&gt;
&lt;li&gt;Tests act as documentation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TDD is the professional option.&lt;/li&gt;
&lt;li&gt;Warning what TDD is not
&lt;ul&gt;
&lt;li&gt;You can still write bad code even if your tests pass.&lt;/li&gt;
&lt;li&gt;There are rare situations where TDD is not appropriate and being dogmatic about it can be wrong to do.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practicing&lt;/h3&gt;
&lt;p&gt;All professionals practice programmers should be no exception. There are several different ways you can practice.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Kata_(programming)&quot;&gt;coding kata&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;wasa&lt;/li&gt;
&lt;li&gt;Contributing to open source&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The important thing is that you practice and practice often to keep your skills sharp.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;All professionals practice (examples: doctors, musicians, sports players, etc)&lt;/li&gt;
&lt;li&gt;practicing is not a new concept consider &quot;Hello, World!&quot;&lt;/li&gt;
&lt;li&gt;cycle times on development have gotten better due to Moore&apos;s law.&lt;/li&gt;
&lt;li&gt;There are things called coding dojo&apos;s in which you can solve a known issue with other developers in a room.&lt;/li&gt;
&lt;li&gt;A coding kata is a good way to sharpen your skills. Solve a known issue practicing TDD.&lt;/li&gt;
&lt;li&gt;A wasa is like a kata but done as a team.
&lt;ul&gt;
&lt;li&gt;For example, one person might write a test then the next might get it to pass and write the next test, and so on until the issue is solved.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Open source is a good way to practice and build a resume.&lt;/li&gt;
&lt;li&gt;Professional programmers practice on their own time.&lt;/li&gt;
&lt;li&gt;become a polyglot&lt;/li&gt;
&lt;li&gt;&quot;Practicing is what you do when you are not getting paid. You do it so that you will be paid, and paid well&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Acceptance Testing&lt;/h3&gt;
&lt;p&gt;Acceptance tests are a great way to make sure the business needs are understood and tested when a feature is created. These tests serve as the best form of documentation of requirements for developers. Acceptance tests must be written in a collaborative effort by both programmers and stakeholders.&lt;/p&gt;
&lt;p&gt;While acceptance tests are different than integration and unit tests they should be automated much the same as a unit or integration test would be. In a perfect world, developers would not write these tests instead QA or business analysts would write the tests.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;A professional developer is a communications role as well as a development role.&lt;/li&gt;
&lt;li&gt;Starts with an interesting story about how Bob wrote a feature from start to finish with a coworker and gained insights on how features are communicated.&lt;/li&gt;
&lt;li&gt;premature precision is an issue on both sides.
&lt;ul&gt;
&lt;li&gt;Business people what you know what they are going to get before they ok a project&lt;/li&gt;
&lt;li&gt;developers want to know what they are supposed to deliver before they estimate the project.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Things appear differently on a piece of paper than they do in a working system.&lt;/li&gt;
&lt;li&gt;Even with perfect information developer estimates will have huge variance.&lt;/li&gt;
&lt;li&gt;requirements will change making perfect information impossible&lt;/li&gt;
&lt;li&gt;professional developers know that estimates can, and should be made based on low precision requirements.&lt;/li&gt;
&lt;li&gt;a solution to premature precision is to defer as long as possible.
&lt;ul&gt;
&lt;li&gt;This can lead to late ambiguity.
&lt;ul&gt;
&lt;li&gt;This can lead to incorrect features being developed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Acceptance tests are the answer. In this case, an acceptance test is &quot;tests written by a collaboration of stakeholders and the programmers to define when a requirement is done.&quot;&lt;/li&gt;
&lt;li&gt;done is when all tests pass, QA and stakeholders have accepted.&lt;/li&gt;
&lt;li&gt;Professional developers work with stakeholders and QA to ensure that automated tests are a complete specification of done.&lt;/li&gt;
&lt;li&gt;The purpose of acceptance tests is communication, clarity, and precision.&lt;/li&gt;
&lt;li&gt;Acceptance tests should always be automated. The reason for doing this is simple manual tests cost more money.&lt;/li&gt;
&lt;li&gt;While it does appear that it is more work in the long run it is less work than having manual tests.&lt;/li&gt;
&lt;li&gt;In a perfect world, QA and stakeholders would collaborate to write tests and developers would review for consistency.&lt;/li&gt;
&lt;li&gt;If developers write tests then the developer who wrote the feature must not also write the test. (interesting)&lt;/li&gt;
&lt;li&gt;Business analysts tend to write happy path tests.&lt;/li&gt;
&lt;li&gt;QA tends to write unhappy path tests.&lt;/li&gt;
&lt;li&gt;developers should negotiate with test authors for better tests when the test does not make sense.&lt;/li&gt;
&lt;li&gt;Don&apos;t be passive-aggressive &quot;Well, that&apos;s what the test says, so that&apos;s what I&apos;m going to do.&quot; should never be the answer.&lt;/li&gt;
&lt;li&gt;Acceptance tests are not unit tests.
&lt;ul&gt;
&lt;li&gt;unit tests are written by developers for developers.&lt;/li&gt;
&lt;li&gt;acceptance tests are written by business for business.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;GUIs are hard to acceptance test.&lt;/li&gt;
&lt;li&gt;GUIs should follow SRP (single responsibility principle)&lt;/li&gt;
&lt;li&gt;Test using the correct interface. It&apos;s often better to test via an API instead of via the GUI.&lt;/li&gt;
&lt;li&gt;Acceptance tests should be run often in &lt;a href=&quot;https://en.wikipedia.org/wiki/Continuous_integration&quot;&gt;CI&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If tests are broken in CI this should be viewed as an emergency.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Testing Strategies&lt;/h3&gt;
&lt;p&gt;As a professional developer, it is important to have a good testing strategy. Generally, a testing strategy should have a mix of unit, component, integration, system, and manual tests.&lt;/p&gt;
&lt;p&gt;Unit tests should cover most if not all code paths. These unit tests are tests for developers not for business. Unit tests should be run in CI.&lt;/p&gt;
&lt;p&gt;Component tests are tests against individual components of a system. These are generally acceptance tests defined by the business. Since these only test a single component mocking strategies should be used. Ideally, these tests cover 50% of your code and are written by QA.&lt;/p&gt;
&lt;p&gt;Integration tests are tests that run against multiple components. These tests make sure the connections between components are working properly. Component tests should be written by architects or designers and should not be run in CI. While these do not run in CI they should be automated and they should run periodically.&lt;/p&gt;
&lt;p&gt;System tests are tests that run against the entire integrated system. These tests are written by architects or technical leads.&lt;/p&gt;
&lt;p&gt;Manual tests are exploratory tests conducted by humans. These are important tests but they should have the least coverage. The important thing is humans are creative and will be able to find new ways to break things or notice subtle bad behaviors.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Every professional developer has a good testing strategy.&lt;/li&gt;
&lt;li&gt;Bug hunts can be a testing strategy.&lt;/li&gt;
&lt;li&gt;QA should find nothing wrong. This will rarely happen but when QA finds a bug this should cause alarm for the development team (how did we let this happen)&lt;/li&gt;
&lt;li&gt;QA and development should work together and not be adversarial.&lt;/li&gt;
&lt;li&gt;QA should create automated acceptance tests.&lt;/li&gt;
&lt;li&gt;QA should use the discipline of exploratory testing.&lt;/li&gt;
&lt;li&gt;Mention of the test automation pyramid.
&lt;ul&gt;
&lt;li&gt;~100% unit test (&lt;a href=&quot;https://xunit.net/&quot;&gt;xunit&lt;/a&gt;, &lt;a href=&quot;https://junit.org/&quot;&gt;junit&lt;/a&gt;, &lt;a href=&quot;https://jestjs.io/&quot;&gt;jest&lt;/a&gt;, etc)&lt;/li&gt;
&lt;li&gt;~50% component tests (api)&lt;/li&gt;
&lt;li&gt;~20% integration tests (api)&lt;/li&gt;
&lt;li&gt;~10% system tests (gui)&lt;/li&gt;
&lt;li&gt;~5% manual exploratory tests&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;unit tests
&lt;ul&gt;
&lt;li&gt;written by programmers for programmers&lt;/li&gt;
&lt;li&gt;in the programming language of the system.&lt;/li&gt;
&lt;li&gt;Are executed in CI&lt;/li&gt;
&lt;li&gt;Should provide as close to 100% coverage as possible&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Component tests
&lt;ul&gt;
&lt;li&gt;are written against individual components of a system.&lt;/li&gt;
&lt;li&gt;these are acceptance tests for the business rules of the component.&lt;/li&gt;
&lt;li&gt;appropriate mocking should be used.&lt;/li&gt;
&lt;li&gt;written by QA.&lt;/li&gt;
&lt;li&gt;cover about 50% of the system.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Integration tests.
&lt;ul&gt;
&lt;li&gt;test a collection of components&lt;/li&gt;
&lt;li&gt;basically a connections test.&lt;/li&gt;
&lt;li&gt;Often written by system architects or lead designers of the system.&lt;/li&gt;
&lt;li&gt;might include performance or throughput tests.&lt;/li&gt;
&lt;li&gt;These are not part of CI&lt;/li&gt;
&lt;li&gt;Run periodically (weekly or nightly)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;System tests
&lt;ul&gt;
&lt;li&gt;execute against the entire integrated system.&lt;/li&gt;
&lt;li&gt;do not test business rules directly.&lt;/li&gt;
&lt;li&gt;written by system architects and technical leads.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Manual Exploratory tests
&lt;ul&gt;
&lt;li&gt;are not automated or scripted.&lt;/li&gt;
&lt;li&gt;intended to find unexpected behaviors.&lt;/li&gt;
&lt;li&gt;it helps to have human brains and human creativity to find issues with the system.&lt;/li&gt;
&lt;li&gt;There should be no written test plan for these.&lt;/li&gt;
&lt;li&gt;The goal is not coverage instead it is to make sure the system works correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Time Management&lt;/h3&gt;
&lt;p&gt;Part of being a professional developer is managing your time appropriately. A major key to this is good meeting etiquette. While meetings are critical they can also be major time wasters. As a professional, you need to balance what meetings you should and should not be attending. Some things to consider when accepting a meeting. It is important to remember, the person inviting you to a meeting is not responsible for your time. One of the most important duties of your manager is to keep you out of meetings. Since meetings are large time sinks it is important to keep them on topic. In general, you should never accept a meeting request if no agenda is present. If at any time a meeting strays from the agenda it is important to stop and consider if a new meeting needs to be created.&lt;/p&gt;
&lt;p&gt;Disagreements are common in software engineering. The best way to deal with these is to provide data. Brute force is never the right approach to resolving a disagreement. If there is insufficient data for either side of a disagreement sometimes the best option is a coin flip.&lt;/p&gt;
&lt;h4&gt;Original Notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;8 hours is not a lot of time?&lt;/li&gt;
&lt;li&gt;meetings
&lt;ul&gt;
&lt;li&gt;According to bob meetings cost around 200$ per attendee&lt;/li&gt;
&lt;li&gt;meetings are necessary&lt;/li&gt;
&lt;li&gt;meetings are huge time wasters.&lt;/li&gt;
&lt;li&gt;some attendees may find a meeting to be invaluable while others can find it redundant or useless.&lt;/li&gt;
&lt;li&gt;You don&apos;t have to go to every meeting you are invited to, doing so would be unprofessional?&lt;/li&gt;
&lt;li&gt;be careful about which meetings to politely refuse.&lt;/li&gt;
&lt;li&gt;the person inviting you to the meeting is not responsible for your time you are.&lt;/li&gt;
&lt;li&gt;examples that are choices you must make
&lt;ul&gt;
&lt;li&gt;something you are interested in but is not immediately necessary.&lt;/li&gt;
&lt;li&gt;something you can contribute to but is not immediately significant.&lt;/li&gt;
&lt;li&gt;In these cases, you can work with your manager to see if you should participate.&lt;/li&gt;
&lt;li&gt;One of the most important duties of your manager is to keep you out of meetings.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Leaving is an option when meetings get boring leave?
&lt;ul&gt;
&lt;li&gt;Do this politely by asking if your presence is still required.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Meetings should have an agenda and a goal.&lt;/li&gt;
&lt;li&gt;things you should know going into the meeting
&lt;ul&gt;
&lt;li&gt;what discussions are on the table?&lt;/li&gt;
&lt;li&gt;how much time is allotted for them?&lt;/li&gt;
&lt;li&gt;what is the goal to be achieved?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If the meeting agenda has been high-jacked or abandoned, request the new topic be tabled and the agenda forwarded.&lt;/li&gt;
&lt;li&gt;Stand-up meetings.
&lt;ul&gt;
&lt;li&gt;part of the Agile cannon.&lt;/li&gt;
&lt;li&gt;The only thing that should be discussed are these three topics.
&lt;ul&gt;
&lt;li&gt;What did I do yesterday?&lt;/li&gt;
&lt;li&gt;What am I going to do today?&lt;/li&gt;
&lt;li&gt;What&apos;s in my way?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;each question should require no more than 20 seconds.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Iteration planning meetings
&lt;ul&gt;
&lt;li&gt;Also part of agile cannon.&lt;/li&gt;
&lt;li&gt;It takes skill for these meetings to go well.&lt;/li&gt;
&lt;li&gt;Point is to select backlog items to work on next iteration.&lt;/li&gt;
&lt;li&gt;Estimates should be done for candidate items.&lt;/li&gt;
&lt;li&gt;In an exceptionally good organization, acceptance/component tests will already be written or at least sketched out.&lt;/li&gt;
&lt;li&gt;No more than 5 or 10 minutes should be spent on any one item.
&lt;ul&gt;
&lt;li&gt;If more discussion is needed it should be scheduled at a different time with a smaller subset of people.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Bob&apos;s rule of thumb this meeting should take no longer than 5% of the total time in the iteration. (ex: 1-week iteration should be over within two hours.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Iteration Retrospective and demo
&lt;ul&gt;
&lt;li&gt;Discuss what went right and wrong.&lt;/li&gt;
&lt;li&gt;stakeholders see a demo.&lt;/li&gt;
&lt;li&gt;These meetings are often abused.&lt;/li&gt;
&lt;li&gt;Bob&apos;s rule of thumb these should take 45 minutes. 20 for retrospective and 25 for demo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Disagreements
&lt;ul&gt;
&lt;li&gt;&quot;Any argument that can&apos;t be settled in five minutes can&apos;t be settled by arguing.&quot; Kent Beck.&lt;/li&gt;
&lt;li&gt;Technical disagreements are rarely grounded in data.&lt;/li&gt;
&lt;li&gt;Force does not settle disagreements data does.&lt;/li&gt;
&lt;li&gt;Being passive-aggressive in an argument just to sabotage it later is the worst kind of unprofessional.
&lt;ul&gt;
&lt;li&gt;If you agree you must engage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How to settle a disagreement.
&lt;ul&gt;
&lt;li&gt;run experiments.&lt;/li&gt;
&lt;li&gt;sometimes flipping a coin is the best option.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It is a good idea to agree to a time and set of criteria for abandoning a path.&lt;/li&gt;
&lt;li&gt;Avoid meetings that exist just to vent a disagreement.&lt;/li&gt;
&lt;li&gt;If an argument must be settled ask each arguer to present their case to the team in five minutes or less.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Programming is an intellectual exercise that requires extended periods of concentration and focus. After you have used up all your focus you will have to recharge by doing unfocused activities for an hour or more.&lt;/li&gt;
&lt;li&gt;Managing focus is a key skill for professional developers.&lt;/li&gt;
&lt;li&gt;Sleep is key to good focus.&lt;/li&gt;
&lt;li&gt;Caffeine can help with focus but too much can cause jitter focus&lt;/li&gt;
&lt;li&gt;Good ways to recharge focus
&lt;ul&gt;
&lt;li&gt;take a walk&lt;/li&gt;
&lt;li&gt;spend some time looking out the window.&lt;/li&gt;
&lt;li&gt;talk with friends&lt;/li&gt;
&lt;li&gt;meditate&lt;/li&gt;
&lt;li&gt;get a power nap.&lt;/li&gt;
&lt;li&gt;listen to a podcast&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;physical focus can help mental focus (workout)&lt;/li&gt;
&lt;li&gt;A good way to manage time and focus is to use the Pomodoro technique (kindly reject all distractions over a 25 minute period). Repeat this process with 5-30 minute breaks in between.&lt;/li&gt;
&lt;li&gt;priority inversion is when you convince yourself something is more important or urgent than a task you do not want to do (for whatever reason). Professionals should not engage in this behavior.&lt;/li&gt;
&lt;li&gt;Avoid blind alleys it&apos;s easy to get too far down a technical pathway that will go nowhere. Keep an open mind to other ideas so when you hit a dead-end you still have options.&lt;/li&gt;
&lt;li&gt;Messes are worse than blind alleys. A mess can be worked by sheer brute force but are major progress impeders&lt;/li&gt;
&lt;li&gt;Messes are often the result of a bad design choice realized late into the product.&lt;/li&gt;
&lt;li&gt;Once you realize you have a mess you hit an inflection point: you can go back and fix the design or you can continue to go forward.
&lt;ul&gt;
&lt;li&gt;Going back means reworking existing code.&lt;/li&gt;
&lt;li&gt;Going back is never easy.&lt;/li&gt;
&lt;li&gt;If you go forward you may never escape.&lt;/li&gt;
&lt;li&gt;Professionals are always on the lookout for messes and will expend all necessary effort to escape from them as early as possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Estimation&lt;/h3&gt;
&lt;p&gt;Estimation is an important part of feature development. In general, the business views an estimate as a commitment while a developer views an estimate as a guess. A professional developer mustn&apos;t commit unless they know they can achieve it. As a professional, it is your job to make a clear distinction between an estimate and a commitment.&lt;/p&gt;
&lt;p&gt;Various strategies can be used to generate an estimate. One interesting but somewhat involved estimation process is &lt;a href=&quot;https://en.wikipedia.org/wiki/Program_evaluation_and_review_technique&quot;&gt;PERT&lt;/a&gt;. In PERT you end up generating an estimate by considering the best possible case, worse possible case, and average case.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Businesses view estimates as commitments&lt;/li&gt;
&lt;li&gt;developers view estimates as guesses.&lt;/li&gt;
&lt;li&gt;Professionals do not make commitments unless they know they can achieve them.
&lt;ul&gt;
&lt;li&gt;never commit to something you are uncertain about.&lt;/li&gt;
&lt;li&gt;missing a commitment is an act of dishonesty.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;An estimate is a guess, no commitment is implied.&lt;/li&gt;
&lt;li&gt;developers are bad at estimates.&lt;/li&gt;
&lt;li&gt;estimates are a probability distribution.&lt;/li&gt;
&lt;li&gt;professionals draw a clear distinction between estimates and commitments.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Program_evaluation_and_review_technique&quot;&gt;PERT&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;a simple but effective way to convert estimates into probability distributions.&lt;/li&gt;
&lt;li&gt;when estimating a task provide 3 numbers (trivariate analysis)
&lt;ul&gt;
&lt;li&gt;O: Optimistic Estimate. A wildly optimistic number. (less than a 1% chance of happening)&lt;/li&gt;
&lt;li&gt;N: Nominal Estimate. The most likely estimate to be true.&lt;/li&gt;
&lt;li&gt;P: Pessimistic Estimate. A wildly pessimistic number. (less than a 1% chance of happening)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Distribution based on these numbers. µ = O+4N+P/6&lt;/li&gt;
&lt;li&gt;µ is the expected duration of the task&lt;/li&gt;
&lt;li&gt;To calculate the standard deviate one can use this equation. σ = P-O/6 (how uncertain is the task)&lt;/li&gt;
&lt;li&gt;PERT is a good way to prevent overly optimistic estimates.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Estimating should be done with teammates, the group can estimate better than the individual.&lt;/li&gt;
&lt;li&gt;wideband delphi is a technique that aims at a consensus in estimation.&lt;/li&gt;
&lt;li&gt;Flying fingers is a strategy where everyone sits at a table, discusses the issue carefully, and puts up some fingers 1-5. If an agreement is not reached the topic is discussed further (this seems like the only way I have known estimation to work)&lt;/li&gt;
&lt;li&gt;Planning poker (what I have used) for the most part is a software refinement on the flying fingers strategy.&lt;/li&gt;
&lt;li&gt;Affinity estimation
&lt;ul&gt;
&lt;li&gt;all cards of stories are laid out.&lt;/li&gt;
&lt;li&gt;No talking is to happen.&lt;/li&gt;
&lt;li&gt;Cards are moved left to right (left being easiest relative to others and right being hardest)&lt;/li&gt;
&lt;li&gt;Anyone can move a card at any time.&lt;/li&gt;
&lt;li&gt;If a card is moved N times then it is set aside for discussion.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;you can use these same strategies to generate your optimistic and pessimistic values.&lt;/li&gt;
&lt;li&gt;To mitigate error you can take advantage of the Law of Large Numbers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Pressure&lt;/h3&gt;
&lt;p&gt;A professional software engineer understands how to manage pressure while still behaving professionally. A large portion of this is understanding how to avoid and manage pressure.&lt;/p&gt;
&lt;p&gt;As far as avoidance goes it is important to avoid making commitments unless you know they can be met. It is also important to reject unrealistic commitments as it is a disservice to everyone.&lt;/p&gt;
&lt;p&gt;An interesting thing is under pressure you find what your disciplines are. If you find that in a bind you stop following TDD then you know that TDD is not something you value. In these cases, it is important to stick with what you believe in. If you start doubling down on practices you do not find value in it will only increase pressure.&lt;/p&gt;
&lt;p&gt;When you are under pressure it is important to manage it as best as you can. One great way to help is to make sure you are getting enough sleep. Even though you are under pressure it is very important not to rush. Rushing will lead to problems later on and will likely cause more stress.&lt;/p&gt;
&lt;p&gt;When you are under stress communication is a great tool. In these cases make sure your manager is aware and see if there is anything they can do to help. Another great trick is to pair program. This can help reduce your stress while keeping code quality high. Your peer might spot issues you are making while under stress. It is also important that when you see others in these situations you offer your help.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;starts with a comparison of a surgeon to a typical developer. The surgeon is cool and collected under pressure the developer is not.&lt;/li&gt;
&lt;li&gt;goes on to explain his time at what sounds like a toxic startup with insane time pressures.&lt;/li&gt;
&lt;li&gt;a good way to stay calm under pressure is to avoid situations that cause pressure.&lt;/li&gt;
&lt;li&gt;avoidance is not always an option so limit the required high-pressure situations.&lt;/li&gt;
&lt;li&gt;avoid making commitments unless you are sure they can be met.&lt;/li&gt;
&lt;li&gt;accepting unrealistic commitments is a disservice to developers and the business.&lt;/li&gt;
&lt;li&gt;sometimes commitments are made for us. In those cases, we must help the business find a way to meet those commitments. That being said we do not have to accept the commitments. (Interesting)
&lt;ul&gt;
&lt;li&gt;By not accepting the commitment we hold those who committed responsible instead of taking the fall.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You can always hunt for a new job.&lt;/li&gt;
&lt;li&gt;It is important to stay clean to meet deadlines.&lt;/li&gt;
&lt;li&gt;&quot;Quick and dirty&quot; is an oxymoron, dirty is always slow.&lt;/li&gt;
&lt;li&gt;A crisis is a good measure of what you believe. If you follow your disciplines in a crisis then you believe in those disciplines.
&lt;ul&gt;
&lt;li&gt;For example, if you use TDD in noncrisis times but abandon it in a crisis you do not think TDD is helpful.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Handling Pressure
&lt;ul&gt;
&lt;li&gt;Sometimes you cannot avoid it.&lt;/li&gt;
&lt;li&gt;Manage stress, get sleep.&lt;/li&gt;
&lt;li&gt;Resist temptation and do not rush. Rushing only makes things worse.&lt;/li&gt;
&lt;li&gt;Let your team and manager know you are in trouble.
&lt;ul&gt;
&lt;li&gt;Let them know your plans for getting out of that trouble.&lt;/li&gt;
&lt;li&gt;ask for input/guidance.&lt;/li&gt;
&lt;li&gt;avoid surprises.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;trust your disciplines. you have them for a reason now is not the time to abandon them.&lt;/li&gt;
&lt;li&gt;Instead of looking for a solution to get it done faster buckle down on what you know and your disciplines.&lt;/li&gt;
&lt;li&gt;Do pair programming. Partners help you find things you missed and often have helpful ideas.&lt;/li&gt;
&lt;li&gt;When someone else is under pressure offer them help.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Collaboration&lt;/h3&gt;
&lt;p&gt;Software development is all about working with others. There is a stereotype that is sadly often true in this industry that all programmers are arrogant introverts. It is important for professionals not to act in such ways.&lt;/p&gt;
&lt;p&gt;Outside of working well with other developers, a professional software engineer must also be able to work with a variety of other roles in the company with varying levels of technical skill. To help these communications you must understand the business&apos;s problems, not just technical solutions.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;It is unprofessional to be a loner or a recluse on a team.&lt;/li&gt;
&lt;li&gt;Starts with an interesting tale of Bob and Tim working together to speed up a searching algorithm for their codebase.&lt;/li&gt;
&lt;li&gt;Most programmers are introverts that would rather work alone (based on stereotypes that are often true)&lt;/li&gt;
&lt;li&gt;It&apos;s good to be passionate about what we do, but it&apos;s also good to keep your eyes on the goals of the people who pay you.&lt;/li&gt;
&lt;li&gt;It is your job to meet the needs of your employer
&lt;ul&gt;
&lt;li&gt;This means you will have to work with other people: testers, business analysts, managers, etc.&lt;/li&gt;
&lt;li&gt;You need to understand why you are writing the code you are writing and the benefit of that code.&lt;/li&gt;
&lt;li&gt;The worst thing you can do is get wrapped up in the technology while the business is burning all around you.&lt;/li&gt;
&lt;li&gt;take time to understand the business. Talk to people to understand it better&lt;/li&gt;
&lt;li&gt;pay attention to the companies health.&lt;/li&gt;
&lt;li&gt;Bob goes on to tell the story of the time he was fired from a job for not understanding his employer&apos;s needs and work culture.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Programmer conflict
&lt;ul&gt;
&lt;li&gt;a symptom of a dysfunctional team is when each programmer safeguards their code and does not let anyone else touch it.
&lt;ul&gt;
&lt;li&gt;This often leads to massive code duplication.&lt;/li&gt;
&lt;li&gt;It can also lead to incorrect interfaces.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It&apos;s important to break down walls of code ownership (silos are bad)&lt;/li&gt;
&lt;li&gt;All team members should be allowed to make changes to any module.&lt;/li&gt;
&lt;li&gt;Professionals do not prevent others from working in their code.&lt;/li&gt;
&lt;li&gt;Professionals learn from working with each other.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Pair-programming is the most efficient way to solve a problem(?)&lt;/li&gt;
&lt;li&gt;Pair programming is a great way to share knowledge.&lt;/li&gt;
&lt;li&gt;All team members have a position to play.&lt;/li&gt;
&lt;li&gt;Pairing is the best way to review code.&lt;/li&gt;
&lt;li&gt;Working alone might be better for you but it is not better for the team.&lt;/li&gt;
&lt;li&gt;While we might not have gotten into this industry to work with people, programming is all about working with people.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Teams and Projects&lt;/h3&gt;
&lt;p&gt;A good team is something to be envied in software development. The best way to create a good team is to keep that team consistent. It often takes a long time for people to get used to working with one another and creating ad-hoc teams constantly does not help.&lt;/p&gt;
&lt;p&gt;By keeping a consistent team it becomes easy to change priorities on a whim since a new team does not have to be formed and the team members are already used to working with one another.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;There is no such thing as a half-person. Often we do not fully resource a developer to a task.&lt;/li&gt;
&lt;li&gt;It does not make sense to have a developer devoted to two different projects especially when there are different project managers, business analysts, developers, and testers on each project.&lt;/li&gt;
&lt;li&gt;It takes time for a team to form/gel&lt;/li&gt;
&lt;li&gt;A team that has &quot;gelled&quot; is very special as they know how to work with each other very well. In these cases, things get done much better.&lt;/li&gt;
&lt;li&gt;A team should consist of: programmers, testers, analysts, and a project manager.&lt;/li&gt;
&lt;li&gt;analysts develop the requirements and write automated acceptance tests.&lt;/li&gt;
&lt;li&gt;testers write those acceptance tests.&lt;/li&gt;
&lt;li&gt;the project manager tracks the team&apos;s progress and makes sure the team understands schedules and priorities.&lt;/li&gt;
&lt;li&gt;It takes a while for team members to work out their differences. This can take up to a year, but once it&apos;s done it&apos;s worth it.&lt;/li&gt;
&lt;li&gt;Once a team has gelled it would be crazy to break that team up.&lt;/li&gt;
&lt;li&gt;Professional development organizations allocate projects to existing teams, they do not create ad-hoc teams.&lt;/li&gt;
&lt;li&gt;To measure these teams look at their velocities.&lt;/li&gt;
&lt;li&gt;Reallocating priorities in an emergency is virtually impossible with ad-hoc teams.&lt;/li&gt;
&lt;li&gt;This allows the business to change priorities on a whim.
&lt;ul&gt;
&lt;li&gt;This can intimidate project owners(?) however it is part of their job to make a case of their project.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Teams are harder to build than projects so keep functioning teams together.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Mentoring, Apprenticeship, and Craftmanship&lt;/h3&gt;
&lt;p&gt;Mentoring is a major gap in the software industry currently. Often college graduates are expected to be able to go straight into the industry and be productive. This mentality is crazy. There are plenty of other fields in which this would never happen and software is becoming too critical to be built by un-prepared individuals.&lt;/p&gt;
&lt;p&gt;One idea as to how to handle this issue is to introduce the concept of apprenticeships into the software industry. In this program, there would be three major roles the master, the journeyman, and the apprentice.&lt;/p&gt;
&lt;p&gt;Masters are veterans in the industry and have worked in many different programming languages and systems. The master needs to stay up to date on the technology. Part of the responsibilities of the master is working with journeymen and testing apprentices to see if they are ready to become journeymen.&lt;/p&gt;
&lt;p&gt;Journeymen are individuals that are knowledgeable but have not quite yet proven themselves to be masters. They are often very skilled at one language and one system. For the most part, it is the responsibility of the journeyman to work closely with the apprentices and mentor them.&lt;/p&gt;
&lt;p&gt;The apprentice is where everyone should start their career. Apprentices should be under close supervision by journeymen and should spend a good amount of time peer programming without actually directly authoring any code.&lt;/p&gt;
&lt;p&gt;While this might not be the best approach it certainly seems better than the current approach of trial by fire on production-grade software.&lt;/p&gt;
&lt;h4&gt;Original Notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;cs graduates have not been taught what programming is all about&lt;/li&gt;
&lt;li&gt;nearly all cs graduates taught themselves to code before college and continued to teach themselves during college.
&lt;ul&gt;
&lt;li&gt;The system can teach you but it can also act as a diploma farm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;cs programs often do not prepare people for what they will find in the industry.
&lt;ul&gt;
&lt;li&gt;This is apparently common in most disciplines?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Mentoring can happen just through observation&lt;/li&gt;
&lt;li&gt;Mentoring can happen from a manual that is well written.&lt;/li&gt;
&lt;li&gt;Mentoring can come in many forms&lt;/li&gt;
&lt;li&gt;Doctors do not just start on the field. The medical field has a discipline of intense mentoring.&lt;/li&gt;
&lt;li&gt;The medical profession oversees universities to make sure graduates have the best education.&lt;/li&gt;
&lt;li&gt;Even with a degree doctors are required to send a year under supervision (internship). After this internship, they go on to do a residency for 3 to 5 years. Once all of this is done they can finally take an exam to become board certified.&lt;/li&gt;
&lt;li&gt;If doctors have this intense process why don&apos;t we do it for software? While deaths are uncommon from software there are possibilities for major monetary loss.&lt;/li&gt;
&lt;li&gt;It is insane to expect to hire someone right out of college and ask them to work with a team to build a critical system.
&lt;ul&gt;
&lt;li&gt;This practice is seen basically nowhere: plumbers, painters, and electricians do not even do this.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This topic does matter software is far more important than we may realize basically our whole civilization runs on it anymore.&lt;/li&gt;
&lt;li&gt;Apprenticeship
&lt;ul&gt;
&lt;li&gt;Masters
&lt;ul&gt;
&lt;li&gt;Have taken lead on more than one significant project.&lt;/li&gt;
&lt;li&gt;typically have 10+ years experience&lt;/li&gt;
&lt;li&gt;have worked in many languages, systems, and operating systems.&lt;/li&gt;
&lt;li&gt;know how to lead and coordinate multiple teams.&lt;/li&gt;
&lt;li&gt;are proficient designers and architects.&lt;/li&gt;
&lt;li&gt;can code circles around everyone else&lt;/li&gt;
&lt;li&gt;Generally have been offered management positions&lt;/li&gt;
&lt;li&gt;maintain a technical role by reading, studying, practicing, doing, and teaching.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Journeymen
&lt;ul&gt;
&lt;li&gt;Programmers that are trained, competent and energetic&lt;/li&gt;
&lt;li&gt;Learns to work well with a team and how to become a team leader.&lt;/li&gt;
&lt;li&gt;Knowledge about technology but lack experience with diverse systems.&lt;/li&gt;
&lt;li&gt;Tend to know one language, one system, and one platform.&lt;/li&gt;
&lt;li&gt;Average is around 5 years experience&lt;/li&gt;
&lt;li&gt;Inbetween Master and Apprentice stages.&lt;/li&gt;
&lt;li&gt;supervised by masters&lt;/li&gt;
&lt;li&gt;seldom allowed autonomy&lt;/li&gt;
&lt;li&gt;code is scrutinized.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Apprentices/Interns
&lt;ul&gt;
&lt;li&gt;Starting point&lt;/li&gt;
&lt;li&gt;have no autonomy&lt;/li&gt;
&lt;li&gt;closely supervised by journeymen&lt;/li&gt;
&lt;li&gt;start off taking no tasks at all and instead just assist journeymen&lt;/li&gt;
&lt;li&gt;Intense pair-programming stage.&lt;/li&gt;
&lt;li&gt;foundational period for values&lt;/li&gt;
&lt;li&gt;journeymen teach them: design principles, design patterns, disciplines, and rituals. For example, things like TDD, refactoring, and estimation would be taught this way.&lt;/li&gt;
&lt;li&gt;Should last at least a year&lt;/li&gt;
&lt;li&gt;masters should evaluate a deemed ready apprentice to see if they should become a journeyman.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;In reality
&lt;ul&gt;
&lt;li&gt;Graduates are generally supervised by young team leads.&lt;/li&gt;
&lt;li&gt;supervision is not technical&lt;/li&gt;
&lt;li&gt;programmers get raises and promotions because that is just what you do&lt;/li&gt;
&lt;li&gt;the key difference between reality and ideal (other points before this) is to focus on technical teaching, training, supervision, and review.&lt;/li&gt;
&lt;li&gt;What is missing today is the responsibility of elders to teach the young.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A craftsman is someone who works quickly, but without rushing, who provides reasonable estimates, and meets commitments.&lt;/li&gt;
&lt;li&gt;Craftsmanship is a mindset held by craftsmen (duh)&lt;/li&gt;
&lt;li&gt;Craftsmanship is handed from one person to another and is taught by elders to young.&lt;/li&gt;
&lt;li&gt;You can&apos;t convince people to be craftsmen. To get others to emulate craftsmanship you must become a craftsman first and let your craftsmanship show.&lt;/li&gt;
&lt;li&gt;It is time for apprenticeship to be a part of software.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Tooling&lt;/h3&gt;
&lt;p&gt;As time has gone on tooling has become better. This chapter is mostly about Bob&apos;s preferences for tooling.&lt;/p&gt;
&lt;h4&gt;Original notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;best source control tooling comes from open source. ones not made this way are generally tools that are sold to managers, not developers.&lt;/li&gt;
&lt;li&gt;pessimistic locking is dead. tooling has become more advanced and merging issues are now manageable.&lt;/li&gt;
&lt;li&gt;The power of git is its branching strategy.&lt;/li&gt;
&lt;li&gt;git and tools like it are the future of source control.&lt;/li&gt;
&lt;li&gt;editors
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Vi&quot;&gt;vi&lt;/a&gt; is tried and true it may be old but it maintains its presence due to its speed and ease of use.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Emacs&quot;&gt;emacs&lt;/a&gt; is one of the most powerful editors around.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.eclipse.org/ide/&quot;&gt;Eclipse&lt;/a&gt; and &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;Intellij&lt;/a&gt;, these editors allow for much more sophisticated manipulation of source code. They have powerful tools for renaming variables, class manipulation, and other similar features.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://macromates.com/&quot;&gt;TextMate&lt;/a&gt; is powerful and lightweight&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;common tools for issue tracking: &lt;a href=&quot;https://www.pivotaltracker.com/&quot;&gt;Pivotal Tracker&lt;/a&gt;, &lt;a href=&quot;https://lighthouseapp.com/&quot;&gt;Lighthouse&lt;/a&gt;, and Wikis. The best place to start is often manual then find a tool that matches your style.&lt;/li&gt;
&lt;li&gt;Having thousands of bugs or features often means you have done something wrong.&lt;/li&gt;
&lt;li&gt;CI
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/&quot;&gt;Jenkins&lt;/a&gt; is a solid tool.&lt;/li&gt;
&lt;li&gt;CI should run automatically on every code check-in&lt;/li&gt;
&lt;li&gt;The build must be working at all times.&lt;/li&gt;
&lt;li&gt;Failure should never be allowed to persist for over a day or two.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Unit testing
&lt;ul&gt;
&lt;li&gt;Bob&apos;s favorites: &lt;a href=&quot;https://junit.org/&quot;&gt;JUnit&lt;/a&gt;, &lt;a href=&quot;https://rspec.info/&quot;&gt;RSPEC&lt;/a&gt;, &lt;a href=&quot;https://nunit.org/&quot;&gt;NUnit&lt;/a&gt;, &lt;a href=&quot;https://github.com/marick/Midje&quot;&gt;Midje&lt;/a&gt;, &lt;a href=&quot;http://cpputest.github.io/&quot;&gt;CppUTest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;features all testing frameworks should have.
&lt;ul&gt;
&lt;li&gt;should be quick and easy to run tests.&lt;/li&gt;
&lt;li&gt;should give a clear pass-fail indication.&lt;/li&gt;
&lt;li&gt;should give a clear visual indicator of progress.&lt;/li&gt;
&lt;li&gt;should discourage individual tests for communicating with one another.&lt;/li&gt;
&lt;li&gt;should make it easy to write tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Component testing
&lt;ul&gt;
&lt;li&gt;API testing tools&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://fitnesse.org/&quot;&gt;FitNesse&lt;/a&gt;, is Bob&apos;s own creation and he likes to use it for component testing.&lt;/li&gt;
&lt;li&gt;Other tools in this camp: RobotFx, Green Pepper, &lt;a href=&quot;https://cucumber.io/&quot;&gt;Cucumber&lt;/a&gt;, and &lt;a href=&quot;https://jbehave.org/&quot;&gt;JBehave&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Good UI testing tools are &lt;a href=&quot;https://www.selenium.dev/&quot;&gt;selenium&lt;/a&gt; and &lt;a href=&quot;http://watir.com/&quot;&gt;Watir&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;UML has not proven to be a sufficient tool to express all of the details of a program. This is why we still write code instead of UML documents.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Insights&lt;/h2&gt;
&lt;p&gt;Coming into this book I did not know if I was going to like it or not. This book is highly focused on the soft skills of programming that are rarely focused on in our industry. While I do not agree with Robert on every point I found myself in agreement a good amount of the time.&lt;/p&gt;
&lt;p&gt;There is a common thread I did notice while reading this book. Robert loves to tell a story. What is interesting about this is while some of these stories and annecdotes are amusing they often contain a nugget of wisdom. While I do not fully understand how someone can make some of the mistakes Robert has in his career I did enjoy reading them. I often find the best way to learn is to make a mistake and its even better when you can learn from someone elses mistakes. I am assured that some mistakes shown in this book are not just Robert being a stupid kid and are mistakes even would be professionals could make.&lt;/p&gt;
&lt;p&gt;A lot of this book seems to talk about dealing with pressure. Maybe the industry has changed or I am a personally that is not easily impacted by unrealistic requests, but I do not often feel the same pressures as described in this book. I understand that I get pressure from product owners, product managers and business analysts but I am always sure to let them know what is at stake. In general I see it as me doing my job and them doing their job.&lt;/p&gt;
&lt;p&gt;The concept of practicing and continued studying seems like a no brainer to me but I could see where others might not be willing to devote time into this practice and it is a good call out. Not everything you learn in this industry is on the job.&lt;/p&gt;
&lt;p&gt;I think one of the most impactful parts of this book for me was the apprenticeship discussion. I have always felt like the industry has been missing this. I have often heard of people mixing bootcamps and college but that still doesn&apos;t quite feel right to me. Personally I prefer the idealized apprenticeship model discussed in this book. This is a practice that is done in many trades and professions and it still boggels my mind that this is not a common or documented practice in software.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Book Notes]]></title><description><![CDATA[Book Notes Recently I have found that some of the books on the topic of software engineering and other business endeavors have somewhat left…]]></description><link>https://ilusr.com/books/</link><guid isPermaLink="false">https://ilusr.com/books/</guid><pubDate>Thu, 25 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Book Notes&lt;/h1&gt;
&lt;p&gt;Recently I have found that some of the books on the topic of software engineering and other business endeavors have somewhat left me as time goes on. Ideally, I should be taking notes or at least capturing some insight on these topics as I read these books.&lt;/p&gt;
&lt;p&gt;Every once in a while I will be adding a post about some book I have read. It might not be well thought out and the format is probably going to read like notes with some reflection.&lt;/p&gt;
&lt;p&gt;Since this site is mostly for me and I doubt I have an audience I think this is acceptable. If you have an issue with these posts I am sorry but they are not really for you. If you get value out of them great.&lt;/p&gt;
&lt;p&gt;If you are not interested in this topic I will be sure to prefix all articles with the Title &lt;code&gt;Book Note&lt;/code&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[TCP Transport]]></title><description><![CDATA[TCP Transport As a continuation of the transport layer series, in this blog, we will be looking at our second transport layer protocol. Now…]]></description><link>https://ilusr.com/tcp/</link><guid isPermaLink="false">https://ilusr.com/tcp/</guid><pubDate>Sat, 07 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;TCP Transport&lt;/h1&gt;
&lt;p&gt;As a continuation of the transport layer series, in this blog, we will be looking at our second transport layer protocol. Now that we have taken a look at UDP and understand its reliability issues it&apos;s time to look at its more reliable alternative. This protocol is the transmission control protocol or TCP for short. TCP is meant to be a layered protocol architecture. In this case, TCP is a layer that builds on IP much like UDP, but TCP is also meant to be extended by other protocols like telnet, FTP, and HTTP. The philosophy of TCP emphasizes a couple of different roles that TCP plays.&lt;/p&gt;
&lt;h3&gt;Basic Data Transfer&lt;/h3&gt;
&lt;p&gt;TCP should be able to transfer a continuous stream of octets in each direction by packaging some number of octets into segments for transmission. The availability of a push function should be defined for when users need to be sure all data they have sent has been transmitted.&lt;/p&gt;
&lt;h3&gt;Reliability&lt;/h3&gt;
&lt;p&gt;TCP must be able to recover from data that is damaged, lost, duplicated, or delivered out of order. This could happen for multiple reasons such as a faulty network connection or switch. The reason for the loss is not particularly important what is important is that TCP is resilient to such failures. This is one way in which TCP is drastically different from UDP as UDP had no protection of any such problem. To detect damaged segments a checksum is used.&lt;/p&gt;
&lt;h3&gt;Flow Control&lt;/h3&gt;
&lt;p&gt;TCP provides a window. This window acts as a sizing mechanism that allows the receiver of data to control the amount of data the sender is allowed to send at a time.&lt;/p&gt;
&lt;h3&gt;Multiplexing&lt;/h3&gt;
&lt;p&gt;Since TCP wants to allow multiple processes on a single host to use the protocol, ports are used. In this case, the host is responsible for binding the ports to the processes. The combination of network and host address form a socket. This socket acts as the identifier for one end of a TCP connection. A pair of sockets makes up a unique connection. While a socket identifies one end of a connection it does not have to be used in just one connection. A socket can be reused for multiple different connections at the same time.&lt;/p&gt;
&lt;h3&gt;Connections&lt;/h3&gt;
&lt;p&gt;A connection is made up of the combination of sockets, sequence numbers, and window sizes. This connection is uniquely identified by a pair of sockets. The connection must first be successfully established before two processes can communicate over TCP. This is done using a handshaking mechanism with clock-based sequence numbers to avoid erroneous initializations of connections. When the communication between the two processes is completed the connection is terminated or closed.&lt;/p&gt;
&lt;h3&gt;Precedence and Security&lt;/h3&gt;
&lt;p&gt;TCP includes mechanisms for setting connection precedence and security. In the case of TCP, users can indicate the security and precedence their communication will use. If this is not honored by both sides of the connection then a successful connection cannot be established.&lt;/p&gt;
&lt;p&gt;One other important thing to note before moving on is that TCP introduces the concept of a Transmission Control Block or TCB for short. The TCB stores information about the connection on the host. In a Linux based environment, you can see this information by running the command &lt;code&gt;netstat -at&lt;/code&gt; in a terminal.&lt;/p&gt;
&lt;h2&gt;Reviewing the network protocol&lt;/h2&gt;
&lt;h3&gt;Fields&lt;/h3&gt;
&lt;h4&gt;Source Port&lt;/h4&gt;
&lt;p&gt;16-bit source port number.&lt;/p&gt;
&lt;h4&gt;Destination Port&lt;/h4&gt;
&lt;p&gt;16-bit destination port number.&lt;/p&gt;
&lt;h4&gt;Sequence Number&lt;/h4&gt;
&lt;p&gt;32-bit sequence number of the first data octet in the segment. If SYN is present the sequence number is the initial sequence number (ISN) and the first data octet is ISN+1.&lt;/p&gt;
&lt;h4&gt;Acknowledgment Number&lt;/h4&gt;
&lt;p&gt;32-bit field that contains the value of the next sequence number the sender of the segments is expecting to receive.&lt;/p&gt;
&lt;h4&gt;Data Offset&lt;/h4&gt;
&lt;p&gt;4-bit number that specifies where the data begins. This number represents the number of 32-bit words in the TCP header itself.&lt;/p&gt;
&lt;h4&gt;Reserved&lt;/h4&gt;
&lt;p&gt;6 bits that are reserved for future use.&lt;/p&gt;
&lt;h4&gt;Control bits&lt;/h4&gt;
&lt;p&gt;6 bits that take on any of the following&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;URG&lt;/td&gt;
&lt;td&gt;Urgent pointer field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ACK&lt;/td&gt;
&lt;td&gt;Acknowledgment field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PSH&lt;/td&gt;
&lt;td&gt;Push function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RST&lt;/td&gt;
&lt;td&gt;Reset the function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYN&lt;/td&gt;
&lt;td&gt;Synchronize sequence numbers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FIN&lt;/td&gt;
&lt;td&gt;No more data to transfer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Window&lt;/h4&gt;
&lt;p&gt;16-bit field that specifies the number of data octets starting with the one indicated in the acknowledgment field which the sender is willing to accept.&lt;/p&gt;
&lt;h4&gt;Checksum&lt;/h4&gt;
&lt;p&gt;16-bit field which is the one&apos;s complement of the one&apos;s complement sum of all 16-bit words in the header and text. In the &lt;a href=&quot;http://ilusr.com/udp/&quot;&gt;UDP blog&lt;/a&gt;, I talked more about calculating the checksum, a very similar calculation would happen for TCP.&lt;/p&gt;
&lt;h4&gt;Urgent Pointer&lt;/h4&gt;
&lt;p&gt;16-bit field that communicates the current value of the urgent pointer. This pointer points to the sequence number of the octet following the urgent data.&lt;/p&gt;
&lt;h4&gt;Options&lt;/h4&gt;
&lt;p&gt;Options are variable in size but must be a multiple of 8 bits in length. All options are included in the checksum. All options have an option-kind and may have an option length.&lt;/p&gt;
&lt;h5&gt;End of Option List&lt;/h5&gt;
&lt;p&gt;The end of the options list has a Kind of 0. This option indicates the end of the options list. This option is only needed if the end of the options would not match up with the end of the TCP header. That is to say, if there are extra bytes after the options this option must be provided.&lt;/p&gt;
&lt;h5&gt;No-Operation&lt;/h5&gt;
&lt;p&gt;The no-operation has a Kind of 1. This can be used between options; However, there is no guarantee that senders will use this option.&lt;/p&gt;
&lt;h5&gt;Maximum Segment Size&lt;/h5&gt;
&lt;p&gt;The maximum segment size has a Kind of 2 and a length of 4 bytes. This option communicates the maximum receive segment size to the TCP that sends this segment. This option can only be used in the initial connection request.&lt;/p&gt;
&lt;h4&gt;Padding&lt;/h4&gt;
&lt;p&gt;Padding is a variable-sized field used to ensure that the header ends and data begins on a 32-bit boundary.&lt;/p&gt;
&lt;h4&gt;Data&lt;/h4&gt;
&lt;p&gt;The data that is being sent.&lt;/p&gt;
&lt;h3&gt;Terminology&lt;/h3&gt;
&lt;h4&gt;Send Sequence Variables&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SND.UNA&lt;/td&gt;
&lt;td&gt;send unacknowledged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SND.NXT&lt;/td&gt;
&lt;td&gt;send next&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SND.WND&lt;/td&gt;
&lt;td&gt;send window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SND.UP&lt;/td&gt;
&lt;td&gt;send urgent pointer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SND.WL1&lt;/td&gt;
&lt;td&gt;segment sequence number used for last window update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SND.WL2&lt;/td&gt;
&lt;td&gt;segment acknowledgment number used for last window update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ISS&lt;/td&gt;
&lt;td&gt;initial send sequence number&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Recieve Sequence Variables&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RCV.NXT&lt;/td&gt;
&lt;td&gt;receive next&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RCV.WND&lt;/td&gt;
&lt;td&gt;receive window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RCV.UP&lt;/td&gt;
&lt;td&gt;receive urgent pointer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IRS&lt;/td&gt;
&lt;td&gt;initial receive sequence number&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Segment Variables&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SEG.SEQ&lt;/td&gt;
&lt;td&gt;segment sequence number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEG.ACK&lt;/td&gt;
&lt;td&gt;segment acknowledgment number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEG.LEN&lt;/td&gt;
&lt;td&gt;segment length&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEG.WND&lt;/td&gt;
&lt;td&gt;segment window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEG.UP&lt;/td&gt;
&lt;td&gt;segment urgent pointer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEG.PRC&lt;/td&gt;
&lt;td&gt;segment precedence value&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Connection states&lt;/h4&gt;
&lt;p&gt;TCP is driven by different connection states. A connection moves from one connection state to another in response to events. The events a user can call to influence connection state are: OPEN, SEND, RECEIVE, CLOSE, ABORT, and STATUS. Information about the connection state can be found on the TCB.&lt;/p&gt;
&lt;h5&gt;LISTEN&lt;/h5&gt;
&lt;p&gt;In the listen state socket is waiting for a connection request from any remote TCP and port.&lt;/p&gt;
&lt;h5&gt;SYN-SENT&lt;/h5&gt;
&lt;p&gt;In the SYN-SENT state, the socket is waiting for a matching connection request after having sent a connection request of its own.&lt;/p&gt;
&lt;h5&gt;SYN-RECEIVED&lt;/h5&gt;
&lt;p&gt;In the SYN-RECEIVED state, the socket is waiting for a confirmation connection request acknowledgment after having both sent and received a connection request.&lt;/p&gt;
&lt;h5&gt;ESTABLISHED&lt;/h5&gt;
&lt;p&gt;In the ESTABLISHED state, the socket is an open connection. This is the normal data transfer phase of the connection.&lt;/p&gt;
&lt;h5&gt;FIN-WAIT-1&lt;/h5&gt;
&lt;p&gt;In the FIN-WAIT-1 state, the socket is waiting for a connection termination request from the remote TCP or an acknowledgment of the connection termination request that had previously been sent.&lt;/p&gt;
&lt;h5&gt;FIN-WAIT-2&lt;/h5&gt;
&lt;p&gt;In the FIN-WAIT-2 state, the socket is waiting for a connection termination request from the remote TCP.&lt;/p&gt;
&lt;h5&gt;CLOSE-WAIT&lt;/h5&gt;
&lt;p&gt;In the CLOSE-WAIT state, the socket is waiting for a connection termination request from the local user.&lt;/p&gt;
&lt;h5&gt;CLOSING&lt;/h5&gt;
&lt;p&gt;In the CLOSING state the socket is waiting for a connection termination request acknowledgment from the remote TCP.&lt;/p&gt;
&lt;h5&gt;LAST-ACK&lt;/h5&gt;
&lt;p&gt;In the LAST-ACK state, the socket is waiting for an acknowledgment of the connection termination request that had previously been sent to the remote TCP.&lt;/p&gt;
&lt;h5&gt;TIME-WAIT&lt;/h5&gt;
&lt;p&gt;In the TIME-WAIT state, the socket is waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request.&lt;/p&gt;
&lt;h5&gt;CLOSED&lt;/h5&gt;
&lt;p&gt;In the CLOSED state, the socket has no connection.&lt;/p&gt;
&lt;h4&gt;Sequence Numbers&lt;/h4&gt;
&lt;p&gt;Sequence numbers are a key part of how TCP ensures no packet loss or duplication. In TCP every octet of data sent on the wire has a sequence number. Each of these sequence numbers can be acknowledged by the remote TCP. In the case of TCP acknowledgment is a cumulative mechanism. In the case of acknowledgment, if you acknowledge sequence N that means the receiving TCP has acknowledged all data octets up to but not including N. Sequence numbers occupy a finite space, however that space is rather large 0 - 2&lt;sup&gt;32&lt;/sup&gt; - 1. Since a sequence number occupies a finite amount of space, all arithmetic dealing with sequence numbers must be performed with modulo 2&lt;sup&gt;32&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Some examples of arithmetic required for dealing with sequence numbers include the following.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Determining that an acknowledgment refers to some sequence number sent but not acknowledged.&lt;/li&gt;
&lt;li&gt;Determining that all sequence numbers occupied by a segment have been acknowledged.&lt;/li&gt;
&lt;li&gt;Determining that an incoming segment contains sequence numbers that are expected.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When it comes to processing acknowledgments there are a couple of different comparisons that are required.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SND:UNA&lt;/td&gt;
&lt;td&gt;The oldest unacknowledged sequence number.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SND.NXT&lt;/td&gt;
&lt;td&gt;The next sequence number to be sent.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEG.ACK&lt;/td&gt;
&lt;td&gt;An acknowledgment from the receiving TCP.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEG.SEQ&lt;/td&gt;
&lt;td&gt;The first sequence number of a segment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEG.LEN&lt;/td&gt;
&lt;td&gt;The number of octets occupied by the data in the segment.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;With these variables, you can combine values to produce additional information. For example, &lt;code&gt;SEG.SEQ+SEG.LEN-1&lt;/code&gt; represents the last sequence number of a segment. Likewise, you can tell if a segment on the retransmission queue is fully acknowledged. In this case, if the sum of its sequence number and length is less or equal to the acknowledgment value in the incoming request. This could be represented in this way &lt;code&gt;SND.UNA &amp;#x3C; SEG.ACK =&amp;#x3C; SND.NXT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When it comes to processing received data a different set of comparisons is required.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RCV.NXT&lt;/td&gt;
&lt;td&gt;The next sequence number expected on an incoming segment. This is the left or lower edge of the receive window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RVC.NXT+RCV.WND-1&lt;/td&gt;
&lt;td&gt;The last sequence number expected on an incoming segment. This is the right upper edge of the receive window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEG.SEQ&lt;/td&gt;
&lt;td&gt;The first sequence number occupied by the incoming segment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEG.SEQ+SEG.LEN-1&lt;/td&gt;
&lt;td&gt;The last sequence number occupied by the incoming segment.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;TCP can determine if a segment occupies a portion of a valid receive sequence using either &lt;code&gt;RCV.NXT =&amp;#x3C; SEG.SEQ &amp;#x3C; RCV.NXT+RCV.WND&lt;/code&gt; or &lt;code&gt;RCV.NXT =&amp;#x3C; SEG.SEQ+SEG.LEN-1 &amp;#x3C; RCV.NXT+RCV.WND&lt;/code&gt;. In the case of &lt;code&gt;RCV.NXT =&amp;#x3C; SEG.SEQ &amp;#x3C; RCV.NXT+RCV.WND&lt;/code&gt; this operation is checking to see if the beginning of the segment falls in a window. In the case of &lt;code&gt;RCV.NXT =&amp;#x3C; SEG.SEQ+SEG.LEN-1 &amp;#x3C; RCV.NXT+RCV.WND&lt;/code&gt; this operation is checking to see if the end of the segment falls in a window. One thing that can complicate this logic is if the window size is zero or a zero segment exists. This is possible but a bit of an edge case.&lt;/p&gt;
&lt;p&gt;There are a couple of special cases when it comes to sequence numbers. In the case of TCP SYN and FIN are not subject to sequence numbers. SYN is always expected to occur before the first data octet while FIN is always expected to occur after the last data octet.&lt;/p&gt;
&lt;h5&gt;Initial Sequence number&lt;/h5&gt;
&lt;p&gt;The initial sequence number or ISN for short is used to help TCP identify duplicate segments from previous connections. This kind of problem and typically happen when a connection is opened and closed in quick succession or when a connection breaks with loss of memory and is reestablished. Even in the case of a crash with a total loss of knowledge of sequence numbers TCP must prevent segment reuse. To prevent segment reuse an ISN generator is used to create a rather unique number. This generator selects a 32-bit ISN based on a 32-bit clock. The 32-bit clock is incremented around every 4 microseconds giving the ISN cycle time a 4.55-hour window. Since 4.55 hours is not unique enough due to the long-lived nature of some TCP connections, the addition of a Maximum Segment Lifetime or MSL is required. The MSL is used to make sure TCP does not create a segment that carries a duplicated sequence number. TCP must keep quiet for the MSL before it is allowed to assign any sequence numbers after recovering from a crash in which memory loss of sequence numbers in use occurred. When the MSL is less than 4.55 hours we can assume that ISN&apos;s are unique. Every connection has a send sequence number and a receive sequence number. The initial send sequence number or ISS is decided by the data sending TCP. The initial receive sequence number or IRS is learned during the connection establishing procedure. For a TCP connection to be established or initialized both TCPs must synchronize based on each other&apos;s ISN. This exchange of segments is done with a SYN and the sequence numbers. The process of synchronization requires each TCP to send its ISN and receive confirmation of it in an ACK.&lt;/p&gt;
&lt;p&gt;Example flow&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A --&gt; B SYN sequence number is X&lt;/li&gt;
&lt;li&gt;A &amp;#x3C;-- B ACK sequence number is X&lt;/li&gt;
&lt;li&gt;A &amp;#x3C;-- B SYN sequence number is Y&lt;/li&gt;
&lt;li&gt;A --&gt; B ACK sequence number is Y&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;steps 2 and 3 can be combined in a single message. This the three-way handshake.&lt;/p&gt;
&lt;h4&gt;Establishing a connection&lt;/h4&gt;
&lt;p&gt;Since TCP is not able to be tied to a global clock for ISN generation, the process of exchanging ISNs is done through a three-way handshake. Below are some examples of how this handshake works.&lt;/p&gt;
&lt;h5&gt;Simple Three-way handshake&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TCP A&lt;/th&gt;
&lt;th&gt;TCP A Direction&lt;/th&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;th&gt;TCP B Direction&lt;/th&gt;
&lt;th&gt;TCP B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CLOSED&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;LISTEN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYN-SENT&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=100&gt;&amp;#x3C;CTL=SYN&gt;&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;SYN-RECEIVED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESTABLISHED&lt;/td&gt;
&lt;td&gt;&amp;#x3C;--&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=300&gt;&amp;#x3C;ACK=101&gt;&amp;#x3C;CTL=SYN,ACK&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;--&lt;/td&gt;
&lt;td&gt;SYN-RECEIVED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESTABLISHED&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=101&gt;&amp;#x3C;ACK=301&gt;&amp;#x3C;CTL=ACK&gt;&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;ESTABLISHED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESTABLISHED&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=101&gt;&amp;#x3C;ACK=301&gt;&amp;#x3C;CTL=ACK&gt;&lt;DATA&gt;&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;ESTABLISHED&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;Simultaneous Three-way handshake&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TCP A&lt;/th&gt;
&lt;th&gt;TCP A Direction&lt;/th&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;th&gt;TCP B Direction&lt;/th&gt;
&lt;th&gt;TCP B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CLOSED&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;CLOSED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYN-SENT&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=100&gt;&amp;#x3C;CTL=SYN&gt;&lt;/td&gt;
&lt;td&gt;In transit&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYN-RECEIVED&lt;/td&gt;
&lt;td&gt;&amp;#x3C;--&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=300&gt;&amp;#x3C;CTL=SYN&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;--&lt;/td&gt;
&lt;td&gt;SYN-SENT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;In transit&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=100&gt;&amp;#x3C;CTL=SYN&gt;&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;SYN-RECIEVED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYN-RECIEVED&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=100&gt;&amp;#x3C;ACK=301&gt;&amp;#x3C;CTL=SYN,ACK&gt;&lt;/td&gt;
&lt;td&gt;In transit&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESTABLISHED&lt;/td&gt;
&lt;td&gt;&amp;#x3C;--&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=300&gt;&amp;#x3C;ACK=101&gt;&amp;#x3C;CTL=SYN,ACK&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;--&lt;/td&gt;
&lt;td&gt;SYN-RECEIVED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;In transit&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=101&gt;&amp;#x3C;ACK=301&gt;&amp;#x3C;CTL=ACK&gt;&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;ESTABLISHED&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The three-way handshake allows for recovery from duplicate messages by using the reset function.&lt;/p&gt;
&lt;h5&gt;Recovery from a crash (half-open)&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TCP A&lt;/th&gt;
&lt;th&gt;TCP A Direction&lt;/th&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;th&gt;TCP B Direction&lt;/th&gt;
&lt;th&gt;TCP B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;(Crash)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLOSED&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYN-SENT&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=400&gt;&amp;#x3C;CTL=SYN&gt;&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;invalid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bad response&lt;/td&gt;
&lt;td&gt;&amp;#x3C;--&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=300&gt;&amp;#x3C;ACK=100&gt;&amp;#x3C;CTL=ACK&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;--&lt;/td&gt;
&lt;td&gt;ESTABLISHED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYN-SENT&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=100&gt;&amp;#x3C;CTL=RST&gt;&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;Abort&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYN-SENT&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;CLOSED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYN-SENT&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;&amp;#x3C;SEQ=400&gt;&amp;#x3C;CTL=SYN&gt;&lt;/td&gt;
&lt;td&gt;--&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;Resets&lt;/h5&gt;
&lt;p&gt;Resets are used to reset the connection in the case of invalid or unexpected data. For example, if a segment arrives which is not intended for the current connection, or the connection does not exist then a reset must be sent. Another case in which a reset should be sent would be when the connection gets into a non-synchronized state. An example of this state would be a TCP receiving an acknowledgment for a segment that has not been sent yet. To validate a reset the sequence fields are used. If the sequence number is in the window then the reset is considered valid. Once a receiver validates a reset request it then changes state. In the case that the receiver was in the LISTEN state the reset request is ignored. In the case that the receiver is in the SYN-RECEIVED state they will return to the LISTEN state. In all other cases, the receiver will abort the connection and go to the CLOSED state.&lt;/p&gt;
&lt;h5&gt;Closing connection&lt;/h5&gt;
&lt;p&gt;In the case of TCP, the CLOSE operations signal that &quot;I have no more data to send.&quot; In this case, the issuer of the close request may continue to receive data until they are told that the other side has closed the connection as well. By doing this TCP ensures that all data buffers sent before the connection was closed had been delivered. There are a couple of cases in which a connection can be closed.&lt;/p&gt;
&lt;p&gt;The first case is when the local user initiates the close. In this case, a FIN segment is created and placed on the outgoing segment queue. Past this point no further SENDs from the user will be accepted, only receives are allowed from this state. When the other TCP has acknowledged the FIN and sent a FIN of its own the closing TCP can ACK the FIN and end the connection.&lt;/p&gt;
&lt;p&gt;The second case is when a TCP receives a FIN from the network. This is FIN is considered unsolicited. In this case, the TCP that received the FIN will respond with a CLOSE. If an ACK does not come within a timeout then the connection is aborted.&lt;/p&gt;
&lt;p&gt;The third case is when both sides of the connection close at the same time. In this case, both sides exchange FIN segments. Once both sides have received ACKs the connection will be deleted.&lt;/p&gt;
&lt;h4&gt;Precedence and security&lt;/h4&gt;
&lt;p&gt;Precedence and security are used to make sure the connection between ports are operating on the same security and compartment values. Any connection attempt with mismatched security or compartment values must be rejected by sending a reset.&lt;/p&gt;
&lt;h4&gt;Data Communication&lt;/h4&gt;
&lt;p&gt;TCP is a data communication protocol, so the exchange of data is very important. In the case of TCP data is communicated by the exchange of segments. Unlike with UDP TCP uses retransmission to handle the loss of segments due to errors or network congestion. Since TCP does use retransmission duplicate segments can arrive but this is not an issue due to the way segments are acknowledged. In these cases, the sender keeps track of the next expected sequence number in the SND.NXT while the receiver keeps track of the next sequence number in the RCV.NXT. The sender also keeps track of the oldest unacknowledged sequence number in the SND.UNA. One important thing to note is that SND,NXT and RCV.NXT is incremented by the length of data in the segment.&lt;/p&gt;
&lt;p&gt;When sending data over TCP an important thing to consider is the window size. In the case of a large window transmissions are encouraged, but in the case of a small window transmission of data can be restricted to the point of introducing a round trip delay.&lt;/p&gt;
&lt;h4&gt;Interfaces&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;User Commands
&lt;ul&gt;
&lt;li&gt;Open - opens the TCP connection.&lt;/li&gt;
&lt;li&gt;Send - sends data in a buffer. Send is considered an error if it occurs on a connection that is not open. Multiple sends can be called before closing the connection.&lt;/li&gt;
&lt;li&gt;Receive - Waits for data and returns to the program once the buffer is filled.&lt;/li&gt;
&lt;li&gt;Close - causes a connection to be closed.&lt;/li&gt;
&lt;li&gt;Status - Information from the TCB about the connection.
&lt;ul&gt;
&lt;li&gt;foreign socket&lt;/li&gt;
&lt;li&gt;local connection name&lt;/li&gt;
&lt;li&gt;receive window&lt;/li&gt;
&lt;li&gt;send window&lt;/li&gt;
&lt;li&gt;connection state&lt;/li&gt;
&lt;li&gt;number of buffers awaiting ack&lt;/li&gt;
&lt;li&gt;number of buffers pending receipt&lt;/li&gt;
&lt;li&gt;urgent state&lt;/li&gt;
&lt;li&gt;precedence&lt;/li&gt;
&lt;li&gt;security&lt;/li&gt;
&lt;li&gt;transmission timeout&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Abort - cancels all pending SENDs and RECEIVEs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TCP to user messages
&lt;ul&gt;
&lt;li&gt;When TCP signals a user program it should provide the following information
&lt;ul&gt;
&lt;li&gt;Local Connection Name&lt;/li&gt;
&lt;li&gt;Response String&lt;/li&gt;
&lt;li&gt;Buffer Address&lt;/li&gt;
&lt;li&gt;Byte count&lt;/li&gt;
&lt;li&gt;Push flag&lt;/li&gt;
&lt;li&gt;Urgent flag&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Event Processing&lt;/h4&gt;
&lt;p&gt;The activity of TCP can be defined as responding to events. In the case of TCP, there are 3 different kinds of events.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User Calls
&lt;ul&gt;
&lt;li&gt;OPEN&lt;/li&gt;
&lt;li&gt;SEND&lt;/li&gt;
&lt;li&gt;RECEIVE&lt;/li&gt;
&lt;li&gt;CLOSE&lt;/li&gt;
&lt;li&gt;ABORT&lt;/li&gt;
&lt;li&gt;STATUS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Arriving Segments
&lt;ul&gt;
&lt;li&gt;SEGMENT ARRIVES&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Timeouts
&lt;ul&gt;
&lt;li&gt;USER TIMEOUT&lt;/li&gt;
&lt;li&gt;RETRANSMISSION TIMEOUT&lt;/li&gt;
&lt;li&gt;TIME-WAIT TIMEOUT&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Example of a standard library&lt;/h3&gt;
&lt;p&gt;Much like UDP, TCP is a standard protocol and it is relatively easy to find support for it in most languages standard library. Below are just a few examples of programming languages and their associated TCP library.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;nodejs - &lt;a href=&quot;https://nodejs.org/api/net.html&quot;&gt;https://nodejs.org/api/net.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Java - &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html&quot;&gt;https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Go - &lt;a href=&quot;https://golang.org/pkg/net/&quot;&gt;https://golang.org/pkg/net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Python - &lt;a href=&quot;https://docs.python.org/3/library/socket.html&quot;&gt;https://docs.python.org/3/library/socket.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rust - &lt;a href=&quot;https://doc.rust-lang.org/beta/std/net/struct.TcpStream.html&quot;&gt;https://doc.rust-lang.org/beta/std/net/struct.TcpStream.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Example of a client-server application using the protocol&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/tcp-example-app&quot;&gt;https://github.com/JeffreyRiggle/tcp-example-app&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This application is very similar to the one covered in the last blog about UDP. The notable differences in this example are: there is a disconnect button, and the application uses TCP instead of UDP.&lt;/p&gt;
&lt;h3&gt;Look at the results in a network capture&lt;/h3&gt;
&lt;p&gt;Similar to the UDP analysis we will be using &lt;a href=&quot;https://www.wireshark.org/&quot;&gt;Wireshark&lt;/a&gt; to look at the network captures. For more information on install and setup see the previous blog.&lt;/p&gt;
&lt;h4&gt;Initial connection&lt;/h4&gt;
&lt;p&gt;In this case, we can see a simple three-way handshake occurs between the connecting client at port 50174 and the server on port 7000.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source Port&lt;/th&gt;
&lt;th&gt;Destination Port&lt;/th&gt;
&lt;th&gt;Flags&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;50174&lt;/td&gt;
&lt;td&gt;7000&lt;/td&gt;
&lt;td&gt;SYN&lt;/td&gt;
&lt;td&gt;Initial connection request from the client with an ISN of 1047673890&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 3c ad db 40 00 40 06 8e de 7f 00 00 01 7f 00   .&amp;#x3C;.Û@&lt;a href=&quot;mailto:.@..&quot;&gt;.@..&lt;/a&gt;Þ......&lt;br&gt;0020   00 01 c3 fe 1b 58 3e 72 3c 22 00 00 00 00 a0 02   ..Ãþ.X&gt;r&amp;#x3C;&quot;.... .&lt;br&gt;0030   ff d7 fe 30 00 00 02 04 ff d7 04 02 08 0a 66 e1   ÿ×þ0....ÿ×....fá&lt;br&gt;0040   a0 f1 00 00 00 00 01 03 03 07                      ñ........&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7000&lt;/td&gt;
&lt;td&gt;50174&lt;/td&gt;
&lt;td&gt;SYN, ACK&lt;/td&gt;
&lt;td&gt;Acknowledge the connection and provide ISN 3883755340&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 3c 00 00 40 00 40 06 3c ba 7f 00 00 01 7f 00   .&amp;#x3C;&lt;a href=&quot;mailto:..@.&quot;&gt;..@.&lt;/a&gt;@.&amp;#x3C;º......&lt;br&gt;0020   00 01 1b 58 c3 fe e7 7d 67 4c 3e 72 3c 23 a0 12   ...XÃþç}gL&gt;r&amp;#x3C;# .&lt;br&gt;0030   ff cb fe 30 00 00 02 04 ff d7 04 02 08 0a 66 e1   ÿËþ0....ÿ×....fá&lt;br&gt;0040   a0 f2 66 e1 a0 f1 01 03 03 07                      òfá ñ....&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50174&lt;/td&gt;
&lt;td&gt;7000&lt;/td&gt;
&lt;td&gt;ACK&lt;/td&gt;
&lt;td&gt;Acknowledge the ISN&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 34 ad dc 40 00 40 06 8e e5 7f 00 00 01 7f 00   .4.Ü@&lt;a href=&quot;mailto:.@..&quot;&gt;.@..&lt;/a&gt;å......&lt;br&gt;0020   00 01 c3 fe 1b 58 3e 72 3c 23 e7 7d 67 4d 80 10   ..Ãþ.X&gt;r&amp;#x3C;#ç}gM..&lt;br&gt;0030   02 00 fe 28 00 00 01 01 08 0a 66 e1 a0 f2 66 e1   ..þ(......fá òfá&lt;br&gt;0040   a0 f2                                              ò&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Client sending a message&lt;/h4&gt;
&lt;p&gt;In this case, we send a simple hello world message to the server. Just like in the UDP example the client sends a custom byte structure while the server sends a JSON response.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source Port&lt;/th&gt;
&lt;th&gt;Destination Port&lt;/th&gt;
&lt;th&gt;Flags&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;50174&lt;/td&gt;
&lt;td&gt;7000&lt;/td&gt;
&lt;td&gt;PSH,ACK&lt;/td&gt;
&lt;td&gt;The client is sending a hello world message to the server.&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 41 ad df 40 00 40 06 8e d5 7f 00 00 01 7f 00   .A.ß@&lt;a href=&quot;mailto:.@..&quot;&gt;.@..&lt;/a&gt;Õ......&lt;br&gt;0020   00 01 c3 fe 1b 58 3e 72 3c 24 e7 7d 67 65 80 18   ..Ãþ.X&gt;r&amp;#x3C;$ç}ge..&lt;br&gt;0030   02 00 fe 35 00 00 01 01 08 0a 66 f1 44 8d 66 e1   ..þ5......fñD.fá&lt;br&gt;0040   a1 52 02 48 65 6c 6c 6f 20 57 6f 72 6c 64 21      ¡R.Hello World!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7000&lt;/td&gt;
&lt;td&gt;50174&lt;/td&gt;
&lt;td&gt;PSH,ACK&lt;/td&gt;
&lt;td&gt;The server acknowledges the message and sends a message of its own.&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 7b 8c 49 40 00 40 06 b0 31 7f 00 00 01 7f 00   .{&lt;a href=&quot;mailto:.I@.&quot;&gt;.I@.&lt;/a&gt;@.°1......&lt;br&gt;0020   00 01 1b 58 c3 fe e7 7d 67 65 3e 72 3c 31 80 18   ...XÃþç}ge&gt;r&amp;#x3C;1..&lt;br&gt;0030   02 00 fe 6f 00 00 01 01 08 0a 66 f1 44 8e 66 f1   ..þo......fñD.fñ&lt;br&gt;0040   44 8d 7b 22 69 74 65 6d 73 22 3a 5b 7b 22 74 69   D.{&quot;items&quot;:[{&quot;ti&lt;br&gt;0050   6d 65 22 3a 31 36 30 34 36 35 39 35 31 36 36 30   me&quot;:160465951660&lt;br&gt;0060   30 2c 22 6d 65 73 73 61 67 65 22 3a 22 48 65 6c   0,&quot;message&quot;:&quot;Hel&lt;br&gt;0070   6c 6f 20 57 6f 72 6c 64 21 22 7d 5d 2c 22 73 65   lo World!&quot;}],&quot;se&lt;br&gt;0080   67 6d 65 6e 74 22 3a 31 7d                        gment&quot;:1}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50174&lt;/td&gt;
&lt;td&gt;7000&lt;/td&gt;
&lt;td&gt;ACK&lt;/td&gt;
&lt;td&gt;The client acknowledges the last message from the server.&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 34 ad e0 40 00 40 06 8e e1 7f 00 00 01 7f 00   .4.à@&lt;a href=&quot;mailto:.@..&quot;&gt;.@..&lt;/a&gt;á......&lt;br&gt;0020   00 01 c3 fe 1b 58 3e 72 3c 31 e7 7d 67 ac 80 10   ..Ãþ.X&gt;r&amp;#x3C;1ç}g¬..&lt;br&gt;0030   02 00 fe 28 00 00 01 01 08 0a 66 f1 44 8e 66 f1   ..þ(......fñD.fñ&lt;br&gt;0040   44 8e                                             D.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Client disconnect&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source Port&lt;/th&gt;
&lt;th&gt;Destination Port&lt;/th&gt;
&lt;th&gt;Flags&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;50174&lt;/td&gt;
&lt;td&gt;7000&lt;/td&gt;
&lt;td&gt;FIN,ACK&lt;/td&gt;
&lt;td&gt;Request to close connection from the client.&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 34 ad e1 40 00 40 06 8e e0 7f 00 00 01 7f 00   .4.á@&lt;a href=&quot;mailto:.@..&quot;&gt;.@..&lt;/a&gt;à......&lt;br&gt;0020   00 01 c3 fe 1b 58 3e 72 3c 31 e7 7d 67 ac 80 11   ..Ãþ.X&gt;r&amp;#x3C;1ç}g¬..&lt;br&gt;0030   02 00 fe 28 00 00 01 01 08 0a 66 f6 ea 0e 66 f1   ..þ(......föê.fñ&lt;br&gt;0040   44 8e                                             D.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7000&lt;/td&gt;
&lt;td&gt;50174&lt;/td&gt;
&lt;td&gt;FIN,ACK&lt;/td&gt;
&lt;td&gt;Acknowledge close and request close from the server.&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 34 8c 4a 40 00 40 06 b0 77 7f 00 00 01 7f 00   &lt;a href=&quot;mailto:.4.J@.&quot;&gt;.4.J@.&lt;/a&gt;@.°w......&lt;br&gt;0020   00 01 1b 58 c3 fe e7 7d 67 ac 3e 72 3c 32 80 11   ...XÃþç}g¬&gt;r&amp;#x3C;2..&lt;br&gt;0030   02 00 fe 28 00 00 01 01 08 0a 66 f6 ea 0e 66 f6   ..þ(......föê.fö&lt;br&gt;0040   ea 0e                                             ê.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50174&lt;/td&gt;
&lt;td&gt;7000&lt;/td&gt;
&lt;td&gt;ACK&lt;/td&gt;
&lt;td&gt;Acknowledge the close connection from the server.&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 34 ad e2 40 00 40 06 8e df 7f 00 00 01 7f 00   .4.â@&lt;a href=&quot;mailto:.@..&quot;&gt;.@..&lt;/a&gt;ß......&lt;br&gt;0020   00 01 c3 fe 1b 58 3e 72 3c 32 e7 7d 67 ad 80 10   ..Ãþ.X&gt;r&amp;#x3C;2ç}g...&lt;br&gt;0030   02 00 fe 28 00 00 01 01 08 0a 66 f6 ea 0e 66 f6   ..þ(......föê.fö&lt;br&gt;0040   ea 0e                                             ê.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Interesting finds&lt;/h3&gt;
&lt;p&gt;While looking into this I did find a couple of interesting finds. One find that I was remotely aware of is that many variants of HTTP are built on TCP. One notable exception to that rule is the upcoming HTTP3 or QUICK which is built on a multiplexed UDP connection. Another interesting find was that many online games use TCP as the transmission protocol. The thing that was a bit surprising about this is that TCP adds a lot of overhead with all of the acknowledgments so I was unsure that an online game could perform at the speed expected with all that additional checking.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc793&quot;&gt;https://tools.ietf.org/html/rfc793&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[UDP Transport]]></title><description><![CDATA[UDP Transport This is the first in the transport layer series. In this blog, we will look into the User Datagram Protocol or UDP for short…]]></description><link>https://ilusr.com/udp/</link><guid isPermaLink="false">https://ilusr.com/udp/</guid><pubDate>Tue, 02 Jun 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;UDP Transport&lt;/h1&gt;
&lt;p&gt;This is the first in the transport layer series. In this blog, we will look into the User Datagram Protocol or UDP for short. UDP is part of the Internet Protocol (IP) suite and resides in the application layer. UDP is an unreliable protocol, that is not to say it is bad it just does not guarantee packet delivery like some other protocols.&lt;/p&gt;
&lt;h3&gt;Reviewing the network protocol&lt;/h3&gt;
&lt;p&gt;UDP is made up of 5 parts: Source Port, Destination Port, Length, Checksum, and data octets.&lt;/p&gt;
&lt;h4&gt;Source Port&lt;/h4&gt;
&lt;p&gt;The source port is an optional field. This field indicates the port that the sending process is using to communicate.&lt;/p&gt;
&lt;h4&gt;Destination Port&lt;/h4&gt;
&lt;p&gt;This is the port that has a meaning within the context of a particular internet destination address.&lt;/p&gt;
&lt;h4&gt;Length&lt;/h4&gt;
&lt;p&gt;Length is the number in octets of the user datagram including the header and the data. The minimum possible value for length is 8.&lt;/p&gt;
&lt;h4&gt;Checksum&lt;/h4&gt;
&lt;p&gt;The checksum is the 16-bit one&apos;s complement of the ones complement sum of a pseudo-header using the IP header, the UDP header, and the data. This is padded with zero octets and the end to make a multiple of two octets.&lt;/p&gt;
&lt;p&gt;Example&lt;/p&gt;
&lt;p&gt;Source IP address: 192.168.0.15
Destination IP address: 192.168.0.23
Source Port: 35
Destination Port: 40
Length: 10
Message: Hi&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;Decimal&lt;/th&gt;
&lt;th&gt;Binary&lt;/th&gt;
&lt;th&gt;Hex&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Source IP&lt;/td&gt;
&lt;td&gt;192.168 &lt;br&gt; 0.15&lt;/td&gt;
&lt;td&gt;1100 0000 1010 1000 &lt;br&gt; 0000 0000 0000 1111&lt;/td&gt;
&lt;td&gt;C0 A8 &lt;br&gt; 00 0F&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Destination IP&lt;/td&gt;
&lt;td&gt;192.168 &lt;br&gt; 0.23&lt;/td&gt;
&lt;td&gt;1100 0000 1010 1000 &lt;br&gt; 0000 0000 0001 0111&lt;/td&gt;
&lt;td&gt;C0 A8 &lt;br&gt; 00 17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reserved/UDP&lt;/td&gt;
&lt;td&gt;0/17&lt;/td&gt;
&lt;td&gt;0000 0000 0001 0001&lt;/td&gt;
&lt;td&gt;00 11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Padding&lt;/td&gt;
&lt;td&gt;0/10&lt;/td&gt;
&lt;td&gt;0000 0000 0000 1010&lt;/td&gt;
&lt;td&gt;00 0A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source Port&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;td&gt;0000 0000 0010 0011&lt;/td&gt;
&lt;td&gt;00 23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Destination Port&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;0000 0000 0010 1000&lt;/td&gt;
&lt;td&gt;00 28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0000 0000 0000 1010&lt;/td&gt;
&lt;td&gt;00 0A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data&lt;/td&gt;
&lt;td&gt;Hi&lt;/td&gt;
&lt;td&gt;0100 1000 0110 1001&lt;/td&gt;
&lt;td&gt;48 69&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Add up all numbers to generate pseudo-header&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1100 0000 1010 1000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0000 0000 0000 1111&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1100 0000 1010 1000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0000 0000 0001 0111&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0000 0000 0001 0001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0000 0000 0000 1010&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0000 0000 0010 0011&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0000 0000 0010 1000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0000 0000 0000 1010&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0100 1000 0110 1001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;=&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1 1100 1010 0110 1111&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;br&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Since this number overflows split into two 16bit address spaces and add.&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0000 0000 0000 0001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1100 1010 0110 1111&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;=&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1100 1010 0111 0000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Take ones compliment to get checksum value.
&lt;br&gt;
&lt;strong&gt;0011 0101 1000 1111&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;Data Octets&lt;/h4&gt;
&lt;p&gt;The actual data you want to send in the packet.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;field&lt;/th&gt;
&lt;th&gt;bit range&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Source Port&lt;/td&gt;
&lt;td&gt;0-15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Destination Port&lt;/td&gt;
&lt;td&gt;16-31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;32-47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checksum&lt;/td&gt;
&lt;td&gt;48-63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data octets&lt;/td&gt;
&lt;td&gt;remaning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Example of a standard library&lt;/h3&gt;
&lt;p&gt;UDP is a standard protocol and it is relatively easy to find support for it in most languages standard library. Below are just a few examples of programming languages and their associated UDP library.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;nodejs - &lt;a href=&quot;https://nodejs.org/api/dgram.html&quot;&gt;https://nodejs.org/api/dgram.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Java - &lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/net/DatagramSocket.html&quot;&gt;https://docs.oracle.com/javase/7/docs/api/java/net/DatagramSocket.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Go - &lt;a href=&quot;https://golang.org/pkg/net/&quot;&gt;https://golang.org/pkg/net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Python - &lt;a href=&quot;https://docs.python.org/3/library/socket.html&quot;&gt;https://docs.python.org/3/library/socket.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rust - &lt;a href=&quot;https://doc.rust-lang.org/std/net/struct.UdpSocket.html&quot;&gt;https://doc.rust-lang.org/std/net/struct.UdpSocket.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Example of a client-server application using the protocol&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/JeffreyRiggle/udp-example-app&quot;&gt;https://github.com/JeffreyRiggle/udp-example-app&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The following Github page shows a simple example of a UDP based client-server. In this example, we have a UDP server that listens on port 4000.&lt;/p&gt;
&lt;p&gt;The client in this case is an electron-based application. To reduce complexity the UI does not use any modern framework and just interacts directly with the DOM API.&lt;/p&gt;
&lt;p&gt;Overview of the architecture&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/udp/UDPServerDiagram.png&quot; alt=&quot;UDP Server Diagram&quot;&gt;&lt;/p&gt;
&lt;p&gt;For now to show that UDP does not enforce any structure on the payload the messages sent to the server use a binary like structure. However, the response from the UDP server is in JSON and can be parsed.&lt;/p&gt;
&lt;h3&gt;Look at the results in a network capture&lt;/h3&gt;
&lt;p&gt;To take a look at how this application works at the network layer &lt;a href=&quot;https://www.wireshark.org/&quot;&gt;Wireshark&lt;/a&gt; will be used. This application can be rather easily installed on most operating systems.&lt;/p&gt;
&lt;p&gt;Once Wireshark has installed a capture of network traffic can be issued. Since I am running this on my local machine I need to capture network on my loopback interface.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/udp/loopback.png&quot; alt=&quot;Loopback Interface&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now that the capture is running using the very simple example application we should be able to see UDP traffic flowing from the electron application to the UDP server.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Seq&lt;/th&gt;
&lt;th&gt;Info&lt;/th&gt;
&lt;th&gt;packet&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Request existing messages&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   .......&lt;br&gt;.......E.&lt;br&gt;0010   00 1d 5a 29 40 00 40 11 e2 a4 7f 00 00 01 7f 00   ..Z)@&lt;a href=&quot;mailto:.@.&quot;&gt;.@.&lt;/a&gt;â¤......&lt;br&gt;0020   00 01 e3 77 0f a0 00 09 fe 1c 01                  ..ãw. ..þ..&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Respond with existing&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ...........&lt;br&gt;...E.&lt;br&gt;0010   00 34 5a 2a 40 00 40 11 e2 8c 7f 00 00 01 7f 00   .4Z*@&lt;a href=&quot;mailto:.@.&quot;&gt;.@.&lt;/a&gt;â.......&lt;br&gt;0020   00 01 0f a0 e3 77 00 20 fe 33 7b 22 69 74 65 6d   ... ãw. þ3{&quot;item&lt;br&gt;0030   73 22 3a 5b 5d 2c 22 73 65 67 6d 65 6e 74 22 3a   s&quot;:[],&quot;segment&quot;:&lt;br&gt;0040   30 7d                                             0}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Send new message&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 29 5a c0 40 00 40 11 e2 01 7f 00 00 01 7f 00   .)ZÀ@&lt;a href=&quot;mailto:.@.&quot;&gt;.@.&lt;/a&gt;â.......&lt;br&gt;0020   00 01 e3 77 0f a0 00 15 fe 28 02 48 65 6c 6c 6f   ..ãw. ..þ(.Hello&lt;br&gt;0030   20 57 6f 72 6c 64 21                               World!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Ack message&lt;/td&gt;
&lt;td&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.&lt;br&gt;0010   00 63 5a c1 40 00 40 11 e1 c6 7f 00 00 01 7f 00   .cZÁ@&lt;a href=&quot;mailto:.@.&quot;&gt;.@.&lt;/a&gt;áÆ......&lt;br&gt;0020   00 01 0f a0 e3 77 00 4f fe 62 7b 22 69 74 65 6d   ... ãw.Oþb{&quot;item&lt;br&gt;0030   73 22 3a 5b 7b 22 74 69 6d 65 22 3a 31 35 39 31   s&quot;:[{&quot;time&quot;:1591&lt;br&gt;0040   30 30 39 32 36 37 32 39 33 2c 22 6d 65 73 73 61   009267293,&quot;messa&lt;br&gt;0050   67 65 22 3a 22 48 65 6c 6c 6f 20 57 6f 72 6c 64   ge&quot;:&quot;Hello World&lt;br&gt;0060   21 22 7d 5d 2c 22 73 65 67 6d 65 6e 74 22 3a 31   !&quot;}],&quot;segment&quot;:1&lt;br&gt;0070   7d                                                }&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Looking at these messages you will notice that all messages going to the server are buffers and all messages coming from the server are buffers containing JSON based strings. As mentioned earlier this was done to show that UDP does not enforce structure on message content.&lt;/p&gt;
&lt;p&gt;To better understand what is going on here lets take a closer look at sequence packets 3 and 4.&lt;/p&gt;
&lt;p&gt;In packet 3 the client (electron application) is sending a new message to the server.
0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00&lt;br&gt;
0010   00 29 5a c0 40 00 40 11 e2 01 7f 00 00 01 7f 00&lt;br&gt;
0020   00 01 e3 77 0f a0 00 15 fe 28 02 48 65 6c 6c 6f&lt;br&gt;
0030   20 57 6f 72 6c 64 21&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Byte range&lt;/th&gt;
&lt;th&gt;Bytes&lt;/th&gt;
&lt;th&gt;Infomation&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0 - 5&lt;/td&gt;
&lt;td&gt;00 00 00 00 00 00&lt;/td&gt;
&lt;td&gt;Destination IP Address&lt;/td&gt;
&lt;td&gt;0.0.0.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6 - 11&lt;/td&gt;
&lt;td&gt;00 00 00 00 00 00&lt;/td&gt;
&lt;td&gt;Source IP Address&lt;/td&gt;
&lt;td&gt;0.0.0.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12 - 13&lt;/td&gt;
&lt;td&gt;08 00&lt;/td&gt;
&lt;td&gt;Type&lt;/td&gt;
&lt;td&gt;IPv4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;Header Length&lt;/td&gt;
&lt;td&gt;20 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;00&lt;/td&gt;
&lt;td&gt;Explicit Congestion Notification&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16 - 17&lt;/td&gt;
&lt;td&gt;00 29&lt;/td&gt;
&lt;td&gt;Total Length&lt;/td&gt;
&lt;td&gt;41&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18 - 19&lt;/td&gt;
&lt;td&gt;5A C0&lt;/td&gt;
&lt;td&gt;Identification&lt;/td&gt;
&lt;td&gt;23232&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20 - 21&lt;/td&gt;
&lt;td&gt;40 00&lt;/td&gt;
&lt;td&gt;Fragment offset&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;Time to live&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Protocol (start of UDP protocol)&lt;/td&gt;
&lt;td&gt;UDP (17)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;24 - 25&lt;/td&gt;
&lt;td&gt;E2 01&lt;/td&gt;
&lt;td&gt;Header checksum&lt;/td&gt;
&lt;td&gt;0xE201&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;26 - 29&lt;/td&gt;
&lt;td&gt;7F 00 00 01&lt;/td&gt;
&lt;td&gt;Source&lt;/td&gt;
&lt;td&gt;127.0.0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30 - 33&lt;/td&gt;
&lt;td&gt;7F 00 00 01&lt;/td&gt;
&lt;td&gt;Destination&lt;/td&gt;
&lt;td&gt;127.0.0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;34 - 35&lt;/td&gt;
&lt;td&gt;E3 77&lt;/td&gt;
&lt;td&gt;Source Port&lt;/td&gt;
&lt;td&gt;58231&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;36 - 37&lt;/td&gt;
&lt;td&gt;0F A0&lt;/td&gt;
&lt;td&gt;Destination Port&lt;/td&gt;
&lt;td&gt;4000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;38 - 39&lt;/td&gt;
&lt;td&gt;00 15&lt;/td&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;40 - 41&lt;/td&gt;
&lt;td&gt;FE 28&lt;/td&gt;
&lt;td&gt;Checksum&lt;/td&gt;
&lt;td&gt;0xFE28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;42 - 54&lt;/td&gt;
&lt;td&gt;02 48 65 6C 6C 6F 20 57 6F 72 6C 64 21&lt;/td&gt;
&lt;td&gt;Data&lt;/td&gt;
&lt;td&gt;.Hello World!&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If we break down the data we will notice that the message data is comprised of two parts a type and a message. In this case, 02 is the type and for the application in question 02 is a new message. The remainder of the message 48 65 6C 6C 6F 20 57 6F 72 6C 64 21, is Hello World! as a UTF-8 byte array.&lt;/p&gt;
&lt;p&gt;Moving on to packet 4 the server has seen and processed packet 3 and is ready to respond.&lt;/p&gt;
&lt;p&gt;0000   00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00&lt;br&gt;
0010   00 63 5a c1 40 00 40 11 e1 c6 7f 00 00 01 7f 00&lt;br&gt;
0020   00 01 0f a0 e3 77 00 4f fe 62 7b 22 69 74 65 6d&lt;br&gt;
0030   73 22 3a 5b 7b 22 74 69 6d 65 22 3a 31 35 39 31&lt;br&gt;
0040   30 30 39 32 36 37 32 39 33 2c 22 6d 65 73 73 61&lt;br&gt;
0050   67 65 22 3a 22 48 65 6c 6c 6f 20 57 6f 72 6c 64&lt;br&gt;
0060   21 22 7d 5d 2c 22 73 65 67 6d 65 6e 74 22 3a 31&lt;br&gt;
0070   7d&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Byte range&lt;/th&gt;
&lt;th&gt;Bytes&lt;/th&gt;
&lt;th&gt;Infomation&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0 - 5&lt;/td&gt;
&lt;td&gt;00 00 00 00 00 00&lt;/td&gt;
&lt;td&gt;Destination IP Address&lt;/td&gt;
&lt;td&gt;0.0.0.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6 - 11&lt;/td&gt;
&lt;td&gt;00 00 00 00 00 00&lt;/td&gt;
&lt;td&gt;Source IP Address&lt;/td&gt;
&lt;td&gt;0.0.0.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12 - 13&lt;/td&gt;
&lt;td&gt;08 00&lt;/td&gt;
&lt;td&gt;Type&lt;/td&gt;
&lt;td&gt;IPv4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;Header Length&lt;/td&gt;
&lt;td&gt;20 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;00&lt;/td&gt;
&lt;td&gt;Explicit Congestion Notification&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16 - 17&lt;/td&gt;
&lt;td&gt;00 63&lt;/td&gt;
&lt;td&gt;Total Length&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18 - 19&lt;/td&gt;
&lt;td&gt;5A C1&lt;/td&gt;
&lt;td&gt;Identification&lt;/td&gt;
&lt;td&gt;23233&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20 - 21&lt;/td&gt;
&lt;td&gt;40 00&lt;/td&gt;
&lt;td&gt;Fragment offset&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;Time to live&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Protocol (start of UDP protocol)&lt;/td&gt;
&lt;td&gt;UDP (17)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;24 - 25&lt;/td&gt;
&lt;td&gt;E1 C6&lt;/td&gt;
&lt;td&gt;Header checksum&lt;/td&gt;
&lt;td&gt;0xE1C6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;26 - 29&lt;/td&gt;
&lt;td&gt;7F 00 00 01&lt;/td&gt;
&lt;td&gt;Source&lt;/td&gt;
&lt;td&gt;127.0.0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30 - 33&lt;/td&gt;
&lt;td&gt;7F 00 00 01&lt;/td&gt;
&lt;td&gt;Destination&lt;/td&gt;
&lt;td&gt;127.0.0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;34 - 35&lt;/td&gt;
&lt;td&gt;0F A0&lt;/td&gt;
&lt;td&gt;Source Port&lt;/td&gt;
&lt;td&gt;4000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;36 - 37&lt;/td&gt;
&lt;td&gt;E3 77&lt;/td&gt;
&lt;td&gt;Destination Port&lt;/td&gt;
&lt;td&gt;58231&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;38 - 39&lt;/td&gt;
&lt;td&gt;00 4F&lt;/td&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;40 - 41&lt;/td&gt;
&lt;td&gt;FE 62&lt;/td&gt;
&lt;td&gt;Checksum&lt;/td&gt;
&lt;td&gt;0xFE62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;42 - 112&lt;/td&gt;
&lt;td&gt;7b 22 69 74 65 6d&lt;br&gt;73 22 3a 5b 7b 22 74 69 6d 65 22 3a 31 35 39 31&lt;br&gt;30 30 39 32 36 37 32 39 33 2c 22 6d 65 73 73 61&lt;br&gt;67 65 22 3a 22 48 65 6c 6c 6f 20 57 6f 72 6c 64&lt;br&gt;21 22 7d 5d 2c 22 73 65 67 6d 65 6e 74 22 3a 31&lt;br&gt;7d&lt;/td&gt;
&lt;td&gt;Data&lt;/td&gt;
&lt;td&gt;.{&quot;item&lt;br&gt;s&quot;:[{&quot;time&quot;:1591&lt;br&gt;009267293,&quot;messa&lt;br&gt;ge&quot;:&quot;Hello World&lt;br&gt;!&quot;}],&quot;segment&quot;:1&lt;br&gt;}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In this case, we can see that the server has acknowledged the message and added it to the messages list. In our acknowledgment, we can see that &lt;code&gt;Hello World!&lt;/code&gt; is segment 1 and the response from the server contained 1 segment. We can also see that the server used a JSON format to send the data back to the client.&lt;/p&gt;
&lt;h3&gt;Interesting finds&lt;/h3&gt;
&lt;h4&gt;QUIC (HTTP/3)&lt;/h4&gt;
&lt;p&gt;HTTP/3 is backed by UDP due to its increased flexibility. In previous HTTP protocol versions, TCP was used as a base transport.&lt;/p&gt;
&lt;h4&gt;BISON&lt;/h4&gt;
&lt;p&gt;While working on this blog I got a bit carried away wondering if I could compress JSON into a smaller binary stream. I am not the first person who thought to do it but I had a lot of fun creating &lt;a href=&quot;https://github.com/JeffreyRiggle/bison&quot;&gt;https://github.com/JeffreyRiggle/bison&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc768&quot;&gt;https://tools.ietf.org/html/rfc768&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc1122#page-9&quot;&gt;https://tools.ietf.org/html/rfc1122#page-9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/wg/quic/charter/&quot;&gt;https://datatracker.ietf.org/wg/quic/charter/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Transport Layer]]></title><description><![CDATA[Transport Layer For the first time, I am going to dedicate a series of blogs to a single topic. In this case, I am going to dive into…]]></description><link>https://ilusr.com/transport-layer/</link><guid isPermaLink="false">https://ilusr.com/transport-layer/</guid><pubDate>Wed, 06 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Transport Layer&lt;/h1&gt;
&lt;p&gt;For the first time, I am going to dedicate a series of blogs to a single topic. In this case, I am going to dive into network protocols. In this series I am hoping to dive into a couple of different protocols starting with UDP and ending with HTTP, possibly including HTTP/3.&lt;/p&gt;
&lt;h2&gt;Why do this?&lt;/h2&gt;
&lt;p&gt;I usually enjoy looking at the lower levels of client-server applications, which in many cases is the network layer between the client and server. In the past, I have used TCP and HTTP in client server-based applications, but I have never really gotten to dig in as far as I would like to. I will also be using this as an opportunity to learn more about the network protocols that I use often.&lt;/p&gt;
&lt;h2&gt;General Format&lt;/h2&gt;
&lt;p&gt;In general, these next few blogs should follow a consistent pattern.&lt;/p&gt;
&lt;h3&gt;Reviewing the network protocol&lt;/h3&gt;
&lt;p&gt;At this point, we will look at the network protocol and help break down how the protocol is supposed to work. This will mostly be a recap of related RFC&apos;s maybe with some diagrams or other visuals to help aid in explaining how the protocol is supposed to work.&lt;/p&gt;
&lt;h3&gt;Building an example of the protocol&lt;/h3&gt;
&lt;p&gt;In this section, I hope to create a very basic implementation of the protocol in either Java or Javascript. This will simply talk about building it and layout some highlights but most of the work will be done in a Github repository and referenced in this section.&lt;/p&gt;
&lt;h3&gt;Look at the results in a network capture&lt;/h3&gt;
&lt;p&gt;Take a bit to show how you could use a wire capture application like Wireshark to look at the bytes in transit over the wire.&lt;/p&gt;
&lt;h3&gt;Example of a standard library&lt;/h3&gt;
&lt;p&gt;Since creating a unique implementation of a wire protocol is probably not the best idea and probably not the most secure, at this point, I will give examples of more reliable libraries that do the same sort of transportation.&lt;/p&gt;
&lt;h3&gt;Example of a client server application using the protocol&lt;/h3&gt;
&lt;p&gt;In this section, we will use the protocol to create a simple client-server application. This might be something simple like a chat system or something like that.&lt;/p&gt;
&lt;h3&gt;Interesting finds&lt;/h3&gt;
&lt;p&gt;In this section, I will highlight any interesting finds I maybe have stumbled upon during my research.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;p&gt;What I referenced to create this blog post.&lt;/p&gt;
&lt;h2&gt;What I will not be covering&lt;/h2&gt;
&lt;p&gt;While I am hoping to take a good look at network protocols in these blogs, I will not be looking at network security. In my opinion network security (UDPS, TLS, HTTPS) fall into a slightly different realm than what I am looking at right now. At some later point if I enjoy this process I might attempt another series on cryptography in which I would look at things like https.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Aurelia]]></title><description><![CDATA[Coming back to Aurelia A while back I was comparing a couple of different javascript front-end frameworks. In hindsight, I probably could…]]></description><link>https://ilusr.com/aurelia/</link><guid isPermaLink="false">https://ilusr.com/aurelia/</guid><pubDate>Tue, 18 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Coming back to Aurelia&lt;/h1&gt;
&lt;p&gt;A while back I was &lt;a href=&quot;https://github.com/JeffreyRiggle/useless-user-results&quot;&gt;comparing&lt;/a&gt; a couple of different javascript front-end frameworks. In hindsight, I probably could have saved some time using &lt;a href=&quot;https://github.com/gothinkster/realworld&quot;&gt;Real World&lt;/a&gt; for my comparisons.&lt;/p&gt;
&lt;p&gt;During this time I decided to give &lt;a href=&quot;https://aurelia.io/&quot;&gt;Aurelia&lt;/a&gt; a shot. At first, it seemed like an ideal framework. At the time I had mostly been using &lt;a href=&quot;https://angularjs.org/&quot;&gt;Angularjs&lt;/a&gt; (1.x era) and anything without scope was starting to sound like a better framework.&lt;/p&gt;
&lt;h1&gt;Why Aurelia?&lt;/h1&gt;
&lt;p&gt;If you happened to look at the comparison you would notice that I evaluated two rather popular choices and one not so well known choice. At the time &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt; still seemed like a questionable choice to me. I was having a hard time believing that the virutual dom would not cause so much memory pressure on the heap.&lt;/p&gt;
&lt;p&gt;As for Aurelia, it was similar to Angular in the sense that it used an MVC pattern to present the view. The one thing I had liked was the syntax and oftentimes lack of it. I realize that starting in Angular 2+ the syntax got better, but still confusing bindings like &lt;code&gt;[src]&lt;/code&gt;, &lt;code&gt;*ngFor&lt;/code&gt;, and &lt;code&gt;(click)&lt;/code&gt; still bothered me. From a readability standpoint it&apos;s hard to remember the difference between those. Aurelia, on the other hand, chose to be a bit more explicit about its binding to the template. Instead, you would have bindings like &lt;code&gt;src.bind&lt;/code&gt;, &lt;code&gt;repeat.for&lt;/code&gt; and &lt;code&gt;click.delegate&lt;/code&gt;. To me, this seemed a lot more readable and produced less mysterious-looking code.&lt;/p&gt;
&lt;h1&gt;What I learned&lt;/h1&gt;
&lt;p&gt;While I fully enjoyed using Aurelia, I grew to find certain aspects of the framework to be painstaking. What I had come to realize is that like in many frameworks I would hit a snag in my work and have to turn to documentation or sources like stack overflow to get moving in the right direction again. However, this time I found out that finding the answers to my questions was a lot harder. Documentation was sparse on the issues I was running into and the examples I had found ended up being years out of date.&lt;/p&gt;
&lt;p&gt;I had also found that access to different plugins and wrappers for the language was limited. Where in other popular frameworks I would have a slew of choices for plugins, libraries, and tools, in Aurelia most of these did not exist or appeared to be years out of date.&lt;/p&gt;
&lt;p&gt;Even finding the right combination of tools to use for something like testing was hard. Some examples showed and recommended jest while others used karma and jasmine. While the tool was not available at the time, eventually Aurelia did create a &lt;a href=&quot;https://aurelia.io/docs/cli/basics#introduction&quot;&gt;CLI&lt;/a&gt; which might have addressed many of the pain points I had encountered getting setup.&lt;/p&gt;
&lt;p&gt;The hardest challenge for Aurelia is the lack of a strong community. While this is not the best metric in the world, it seems pretty clear to me using Github stars that Aurelia is not a super popular choice.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;Stars&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Aurelia&lt;/td&gt;
&lt;td&gt;653&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Angular&lt;/td&gt;
&lt;td&gt;57.9k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React&lt;/td&gt;
&lt;td&gt;144k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vue&lt;/td&gt;
&lt;td&gt;157k&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;I had never really known how much of a difference a large community makes on a project, but after this experience, it has become clear to me that it makes a rather large difference. I am personally glad I learn this lesson in a way that the maintenance burden only effects me.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Easy CI/CD with github actions]]></title><description><![CDATA[Getting into it Recently I had decided I wanted to start creating a CI/CD (Continuous Integration / Continuous Delivery) pipeline for some…]]></description><link>https://ilusr.com/github-actions/</link><guid isPermaLink="false">https://ilusr.com/github-actions/</guid><pubDate>Tue, 07 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Getting into it&lt;/h1&gt;
&lt;p&gt;Recently I had decided I wanted to start creating a CI/CD (Continuous Integration / Continuous Delivery) pipeline for some of the code I have up on Github. I have dealt with CI/CD in the past and generally have enjoyed the consistent feedback loop on the changes I push. One thing I did want with this CI was some kind of feedback loop in Github to show the current state of the project (failing, passing, etc).&lt;/p&gt;
&lt;p&gt;Normally in these cases, I would reach for &lt;a href=&quot;https://jenkins.io/&quot;&gt;Jenkins&lt;/a&gt;, but I tend to like to try something different when I am working on non-work related projects. Looking around the big competitors I noticed had been &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis&lt;/a&gt; and &lt;a href=&quot;https://circleci.com/&quot;&gt;Circle&lt;/a&gt;. However, I had heard of &lt;a href=&quot;https://github.com/features/actions&quot;&gt;Github Actions&lt;/a&gt; and that sounded like a perfect fit for what I wanted to do.&lt;/p&gt;
&lt;p&gt;It just so happened that the public release of Github&apos;s actions timed very well with me wanting to create some CI/CD for my projects.&lt;/p&gt;
&lt;h1&gt;Enter Github actions&lt;/h1&gt;
&lt;p&gt;Recently Github released &lt;a href=&quot;https://github.com/features/actions&quot;&gt;Github Actions&lt;/a&gt; to the general public. Github actions is a CI/CD system for code hosted on Github. Actions can be added to any Github project by creating a &lt;a href=&quot;https://yaml.org/&quot;&gt;YAML&lt;/a&gt; file in .github/workflows.&lt;/p&gt;
&lt;p&gt;In a workflow there are a couple of important properties to know about.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;name: The name property gives the workflow a name.&lt;/li&gt;
&lt;li&gt;on: This can be one of a couple of different values. This is the trigger condition, when can this action be automatically executed. For me, the most valuable actions are triggered on &lt;code&gt;push&lt;/code&gt; or &lt;code&gt;pull_request&lt;/code&gt; but there are plenty of other triggers listed &lt;a href=&quot;https://help.github.com/en/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;jobs: This is the key to the workflow. A workflow has at least 1 job and a job is the main body of work to be done in a workflow.
&lt;ul&gt;
&lt;li&gt;runs-on: Controls what the job runs on. So far I have only had to use &lt;code&gt;ubuntu-latest&lt;/code&gt;, but Windows and Mac OS&apos;s are supported. For more information see this &lt;a href=&quot;https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idruns-on&quot;&gt;page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;steps: These are the individual actions that a job will take.&lt;/li&gt;
&lt;li&gt;run: This is the script that will run in the step. In the case of ubuntu, this should be a bash script.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Simple example workflow&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; My CI
&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;push&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pull_request&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;greet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Greet
        &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
        &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Greet
              &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; echo &apos;Hello world&apos;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Putting actions to use&lt;/h1&gt;
&lt;p&gt;After a bit of research, I started getting to work on creating a CI pipeline for one of my &lt;a href=&quot;https://golang.org/&quot;&gt;go&lt;/a&gt; based projects.&lt;/p&gt;
&lt;p&gt;In this process, I created two jobs a build job and an integration test job. In the build job, a couple of things had been done.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install go on the ubuntu image.&lt;/li&gt;
&lt;li&gt;Checkout related go code from Github.&lt;/li&gt;
&lt;li&gt;Install dependencies for go code.&lt;/li&gt;
&lt;li&gt;Build the go application.&lt;/li&gt;
&lt;li&gt;Run the unit tests.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the integration test job, a couple more things would be done.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install go on the ubuntu image.&lt;/li&gt;
&lt;li&gt;Checkout related go code from Github&lt;/li&gt;
&lt;li&gt;Install dependencies and start the go application.&lt;/li&gt;
&lt;li&gt;Install NodeJS&lt;/li&gt;
&lt;li&gt;Build and start a simple web application. This was used to test Webhooks with my go application.&lt;/li&gt;
&lt;li&gt;Install python 2.&lt;/li&gt;
&lt;li&gt;Run integration tests that were written in python to test the go server.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The end result for all of this is the following yml file.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Go
&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;push&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pull_request&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

  &lt;span class=&quot;token key atrule&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Build
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Set up Go 1.13
      &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;go@v1
      &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;go-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.13&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; go

    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Check out code into the Go module directory
      &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v1

    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Get dependencies
      &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
        go get -v -d -t ./...
        if [ -f Gopkg.toml ]; then
            curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
            dep ensure
        fi&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Build
      &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; go build &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;v .
      &lt;span class=&quot;token key atrule&quot;&gt;working-directory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./src

    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Test
      &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; go test
      &lt;span class=&quot;token key atrule&quot;&gt;working-directory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./src

  &lt;span class=&quot;token key atrule&quot;&gt;Test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Set up Go 1.13
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;go@v1
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;go-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.13&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; go

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Check out code into the Go module directory
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v1

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Get dependencies
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
          go get -v -d -t ./...
          if [ -f Gopkg.toml ]; then
              curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
              dep ensure
          fi&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Start
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
          go build -v .  
          ./src ../test/RuntimeConfig.json &amp;amp;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;working-directory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./src
    
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install node
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node@v1
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;10.x&apos;&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Start web hook server
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
          npm install
          npm run start &amp;amp;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;working-directory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./test/webhooktester
          
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install python
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;python@v1
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;python-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2.x&apos;&lt;/span&gt;
      
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install dependencies
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
          pip install requests
          pip install assertpy&lt;/span&gt;
      
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Run E2E Tests
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; python apitest.py
        &lt;span class=&quot;token key atrule&quot;&gt;working-directory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;UI&lt;/h1&gt;
&lt;h3&gt;Run output&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/github-actions/basicview.png&quot; alt=&quot;Run output&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Commit feedback&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/JeffreyRiggle/my-site/master/content/blog/github-actions/commit.png&quot; alt=&quot;Commit feedback&quot;&gt;&lt;/p&gt;
&lt;h1&gt;Final thoughts&lt;/h1&gt;
&lt;p&gt;Github actions are really easy to get up and running. All you have to do is add a yml file to your source control and you are up and running. There is no concern around managing infrastructure like you would have to do with Jenkins.&lt;/p&gt;
&lt;p&gt;One big difference that I was worried about was the loss of a scripting language in my pipeline. Again I am used to Jenkins in which I could define my workflow and have the power of &lt;a href=&quot;http://groovy-lang.org/&quot;&gt;groovy&lt;/a&gt;. At no point did I really feel limited by only being able to execute bash scripts.&lt;/p&gt;
&lt;p&gt;It is also incredibly nice to have a decent UI to show my Job status as well as immediate feedback on my commit or PR around CI status.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Revisiting java]]></title><description><![CDATA[Why java? As part of creating my website, I decided it would be a good idea to go back and update some projects I haven't touched in a while…]]></description><link>https://ilusr.com/revisit-java/</link><guid isPermaLink="false">https://ilusr.com/revisit-java/</guid><pubDate>Mon, 12 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why java?&lt;/h2&gt;
&lt;p&gt;As part of creating my website, I decided it would be a good idea to go back and update some projects I haven&apos;t touched in a while. If you haven&apos;t read my last post the idea is that my projects are listed on my website and those pull from my GitHub repositories to create pages.&lt;/p&gt;
&lt;p&gt;While going through these I stumbled upon some of the first projects I put into Github. Most of these projects had been java based projects. Looking back on these projects I wanted to do two things: package javadocs, and upgrade to java 11. All of my projects had been written in java 8 before &lt;a href=&quot;https://openjdk.java.net/projects/jigsaw/&quot;&gt;jigsaw&lt;/a&gt;, so I knew this might be a bit of a challenge.&lt;/p&gt;
&lt;h2&gt;Getting down to it.&lt;/h2&gt;
&lt;p&gt;Almost immediately I ran into issues. The first library I decided to work on was my &lt;a href=&quot;https://github.com/JeffreyRiggle/java-core&quot;&gt;core library&lt;/a&gt;. The first change I noticed was that &lt;a href=&quot;https://openjfx.io/&quot;&gt;JavaFX&lt;/a&gt; was no longer in the standard library. It appears that this had a relatively short run under the jdk justified by &lt;a href=&quot;https://blogs.oracle.com/java-platform-group/the-future-of-JavaFX-and-other-java-client-roadmap-updates&quot;&gt;release cadence&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So after figuring out my JavaFX issue the process went rather smoothly. Figuring out jigsaw was not as hard as I imagined it might be. My toolchain had little to no issue handling java 11. Maven worked fine and my testing frameworks continued to work great.&lt;/p&gt;
&lt;p&gt;However, at some point I got around to working more with JavaFX and started to run into more issues. I think I might just be an edge case, but in java 8 I was abusing some &lt;code&gt;internal/protected&lt;/code&gt; features of JavaFX to solve problems I had. Since jigsaw did a good job of encapsulating protected features, I immediately had issues to solve. The big problem I had was JavaFX seems to be a rather mature UI toolkit but it is still missing some features.&lt;/p&gt;
&lt;p&gt;The big feature I was having issues around was JavaFX&apos;s Tab. From what I can tell my use case might have been a bit of an edge case and there is an open issue with the &lt;a href=&quot;https://bugs.openjdk.java.net/browse/JDK-8091261&quot;&gt;jdk&lt;/a&gt; this issue. In the end, I had to duplicate logic from the library itself to accomplish the same outcome.&lt;/p&gt;
&lt;h2&gt;Take aways&lt;/h2&gt;
&lt;h3&gt;Java is not my first choice for UI anymore.&lt;/h3&gt;
&lt;p&gt;I have spent a decent portion of my time writing software working with front-end technologies. I have used many frameworks and languages including: &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/framework/winforms/&quot;&gt;WinForms&lt;/a&gt;, &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/framework/wpf/&quot;&gt;WPF&lt;/a&gt;, &lt;a href=&quot;https://www.microsoft.com/silverlight/&quot;&gt;Silverlight&lt;/a&gt;, &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/technotes/guides/swing/&quot;&gt;swing&lt;/a&gt;, &lt;a href=&quot;https://openjfx.io/&quot;&gt;JavaFX&lt;/a&gt; and &lt;a href=&quot;https://www.qt.io/&quot;&gt;qt&lt;/a&gt;. In my experience, the frameworks that seem to get it right separate the view logic from the interaction logic (sorry WinForms and swing). One thing I do really like about JavaFX is that it separates the view logic (fxml), the interaction logic (java) and the style logic (css).&lt;/p&gt;
&lt;p&gt;I have, however, spent a good amount of time working in html/javascript based UI&apos;s. In this time I have noticed that UI development goes quite a bit faster when every tweak does not require a full recompile of your application. I have also noticed that it is rather nice to not have to switch between a bunch of optional tooling to debug your issues.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;JavaFX&lt;/th&gt;
&lt;th&gt;web&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Code Debugging&lt;/td&gt;
&lt;td&gt;Console output or ide of your choice (eclipse/netbeans)&lt;/td&gt;
&lt;td&gt;Browser of your choice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Style inspection&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/JonathanGiles/scenic-view&quot;&gt;Scenic View&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Browser of your choice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toolchain&lt;/td&gt;
&lt;td&gt;Maven or Gradle&lt;/td&gt;
&lt;td&gt;Too many options, but none are actually required&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Outside of that, the things that java might be better able to handle are interacting with the OS and maybe performance.&lt;/p&gt;
&lt;h4&gt;Performance&lt;/h4&gt;
&lt;p&gt;I have not done any real performance testing and I might do this in the future. However, in both JavaFX and web-based technologies you are interacting with the OS via a virtual machine. The only framework above that would not be limited to a virtual machine would be qt. Because of this, I am likely to believe that performance should be relatively equal between JavaFX and web-based UI&apos;s.&lt;/p&gt;
&lt;h4&gt;OS access&lt;/h4&gt;
&lt;p&gt;This one is a bit tricky. While web-based technologies cannot and should not be able to access the host OS from the browser, there is a way to work around the restrictions of the browser. In many cases, this comes in the way of &lt;a href=&quot;https://electronjs.org/&quot;&gt;Electron&lt;/a&gt; or &lt;a href=&quot;https://nwjs.io/&quot;&gt;NW.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are plenty of resources for Electron, but I will give a quick recap. Electron allows you to distribute your web UI as a standalone application. This application ships its own version of chromium and uses NodeJS to interact with the host OS.&lt;/p&gt;
&lt;p&gt;In the case of required OS access, there might be a good argument for using something like JavaFX instead of something like Electron.&lt;/p&gt;
&lt;h3&gt;Final thoughts&lt;/h3&gt;
&lt;p&gt;Java isn&apos;t a terrible language nor is JavaFX a bad technology. However, lately, I am finding it hard to justify spending the extra time to write a side project in something like JavaFX versus a web-based technology.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Using Gatsbyjs]]></title><description><![CDATA[The idea Recently I decided it was time to make my own personal website. You might be on this site right now. I knew to go into this that I…]]></description><link>https://ilusr.com/gastby-js/</link><guid isPermaLink="false">https://ilusr.com/gastby-js/</guid><pubDate>Mon, 15 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;The idea&lt;/h2&gt;
&lt;p&gt;Recently I decided it was time to make my own personal website. You might be on this site right now. I knew to go into this that I was going to want to make a &lt;code&gt;static&lt;/code&gt; site of some sort but I was not sure what I would settle on.&lt;/p&gt;
&lt;h2&gt;The requirements&lt;/h2&gt;
&lt;p&gt;I wanted this site to combine data about all the little projects I work on in my free time into a site. I also wanted to get this data as dynamically as possible so that when I made changes in github I would have to do very little to update this site.&lt;/p&gt;
&lt;h2&gt;First attempt&lt;/h2&gt;
&lt;p&gt;Initially, I thought I would just cobble together some kind of nodejs application that takes data from multiple sources and transform data and markdown files into html files. However, I quickly found that doing this was leading to difficult to maintain spaghetti code. At this point, I was starting to realize that maybe a framework would help me accomplish my goals.&lt;/p&gt;
&lt;h2&gt;After a bit of research&lt;/h2&gt;
&lt;p&gt;After some research, I found a couple of different frameworks that might help. During this period I looked at &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;jekyll&lt;/a&gt;, &lt;a href=&quot;https://www.11ty.io/&quot;&gt;Eleventy&lt;/a&gt;, and &lt;a href=&quot;https://www.gatsbyjs.org/&quot;&gt;Gatsby&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Jekyll&lt;/h3&gt;
&lt;p&gt;From what I was able to gather this has been around for a while, is stable and has been used by quite a few. To be fair I did not give this an honest try. While I know ruby I prefer to avoid using it where I can.&lt;/p&gt;
&lt;h3&gt;Eleventy&lt;/h3&gt;
&lt;p&gt;This seemed similar to Jekyll but build on nodejs instead. While I gave this an initial try the big hang-up I had was is was pretty hard to get sources from github and get them into a format that worked. It required a lot of manual pulling of files and attempting transforms on existing markdown files. While I found this to be an interesting choice, the process just didn&apos;t work well enough for my use case.&lt;/p&gt;
&lt;h3&gt;Gasbyjs&lt;/h3&gt;
&lt;p&gt;As you might be able to tell by the title of this post, this is the framework I eventually landed on. It seemed like Gatsby was built to handle the type of issue I was trying to solve, combining data from multiple sources into components. It also helped that it has a setup that feels like a rather modern web development experience. These are the major reasons I ended up sticking with this choice.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Graphql&lt;/li&gt;
&lt;li&gt;Reactjs&lt;/li&gt;
&lt;li&gt;webpack like system.&lt;/li&gt;
&lt;li&gt;community&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Thoughts&lt;/h2&gt;
&lt;h3&gt;Graphql&lt;/h3&gt;
&lt;p&gt;While working on with Gatsby early on it became apparent that I was going to have to learn graphql. I have heard a lot about graphql but I had never had a reason to use it up until this point.&lt;/p&gt;
&lt;p&gt;The way I understood graphql was that it was a query language for API&apos;s that allows you to join multiple or complex requests into one request. What I found is that is true but I expected graphql to do more that it does.&lt;/p&gt;
&lt;p&gt;The query I wanted to create would pull all repositories I owned and then would grab the content using a different request. My initial approach did not work because you cannot pass results from one query into another. So in my case, I was trying to make the following requests.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;GET users/JeffreyRiggle/repos&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;GET repos/JeffreyRiggle/{resultn}/readme&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is not able to be expressed in graphql so I had to go with a different approach. that just used the &lt;code&gt;repo&lt;/code&gt; api.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;{
  viewer {
    name
    repositories(last: 100) {
      nodes {
        name
        description
        id
        descriptionHTML
        url
        first: object(expression: &quot;master:README.md&quot;) {
          id
          ... on Blob {
            text
          }
        }
        second: object(expression: &quot;master:doc/doc.json&quot;) {
          id
          ... on Blob {
            text
          }
        }
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only issue I have with this approach is the last 100 bit. While it&apos;s minor I ended up having to maintain a basic knowledge of how many repositories I have.&lt;/p&gt;
&lt;h3&gt;Reactjs&lt;/h3&gt;
&lt;p&gt;This is a rather familiar framework for me by now. This made creating components easy for me to figure out in Gatsbyjs.&lt;/p&gt;
&lt;h3&gt;Webpack&lt;/h3&gt;
&lt;p&gt;Gatsby uses a Webpack like configuration system. Since webpack is becoming a standard these days it was pretty easy to reason about how the configuration would work in Gatsbyjs.&lt;/p&gt;
&lt;h3&gt;Community&lt;/h3&gt;
&lt;p&gt;This is really what sold me on Gatsbyjs. It just has a really large community. I did not struggle to find any documentation or examples of how others have been using this tool. This was a really big win for me since I have a limited amount of free time to figure things out.&lt;/p&gt;
&lt;h2&gt;How the generation actually came together&lt;/h2&gt;
&lt;p&gt;In the end, I created a simple website that has information about the side projects I work on in github and a blog.&lt;/p&gt;
&lt;p&gt;The github part queries github using the earlier mentioned graphql statement. Then it creates pages for each project. However, if the project has a doc.json file it will do some extra work to create a more complex page with additional child pages. This allows me to create different pages for Installation, Usage, development or whatever else I might need.&lt;/p&gt;
&lt;p&gt;After all this is done it scraps the current directory structure to generate my blog pages.&lt;/p&gt;
&lt;h2&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;All in all this was a pretty fun project and I got to learn a lot about static site generation. Since I had never had a reason to do static site generation before I had a lot to learn. Gastbyjs  made this process easy for me and I would recommend it to anyone familiar with a more modern frontend web stack.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Hello World]]></title><description><![CDATA[It only seems fitting that I start this like I would any other programming adventure, with a hello world. I have decided its time to create…]]></description><link>https://ilusr.com/hello-world/</link><guid isPermaLink="false">https://ilusr.com/hello-world/</guid><pubDate>Thu, 11 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It only seems fitting that I start this like I would any other programming adventure, with a hello world.&lt;/p&gt;
&lt;p&gt;I have decided its time to create a personal site and attach a blog while I am at it. I have no idea how consistent I will be about making posts or updating this site but I figure its worth a shot.&lt;/p&gt;
&lt;p&gt;I am hoping to use this blog to track the things I have learned and any frustrations I have encountered along the way. If nothing else I hope this will serve as documentation for my future self.&lt;/p&gt;</content:encoded></item></channel></rss>