<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Software, Fitness, and Gaming &#8211; Jesse Warden</title>
	<atom:link href="https://jessewarden.com/feed" rel="self" type="application/rss+xml" />
	<link>https://jessewarden.com</link>
	<description>Software &#124; Fitness &#124; Gaming</description>
	<lastBuildDate>Sat, 04 Apr 2026 15:07:41 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://jessewarden.com/wp-content/uploads/2016/08/cropped-Lambda2-32x32.png</url>
	<title>Software, Fitness, and Gaming &#8211; Jesse Warden</title>
	<link>https://jessewarden.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Quick History on Dependency Injection</title>
		<link>https://jessewarden.com/2026/04/quick-history-on-dependency-injection.html</link>
					<comments>https://jessewarden.com/2026/04/quick-history-on-dependency-injection.html#respond</comments>
		
		<dc:creator><![CDATA[JesterXL]]></dc:creator>
		<pubDate>Sat, 04 Apr 2026 14:37:37 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<guid isPermaLink="false">https://jessewarden.com/?p=6917</guid>

					<description><![CDATA[A quick history on Dependency Injection (DI) because I&#8217;ve experienced 2 extremely visceral reactions to it by experienced developers in the past year. I&#8217;m concerned either there are more than 2 devs who have a bad impression of it, or some are spreading misinformation which can negatively affect how you build &#38; test your software. [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>A quick history on Dependency Injection (DI) because I&#8217;ve experienced 2 extremely visceral reactions to it by experienced developers in the past year. I&#8217;m concerned either there are more than 2 devs who have a bad impression of it, or some are spreading misinformation which can negatively affect how you build &amp; test your software.</p>



<span id="more-6917"></span>



<p>One developer I debated with this on has a training course, and it looks quite thorough and good based on a 5 minute scan. That is also worrisome because in our debate he said &#8220;DI injection has nothing to do with testing&#8221; and &#8220;adding DI in just so it&#8217;s &#8216;easier&#8217; to test is a terrible choice. DI doesn&#8217;t make testing easier. It makes testing systems that use DI easier, and that&#8217;s a big distinction.&#8221;</p>



<p>Given the amount of AI psychosis going around currently, I&#8217;ve been introspective to ensure it&#8217;s not &#8220;me&#8221; that&#8217;s confused. When they say &#8220;AI does all coding&#8221;, no it doesn&#8217;t. When they say &#8220;AI is worthless&#8221;, no, it can be helpful. I&#8217;ve used various models, tools, and practices to learn. I&#8217;m left with either I&#8217;m a rational centrist&#8230; or both of them are lying or crazy&#8230; wait, am I the one who is crazy?</p>



<p>For DI, I have no insecurities. The industry has been doing this for 40+ years, and for good reasons. Over half to do with testing, the rest with design despite design being the origins. It&#8217;s long and documented. To say it has nothing to do with testing, or is as bad choice is just wrong. To build a training course without using DI at this point is willful ignorance.</p>



<h2 class="wp-block-heading">Introduction</h2>



<p>There is some negative cultural stigma associated with DI because in early Java, there was a large exodus of developers to other languages. While Java development &amp; industry use remains strong, so to does the stigma of &#8220;Java esque&#8221; connotations.</p>



<p>I hate when YouTube videos dive into history for 7 minutes instead &#8220;just tell me why DI is good/bad!&#8221;. DI is good, for both Object-Oriented Programming and Functional Programming. However, to understand why it&#8217;s so tainted, understanding the history explains why you get completely different reactions from from developers when it &#8220;seems so obvious to just use it&#8221;.</p>



<p>I get it, but you&#8217;ll need to have this context if you ever start &#8220;just coding, DI is a normal part of that&#8221; and you have a new co-worker or client who freaks out, or the reverse, you see they use no DI in their code, and their tests are&#8230; &#8220;interesting&#8221;. (That&#8217;s tact for &#8220;I need a new job, I can&#8217;t work with this code base&#8221;).</p>



<h2 class="wp-block-heading">Java/.NET Egress</h2>



<p>Many Java developers in the 2000&#8217;s fled to Ruby and Rails with it&#8217;s simplicity and basically one way to do things. A lot less code, a lot less configuration (hence the convention over configuration mantra they have).</p>



<p>Years later, many did the same to Node.js. Specifically, JavaScript on the server, not the client. While it may seem normal to lump JavaScript server-side developers with web developers, they are definitely two different communities and do not always agree.</p>



<p>Understand that many in this world WERE OOP devs at heart, they just disagreed with the approach Java took, and were heavily prejudiced against the complexity. Understand, too, the age differences. Some were from a C++ background from the 80&#8217;s and 90&#8217;s, and had similiar feelings. Others were much younger, but after a short stint in both languages, without all the experience, and context, many were quick to say &#8220;This seems much simpler than Java&#8221;. So you had a type of cargo culting happening as well to varying degree&#8217;s, but it was encouraged, sometimes unknowingly.</p>



<p>The same with Python and Django. What all 3 had in common was they still supported Object-Oriented Programming (OOP) paradigms, but without the low return on investment type ceremony in early Java, and all the configuration complexity. This meant getting up to speed, from a variety of skill levels, was much easier, but you could still pick and choose to bring what you knew. The same applied to early .NET/C# as well. Want to use the same class keyword, and a few OOP design patterns? Works about the same. What to build a lighter weight Inversion of Control framework? Much easier to do in dynamic languages.</p>



<p>These are the people who taught me.</p>



<h2 class="wp-block-heading">Why DI?</h2>



<p>DI was created in the 80&#8217;s to make configuring OOP code bases easier. Whether using a concrete class, or an interface, you could make your classes more flexible by injecting the class or interface instead of having the class build itself. Classes are often a black box; that&#8217;s the whole point of OOP, encapsulation &amp; abstraction (I&#8217;m ignoring message passing because that is a depressing path).</p>



<p>Instead of a class instantiating it&#8217;s own logger:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyGame</span> </span>{
  <span class="hljs-keyword">constructor</span>() {
    <span class="hljs-keyword">this</span>.logger = <span class="hljs-keyword">new</span> Logger()
  }

  movePlayer() {
    <span class="hljs-keyword">this</span>.logger.info(<span class="hljs-string">"Moved to new position."</span>)
  }
}</code></span></pre>


<p>You&#8217;d instead inject a logger instance in the class constructor:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyGameDI</span> </span>{
  <span class="hljs-keyword">constructor</span>(logger) {
    <span class="hljs-keyword">this</span>.logger = logger
  }

  movePlayer() {
    <span class="hljs-keyword">this</span>.logger.info(<span class="hljs-string">"Moved to new position."</span>)
  }
}</code></span></pre>


<p>This was often called &#8220;Inversion of Control&#8221;. Before, the class you created had control of what it created and when, but now, it&#8217;s done by classes higher up the class tree. The advantages were it was easier to swap out a new class that did something different (in-memory logger for profiling vs disk), or multiple implementations (decoding mp3, ogg, wav, etc files for an audio player).</p>



<p>Around the same time (in non-Java circles) there was a small rejection of inheritance being a good idea. It took awhile, but many in OOP felt composition, having classes inside of classes instead of extending a base class, was a better idea for easier to maintain code. DI helped make composition easier and throughout the late 90&#8217;s and early 2000&#8217;s, the &#8220;Composition Over Inheritance&#8221; phrase grew in popularity. The cargo culting here was less because all a developer had to do was create large inheritance hierarchies, then maintain the mess they created. So the general idea that classes should not create their dependencies, but instead receive them from the outside became a lot more standardized (but still not widely accepted).</p>



<p>Years later it was also discovered this made testing a whole lot easier because the tests could inject fake versions and the real code could inject the real versions, but your main source code didn&#8217;t need to change. This really helped software quality and speed, while still retaining the design &amp; architecture benefits.</p>



<h2 class="wp-block-heading">Testing</h2>



<p>During the 90&#8217;s, developers from many backgrounds started recognizing DI&#8217;s usefulness in testing. At the same time, a ground swell was happening in both how you test, and how you build software. Kent Beck&#8217;s XP book, which talked about Test Driven Development, came out in 1999, and then 2 years later in 2001, the Agile Manifesto came out. A year later, the Spring Framework for Java came out, utilizing the &#8220;DI Container&#8221;.</p>



<p>Despite the <a href="https://www.youtube.com/watch?v=QyJZzq0v7Z4">$500,000,000 Sun marketing budget for Java and OOP</a>, there was also this growing sense of software craftsmanship culture growing. 3 years later in 2004, Martin Fowler wrote the seminal &#8220;<a href="https://martinfowler.com/articles/injection.html">Inversion of Control Containers and the Dependency Injection pattern</a>&#8221; that further popularized and cemented DI as the term.</p>



<p>From then on, you had this perception that DI was strictly for testing, and had nothing to do with design despite DI&#8217;s original purpose being for design.</p>



<h2 class="wp-block-heading">Containers</h2>



<p>What never finalized was &#8220;who creates the dependencies&#8221; in production code. In tests it was straightforward; the test. However, with the advent of Spring, DI Containers, e.g. &#8220;things to make the dependencies&#8221; became the norm in multiple languages, namely Java, .NET, and even in niche communities like ActionScript in Flash. These started as a class with no state; just 2 static methods that &#8220;make the production dependencies&#8221; and &#8220;make the test dependencies&#8221;. They weren&#8217;t all bad; having a global way to inject different behaviors was powerful, no doubt, but they never stayed simple.</p>



<p>The myriad of type systems, and their continued low value also complicated approaches. Some used interfaces &#8220;because that&#8217;s what the Java OOP people do&#8221;, whereas in the dynamic languages, you didn&#8217;t need any of that.</p>



<p>The complexity just spread from there, eventually infecting the tests. Around the same time, JUnit and other frameworks inadvertently created confusion around which <a href="https://en.wikipedia.org/wiki/Test_double">test-double</a> to use, when. To this day, even with Gerard Meszaros&#8217;s definitions, no one can agree on what they mean.</p>



<p>The Python, Ruby, JavaScript, and other communities rejected wholesale any type of DI Containers, but oddly imported the test-double confusion.</p>



<p>They keep trying to make a comeback in various languages with various success and failures. .NET continues to have many projects happily using DI containers, whereas in Node.js <a href="https://nestjs.com/">NestJS</a> (Nest, not Next)does have some traction, but goes against the core, original Node.js rejection of overly complicated Java DI setups and design pattern soup.</p>



<h2 class="wp-block-heading">Functional Programming and DI</h2>



<p>In the background, Functional Programming was still practiced in niches and dark shadows. Many intelligent programmers visited, and some of those came back with good ideas, most of the smarter ones not explaining where they got them to ensure better adoption.</p>



<p>Two particular things that helped popularize DI in the FP world was:</p>



<ol class="wp-block-list">
<li>some FP languages had side-effects</li>



<li>the type systems removed the need for interfaces</li>
</ol>



<p>And, a 1b, those practicing FP ideas in non-FP languages also had to deal with side-effects.</p>



<p>If you&#8217;re not an FP developer, I cannot underscore how much FP developers detest side-effects and spend every waking moment attempting to avoid side-effects. This is because the draw to FP is determinism. If you base all your code on math, and math is always right, and always wrong, then you feel super comfortable and excited to build an entire program out of it&#8230; because your program will be predictable.</p>



<p>Except, that&#8217;s not how the real world works; at a minimum, you have side-effects, things that aren&#8217;t deterministic like reading a file, connecting to a server, or accessing environment variables. Will they work? Who knows.</p>



<p>Since everything in functional programming (Scala/OCAML being weird) is <a href="https://www.youtube.com/watch?v=BWZTlfrneD8">usually functions</a>, that means dependencies are passed in as parameters, just like you&#8217;d do it in class constructors.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">movePlayer</span>(<span class="hljs-params">logger</span>) </span>{ ... }</code></span></pre>


<p>There is one thing you can do, though, even in non-FP languages, and that&#8217;s build pure functions that always work, or always fail. That means, using stubs, you can use DI to inject happy path stubs and unhappy path stubs for testing, just like you&#8217;d do in OOP.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">stubInfo = <span class="hljs-function">(<span class="hljs-params">...rest</span>) =&gt;</span> {}
stubLogger = { <span class="hljs-attr">info</span>: stubInfo }
result = movePlayer(stubLogger)</code></span></pre>


<p>That&#8217;s the reason you never see &#8220;DI Containers&#8221; in FP languages because why would you build a framework around passing a parameter to a function?</p>



<p>The last part is types. Type systems traditionally have been much better in FP languages. This means creating those stubs in FP tests is easier because the function has to match a type. Interfaces in classes typically <em>start</em> with 1 method, but never stay that way because it&#8217;s too easy to add more, which is why it gets harder and harder to create test-doubles for things in older OOP projects. In FP, a function type is 1 function type; that&#8217;s it. You can easily create a function that returns a particular value in a test. The types ensure they match; no need for interfaces, importing those interfaces, then creating a fake class to implement that interface. This varies between languages; some are easier, but less type safe, and some are more type safe, but harder to stub.</p>



<p>Either way, while one could say DI exists naturally FP, it&#8217;s quite the opposite; passing parameters to functions has been normal since functions and methods were created. OOP became so complicated, they had to invent Inversion of Control, then rebrand to Dependency Injection, cut their teeth on the mostly bad parts of DI containers, then learn that &#8220;huh, you know, instead of Constructor Injection, you could just pass the dependencies in on the method that needs it, we could call it Parameter Injection, like&#8230; passing a parameter to a function&#8221;.</p>



<h2 class="wp-block-heading">Conclusions</h2>



<p>DI has a 40+ year history from starting as a code design tool to eventually becoming a core testing tool for both OOP and FP languages over 20 years ago. It is a powerful design tool, and powerful testing tool, and it&#8217;s normal, and expected to use it. If someone says it shouldn&#8217;t be used for testing, they don&#8217;t know what they&#8217;re talking about.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://jessewarden.com/2026/04/quick-history-on-dependency-injection.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Using Types to Prevent Null in Lists</title>
		<link>https://jessewarden.com/2026/03/using-types-to-prevent-null-in-lists.html</link>
					<comments>https://jessewarden.com/2026/03/using-types-to-prevent-null-in-lists.html#respond</comments>
		
		<dc:creator><![CDATA[JesterXL]]></dc:creator>
		<pubDate>Mon, 23 Mar 2026 11:43:56 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<guid isPermaLink="false">https://jessewarden.com/?p=6910</guid>

					<description><![CDATA[Your east/west dashboard shows &#8220;us-east-1, us-west-2, and NULL&#8221; (1st image). How can types prevent that? Our types currently: The regions Array is actually a union of string or null, so: That means you&#8217;d have to filter them out at runtime. Kibosh that nonsense, let&#8217;s have an Array of strings only: Oh no, that removed the [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Your east/west dashboard shows &#8220;us-east-1, us-west-2, and NULL&#8221; (1st image). How can types prevent that?</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="844" height="370" src="https://jessewarden.com/wp-content/uploads/2026/03/dashboard-null.png" alt="" class="wp-image-6911" srcset="https://jessewarden.com/wp-content/uploads/2026/03/dashboard-null.png 844w, https://jessewarden.com/wp-content/uploads/2026/03/dashboard-null-300x132.png 300w, https://jessewarden.com/wp-content/uploads/2026/03/dashboard-null-768x337.png 768w" sizes="(max-width: 844px) 100vw, 844px" /></figure>



<p><br></p>



<span id="more-6910"></span>



<p>Our types currently:<br></p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">type RegionsPossibly = <span class="hljs-built_in">Array</span>&lt;any&gt;
regions1 = &#91; <span class="hljs-string">'us-east-1'</span>, <span class="hljs-string">'us-west-2'</span>, <span class="hljs-literal">null</span> ]</code></span></pre>


<p>The regions Array is actually a union of string or null, so:<br></p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">type RegionsMaybe = <span class="hljs-built_in">Array</span>&lt;string | <span class="hljs-literal">null</span>&gt;</code></span></pre>


<p>That means you&#8217;d have to filter them out at runtime.<br><br>Kibosh that nonsense, let&#8217;s have an Array of strings only:<br></p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">type Regions = <span class="hljs-built_in">Array</span>&lt;string&gt;
regions3 = &#91; <span class="hljs-string">'us-east-1'</span>, <span class="hljs-string">'us-moo-cow-moo'</span> ]</code></span></pre>


<p>Oh no, that removed the null&#8217;s/undefined&#8217;s, but now we have the possibly a region isn&#8217;t really a region.<br><br>&#8230; what _is_ a Region?<br><br>Let&#8217;s define a region using a Union to narrow it to just 2:<br></p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">type Region = <span class="hljs-string">'us-east-1'</span> | <span class="hljs-string">'us-west-2'</span>
type RegionsForRealDoh = <span class="hljs-built_in">Array</span>&lt;Region&gt;</code></span></pre>


<p>We&#8217;re good now, right?</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">regions4 = &#91; <span class="hljs-string">'us-east-1'</span>, <span class="hljs-string">'us-west-2'</span>, <span class="hljs-string">'us-east-1'</span> ]</code></span></pre>


<p>Oh no&#8230; Array&#8217;s allow duplicates!<br><br>Tuple&#8217;s are fixed length Array&#8217;s and fixed position. Let&#8217;s define all possible combo&#8217;s:<br></p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">type RegionsAndOnlyOne =
  | &#91;<span class="hljs-string">'us-east-1'</span>, <span class="hljs-string">'us-west-2'</span>]
  | &#91;<span class="hljs-string">'us-west-2'</span>, <span class="hljs-string">'us-east-1'</span>]</code></span></pre>


<p>Nice! This compiles:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">regions5 = &#91;<span class="hljs-string">'us-east-1'</span>, <span class="hljs-string">'us-west-2'</span>]</code></span></pre>


<p>But if you added dupes, it wouldn&#8217;t.<br><br>&#8220;Hey, can you add &#8216;eu-west-2&#8217;?&#8221;<br><br>Dude&#8230; tuples are cool, but also exponential based on their amount. That&#8217;s a type with >9 possible combo&#8217;s, I&#8217;m not writing all that! What if there were a way to create a type from a Union that handled that in case you need to add a new one later?</p>


<pre class="wp-block-code"><span><code class="hljs">type Permutations&lt;T, U = T&gt; =
  &#91;T] extends &#91;never]
    ? &#91;]
    : T extends T
      ? &#91;T, ...Permutations&lt;Exclude&lt;U, T&gt;&gt;]
      : never</code></span></pre>


<p>Think of Permutations like a function, but for types.<br><br>We can use that to create a more flexible way to creating fixed tuples for drawing lists in our UI code without having to manually type all permutations. As the list grows, the type will become quite unreadable too.<br><br>Let&#8217;s add our new region to our Union:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">type RegionNew = <span class="hljs-string">'us-east-1'</span> | <span class="hljs-string">'us-west-2'</span> | <span class="hljs-string">'eu-west-2'</span></code></span></pre>


<p>Then create a type using our type function vs. manually typing all the possible tuples:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">type RegionsWithEU = Permutations&lt;RegionNew&gt;

regions6:RegionsWithEU = &#91;
  <span class="hljs-string">'us-east-1'</span>,
  <span class="hljs-string">'us-west-2'</span>,
  <span class="hljs-string">'eu-west-2'</span>
]</code></span></pre>


<p>That allows any order with no duplicates. It&#8217;s safe to use in your naive React/Angular/Vue code to iterate through a list and draw it, no Cypress/Playwright or Unit Tests needed to validate.<br><br>Much more preferable, and flexible compared to the 2nd attached image <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f605.png" alt="😅" class="wp-smiley" style="height: 1em; max-height: 1em;" />.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="770" height="352" src="https://jessewarden.com/wp-content/uploads/2026/03/Screenshot-2026-03-22-at-11.30.41-AM.png" alt="" class="wp-image-6912" srcset="https://jessewarden.com/wp-content/uploads/2026/03/Screenshot-2026-03-22-at-11.30.41-AM.png 770w, https://jessewarden.com/wp-content/uploads/2026/03/Screenshot-2026-03-22-at-11.30.41-AM-300x137.png 300w, https://jessewarden.com/wp-content/uploads/2026/03/Screenshot-2026-03-22-at-11.30.41-AM-768x351.png 768w" sizes="(max-width: 770px) 100vw, 770px" /></figure>



<p>And with that, your NULL/undefined issue in your UI is crushed, no unit tests or acceptance tests needed. (That said, you should still write tests).<br><br>Happy (and safe) array dot map &#8216;ing!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://jessewarden.com/2026/03/using-types-to-prevent-null-in-lists.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>You Aren&#8217;t Going to Be Replaced by AI, You&#8217;re Getting New Toys</title>
		<link>https://jessewarden.com/2026/01/you-arent-going-to-be-replaced-by-ai-youre-getting-new-toys.html</link>
					<comments>https://jessewarden.com/2026/01/you-arent-going-to-be-replaced-by-ai-youre-getting-new-toys.html#respond</comments>
		
		<dc:creator><![CDATA[JesterXL]]></dc:creator>
		<pubDate>Sun, 11 Jan 2026 19:18:36 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<guid isPermaLink="false">https://jessewarden.com/?p=6902</guid>

					<description><![CDATA[Gen Z programmers, breathe a sigh of relief. Millennials devs, it&#8217;s all good. Your Gen X &#38; Boomer elders have seen this &#8220;X technology will replace programmers&#8221; before. Jesse Warden has got you. 1959: COBOL was called &#8220;Common Business Language&#8221; so non-programmers can read it. We were so expensive, the Pentagon got involved. Now COBOL [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p id="ember508">Gen Z programmers, breathe a sigh of relief. Millennials devs, it&#8217;s all good. Your Gen X &amp; Boomer elders have seen this &#8220;X technology will replace programmers&#8221; before. Jesse Warden has got you.</p>



<p id="ember509"><strong>1959</strong>: COBOL was called &#8220;Common Business Language&#8221; so non-programmers can read it. We were so expensive, the Pentagon got involved. Now COBOL Cowboys charge up to $1,000 per hour. The syntax morphed to OOP to be more likeable/usable by programmers.</p>



<span id="more-6902"></span>



<p id="ember510"><strong>197?</strong>: MYCIN, the 1st AI/LLM like inference engine, used to recommend antibiotics for infections. Despite high scores, wasn&#8217;t used because of hardware limitations (like the data center bulid out &amp; RAM shortage drama we have today). Later Intellicorps LiveModel allowed you to leverage this AI to model business processes. This in turn spawned many data scientist &amp; software consulting opportunities.</p>



<p id="ember511"><strong>1973</strong>: Wang 2200 computer was called &#8220;computing calculator&#8221; so it wouldn&#8217;t scare customers. Marketed as &#8220;exceptionally easy to operate&#8221; and &#8220;no esoteric skills are required&#8221;. Yet saving files was so obtuse, many users would reach out to tech support (reminds me if iPhone file saving). You had to program it in BASIC vs. &#8220;File &gt; Save As or Command + Shift + F&#8221;.</p>



<p id="ember512"><strong>1982</strong>: OpenEdge Advanced Business Language: programming language w/integrated database build for people who weren&#8217;t computer scientists. Same later &#8220;I guess only programmers use this, let&#8217;s make it more OOP&#8221;.</p>



<p id="ember513"><strong>1983</strong>: IBM&#8217;s Query Management Facility &amp; Crystal Reports ensured business people could get reports without IT involvement. Some of my early consulting work was &#8220;customizing <em>these</em> charts for this <em>data</em> with <em>these</em> systems&#8221;.</p>



<p id="ember514"><strong>1985</strong>: Went the other way, attempting to remove the Domain Expert via CLIPS (NASA&#8217;s AI Language). Some used these Expert Systems to generate code which sometimes was better than a dev could write. You don&#8217;t hear much about expert systems from the 90&#8217;s &#8211; 2000&#8217;s, but you DO hear about devs building rules engines leveraging those Domain Expert&#8217;s and their knowledge.</p>



<p id="ember515"><strong>1991</strong>: Visual Basic, PowerBuilder, and Delphi lead the way in &#8220;using visuals, you don&#8217;t have to know much about code and databases&#8221;. Then those apps reached a level of complexity, consultants/freelancer devs were hired to fix, modify, or rewrite these apps.</p>



<p id="ember516"><strong>1994</strong>: Many CASE tools like Rational Rose utilized visual boxes and arrows to represent domain models, such as UML, and these would generate your application, not needing developers. UML&#8217;s creators today use UML to communicate architecture to other devs, but doesn&#8217;t use it to generate the code.</p>



<p id="ember517"><strong>2000&#8217;s</strong>: Business Rules Engines were touted to allow Business Analysts to make decisions without programmers (offering a loan, credit card, or mortgage). Many data specifications, tools, libraries, and microservices are created to allow access to these rules, and today many devs &amp; data scientists build these systems to run businesses.</p>



<p id="ember518"><strong>Excel</strong>: &#8230; yes, the business doesn&#8217;t need us here. All hail the almighty Excel.</p>



<p id="ember519">With the exception of Excel, all of these innovations created to replace devs either led to more of us needed or new job roles created. All lead to new tools and approaches. COBOL to using English vs math in coding syntax, MYCIN for LISP &amp; Prolog to be cool, inference engines to be a thing, including Bayesian networks, RAG, logic programming, and truth engines.</p>



<p id="ember520">Wang + others lead to the personal computer market, word processors, &amp; accessible accounting tools to run businesses &amp; people&#8217;s lives. PC&#8217;s were gateway drugs for many people to be exposed to BASIC, VB, and game dev. The UI &amp; case tools of the 90&#8217;s raised the bar on expectations of developers for IDE&#8217;s; we expect IDE&#8217;s nowadays to visually help us navigate our code intelligently and allow the LLMS to help.</p>



<p id="ember521">The RAD Tooling was overshadowed by the RAD development style which helped influence the world away from Waterfall to more Agile styles of working. This allows us to continually learn with our users to help inform how to build things, leading to constant learning and fun. UML and it&#8217;s ilk has lead to all kinds of great data formats like JSON, Markdown, and Mermaid charts.</p>



<p id="ember522">All of these are cool, new things we can learn to make our jobs better, or <em>new</em> types of jobs with software. They always try to replace us. We always end up with new toys instead.</p>



<p id="ember523">So don&#8217;t worry about your software job being replaced, or no new junior positions. If you like being here because you have a short attention span, love to learn new things, and build stuff&#8230; or all 3, you&#8217;ve chosen a technically great time to get into software dev.</p>



<p id="ember524">We&#8217;re all still figuring this AI thing out, which is fun! Part of software dev is bravely/excitedly wading head first into ambiguity and going &#8220;I wonder how this works&#8230; what does that button do&#8230;&#8221; While opportunities right now suck because of the economy &amp; over hiring, there ARE a lot of people who really don&#8217;t want to be here who are leaving, and the economy historically always gets better. Just keep going.</p>



<p id="ember525">Get that STEM degree, go to that bootcamp, or keep trying to break into your junior role; the amount of software we have to build is only increasing, and we&#8217;ll use AI/LLM&#8217;s to help us do it. Find your passion in the field, whether that&#8217;s web dev like me, game dev, systems programming, data science/machine learning, cyber&#8230; or maybe you just gravitate towards a particular language, that&#8217;s cool too. There are so many fun niches in software dev.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://jessewarden.com/2026/01/you-arent-going-to-be-replaced-by-ai-youre-getting-new-toys.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Learning Motorcycle Suspension</title>
		<link>https://jessewarden.com/2026/01/learning-motorcycle-suspension.html</link>
					<comments>https://jessewarden.com/2026/01/learning-motorcycle-suspension.html#respond</comments>
		
		<dc:creator><![CDATA[JesterXL]]></dc:creator>
		<pubDate>Sat, 10 Jan 2026 15:50:20 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<guid isPermaLink="false">https://jessewarden.com/?p=6899</guid>

					<description><![CDATA[Been trying to learn suspension, specifically on motorcycles. I&#8217;ve almost got the differences between preload, suspension, and damping down. Issue is you can&#8217;t play with those terms unless you have a machine with adjustable suspension (cheap ones only have adjustable preload). There seems to be this trend that light, cheap bikes may have adjustable preload. [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Been trying to learn suspension, specifically on motorcycles. I&#8217;ve almost got the differences between preload, suspension, and damping down. Issue is you can&#8217;t play with those terms unless you have a machine with adjustable suspension (cheap ones only have adjustable preload).</p>



<span id="more-6899"></span>



<p>There seems to be this trend that light, cheap bikes may have adjustable preload. Mid-weight have some combo of adjustable preload, front &amp; rear with much better suspension parts. Heavyweights max out on top brands.</p>



<p>This creates 4 markets:</p>



<ul class="wp-block-list">
<li>oil viscosity</li>



<li>drop-in cartridges ( aka emulators)</li>



<li>fork kits</li>



<li>adjustable rear kits</li>
</ul>



<p>Most of the cheap suspension has little holes in the tubes in the front; liquid goes through these little holes to absorb bumps. It&#8217;s called &#8220;damper rod fork&#8221;.</p>



<p>The rate at which that happens is based on how thick the fork oil is. They can get hydro-locked when the hole is too small or the oil the wrong viscosity; meaning the oil can&#8217;t move fast enough to allow the fork to absorb the bump. Tradeoff of cheap forks. Regardless of suspension, oil viscosity can help / hinder based on road vs dirt.</p>



<p>The cheap way to significantly improve your front forks is to use a drop-in cartridge (aka &#8220;fork emulators&#8221;). Little circles w/valves that go into your front fork and can be adjusted to let more oil in &amp; out. Help prevent hydro-locking &amp; can increase plush feeling.</p>



<p>Many fork kits also come with new springs you drop into the front forks. Some even come with a new tube where you drill your own hole in the metal. They range from $200 &#8211; $400, so a great low-hanging fruit. Emulators + kits can absorb bumps, remove brake dive, &amp; help in turns.</p>



<p>Finally, rear shock kits vary, but many provide preload, rebound, and damping adjustment with JUST a turn click; no tools needed. You can work on the shock, refill the oil reservoir, and they can last a long time. Spring choice here can be customized to your weight as well.</p>



<p>A lot of the above depends on the bike, and what kind of riding they&#8217;re doing, and where. Me, the street is fine, it&#8217;s when I get my ADV bike on off road I notice it&#8217;s not great (at least when compared to the dual sports blasting past me). Worse when I&#8217;m plowing over rocks.</p>



<p>So it appears the lowest hanging fruit is, in order:</p>



<ol class="wp-block-list">
<li>adjust your suspension; most suspensions, even preload, can drastically improve the enjoyment of your riding. Use what you have, no need to buy anything.</li>



<li>doing cartridge drop ins</li>



<li>upgrade rear</li>
</ol>



<p>The rear seems to be least passionate since, off road in the dirt/rocks at least, the front are what contribute the most. Seems opposite for the sport bikes? Anyway, Ari Henning has a good video on how to do the cartridges yourself.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="How To Install Gold Valve Emulators | The Shop Manual" width="500" height="281" src="https://www.youtube.com/embed/mRWmClH0bC0?start=1&#038;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>However, there appears to also be drop in from Cogent which does not drilling anything so much easier to install. I may do some more research to compare the drilling vs not.</p>



<p>I may seem odd buying a bike, then spending $300 &#8211; $3000 on upgrading the suspension. However, regardless of bike and riding style, this seems to be the consistent thing that links them all: everyone loves better suspension. That means even if your bike comes with &#8220;ok&#8221; suspension, EVERYONE seems to be in agreement if you have the money, it&#8217;s always worth it.</p>



<p>The common refrain is &#8220;Once you&#8217;ve experienced good suspension, you never go back&#8221;. Again, the repeated caution is &#8220;your existing suspension _may_ actually be great, you just didn&#8217;t adjust to your weight &amp; riding style&#8221;; even just preload adjustment can help.</p>



<p>That said, $300 seems paltry to improve quality of life + the learning experience, so&#8230; I may give it a go.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://jessewarden.com/2026/01/learning-motorcycle-suspension.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Effects As Types</title>
		<link>https://jessewarden.com/2026/01/effects-as-types.html</link>
					<comments>https://jessewarden.com/2026/01/effects-as-types.html#respond</comments>
		
		<dc:creator><![CDATA[JesterXL]]></dc:creator>
		<pubDate>Fri, 09 Jan 2026 20:39:51 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<guid isPermaLink="false">https://jessewarden.com/?p=6894</guid>

					<description><![CDATA[In this article we&#8217;ll cover a basic Effects As Types example; using types in TypeScript to represent side-effects. We do this to help ensure our code works, leveraging the compiler for fast feedback, and simplifying our unit tests. By the end you&#8217;ll understand how you can leverage the compiler to assert important side-effects happen instead [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>In this article we&#8217;ll cover a basic Effects As Types example; using types in TypeScript to represent side-effects. We do this to help ensure our code works, leveraging the compiler for fast feedback, and simplifying our unit tests. By the end you&#8217;ll understand how you can leverage the compiler to assert important side-effects happen instead of using spies.</p>



<span id="more-6894"></span>



<p>I was inspired to write this because we&#8217;re dealing with testing Observability at work, and <a href="https://martinfowler.com/articles/domain-oriented-observability.html">this article from Pete Hodgson</a> describing the architecture and testing of Observability code in your Domain logic, that is quite good. I noticed the lack of types as a tool to help here, so wanted to add a simple technique that can help make testing easier.</p>



<h2 class="wp-block-heading">Why Care</h2>



<p>First, let&#8217;s cover why spies should be avoided, what they are if you&#8217;re not aware, and what side-effects are so you understand the problem we&#8217;re solving here.</p>



<p>Spies in unit tests should be avoided, and side-effects should at be tested with both types and Acceptance Tests, giving you confidence your code works as intended. This is nuanced depending upon programming language, but with TypeScript, we&#8217;re at a point where the types are good enough you don&#8217;t need to use spyies anymore in unit tests for the side-effects and can use types instead.</p>



<h2 class="wp-block-heading">What&#8217;s Wrong With Spies?</h2>



<p>Spies break encapsulation by knowing how your code works. This can discourage refactoring because even if you don&#8217;t change behavior of the code, it could break the tests. This in turn creates both the inability to easily refactor code and also creates a negative perception of the unit tests (e.g. tests break even though your code still works). You also have more state to remember in your unit test suite (e.g. beforeEach/afterEach). Finally, it increases the amount of code needed to code, read, and maintain in the unit tests.</p>



<p>My background is in Functional Programming with good type systems; there, everything returns a value, and you can use this typed value as part of the function signature to ensure &#8220;it&#8217;s doing the side-effects it needs to be&#8221;.</p>



<h2 class="wp-block-heading">Why Even Use a Spy?</h2>



<p>When writing tests, we often have side-effects in those tests that are important. If everything was just a pure function, our program wouldn&#8217;t actually do anything beyond warm a CPU; side-effects are what do important things in the real world. However, they often don&#8217;t return any value; the effect itself can happen outside of your program (e.g. logging to standard out, making a database update, etc).</p>



<p>It&#8217;s also common in Object Oriented Programming to encapsulate those effects as part of your abstraction. When these best practices were being created, good type systems weren&#8217;t in those languages, so types didn&#8217;t play a part in &#8220;design&#8221;; testing and architecture patterns did. Therefore many class methods will do mutation and other side-effects, and return nothing or <code>void</code>. You&#8217;ll continue to see that in both older blog posts/books &amp; new, including many LLM&#8217;s.</p>



<p>Thus most testing literature will encourage, like us, that testing these side-effects is extremely important. How do they that is typically with what <a href="https://en.wikipedia.org/wiki/Test_double">Gerard Meszaros calls &#8220;Spies&#8221;</a>. After the code under test runs, you can then ask this spy &#8220;Were you called with the data we expect?&#8221;. This gives you confidence the code did it in fact call the side-effect full code in a way you expect.</p>



<h2 class="wp-block-heading">Moving From Spies to Types</h2>



<p>Let&#8217;s first show how a unit test is currently using a spy. Then we&#8217;ll move it towards using types.</p>



<h3 class="wp-block-heading">From Spy</h3>



<p>This code does some business logic and logs the result for Observability reasons (e.g. alerts in Honeycomb or Splunk or New Relic) with associated unit test that uses a spy.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">itsTheBusiness</span>(<span class="hljs-params"></span>):<span class="hljs-title">BusinessResult</span> </span>{
  <span class="hljs-keyword">const</span> result = doTheBusiness()
  <span class="hljs-built_in">console</span>.log({ <span class="hljs-attr">message</span>: <span class="hljs-string">"business"</span>, result })
  <span class="hljs-keyword">return</span> result
}</code></span></pre>


<p>There are 2 unit tests; 1 validates the result that <code>itsTheBusiness</code> returns. We&#8217;re interested in the 2nd test; the one that validates <code>console.log</code> sent our message to ensure our Observability, e.g. our alerts in Honeycomb, continue to work.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">it(<span class="hljs-string">'should send the business result to logs'</span>, () =&gt; {
  <span class="hljs-keyword">const</span> consoleSpy = vi.spyOn(<span class="hljs-built_in">console</span>, <span class="hljs-string">'log'</span>)
  <span class="hljs-keyword">const</span> result = itsTheBusiness()
  expect(result).toBe(<span class="hljs-string">'cow'</span>)
  expect(consoleSpy).toHaveBeenCalled()
});</code></span></pre>


<p>This spy is required to be setup to test the code, and it &#8220;knows&#8221; a <code>console</code> is used, and that it uses the <code>log</code> method. If we comment out the <code>console.log</code>, the test fails, ensuring we log the result.</p>



<h3 class="wp-block-heading">To Types</h3>



<p>The type signature says that this function returns a <code>BusinessResult</code>, but it&#8217;s also doing some logging, so isn&#8217;t telling teh whole store of what this function does through the type signature. Currently, <code>console.log</code> doesn&#8217;t return anything useful; <code>undefined</code> doesn&#8217;t tell us it worked or what the data was. </p>



<p>We&#8217;ll assume <code>console.log</code> is a safe side-effect; meaning it always works, but is a side-effect. Examples include <code>Math.random()</code> and <code>new Date()</code>; non-deterministic, but won&#8217;t crash your program like <code>fetch</code> or <code>fs.readFileSync</code>. The difference is unlike <code>console.log</code>, both of those have return values.</p>



<p>Let&#8217;s create a light wrapper to fix that.</p>



<p>First, a type:</p>


<pre class="wp-block-code"><span><code class="hljs">type LogMessage = { logMessage: any }</code></span></pre>


<p>And second, a lightweight wrapper:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">log</span>(<span class="hljs-params">logMessage:any</span>):<span class="hljs-title">LogMessage</span> </span>{
  <span class="hljs-keyword">return</span> { logMessage }
}</code></span></pre>


<p>Now that our logger has the ability to return a useful return type, we can leverage that type by updating the <code>itsTheBusiness</code> function contract: You must return a <code>BusinessResult</code> AND a <code>LogMessage</code>.</p>


<pre class="wp-block-code"><span><code class="hljs">// this...
function itsTheBusiness():BusinessResult

// ... to this
function itsTheBusiness():&#91;BusinessResult, LogMessage]</code></span></pre>


<p>Why is that subtle change important? Ask yourself &#8220;Where do I get a `LogMessage1?&#8221;</p>



<p>You get it from calling <code>log</code>. If you don&#8217;t call <code>log</code>, then you don&#8217;t have a <code>LogMessage</code>. If you don&#8217;t have a <code>LogMessage</code>, you can&#8217;t compile <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f60a.png" alt="😊" class="wp-smiley" style="height: 1em; max-height: 1em;" />. This ensures compiling means your code is working as expected; the types help enforce that.</p>



<p>Let&#8217;s see what that looks like in practice. We&#8217;ll change our code to fulfill that new type signature:</p>


<pre class="wp-block-code"><span><code class="hljs">function itsTheBusiness(): &#91;BusinessResult, LogMessage] {
  const result = doTheBusiness();
  const logMessage = log({ message: 'business', result });
  return &#91;result, logMessage]
}</code></span></pre>


<p>The test still passes&#8230; ok, not much interesting there, just more to read. Watch what happens when we comment out the <code>log</code> call:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="307" src="https://jessewarden.com/wp-content/uploads/2026/01/Screenshot-2026-01-09-at-2.28.01-PM-1024x307.png" alt="" class="wp-image-6895" srcset="https://jessewarden.com/wp-content/uploads/2026/01/Screenshot-2026-01-09-at-2.28.01-PM-1024x307.png 1024w, https://jessewarden.com/wp-content/uploads/2026/01/Screenshot-2026-01-09-at-2.28.01-PM-300x90.png 300w, https://jessewarden.com/wp-content/uploads/2026/01/Screenshot-2026-01-09-at-2.28.01-PM-768x231.png 768w, https://jessewarden.com/wp-content/uploads/2026/01/Screenshot-2026-01-09-at-2.28.01-PM.png 1246w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>You see the compiler won&#8217;t let you compile; you need a <code>LogMessage</code> and the only way to get it is to call <code>log</code>.</p>



<p>Finally, let&#8217;s clean up the unit test by removing the <code>spy</code>:</p>


<pre class="wp-block-code"><span><code class="hljs language-php">it(<span class="hljs-string">'should send the business result to logs'</span>, () =&gt; {
  <span class="hljs-keyword">const</span> &#91; result ] = itsTheBusiness()
  expect(result).toBe(<span class="hljs-string">'cow'</span>)
});</code></span></pre>


<p>No more <code>spy</code>, but still ensures you&#8217;re logging is happening.</p>



<h2 class="wp-block-heading">Conclusions</h2>



<p>Spies are a way to assert methods/functions are being invoked in ways you expect. They are useful in programming styles where you have side-effects and want to assert those interactions are happening as you expect. Vitest improves this by making them type-safe.</p>



<p>However, they also have too many negative tradeoffs: they know how the code works, what dependencies they are using, and how those dependencies are used. This requires you to setup those spies and tear down those spies in unit tests. This is more state to manage in unit tests, more code to write, read, and maintain. This also creates a negative incentive not to refactor your code because you may break the tests despite the code itself not breaking.</p>



<p>We should continue to use Acceptance Tests to validate our side-effects happen the way we expect. However, types can also help shift the problem left, and add the &#8220;when it compiles, it works&#8221; mantra to add a level of confidence our code does in fact work along with the Acceptance Tests. This leverages both <a href="https://www.infoq.com/presentations/Types-Tests/">types and tests</a> to move towards fearless releases.</p>



<p>We&#8217;ve used a type for a log message, but this can apply to any side-effect you deem important, and start notice you start reaching for a spy. Instead, you can model those effects as types, and ensure they&#8217;re used the way the side-effect should. There are many other <a href="https://effect.website/">benefits of this approach</a> we didn&#8217;t cover, having side-effect types as values. Hopefully this gives you a taste of their benefits.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://jessewarden.com/2026/01/effects-as-types.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
