<?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[blog.mathiasnitzsche.de]]></title><description><![CDATA[I will try to make posting a habit to practice my writing, and improve my thinking.]]></description><link>https://blog.mathiasnitzsche.de</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 15:06:38 GMT</lastBuildDate><atom:link href="https://blog.mathiasnitzsche.de/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Optimizing the hell out of JS Code]]></title><description><![CDATA[In this post, I want to share a few of the learnings I made (over)optimizing the hell out of a tiny JavaScript app.
Background
The basketball league, my son is playing in, doesn't share a ranking table to not make the kids too concerned about their r...]]></description><link>https://blog.mathiasnitzsche.de/optimizing-the-hell-out-of-js-code</link><guid isPermaLink="true">https://blog.mathiasnitzsche.de/optimizing-the-hell-out-of-js-code</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[optimization]]></category><category><![CDATA[Functional Programming]]></category><dc:creator><![CDATA[Mathias Nitzsche]]></dc:creator><pubDate>Wed, 21 Dec 2022 13:17:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671629729561/cDuZ8FGQM.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this post, I want to share a few of the learnings I made (over)optimizing the hell out of a tiny JavaScript app.</p>
<h2 id="heading-background">Background</h2>
<p>The basketball league, my son is playing in, doesn't share a ranking table to not make the kids too concerned about their results. As a curious dad and engineer, I did the only reasonable thing and created a little script myself, which generates the table based on the publically available game results.</p>
<p>After an hour of coding, I had the initial version done. Just simple stuff: fetching, processing, and displaying data:<br /><strong><mark>Initial v0.1 - </mark></strong> <a target="_blank" href="https://github.com/madmaxmatze/code/blob/main/bball/index_v0.1.html"><strong><mark>Code</mark></strong></a> <strong><mark>- </mark></strong> <a target="_blank" href="https://code.mathiasnitzsche.de/bball/index_v0.1.html"><strong><mark>Live Application</mark></strong></a></p>
<p>Over the next few weeks, for some reason I kept applying tiny improvements to the code, which completely escalated:<br /><strong><mark>Final v1.0 - </mark></strong> <a target="_blank" href="https://github.com/madmaxmatze/code/blob/main/bball/index.html"><strong><mark>Code</mark></strong></a> <strong><mark>- </mark></strong> <a target="_blank" href="https://code.mathiasnitzsche.de/bball/"><strong><mark>Live Application</mark></strong></a></p>
<p>Just looking at some hard numbers it's clear that the initial version has little to do with the latest one:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>JS keyword</strong></td><td>Initial v0.1</td><td>Final v1.0</td></tr>
</thead>
<tbody>
<tr>
<td><code>const</code>/<code>var</code></td><td><strong>■■■■■■■■■■■■■■■</strong> 15</td><td><strong>■</strong> 1</td></tr>
<tr>
<td><code>() =&gt; ()</code></td><td><strong>■</strong> 1</td><td><strong>■■■■■■■■</strong> 8</td></tr>
<tr>
<td><code>function</code></td><td><strong>■■■■■</strong> 5</td><td><strong>■■■■■</strong> 5</td></tr>
<tr>
<td><code>return</code></td><td><strong>■■■■■■■</strong> 7</td><td><strong>■■</strong> 2</td></tr>
<tr>
<td><code>for</code></td><td><strong>■■</strong> 2</td><td>0</td></tr>
<tr>
<td><code>if</code></td><td><strong>■■■■■■■</strong> 7</td><td>0</td></tr>
<tr>
<td></td><td></td><td></td></tr>
<tr>
<td>Total lines of JS code</td><td>109</td><td>51</td></tr>
</tbody>
</table>
</div><p>So what happened...</p>
<h2 id="heading-learning-i-functional-programming">Learning I: Functional programming</h2>
<p>As the numbers already tell, the biggest difference between the two versions is of course how much more functional the coding became. I did not intend to go in this direction, but it just felt very natural for data processing to pipe results from function to function, chain calls to array methods, remove temporary variables, etc.<br />Clearly, this coding style takes some time to get used to and might not be for everyone, but without a doubt, it’s much more succinct:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// INITIAL v0.1</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> match <span class="hljs-keyword">of</span> team.matches) {
  <span class="hljs-keyword">if</span> (match &amp;&amp; match[<span class="hljs-number">0</span>] &amp;&amp; match[<span class="hljs-number">0</span>].result) {
    <span class="hljs-keyword">var</span> [homeResult, guestResult] = match[<span class="hljs-number">0</span>].result.split(<span class="hljs-string">':'</span>);
    homeResult = <span class="hljs-built_in">parseInt</span>(homeResult);
    guestResult = <span class="hljs-built_in">parseInt</span>(guestResult);

---

<span class="hljs-comment">// FINAL v1.0</span>
team.matches
  .flat()
  .filter(<span class="hljs-function"><span class="hljs-params">match</span> =&gt;</span> match.result)
  .filter(<span class="hljs-function"><span class="hljs-params">match</span> =&gt;</span>
    [team.homeResult, team.guestResult] = match.result.split(<span class="hljs-string">":"</span>).map(<span class="hljs-built_in">Number</span>);

---

<span class="hljs-comment">/* provided DATA STRUCTURE
team : {
  matches : [
    [{result : "100:50", ..}],
    [{result : null, ..}],         // past game canceled or postponed
    [{result : "20:30", ..}],
    [],                            // idk  ¯\_(ツ)_/¯ 
    ..
  ]
}</span>
</code></pre>
<p>Learn more: <a target="_blank" href="https://medium.com/poka-techblog/simplify-your-javascript-use-map-reduce-and-filter-bd02c593cc2d">Simplify your JavaScript – Use .map(), .reduce(), and .filter()</a></p>
<h2 id="heading-learning-ii-promises-to-prettify-the-flow">Learning II: Promises to prettify the flow</h2>
<p>I’m sure you all know what Promises are good for (and not) and why asynchronous development is awesome, but did you know that they are also a wonderful tool to make the general application flow obvious:</p>
<pre><code class="lang-javascript">
<span class="hljs-comment">// INITIAL v0.1</span>
<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">var</span> dataUrl = <span class="hljs-string">"..."</span>;
  <span class="hljs-keyword">var</span> data = <span class="hljs-keyword">await</span> loadData(dataUrl);
  <span class="hljs-keyword">var</span> table = process(data).sort(sortTable).reverse();
  renderTable(table);
}
app();

---

<span class="hljs-comment">// FINAL v1.0</span>
<span class="hljs-keyword">var</span> dataUrl = <span class="hljs-string">"..."</span>;
proxyLoadData(dataUrl)
    .then(processData)
    .then(outputData)
    .catch(handleError);
</code></pre>
<h2 id="heading-learning-iii-love-for-javascript-magic">Learning III: ♥ for JavaScript magic</h2>
<p>JavaScript is full of little tricks and hacks to get things done quicker. From years of PHP and Perl development, I love all this <code>??</code> , <code>?.</code>, <code>!!</code>, <code>~~</code>, <code>...</code> craziness 😆</p>
<p>Learn more: <a target="_blank" href="https://betterprogramming.pub/25-useful-javascript-shorthands-for-web-developers-771ac550a7ba">25 Useful JavaScript Shorthands for Web Developers</a></p>
<h2 id="heading-learning-iv-fetch-caching-instead-of-localstorage">Learning IV: Fetch Caching instead of LocalStorage</h2>
<p>I wrote an extra article about an interesting solution to avoid using LocalStorage to cache API responses:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.mathiasnitzsche.de/js-fetch-http-caching-instead-of-localstorage">https://blog.mathiasnitzsche.de/js-fetch-http-caching-instead-of-localstorage</a></div>
<p> </p>
<h2 id="heading-learning-v-ask-for-forgiveness-not-permission">Learning V: Ask for forgiveness, not permission</h2>
<p>As always a great way of simplification is to just do stuff, instead of checking if it needs to be done, only avoiding wrong side effects. As an example just check the function <code>processData</code>, where these two lines add the correct number of played games and wins no matter if the game happened, was canceled or postponed, lost or won:</p>
<pre><code class="lang-javascript">team.games += <span class="hljs-built_in">Number</span>(<span class="hljs-built_in">Boolean</span>(match.result));
team.wins += <span class="hljs-built_in">Number</span>(team.gamePoints &gt; team.gamePointsOpponent);
</code></pre>
<h2 id="heading-learning-vi-simplicity">Learning VI: Simplicity</h2>
<p>It was a fun experience just playing around with a single .html file. I almost forgot how easy things can be with no build process, no configs, no libs, no deployment, and no IDE. Just plain code and super quick Trial and Error, which is still the best teacher in the world.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>So first of all, without a doubt I overdid it. I spend way more time on it than would be reasonable for any real-world project. I sacrificed some readability just to show off that I can even save a few more lines, which is the opposite of what is regarded as good software engineering. (see <a target="_blank" href="https://twitter.com/mitchellh/status/1615797167607939072">this wonderful example and discussion on Twitter</a>). But overall, I loved the process and learned, or at least confirmed quite a few things.</p>
<p>In any case, feel free to let me know what you think, and for sure reach out in case you see further simplifications.</p>
]]></content:encoded></item><item><title><![CDATA[JS fetch: HTTP Caching instead of LocalStorage]]></title><description><![CDATA[Whenever you write plain JS without access to external libs, here is a quick hack on how to cache API responses, which I actually used for my homepage and in another small project.
The normal way
The JS function fetch makes remote calls really easy. ...]]></description><link>https://blog.mathiasnitzsche.de/js-fetch-http-caching-instead-of-localstorage</link><guid isPermaLink="true">https://blog.mathiasnitzsche.de/js-fetch-http-caching-instead-of-localstorage</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[fetch API]]></category><category><![CDATA[Cache Bust]]></category><category><![CDATA[cache]]></category><category><![CDATA[localstorage]]></category><dc:creator><![CDATA[Mathias Nitzsche]]></dc:creator><pubDate>Wed, 21 Dec 2022 11:59:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671624485253/fAMH0E_Cc.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whenever you write plain JS without access to external libs, here is a quick hack on how to cache API responses, which I actually used for <a target="_blank" href="https://github.com/madmaxmatze/mathiasnitzsche.de/blob/main/scripts.js">my homepage</a> and in another <a target="_blank" href="https://blog.mathiasnitzsche.de/optimizing-the-hell-out-of-js-code">small project</a>.</p>
<h2 id="heading-the-normal-way">The normal way</h2>
<p>The JS function <code>fetch</code> makes remote calls really easy. But when you want to put some caching around it using <code>localStorage</code> (or <code>CacheAPI</code>), the code quickly becomes a little bulky:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// NORMAL: Fetch using localStorage as cache</span>
<span class="hljs-keyword">const</span> loadData = <span class="hljs-keyword">async</span> (url) {
  <span class="hljs-keyword">var</span> data = <span class="hljs-built_in">localStorage</span>.getItem(url);

  <span class="hljs-keyword">if</span> (data) { <span class="hljs-comment">// check if expired</span>
    data = <span class="hljs-built_in">JSON</span>.parse(data);
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Date</span>.now() - data.timestamp &gt; <span class="hljs-number">600000</span>) { <span class="hljs-comment">// 10mins</span>
      <span class="hljs-built_in">localStorage</span>.removeItem(url);
      data = <span class="hljs-literal">null</span>;
    }
  }

  <span class="hljs-keyword">if</span> (!data) { <span class="hljs-comment">// load fresh</span>
    data = <span class="hljs-keyword">await</span> fetch(url).then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json());
    data.timestamp = <span class="hljs-built_in">Date</span>.now();
    <span class="hljs-built_in">localStorage</span>.setItem(url, <span class="hljs-built_in">JSON</span>.stringify(data));
  }

  <span class="hljs-keyword">return</span> data;
}
</code></pre>
<h2 id="heading-my-proposal">My proposal</h2>
<p>A very neat, but little-used solution for that, is to instead leverage the browser's internal HTTP cache, as shown below:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// PROPOSAL: Fetch using HTTP Caching</span>
<span class="hljs-keyword">const</span> loadData = <span class="hljs-keyword">async</span> (url) =&gt; (
  url += <span class="hljs-string">"?cacheBust="</span> + ~~(<span class="hljs-built_in">Date</span>.now()/<span class="hljs-number">60000</span>/<span class="hljs-number">10</span><span class="hljs-comment">/*mins*/</span>),
  <span class="hljs-keyword">await</span> fetch(url, {<span class="hljs-attr">cache</span>: <span class="hljs-string">"force-cache"</span>})
    .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
);
</code></pre>
<p>Here caching is accomplished by a combination of:<br />a) an additional parameter to the Url specifying the TTL and<br />b) an extra fetch-API parameter <code>{cache: "force-cache"}</code></p>
<h2 id="heading-unfortunately-there-is-no-free-lunch">Unfortunately, there is no free lunch</h2>
<p>First of all, keep in mind that some APIs might not like the additional parameter. Second, accessing the Browsers HTTP Cache (on disk) will take 2–10 ms, while response times from localStorage (in memory) are usually way below 1 ms.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672154481415/e5f37e42-1587-49ce-9826-0c1870c06f5a.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Using this little hack, the code base becomes much leaner, with only a few minor disadvantages to keep in mind. For me, it's running fine for years. So if it suits your use case, don't hesitate to take this idea and share your feedback.</p>
]]></content:encoded></item><item><title><![CDATA[Hello World]]></title><description><![CDATA[Going forward I will try to make posting a habit. Not everything will be super original or even good, but it will certainly help me to practice my writing and even more important improve my thinking.
So let's go...]]></description><link>https://blog.mathiasnitzsche.de/hello-world</link><guid isPermaLink="true">https://blog.mathiasnitzsche.de/hello-world</guid><dc:creator><![CDATA[Mathias Nitzsche]]></dc:creator><pubDate>Tue, 20 Dec 2022 23:21:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671610714109/Xe39_rV26.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Going forward I will try to make posting a habit. Not everything will be super original or even good, but it will certainly help me to practice my writing and even more important improve my thinking.</p>
<p>So let's go...</p>
]]></content:encoded></item></channel></rss>