Maxwell AntonucciJournalist turned full-time coder, part-time ponderer.2023-08-03T00:00:00Zhttps://www.maxwellantonucci.com/Max Antonucci
Does Integrity Allow Failure?
2019-05-05T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/05/05/integrity/<p>Integrity is <strong>acting consistently with your moral values.</strong> But how consistent does a person's actions need to be before they lose their integrity?</p>
<p>In most cases, who I am and who my morals want me to be don't agree. As a (presumed) human, my desires often clash with my morals. I'm not writing the specific morals I struggle with here, so let's use a vegetarian as an example. Someone conflicted between moral objections to meat and their body's craving for meat.</p>
<p>Integrity is the work this vegetarian does to cut meat from their diet. But what if they crave meat so much, one day they cave and eat a hamburger? They feel so ashamed they avoid eating meat again for a year. Do they still have integrity? Or does that slip-up mean they're trying and failing to have it?</p>
<p>What about if they eat meat once every two years? Every six months? Once a month? Every two weeks? Once a week? At what point does this person move from "has integrity" to "doesn't have integrity?"</p>
<p>Another option for integrity is a sliding scale, not a black and white label. A vegetarian who eats meat once a month has some integrity, but one who only eats it once a year has more. This already sounds more reasonable.</p>
<p>If that's the case, the question's no longer "do I have integrity?" It's "do I have as much integrity as I want?"</p>
<p>I'm asking these questions because integrity is a huge part of most people's identities, myself included. It's easy to be selfish, amoral and acting only on impulse. It's harder to have strong morals and act on those morals. <strong>In a way, measuring integrity is one measure of how human we are against how animal we are.</strong> It's asking how human we want to be. How human we <em>can</em> be before we fail.</p>
<p>I can't say for sure how much integrity someone, even myself, should strive for. But considering it as one measure of a person's self-identified humanity, it's worth fighting for as much as possible. Even if that means failing once a year, once every six months, once a week, or every day.</p>
<p>Because if we're not trying our damnest to wring as much integrity from ourselves as possible, are we even worthy of being human?</p>
When Refactoring your Responsive CSS Backfires
2019-05-20T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/05/20/css-refactor-backfire/<p>When Refactoring your Responsive CSS Backfires </p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/css-refactor-backfires.png" alt="Post featured image"></p><p>A few weeks ago, <a href="https://dev.to/jnschrag/refactoring-the-worst-code-i-ve-ever-written-42c7">Dev.to's Jaqcue Schrag posted about refactoring the worst code she'd ever written</a>. I saw it as both an insight into solving old problems with new thinking, and a push to refactor old code of my own.</p>
<p>I dug up the repo with my Sass template for building an Atomic stylesheet, which was long overdue for updates anyway. This post focuses on refactoring one of the most important, and arguably worst-written, parts of the codebase. To my surprise, I actually wound up refactoring the code <em>too</em> well and created an even worse problem I had to solve afterwards.</p>
<p>Such is refactoring, the plot to most romantic comedies, and life itself.</p>
<h2 id="the-wet-responsive-class-setup">The WET Responsive Class Setup <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/20/css-refactor-backfire/#the-wet-responsive-class-setup">#</a></h2>
<p>Several styles in my Atomic CSS setup are built as responsive classes, whose styles can kick in or override others are different breakpoints. For instance, take a <code>div</code> like this.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>atomic-p-base atomic-p-double-md<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> I'm a div!<br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>In a nutshell, the <code>atomic-p-base</code> class gives some padding, and the <code>atomic-p-double-md</code> class overrides that at on larger screens.</p>
<p>This works, but there's two things I wanted to change in my refactor.</p>
<p>First, I wanted <code>md</code> added to the class name differently. Atomic classes should clearly communicate their function at a glance, and writing both the name and breakpoint label with dashes blurs them together too much. <a href="https://tailwindcss.com/">Tailwind CSS</a> uses a colon syntax, such as <code>md:px-4</code>. I wanted to imitate this and change my class name to <code>atomic-p-double:md</code> for the same effect.</p>
<p>Second, the Sass generating this is too WET. The code for the breakpoints and media queries are DRY enough, as you can see here.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Map for the breakpoints and max width</span><br /><span class="token property"><span class="token variable">$breakpoint-map</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span><br /> <span class="token property">xs</span><span class="token punctuation">:</span> 0px<span class="token punctuation">,</span><br /> <span class="token property">sm</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>480px<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token property">md</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>800px<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token property">max</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>1200px<span class="token punctuation">)</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">// Mixin for fast media queries based on the breakpoint map</span><br /><span class="token keyword">@mixin</span> <span class="token function">larger-than</span><span class="token punctuation">(</span><span class="token variable">$point-name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">@if</span> <span class="token punctuation">(</span><span class="token variable">$point-name</span> <span class="token operator">!=</span> <span class="token string">'xs'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token property"><span class="token variable">$width</span></span><span class="token punctuation">:</span> <span class="token function">map-get</span><span class="token punctuation">(</span><span class="token variable">$breakpoint-map</span><span class="token punctuation">,</span> <span class="token variable">$point-name</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> <span class="token variable">$width</span><span class="token punctuation">)</span></span> <span class="token punctuation">{</span> <span class="token keyword">@content</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span> <span class="token keyword">@else</span> <span class="token punctuation">{</span><br /> <span class="token keyword">@content</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>However, if I want to make a new group of classes responsive, I need to rewrite the below logic for making and adding the class name labels each time.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$bp-label</span>, <span class="token variable">$bp</span> in <span class="token variable">$breakpoint-map</span> </span><span class="token punctuation">{</span><br /><br /> <span class="token property"><span class="token variable">$bp-label-final</span></span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">@if</span> <span class="token punctuation">(</span><span class="token variable">$bp-label</span> <span class="token operator">!=</span> <span class="token string">'xs'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property"><span class="token variable">$bp-label-final</span></span><span class="token punctuation">:</span> <span class="token string">'-'</span> <span class="token operator">+</span> <span class="token variable">$bp-label</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">@include</span> <span class="token function">larger-than</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$label</span>, <span class="token variable">$length</span> in <span class="token variable">$spacing-map</span> </span><span class="token punctuation">{</span><br /> <span class="token comment">// Margin</span><br /> <span class="token selector"><span class="token variable">#{$g-nmsp}</span>m-<span class="token variable">#{$label}</span><span class="token variable">#{$bp-label-final}</span> </span><span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token selector"><span class="token variable">#{$g-nmsp}</span>mt-<span class="token variable">#{$label}</span><span class="token variable">#{$bp-label-final}</span> </span><span class="token punctuation">{</span> <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token selector"><span class="token variable">#{$g-nmsp}</span>mr-<span class="token variable">#{$label}</span><span class="token variable">#{$bp-label-final}</span> </span><span class="token punctuation">{</span> <span class="token property">margin-right</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token selector"><span class="token variable">#{$g-nmsp}</span>mb-<span class="token variable">#{$label}</span><span class="token variable">#{$bp-label-final}</span> </span><span class="token punctuation">{</span> <span class="token property">margin-bottom</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token selector"><span class="token variable">#{$g-nmsp}</span>ml-<span class="token variable">#{$label}</span><span class="token variable">#{$bp-label-final}</span> </span><span class="token punctuation">{</span> <span class="token property">margin-left</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Having to write out the logic for <code>$bp-label-final</code> repeatedly isn't ideal. Especially since, if I want to change the naming, I'd need to make that change in several places. So both refactors come down to moving this logic into a Sass mixin.</p>
<p><em>Little did I know the Sass code didn't agree with my plans...</em></p>
<h2 id="the-first-refactor">The First Refactor <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/20/css-refactor-backfire/#the-first-refactor">#</a></h2>
<p>Setting aside the CSS plot twist for now, this was my first attempt at the "responsive class name" mixin.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@mixin</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token variable">$class-name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$bp-label</span>, <span class="token variable">$bp</span> in <span class="token variable">$breakpoint-map</span> </span><span class="token punctuation">{</span><br /><br /> <span class="token property"><span class="token variable">$bp-label-final</span></span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /> <span class="token keyword">@if</span> <span class="token punctuation">(</span><span class="token variable">$bp-label</span> <span class="token operator">!=</span> <span class="token string">'xs'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property"><span class="token variable">$bp-label-final</span></span><span class="token punctuation">:</span> \<span class="token punctuation">:</span> <span class="token operator">+</span> <span class="token variable">$bp-label</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">@include</span> <span class="token function">larger-than</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token selector"><span class="token variable">#{$g-nmsp}</span><span class="token variable">#{$class-name}</span><span class="token variable">#{$bp-label-final}</span> </span><span class="token punctuation">{</span><br /> <span class="token keyword">@content</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>It's a pretty straightforward move of pulling that logic into a reusable mixin, right? All I need to do is pass in the class name, and several responsive classes will be created.</p>
<p>You'll also see the other refactor goal reached in this line.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@if</span> <span class="token punctuation">(</span><span class="token variable">$bp-label</span> <span class="token operator">!=</span> <span class="token string">'xs'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property"><span class="token variable">$bp-label-final</span></span><span class="token punctuation">:</span> \<span class="token punctuation">:</span> <span class="token operator">+</span> <span class="token variable">$bp-label</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre>
<p>The breakpoint label is being added with a namespaced colon, making it end with <code>:md</code> and not <code>-md</code>. Just like Tailwind!</p>
<p>All that's left is replacing the repeated logic in the codebase, like with the responsive classes that add margins.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$label</span>, <span class="token variable">$length</span> in <span class="token variable">$spacing-map</span> </span><span class="token punctuation">{</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token string">'m-#{$label}'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token string">'mt-#{$label}'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token string">'mr-#{$label}'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">margin-right</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token string">'mb-#{$label}'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">margin-bottom</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token string">'ml-#{$label}'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">margin-left</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This reads even better with simpler responsive classes, like those for text alignment.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token string">'text-center'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token string">'text-right'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">text-align</span><span class="token punctuation">:</span> right<span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token string">'text-left'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">text-align</span><span class="token punctuation">:</span> left<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre>
<h2 id="the-cascade-ruins-my-fun">The Cascade Ruins My Fun <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/20/css-refactor-backfire/#the-cascade-ruins-my-fun">#</a></h2>
<p>I later found a subtle difference with how the CSS is generated that renders much of this work useless. Stop and look if you didn't figure it out yet!</p>
<p>Done? Let's continue.</p>
<p>The difference is the order these responsive classes are made in. The first version took a group of classes, made the base versions of each, then made the responsive versions based on the breakpoints in ascending order. The result was something like this:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.atomic-text-center</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> center<br /><span class="token punctuation">}</span><br /><br /><span class="token selector">.atomic-text-right</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> right<br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 30rem<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.atomic-text-center\:sm</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> center<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 30rem<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.atomic-text-right\:sm</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> right<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 50rem<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.atomic-text-center\:md</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> center<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 50rem<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.atomic-text-right\:md</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> right<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>The new one does this differently. The mixin only takes one class at a time. It loops through all the breakpoints for that class, then starts over at the next one.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.atomic-text-center</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> center<br /><span class="token punctuation">}</span><br /><br /><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 30rem<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.atomic-text-center\:sm</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> center<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 50rem<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.atomic-text-center\:md</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> center<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token selector">.atomic-text-right</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> right<br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 30rem<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.atomic-text-right\:sm</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> right<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 50rem<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.atomic-text-right\:md</span> <span class="token punctuation">{</span><br /> <span class="token property">text-align</span><span class="token punctuation">:</span> right<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This seems like nothing, but this is CSS. Seemingly inconsequential changes can destroy the whole thing.</p>
<p>The key is <strong>CSS media queries don't increase a class's specificity.</strong> Each class in these compiled sheets have the same specificity, so they override each other based on the order. Styles lower on the sheet override ones before it.</p>
<p>In this context, I want classes for larger screens to <em>always</em> override those on smaller screens. This only works when all the larger breakpoint classes are placed further down. That's how it worked before, but my changes undid that.</p>
<p>Look back to updated example of compiled CSS from the refactor. Let's say I had an element like this.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>atomic-text-right atomic-text-center:md<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>In the refactored CSS, <code>atomic-text-right</code> is lower in the cascade than <code>atomic-text-center:md</code>. <strong>Even though the responsive class should kick in, the base class overrides it when it shouldn't.</strong> This makes the responsive styling classes have become so inconsistent they border on useless. It's a case of over-fitting, or making the code too focused on solving on one problem that it creates others.</p>
<p>Whenever someone says CSS is easy or "not a real programming language," remember cases like this!</p>
<h3 id="the-second-refactor">The Second Refactor <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/20/css-refactor-backfire/#the-second-refactor">#</a></h3>
<p>As with most cases of over-fitting I've encountered, I needed to take some steps backward. Moving both the naming logic and breakpoints loop into the mixin was too much. So I had the mixin only deal with naming.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@mixin</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">,</span> <span class="token variable">$class-name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token property"><span class="token variable">$bp-label-final</span></span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /> <span class="token keyword">@if</span> <span class="token punctuation">(</span><span class="token variable">$bp-label</span> <span class="token operator">!=</span> <span class="token string">'xs'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property"><span class="token variable">$bp-label-final</span></span><span class="token punctuation">:</span> \<span class="token punctuation">:</span> <span class="token operator">+</span> <span class="token variable">$bp-label</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">@include</span> <span class="token function">larger-than</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token selector"><span class="token variable">#{$g-nmsp}</span><span class="token variable">#{$class-name}</span><span class="token variable">#{$bp-label-final}</span> </span><span class="token punctuation">{</span><br /> <span class="token keyword">@content</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This change means when I want responsive classes, I need to loop through my breakpoint map again. I also need to pass in the breakpoint label to make the right class name.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// For Margin classes</span><br /><span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$bp-label</span>, <span class="token variable">$bp</span> in <span class="token variable">$breakpoint-map</span> </span><span class="token punctuation">{</span><br /> <span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$label</span>, <span class="token variable">$length</span> in <span class="token variable">$spacing-map</span> </span><span class="token punctuation">{</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">,</span> <span class="token string">'m-#{$label}'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">,</span> <span class="token string">'mt-#{$label}'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">,</span> <span class="token string">'mr-#{$label}'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">margin-right</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">,</span> <span class="token string">'mb-#{$label}'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">margin-bottom</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">,</span> <span class="token string">'ml-#{$label}'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">margin-left</span><span class="token punctuation">:</span> <span class="token variable">$length</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token comment">// Also for text alignment classes</span><br /><span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$bp-label</span>, <span class="token variable">$bp</span> in <span class="token variable">$breakpoint-map</span> </span><span class="token punctuation">{</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">,</span> <span class="token string">'text-center'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">,</span> <span class="token string">'text-right'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">text-align</span><span class="token punctuation">:</span> right<span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">@include</span> <span class="token function">rsp-class</span><span class="token punctuation">(</span><span class="token variable">$bp-label</span><span class="token punctuation">,</span> <span class="token string">'text-left'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">text-align</span><span class="token punctuation">:</span> left<span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>It's less DRY than the first refactor, but still much DRYer from where I started. The naming logic was the most burdensome and likely to change, so getting that into a single mixin is still a victory.</p>
<h2 id="an-ultimately-successful-refactor">An Ultimately Successful Refactor <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/20/css-refactor-backfire/#an-ultimately-successful-refactor">#</a></h2>
<p>There's still many refactors in store for my Atomic CSS template, but this was the biggest. It was also the most insightful, since it's a reminder of how tough refactoring code is. What seems right can actually make the code worse if you're not careful. Finding the best solutions with minimal side-effects is the truly tough part, and takes compromise (like accepting my new code can't be 100% dry).</p>
<p>Still, problem-solving like this is what makes programming so enjoyable to me. Even though refactoring is a never-ending battle, each one makes us a little stronger. As Jacque wrote in the post that inspired this one, that growth should be celebrated. So I look forward to the next refactor puzzles like this one!</p>
The Three Little Creational Patterns - A Design Patterns Intro
2019-05-30T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/05/30/three-little-creational-patterns/<p>The Three Little Creational Patterns - A Design Patterns Intro</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/three-little-creational-patterns.jpg" alt="Post featured image"></p><p>Design patterns are essential for programmers to keep in mind, at least to me. These are established solutions to common problems which help keep code maintainable and loosely coupled. The more one knows them, the easier it gets to solve all the problems we face.</p>
<p>Once you learn them you see them everywhere. I use adapters for connecting APIs, singletons for Ember services, state and observers for managing UIs, and facades for both managing objects and fooling my relatives on holidays.</p>
<p>Yet as someone without a computer science background, learning them was a struggle. Every explanation or book was riddled with jargon to sift through. Some of them I <em>still</em> don't quite understand. I barely know how the Flyweight pattern works and anyone who says they do is a liar.</p>
<p>So my idea was explaining design patterns with stories. Stories that are also well-established and solve common problems, but are easier to understand. That is, <strong>fairy tales!</strong></p>
<h2 id="introducing-design-patterns-as-fairy-tales">Introducing Design Patterns as Fairy Tales <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/30/three-little-creational-patterns/#introducing-design-patterns-as-fairy-tales">#</a></h2>
<p>This series is to help people learn the basic functions and uses for design patterns. The examples are bare-bones and a jumping-off point for learning more. They're also in JavaScript, but the ideas apply to any object-oriented language.</p>
<p>Here I'm going to look at <strong>the five creational design patterns. These are patterns to create and manage objects that are more maintainable and with fewer side-effects.</strong></p>
<p>And when it comes to creating things, I think of the Three Little Pigs! Let's begin.</p>
<h2 id="building-a-straw-house-with-a-factory">Building a Straw House with a Factory <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/30/three-little-creational-patterns/#building-a-straw-house-with-a-factory">#</a></h2>
<p>In this version of the fairy tale, let's say each little pig is breaking into the real estate market. The first pig, naturally, does this by making straw houses. He decides to make them with JavaScript classes.</p>
<p>The pig writes this base class for making a straw house. The only argument it needs is the number of needed straw bales.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">StrawHouse</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">straw</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>straw <span class="token operator">=</span> straw<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>As the orders come in, the pig realizes this class isn't efficient for making lots of houses. Customers give him the height of the house they want and if they want the house reinforced with more straw. The pig has to do the math each time, sometimes the same operations more than once.</p>
<p>Creating so many house instances this way is exhausting, so the pig uses the Factory Pattern to manage the work behind making each one.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">StrawHouseFactory</span> <span class="token punctuation">{</span><br /> <span class="token keyword">static</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token parameter">height<span class="token punctuation">,</span> specs</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> strawBase <span class="token operator">=</span> <span class="token punctuation">(</span>specs <span class="token operator">===</span> <span class="token string">'reinforced'</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">350</span> <span class="token operator">:</span> <span class="token number">150</span><span class="token punctuation">,</span><br /> amountOfStraw <span class="token operator">=</span> height <span class="token operator">*</span> strawBase<span class="token punctuation">;</span><br /><br /> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">StrawHouse</span><span class="token punctuation">(</span>amountOfStraw<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p><strong>This straw house factory lets him quickly create a different straw house from the info clients give him, doing the math and returns the desired <code>StrawHouse</code> class instance.</strong> This is a simple yet powerful benefit, which makes sense since the factory is arguably the simplest creational pattern.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> smallStrawHouse <span class="token operator">=</span> StrawHouseFactory<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> strongStrawHouse <span class="token operator">=</span> StrawHouseFactory<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">,</span> <span class="token string">'reinforced'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>As a bonus, the house class and the factory class aren't coupled together too closely. He could change either class fairly easily without breaking the other. That's a common benefit you'll see in other creational patterns, and indeed all design patterns.</p>
<h2 id="building-a-stick-house-with-a-prototype">Building a Stick House with a Prototype <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/30/three-little-creational-patterns/#building-a-stick-house-with-a-prototype">#</a></h2>
<p>The second pig is making stick houses but is facing a different problem. All his clients want to create neighborhoods with similar-looking stick houses. He could try the factory method his brother used for straw houses, but he'd be making the same type of stick house over and over. Writing code to produce the same instances is repetitive and he wants something more efficient.</p>
<p>The second pig uses the Prototype pattern instead. Let's say a group of clients all want a small stick house. <strong>Instead of making multiple instances of the stick house for them, he'll make only one (a prototype) and include a method to copy it as needed.</strong></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">StickHouse</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">height<span class="token punctuation">,</span> sticks</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">=</span> height<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>sticks <span class="token operator">=</span> sticks<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">StickHousePrototype</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">height</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">=</span> height<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>sticks <span class="token operator">=</span> height <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">copy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">StickHouse</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>sticks<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This is less repetitive and ensures each one is exactly the same. He could even make changes to each copy for extra flexibility.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> smallStickHouse <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StickHousePrototype</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> largeStickHouse <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StickHousePrototype</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> housesForFriends <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token string-property property">'Amy'</span><span class="token operator">:</span> smallStickHouse<span class="token punctuation">.</span><span class="token function">copy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token string-property property">'Bob'</span><span class="token operator">:</span> smallStickHouse<span class="token punctuation">.</span><span class="token function">copy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token string-property property">'Cole'</span><span class="token operator">:</span> smallStickHouse<span class="token punctuation">.</span><span class="token function">copy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><br /> <span class="token string-property property">'Dingus'</span><span class="token operator">:</span> largeStickHouse<span class="token punctuation">.</span><span class="token function">copy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token string-property property">'Eragon'</span><span class="token operator">:</span> largeStickHouse<span class="token punctuation">.</span><span class="token function">copy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br /><span class="token punctuation">}</span></code></pre>
<p>Overall this pattern works best if you need lots of instances that are entirely or mostly the same.</p>
<h2 id="building-a-brick-house-with-a-builder">Building a Brick House with a Builder <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/30/three-little-creational-patterns/#building-a-brick-house-with-a-builder">#</a></h2>
<p>The third pig is selling brick houses, a more ambitious goal. Brick houses are trickier and take several steps. Plus due to their newness in the forest, clients often put off deciding on how big it should be until partway through. The third pig realizes he needs a pattern that can handle all this extra complexity without getting overwhelmed.</p>
<p>He stumbles upon the Builder pattern and his piggie prayers are answered!</p>
<p>This is the third pig's base class for making a brick house. It needs the three size dimensions and the amount of cement to stick the bricks together.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">BrickHouse</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">width<span class="token punctuation">,</span> length<span class="token punctuation">,</span> height<span class="token punctuation">,</span> cement</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">=</span> width<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>length <span class="token operator">=</span> length<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">=</span> height<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>cement <span class="token operator">=</span> cement<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>The pig then writes his Builder class. The main things he wants from it are:</p>
<ul>
<li>Individual methods for setting each size dimension. The builder should be able to take a few, pause to run other code, then resume where it left off.</li>
<li>Methods to calculate how much cement is needed once the full size is known.</li>
<li>A final method to take all this info and return the finished brick house.</li>
</ul>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">BrickHouseBuilder</span> <span class="token punctuation">{</span><br /> <span class="token function">setWidth</span><span class="token punctuation">(</span><span class="token parameter">width</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">=</span> width<span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">setLength</span><span class="token punctuation">(</span><span class="token parameter">length</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>length <span class="token operator">=</span> length<span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">setHeight</span><span class="token punctuation">(</span><span class="token parameter">height</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">=</span> height<span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">addCement</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>cement <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getCementBase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getCementForBetweenBricks</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">getFloorSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>width <span class="token operator">*</span> <span class="token keyword">this</span><span class="token punctuation">.</span>length<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">getCementForBetweenBricks</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getFloorSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">0.25</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">getCementBase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getFloorSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>height <span class="token operator">/</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">BrickHouse</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>width<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>height<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>length<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>cement<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>It's a lot to take in, I know. But know the pig can call each method, with whatever data it needs, to carefully build each house.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> newBrickHouse <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BrickHouseBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> smallBrickHouse <span class="token operator">=</span> newBrickHouse<span class="token punctuation">.</span><span class="token function">setWidth</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setLength</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setHeight</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addCement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>It also works when he has to pause construction in the code.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> largeBrickHouse <span class="token operator">=</span> newBrickHouse<span class="token punctuation">.</span><span class="token function">setWidth</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setLength</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">// Extra calculations here as the client decides what to do</span><br /><br />largeBrickHouse<span class="token punctuation">.</span><span class="token function">setHeight</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addCement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><strong>As you can see, Builders are great for abstracting away more complex steps and calculations needed for making larger objects, and over multiple statements.</strong></p>
<h2 id="building-a-business-with-a-singleton">Building a Business with a Singleton <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/30/three-little-creational-patterns/#building-a-business-with-a-singleton">#</a></h2>
<p>Let's fast forward this fairy tale into the future. The three little pigs meet the big bad wolf, and they all form a real estate company called the Pigs and Wolf Partners Real Estate LLC. It's a great new company, and they want to manage their company info with JavaScript.</p>
<p>The three pigs realize they can't use any of patterns from before since they're made for multiple instances of a class. There's only one instance of their company, therefore only one instance of that class. Otherwise, wannabe real-estate animals may try to copy and take over their life's work!</p>
<p>That's where singletons shine. <strong>Singletons are set up so only one instance can be made. Any attempts to create a new one refer back to the original.</strong></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">RealEstateCompany</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">employees</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> RealEstateCompany<span class="token punctuation">.</span>instance <span class="token operator">===</span> <span class="token string">'object'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> RealEstateCompany<span class="token punctuation">.</span>instance<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> RealEstateCompany<span class="token punctuation">.</span>instance <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>employees <span class="token operator">=</span> employees<span class="token punctuation">;</span><br /><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Below you'll see someone trying to make two instances of the company, the second one being fake with different other wildlife.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> company <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RealEstateCompany</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'Pig 1'</span><span class="token punctuation">,</span> <span class="token string">'Pig 2'</span><span class="token punctuation">,</span> <span class="token string">'Pig 3'</span><span class="token punctuation">,</span> <span class="token string">'Wolf'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> fakeCompany <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RealEstateCompany</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'Zebra'</span><span class="token punctuation">,</span> <span class="token string">'Aardvark'</span><span class="token punctuation">,</span> <span class="token string">'Chris Pratt'</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre>
<p>Since it's a singleton, <code>fakeCompany</code> will return the same as <code>company</code>. The pigs can then reference their real company anywhere in their program and get the original instance, including any changes done to it elsewhere. A proper singleton is a reliable "single source of truth."</p>
<h2 id="taking-over-the-housing-market-with-an-abstract-factory">Taking over the Housing Market with an Abstract Factory <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/30/three-little-creational-patterns/#taking-over-the-housing-market-with-an-abstract-factory">#</a></h2>
<p>The pigs have it all going for them. They've got three types of houses in the market, they've got a company, they've each got personal pools and steady girlfriends they hope to one day marry. One thing they also have is large-scale disorganization.</p>
<p>For making all their houses, the pigs need to manage a lot of creational patterns:</p>
<ul>
<li>A factory for straw houses</li>
<li>A prototype maker for stick houses</li>
<li>A builder for brick houses.</li>
</ul>
<p>Thankfully there's one last creational pattern to manage them all: the Abstract Factory!</p>
<p><strong>While the regular factory creates instances of a single class, abstract factories juggle making instances of multiple classes.</strong> The pigs need to manage not one, but three. An abstract factory can call any classes they need, and even add some extra logic to cover common use cases.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">PigHouseAbstractFactory</span> <span class="token punctuation">{</span><br /> <span class="token keyword">static</span> <span class="token function">strawHouse</span><span class="token punctuation">(</span><span class="token parameter">size</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>size <span class="token operator">===</span> <span class="token string">'large'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> StrawHouseFactory<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br /> StrawHouseFactory<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">static</span> <span class="token function">stickHouse</span><span class="token punctuation">(</span><span class="token parameter">size</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>size <span class="token operator">===</span> <span class="token string">'large'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">newStickHousePrototype</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">copy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">newStickHousePrototype</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">copy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">static</span> <span class="token function">brickHouse</span><span class="token punctuation">(</span><span class="token parameter">size</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>size <span class="token operator">===</span> <span class="token string">'large'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">BrickHouseBuilder<span class="token punctuation">.</span>width</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">height</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">height</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getCement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">BrickHouseBuilder<span class="token punctuation">.</span>width</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">height</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getCement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This pattern lets them fill any order starting with a single class, and without coupling any dependent classes too tightly.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> smallStrawHouse <span class="token operator">=</span> PigHouseAbstractFactory<span class="token punctuation">.</span><span class="token function">strawHouse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> largeStrawHouse <span class="token operator">=</span> PigHouseAbstractFactory<span class="token punctuation">.</span><span class="token function">strawHouse</span><span class="token punctuation">(</span><span class="token string">'large'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> smallStickHouse <span class="token operator">=</span> PigHouseAbstractFactory<span class="token punctuation">.</span><span class="token function">stickHouse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> largeStickHouse <span class="token operator">=</span> PigHouseAbstractFactory<span class="token punctuation">.</span><span class="token function">stickHouse</span><span class="token punctuation">(</span><span class="token string">'large'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> smallBrickHouse <span class="token operator">=</span> PigHouseAbstractFactory<span class="token punctuation">.</span><span class="token function">brickHouse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> largeBrickHouse <span class="token operator">=</span> PigHouseAbstractFactory<span class="token punctuation">.</span><span class="token function">brickHouse</span><span class="token punctuation">(</span><span class="token string">'large'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Looks like the pigs have a happy ending in this fairy tale and a bright future in real estate.</p>
<h2 id="the-design-pattern-quest-has-only-begun">The Design Pattern Quest Has Only Begun <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/05/30/three-little-creational-patterns/#the-design-pattern-quest-has-only-begun">#</a></h2>
<p>I hope to cover all 23 of the classic Gang of Four design patterns throughout this series. These posts are by no means all you need to know about them, but I hope they serve as simple foundations for learning each one's complexities. I struggled to find beginner-friendly intros when learning them, and hope these help others avoid the same fate.</p>
<p><em>To Be Continued...</em></p>
Goldilocks and the Three Behavioral Patterns - A Design Patterns Intro
2019-06-12T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/06/12/goldilocks-three-behavioral-patterns/<p>Goldilocks and the Three Behavioral Patterns - A Design Patterns Intro</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/goldilocks-three-behavioral-patterns.jpg" alt="Post featured image"></p><p>Welcome to the second entry in my "Design Pattern Fairy Tales" series!</p>
<p>This series aims to give new coders, or those without a computer science background, a basic intro to design patterns. These are established solutions to common programming problems and are quite useful to know. However, I had a hard time finding explanations for them not drowning in jargon. This series aims to fix this by explaining them in a context we all know - fairy tales!</p>
<p>This post moves our fantastical adventure from creational to behavioral patterns. While creational patterns were ways to make new objects, behavioral patterns are ways to make multiple objects actively work together for complex tasks. There's actually more behavioral patterns than any of the three groups, so I'm devoting two posts to covering them all.</p>
<p>Here I'm going to cover the first batch of behavioral patterns using a fairy tale focused on the bad behavior of its protagonist: <em>Goldilocks and the Three Bears!</em></p>
<h2 id="getting-the-bikes-ready-with-a-strategy">Getting the Bikes Ready with a Strategy <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/12/goldilocks-three-behavioral-patterns/#getting-the-bikes-ready-with-a-strategy">#</a></h2>
<p>Our version of Goldilocks starts similar to the original. The three bears (Papa Bear, Mama Bear, and Baby Bear) have cooked some porridge and set it out to cool. But here let's say they take their bikes for a ride while they wait. More fun, right?</p>
<p>The bears find their bikes and realize their new models let them change the bikes' resistance. This lets them make their trips harder or easier on themselves. The bears examine the class that makes up their bikes.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">BearBike</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">weight<span class="token punctuation">,</span> strategy</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>weight <span class="token operator">=</span> weight<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>strategy <span class="token operator">=</span> strategy<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">setWeight</span><span class="token punctuation">(</span><span class="token parameter">weight</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>weight <span class="token operator">=</span> weight<span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><br /> <span class="token function">getResistance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">strategy</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>weight<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>The <code>BearBike</code> class accepts the bear's algorithms for deciding the resistance. The actual algorithm, however, isn't there. It's passed to the bike in order to get the resistance as a <code>strategy</code>.</p>
<p>They realize this is the Strategy design pattern, where <strong>the needed algorithm(s) are kept separate from the object and passed in.</strong> This gives the bears greater control over calculating the bike's resistance, letting them write and manage the algorithms separately. They can be used here, and in any other classes they want!</p>
<p>The bears write a few functions to get the resistances they want. Papa Bear wants extra resistance for his new diet plan. Mama Bear wants less since she's sore from a big run. Baby Bear wants less since he's still growing, and an extra chunk of it removed since he's carrying extra trip gear.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">PapaBearStrategy</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">weight</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> weight <span class="token operator">*</span> <span class="token number">1.25</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">MamaBearStrategy</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">weight</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> weight <span class="token operator">*</span> <span class="token number">0.8</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">BabyBearStrategy</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">weight</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">(</span>weight <span class="token operator">*</span> <span class="token number">0.6</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">20</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>All the bears need to do now is to create class instances with their respective weights and strategies. The bikes will use each strategy to give each bear the desired resistance.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> PapaBike <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BearBike</span><span class="token punctuation">(</span><span class="token number">150</span><span class="token punctuation">,</span> PapaBearStrategy<span class="token punctuation">)</span><span class="token punctuation">;</span><br />PapaBike<span class="token punctuation">.</span><span class="token function">getResistance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 187.5</span><br /><br /><span class="token keyword">const</span> MamaBike <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BearBike</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token punctuation">,</span> MamaBearStrategy<span class="token punctuation">)</span><span class="token punctuation">;</span><br />MamaBike<span class="token punctuation">.</span><span class="token function">getResistance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 96</span><br /><br /><span class="token keyword">const</span> BabyBike <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BearBike</span><span class="token punctuation">(</span><span class="token number">75</span><span class="token punctuation">,</span> BabyBearStrategy<span class="token punctuation">)</span><span class="token punctuation">;</span><br />BabyBike<span class="token punctuation">.</span><span class="token function">getResistance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 45</span></code></pre>
<p>The bears could use even more complicated algorithms if they wanted, bringing in other classes to calculate resistance based on what they ate, their weight loss goals, or even heat and humidity. All this logic could be brought into their strategies, but since it's only being passed to the bike, nothing risks overlapping too much so they break each other. As usual, loose coupling and maintainability are design patterns perks.</p>
<h2 id="communicating-the-trip-with-an-interpreter">Communicating The Trip with an Interpreter <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/12/goldilocks-three-behavioral-patterns/#communicating-the-trip-with-an-interpreter">#</a></h2>
<p>With their new bikes ready, the bears are biking along a route. Papa Bear is at the front, letting his GPS guide them through the woods to the beach. The bears have never biked to the beach before, so they're relying a lot on the GPS to get there.</p>
<p>The problem is the GPS doesn't have an option to announce directions to a group. Papa could keep checking it and calling out where to go, but last time he did that he got distracted and crashed. So he wrote a program that would make the GPS announce new directions for them.</p>
<p>But the GPS has lots of data floating around, and it's hard to figure it all out. Papa Bear managed this by breaking down his program into small parts based on the language of what he wanted. He used the Interpreter design pattern, since <strong>it lets him design objects and makes them work together based on language elements of what the code does.</strong></p>
<p>This is a bit tough to understand (I'm still trying to myself), so it's best to see it in practice.</p>
<p>Papa Bear wants the GPS to call out sentences set up as "Turn X in around Y yards!" The first part is "turn," so he writes a class for defining a turn. The GPS sees turns only in degrees, but Papa Bear wants it as a basic left, right, or straight. So he sets up his <code>Turn</code> class with an <code>interpret</code> function that does this work for him.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Turn</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">degrees</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>degrees <span class="token operator">=</span> degrees<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token number">0</span> <span class="token operator"><</span> <span class="token keyword">this</span><span class="token punctuation">.</span>degrees <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span>degrees <span class="token operator"><</span> <span class="token number">135</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">'right'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token number">225</span> <span class="token operator"><</span> <span class="token keyword">this</span><span class="token punctuation">.</span>degrees <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span>degrees <span class="token operator"><</span> <span class="token number">360</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">'left'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">return</span> <span class="token string">'straight'</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>He moves on to distance. This one is tricky since there are two quirks with how the GPS gets the distance:</p>
<ol>
<li>The GPS measures distance in meters while the Bears are used to yards. To be fair, the GPS was made in Canada.</li>
<li>The GPS can't find the exact distance to the next turn. It gets a minimum and maximum distance, and the bears need to find the distance between them.</li>
</ol>
<p>Papa Bear addresses each problem one at a time. First, he writes a class defining a basic unit of <code>Distance</code>, which converts meters to yards.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Distance</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">meters</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>meters <span class="token operator">=</span> meters<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>meters <span class="token operator">*</span> <span class="token number">1.09361</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>He then writes an <code>AverageDistance</code> class that takes two <code>Distance</code> instances and gets the average distance between them.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">AverageDistance</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">start<span class="token punctuation">,</span> end</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>start <span class="token operator">=</span> start<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>end <span class="token operator">=</span> end<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> difference <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>end<span class="token punctuation">.</span><span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token keyword">this</span><span class="token punctuation">.</span>start<span class="token punctuation">.</span><span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> Math<span class="token punctuation">.</span><span class="token function">round</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>start<span class="token punctuation">.</span><span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> difference<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>All Papa Bear needs now is a class that takes a distance and a turn, and creates a sentence the GPS can call out to his family.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">CallOut</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">distance<span class="token punctuation">,</span> direction</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>distance <span class="token operator">=</span> distance<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>direction <span class="token operator">=</span> direction<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Go </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>direction<span class="token punctuation">.</span><span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> in around </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>distance<span class="token punctuation">.</span><span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> yards!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>All this can be put together like below. The syntax is expressive and easy to understand since we've defined the grammar of <code>distance</code> and <code>turn</code> that interprets the more abstract data. It reads less like a program and more like a sentence, where each object is one of the words.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">new</span> <span class="token class-name">CallOut</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">AverageDistance</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Distance</span><span class="token punctuation">(</span>minDistance<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Distance</span><span class="token punctuation">(</span>maxDistance<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Turn</span><span class="token punctuation">(</span>turn<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p>You can see these Interpreter objects in action below.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> turn1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CallOut</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">AverageDistance</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Distance</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Distance</span><span class="token punctuation">(</span><span class="token number">140</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Turn</span><span class="token punctuation">(</span><span class="token number">38</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />turn1<span class="token punctuation">.</span><span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Go right in around 131 yards!</span><br /><br /><span class="token keyword">const</span> turn2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CallOut</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">AverageDistance</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Distance</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Distance</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Turn</span><span class="token punctuation">(</span><span class="token number">340</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />turn2<span class="token punctuation">.</span><span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Go left in around 38 yards!</span><br /><br /><span class="token keyword">const</span> turn3 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CallOut</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">AverageDistance</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Distance</span><span class="token punctuation">(</span><span class="token number">85</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Distance</span><span class="token punctuation">(</span><span class="token number">107</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Turn</span><span class="token punctuation">(</span><span class="token number">170</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />turn3<span class="token punctuation">.</span><span class="token function">interpret</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Go straight in around 105 yards!</span></code></pre>
<p>It also makes Papa Bear easier to follow, since now the bears can make their way along the route safely and accurately!</p>
<h2 id="letting-the-porridge-cool-with-a-visitor">Letting the Porridge Cool with a Visitor <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/12/goldilocks-three-behavioral-patterns/#letting-the-porridge-cool-with-a-visitor">#</a></h2>
<p>Let's get to the other character in our fairy tale, Goldilocks! She's been wandering through the woods and, seeing a stranger's home with the door unlocked, she does what any normal person would and waltzes in to eat their food.</p>
<p>Goldilocks sees three bowls of porridge, but each is too hot to eat. She was in such a hurry to invade their home, none had enough time to cool! She wants to wait until each is just right, but doesn't know how long to wait. She looks at the code for each bowl of porridge but is surprised by what she sees.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Porridge</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">weight</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>weight <span class="token operator">=</span> weight<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>coolingTime <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">getCoolingTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>coolingTime<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">accept</span><span class="token punctuation">(</span><span class="token parameter">visitor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token function">visitor</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>The cooling time is 0, so according to the <code>Porridge</code> class, it's already ready to eat. That doesn't make sense! She also sees the class allows a <code>visitor</code>. She's not sure what that means so she looks around the kitchen for clues.</p>
<p>Eventually, she sees a function tucked away in a pantry with "visitor" in the name. It includes logic for setting a cooling time on food.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">cooldownVisitor</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">food</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>food<span class="token punctuation">.</span>weight <span class="token operator">></span> <span class="token number">15</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> food<span class="token punctuation">.</span>coolingTime <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>food<span class="token punctuation">.</span>weight <span class="token operator"><</span> <span class="token number">6</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> food<span class="token punctuation">.</span>coolingTime <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br /> food<span class="token punctuation">.</span>coolingTime <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Goldilocks sees when <code>Porridge</code> accepts this Visitor, it changes the cooling time based on the food's weight to what's needed. This works, but she's still confused. Why not write this logic directly into the class instead of in this function? She eventually sees another class like the <code>Porridge</code> one. It has similar properties and methods to make use of <code>cooldownVisitor</code>.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Coffee</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">weight</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>weight <span class="token operator">=</span> weight<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>coolingTime <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">restOnCounter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>coolingTime<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">addSuger</span><span class="token punctuation">(</span><span class="token parameter">cubes</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Let us add </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cubes<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> cubes of sugar!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">accept</span><span class="token punctuation">(</span><span class="token parameter">visitor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token function">visitor</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This helps Goldilocks see the benefit of this Visitor pattern. The cooldown logic needs to be used in multiple places, but it's impractical to have two very different classes extend off a class with this logic. <strong>Visitors give a more manageable option of separating this logic into other objects and passing them in. Now they can be used in different areas without compromising the simplicity or maintainability of other classes.</strong></p>
<p>Using this visitor, Goldilocks can create <code>Porridge</code> instances based on their weight, add the Visitor, and get the cooling times.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> PapasPorridge <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Porridge</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> MamasPorridge <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Porridge</span><span class="token punctuation">(</span><span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> BabysPorridge <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Porridge</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />PapasPorridge<span class="token punctuation">.</span><span class="token function">accept</span><span class="token punctuation">(</span>cooldownVisitor<span class="token punctuation">)</span><span class="token punctuation">;</span><br />MamasPorridge<span class="token punctuation">.</span><span class="token function">accept</span><span class="token punctuation">(</span>cooldownVisitor<span class="token punctuation">)</span><span class="token punctuation">;</span><br />BabysPorridge<span class="token punctuation">.</span><span class="token function">accept</span><span class="token punctuation">(</span>cooldownVisitor<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />PapasPorridge<span class="token punctuation">.</span><span class="token function">getCoolingTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 20</span><br />MamasPorridge<span class="token punctuation">.</span><span class="token function">getCoolingTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 10</span><br />BabysPorridge<span class="token punctuation">.</span><span class="token function">getCoolingTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 5</span></code></pre>
<p>While there's no coffee out, she can imagine looking up a coffee's cooldown time looks like.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> PapasCoffee <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Coffee</span><span class="token punctuation">(</span><span class="token number">14</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />PapasCoffee<span class="token punctuation">.</span><span class="token function">accept</span><span class="token punctuation">(</span>cooldownVisitor<span class="token punctuation">)</span><span class="token punctuation">;</span><br />PapasCoffee<span class="token punctuation">.</span><span class="token function">restOnCounter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With the cooldown logic added, she's ready to eat food in a stranger's house regardless of what may be in it!</p>
<h2 id="tasting-the-porridge-with-state">Tasting the Porridge with State <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/12/goldilocks-three-behavioral-patterns/#tasting-the-porridge-with-state">#</a></h2>
<p>With the porridge cooled, Goldilocks is ready to eat. But hungry as she is, she also wants to take a nap in the strangers' home because why not?</p>
<p>Goldilocks wants to understand when her body will be ready to sleep as she's eating the porridge. She knows the actions she's going to take - get porridge ready, eat the porridge, and finish eating it. But after the loop the visitor pattern just threw at her, she wants to clearly understand when she'll be ready. She consults some code managing her own State.</p>
<p><strong>An object's State controls what actions it is or isn't capable of, and adjusts these when the state changes.</strong> Goldilocks could be in a <code>hungry</code> state that doesn't allow her to sleep, and need to reach a <code>full</code> State first. Her State determines whether or not she can perform important things, so knowing what it is matters.</p>
<p>Goldilocks starts with the base class that her other States are built off. It makes sure all States have access to the current State, the next State, and can move to the next one.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">PersonState</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> nextState</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> state<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>nextState <span class="token operator">=</span> nextState<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">this<span class="token punctuation">.</span>nextState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>She checks her three different States too. Reading them over, she sees her State will affect what she's thinking, if she can run and if she can sleep. She also sees from the <code>super()</code> argument what the next State for each is. For example, moving on from <code>HungryState</code> changes it to <code>EatingState</code>.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">HungryState</span> <span class="token keyword">extends</span> <span class="token class-name">PersonState</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token string">'Hungry'</span><span class="token punctuation">,</span> EatingState<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>thoughts <span class="token operator">=</span> <span class="token string">"I'm hungry!"</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>canRun <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>canSleep <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">EatingState</span> <span class="token keyword">extends</span> <span class="token class-name">PersonState</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token string">'Eating'</span><span class="token punctuation">,</span> FullState<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>thoughts <span class="token operator">=</span> <span class="token string">"This is tasty!"</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>canRun <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>canSleep <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">FullState</span> <span class="token keyword">extends</span> <span class="token class-name">PersonState</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token string">'Full'</span><span class="token punctuation">,</span> HungryState<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>thoughts <span class="token operator">=</span> <span class="token string">"So full! I want to take a nap."</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>canRun <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>canSleep <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Finally, and most importantly, Goldilocks checks the <code>Person</code> class that makes up herself.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HungryState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>canSleep<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token string">'Time to find a bed! Zzzzz...'</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token string">'I can\'t sleep until I\'ve eaten!'</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">nextState</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>The <code>sleep</code> function depends on if the current State allows the person to sleep. Goldilocks needs to change the State to one that lets her sleep. She'll do this with the <code>nextState</code> function, which moves to the next State in line.</p>
<p>With that in mind, Goldilocks sits down to eat some of the porridge and checks her actions based on her State.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> Goldilocks <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />Goldilocks<span class="token punctuation">.</span>state<span class="token punctuation">.</span>thoughts<span class="token punctuation">;</span><br /><span class="token comment">// I'm hungry!</span><br />Goldilocks<span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// I can't sleep until I've eaten!</span></code></pre>
<p>She's in the <code>HungryState</code>, so she starts to eat. This triggers <code>nextState()</code> and moves her to <code>EatingState</code>. Her thoughts change with the State, but her ability to sleep doesn't.</p>
<pre class="language-javascript"><code class="language-javascript">Goldilocks<span class="token punctuation">.</span><span class="token function">nextState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />Goldilocks<span class="token punctuation">.</span>state<span class="token punctuation">.</span>thoughts<span class="token punctuation">;</span><br /><span class="token comment">// This is tasty!</span><br />Goldilocks<span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// I can't sleep until I've eaten!</span></code></pre>
<p>Once Goldilocks finishes eating, she finally reaches the <code>FullState</code>, which changes her thoughts and sleep action.</p>
<pre class="language-javascript"><code class="language-javascript">Goldilocks<span class="token punctuation">.</span><span class="token function">nextState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />Goldilocks<span class="token punctuation">.</span>state<span class="token punctuation">.</span>thoughts<span class="token punctuation">;</span><br /><span class="token comment">// So full! I want to take a nap.</span><br />Goldilocks<span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Time to find a bed! Zzzzz...</span></code></pre>
<p>Managing these State changes are difficult, but they ensure Goldilocks doesn't take actions when she's not supposed to. This is why State is often crucial for programs to only take actions when they can (or should).</p>
<p>Also note that State doesn't always change in such a predictable, orderly way. It often depends on data being received or user input, which can be much more volatile. These often make keeping the State in sync with accurate data and the view layer a tough but vital task.</p>
<p>But Goldilocks has that under control here. After eating her fill, she moves on to take a nap.</p>
<h2 id="measuring-the-return-path-with-a-template">Measuring the Return Path with a Template <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/12/goldilocks-three-behavioral-patterns/#measuring-the-return-path-with-a-template">#</a></h2>
<p>Back in the woods, the bears are at the end of their trail and want to head back. Papa Bear checks his map and sees there are three routes they can take to get home.</p>
<ol>
<li>The Valley path is the simplest way back but has a steep incline.</li>
<li>The Riverside path has an easier incline, but crossing the bridge adds more distance.</li>
<li>The Street path is the most level, but moving around cars adds increasing amounts of distance.</li>
</ol>
<p>Plus no matter what route they take, they need to take a detour around an accident that will add 10 yards.</p>
<p>There's a lot of calculations, and while some are the same for each trip, the rest is different for each route. It's a tough mix to properly manage.</p>
<p>Papa Bear realizes a Template pattern is perfect to handle this. <strong>Templates define the skeleton of an algorithm, so subclasses can change steps as needed.</strong> This is different than the strategy pattern, which swaps set algorithms around as needed. This pattern lets you change parts of the algorithm itself.</p>
<p>To start, Papa Bear creates the starting Template. It builds in the extra 10 yards each route needs.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">DistanceTemplate</span> <span class="token punctuation">{</span><br /> <span class="token function-variable function">getDistanceHome</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">distance</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">routeDistance</span><span class="token punctuation">(</span>distance<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">10</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>He includes a <code>routeDistance</code> function but doesn't define it here. That's because each subclass will define it themselves to make needed changes to the algorithm.</p>
<p>First, we have the Valley route. It needs to multiply the biking distance by its steep incline, so it's fairly simple. This part of the algorithm must be in the <code>routeDistance</code> function.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">ValleyDistance</span> <span class="token keyword">extends</span> <span class="token class-name">DistanceTemplate</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>incline <span class="token operator">=</span> <span class="token number">1.7</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function-variable function">routeDistance</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">distance</span><span class="token punctuation">)</span> <span class="token operator">=></span> distance <span class="token operator">*</span> <span class="token number">1.7</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Next is the Riverside route. It calculates for an incline and adds the extra 20 yards for crossing the bridge.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">RiversideDistance</span> <span class="token keyword">extends</span> <span class="token class-name">DistanceTemplate</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>incline <span class="token operator">=</span> <span class="token number">1.4</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>bridge <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function-variable function">routeDistance</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">distance</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>distance <span class="token operator">*</span> <span class="token number">1.4</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>bridge<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Last is the Street route. It's the most complicated, taking into account its slight incline and driving around cars. The Template pattern lets it add extra class methods to use in <code>routeDistance</code>.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">StreetDistance</span> <span class="token keyword">extends</span> <span class="token class-name">DistanceTemplate</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><br /> <span class="token function-variable function">carsDistance</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">distance</span><span class="token punctuation">)</span> <span class="token operator">=></span> Math<span class="token punctuation">.</span><span class="token function">round</span><span class="token punctuation">(</span>distance <span class="token operator">/</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token function-variable function">inclineDistance</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">distance</span><span class="token punctuation">)</span> <span class="token operator">=></span> distance <span class="token operator">*</span> <span class="token number">1.05</span><span class="token punctuation">;</span><br /><br /> <span class="token function-variable function">routeDistance</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">distance</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">inclineDistance</span><span class="token punctuation">(</span>distance<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">carsDistance</span><span class="token punctuation">(</span>distance<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>With all the routes written, all Papa Bear needs to do is create class instances and calculate the best route home. Each one returns the full algorithm built off the starting Template.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> fromValley <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ValleyDistance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />fromValley<span class="token punctuation">.</span><span class="token function">getDistanceHome</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 180</span><br /><br /><span class="token keyword">const</span> fromRiverside <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RiversideDistance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />fromRiverside<span class="token punctuation">.</span><span class="token function">getDistanceHome</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 170</span><br /><br /><span class="token keyword">const</span> fromStreet <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StreetDistance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />fromStreet<span class="token punctuation">.</span><span class="token function">getDistanceHome</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 135</span></code></pre>
<p>Looks like the street is the best way! The Template pattern let Papa Bear manage each route's complexity while not repeating code and keeping each object loosely coupled.</p>
<h2 id="waking-goldilocks-with-a-command">Waking Goldilocks with a Command <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/12/goldilocks-three-behavioral-patterns/#waking-goldilocks-with-a-command">#</a></h2>
<p>As the bears head home, Goldilocks is getting ready to sleep. But she's understandably worried about the home's owners arriving and being upset a stranger ate their food and slept in their beds. What if they scare her away? She needs to leave behind a better way they can wake her up.</p>
<p>Goldilocks has an alarm with her but is worried the home's owners won't know how to use it, or even what it is. She decides to write how to use her alarm into a Command. <strong>The Command pattern saves everything about an action into a separate object, so anything using it doesn't need to understand the action itself.</strong> They only need to get the object, run the <code>execute</code> function, and the set action does the rest.</p>
<p>Before going to sleep, Goldilocks checks over the class for her alarm.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Alarm</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>ringing <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>volume <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">quietAlarm</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>volume <span class="token operator">=</span> <span class="token number">30</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>ringing <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">loudAlarm</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>volume <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>ringing <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>If someone arrives, she'd want them to activate the <code>quietAlarm</code> function. So she writes up a Command class that takes in an alarm instance and will execute <code>quietAlarm</code> when prompted.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">WakeCommand</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">alarm</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>alarm <span class="token operator">=</span> alarm<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>alarm<span class="token punctuation">.</span><span class="token function">quietAlarm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>All Goldilocks needs to do now is create the alarm clock instance and attach it to an instance of her Command.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> alarmClock <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Alarm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> wakeGoldilocksCommand <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WakeCommand</span><span class="token punctuation">(</span>alarmClock<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Goldilocks leaves this <code>wakeGoldilocksCommand</code> object next to her and goes to sleep.</p>
<p>A short while later, the three bears arrive home. They're angry their porridge was eaten, and even madder someone's sleeping in one of their beds! Papa Bear is getting ready to roar but notices the <code>wakeGoldilocksCommand</code> next to the girl. Papa Bear doesn't know what it does, but since it's a Command pattern, he doesn't need to. The object with the needed action is already stored inside it and will do the work for him!</p>
<p>He quickly writes up a class that lets him use this Command.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Bear</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">wakeCommand</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>wakeCommand <span class="token operator">=</span> wakeCommand<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">wakeUpStranger</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>wakeCommand<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>He then makes an instance of this class as himself, passes in the <code>wakeUpGoldilocks</code> Command he found, and runs the <code>wakeUpStranger</code> function to use the Command.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> PapaBear <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Bear</span><span class="token punctuation">(</span>wakeUpGoldilocks<span class="token punctuation">)</span><span class="token punctuation">;</span><br />PapaBear<span class="token punctuation">.</span><span class="token function">wakeUpStranger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Papa Bear finds himself reaching for an unfamiliar clock and putting on a quiet alarm. Goldilocks is gently awakened from her nap, sees the bears, and runs from the house screaming. The bears shrug and they live happily ever after.</p>
<h2 id="the-design-pattern-quest-continues">The Design Pattern Quest Continues <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/12/goldilocks-three-behavioral-patterns/#the-design-pattern-quest-continues">#</a></h2>
<p>This post marks the halfway point of this design patterns and fairy tales series. There's still the remaining behavioral and structural patterns along the way. But soon we shall slay the design pattern dragons and save the programming princess in the coding company castle!</p>
<p><em>To Be Continued...</em></p>
A Metaphorical Introduction to Functional JavaScript
2019-06-25T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/<p>A Metaphorical Introduction to Functional JavaScript</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/functional-js-metaphors.jpg" alt="Post featured image"></p><p>Functional JavaScript isn't a tool, framework, 3rd-party addon, npm module, or anything else you'd add on. Functional Programming is an approach for writing code, and Functional JavaScript (FJS) is how to use that approach for JavaScript. Like all approaches, it has benefits and drawbacks, tradeoffs one makes, people who like and dislike it, and different lobbying groups in international governments.</p>
<p>I'm firmly in the "like" camp for FJS. I've been writing JavaScript (poorly and otherwise) for several years and wish I'd learned about it from the start. <strong>I've found the benefits of FJS well worth the learning curve, and it's resulted in code that's more readable, flexible, and maintainable.</strong> I struggled to nail down what it means to write FJS, but once I did I couldn't go back.</p>
<p>From the name, you'd expect Functional Programming to just be about writing lots of functions. In a way that's true, but there are several rules one must follow to achieve that. Rules that are often hard to understand both at first glance and after some Google searches.</p>
<ol>
<li>Use Pure Functions</li>
<li>Don't Mutate State</li>
<li>Declarative, not Imperative</li>
<li>Higher Order Functions</li>
</ol>
<p>In this article, I'm going to try and break down these elements of FJS in ways that are easier to understand. This isn't an exhaustive guide by any means but is meant to be a jumping off point so people can better understand more detailed, thorough resources to learn FJS.</p>
<p>Let's begin!</p>
<h2 id="keep-functions-pure">Keep Functions Pure <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#keep-functions-pure">#</a></h2>
<p>Using Pure Functions and avoiding State Mutation are perhaps the most important parts of writing FJS. Instead of starting with the usual definitions, I'm going to indulge myself and explain them with an imaginary dinner party.</p>
<h3 id="an-angel-and-a-mutant-enter-a-dinner-party...">An Angel and a Mutant Enter a Dinner Party... <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#an-angel-and-a-mutant-enter-a-dinner-party...">#</a></h3>
<p>First, imagine an angel. The angel radiates a soft, pure white with glittering wings and a serene face. They bob gently over the ground and moves with smooth yet purposeful grace. No living person can see this angel, and it passes through anything it touches.</p>
<p>Let's say this angel was in the corner of a crowded dinner party. You tell the angel they need to move across the room and stand next to the punch bowl. The angel nods and starts floating toward this spot. No one can see or touch it. No one's conversations are disturbed and no one needs to move out of their way. Thanks to all this, the angel takes the shortest possible route to the punch bowl. If the dinner party filled with entirely new guests, the angel could do this again along the exact path.</p>
<p>Now imagine almost the exact opposite of this angel: a radioactive mutant. The mutant was once human but has transformed into something grotesque. They could have any grotesque feature you want: waving tentacles, eyes all over their back, feet that are webbed and clawed, a t-shirt with a pop culture reference decades out of date, or they own a real estate business. Whatever you choose, this mutant is scary and you can't look at it too long.</p>
<p>Let's say this mutant had the same task: move from the corner of a dinner party to the punch bowl. You could imagine how horrible that would go. People would be screaming and pushing away from the mutant constantly. Plus its radioactivity would start giving random people different mutations, and guests would run from them too. The mutant would need to push and shove along an unpredictable path to reach that spot. If you restarted this scenario at a party with different guests, the radiation would make different people mutate, and the humans would panic in new ways. The mutant would need to take a different, but just as rough, route to the punch bowl.</p>
<h3 id="to-be-a-pure-function">To be a Pure Function <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#to-be-a-pure-function">#</a></h3>
<p>As you may have guessed, the angel has all the qualities of a pure function.</p>
<ol>
<li><strong>No external state is changed.</strong> The angel goes across the room without anyone or anything changing. A pure function does its job without anything outside the function changing either.</li>
<li><strong>The same input has the same results.</strong> The angel takes the same exact path to the same path every time. A pure function, when given the same input, returns the same result each time.</li>
</ol>
<p>And if the name wasn't a big enough giveaway, the mutant has all the qualities of a function that mutates state.</p>
<ol>
<li><strong>Variables outside the function are affected.</strong> The mutant affects other people by scaring party guests and making other people mutate. Impure functions change variables that exist outside of them, on purpose or by accident.</li>
<li><strong>The same input can have different results.</strong> The mutant makes random people mutate, which will change the type of panic and therefore the path the mutant takes each time. Impure functions return different values due to how they affect outside variables each time.</li>
</ol>
<p>Here's some actual JavaScript to drive all this home. Is the below <code>addNumber</code> function an angel or a mutant?</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> number <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">let</span> <span class="token function-variable function">addNumber</span> <span class="token operator">=</span> <span class="token parameter">x</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> number <span class="token operator">+=</span> x<span class="token punctuation">;</span><br /> <span class="token keyword">return</span> number<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p><code>addNumber</code> is a mutant since it changes <code>number</code>, a variable outside the function. These changes mean we could run this function twice with the same parameter and get different results.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> <span class="token comment">// 5</span><br /><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> <span class="token comment">// 10 (which is not 5)</span></code></pre>
<p>If we wanted a pure angel function, we'd rewrite one like this.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> number <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">let</span> <span class="token function-variable function">addNumbers</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> y</span><span class="token punctuation">)</span> <span class="token operator">=></span> x <span class="token operator">+</span> y<span class="token punctuation">;</span></code></pre>
<p>Instead of relying on an outside variable, we make both numbers variables that we pass in. This keeps all the function's variables in its own scope, and the same inputs give the same results.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">addNumbers</span><span class="token punctuation">(</span>number<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 5</span><br /><span class="token function">addNumbers</span><span class="token punctuation">(</span>number<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 5 (which is 5)!</span></code></pre>
<p>FJS uses pure functions since they're like angels. Angels are good and mutants are bad. Don't let the mutants win. Use pure functions.</p>
<h2 id="be-declarative%2C-not-imperative">Be Declarative, not Imperative <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#be-declarative%2C-not-imperative">#</a></h2>
<p>I've had a hard time understanding the difference between declarative and imperative programming for the longest time. Before anything else, know that <strong>declarative and imperative programming are both valid approaches with their own ups and downs.</strong> Functional programming just favors being declarative.</p>
<p>As for the specifics, let's imagine two different beings again. This time it'll be a southern belle and a stable boy. We ask both of them to fetch us a bucket of milk and give them an empty bucket for the job.</p>
<p>The southern belle is haughty and hates getting her hands dirty. She handles this task by summoning her servant and saying "I <em>do declare</em>, if there is a cow outside, bring me a bucket of milk with a bucket like this!" The servant bows, examines the bucket, leaves, and returns with a bucket of milk. It's in a different bucket that looks identical to the one we gave her. The southern belle takes the milk and hands it to us.</p>
<p>The stable boy enjoys getting his hands dirty. He handles this task by taking the bucket, going to the barn, finding a cow, and going through all the motions to milk it. He chooses the right cow, milks the cow, fills our bucket with the milk, and carries it back to us himself.</p>
<p>Both people got us the bucket of milk, albeit in very different ways. The southern belle wasn't involved in the actual steps to get the milk, she focused on <em>what</em> she needed and used her servant to get it. Meanwhile, the stable boy focused on <em>how</em> to get the milk and went through all the steps.</p>
<p>At its core, that's the difference between declarative and imperative programming. <strong>Declarative programming solves a problem based on what it needs, and avoids direct DOM or variable manipulation.</strong> This is a good fit for pure functions since they're about giving you new data and objects to avoid mutating state. Meanwhile, imperative programming changes the DOM and manipulates state, but in a more focused way that gives better control when done right.</p>
<p>For a good reminder on all this with some code examples, I simply refer you to this tweet!</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">I can’t be the only one always getting the concepts of Imperative and Declarative programming confused... right? 🙏✨⚛️🎀 <a href="https://twitter.com/hashtag/lolsobjs?src=hash&ref_src=twsrc%5Etfw">#lolsobjs</a> <a href="https://twitter.com/hashtag/CodeNewbie?src=hash&ref_src=twsrc%5Etfw">#CodeNewbie</a> <a href="https://twitter.com/hashtag/learntocode?src=hash&ref_src=twsrc%5Etfw">#learntocode</a> <a href="https://t.co/ucgQ6iBaUG">pic.twitter.com/ucgQ6iBaUG</a></p>— LOLSOB.js (@lolsobjs) <a href="https://twitter.com/lolsobjs/status/1140697401155575810?ref_src=twsrc%5Etfw">June 17, 2019</a></blockquote>
<p>When you're not writing JavaScript to manipulate DOMs, I've approached declarative programming <strong>by declaring new variables instead of mutating existing ones.</strong></p>
<p>For example, let's say you had to write a function that doubled all numbers in an array. An imperative approach would manipulate the given array directly and redefine each item.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">doubleArray</span> <span class="token operator">=</span> <span class="token parameter">array</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> array<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> array<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">+=</span> array<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">return</span> array<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>This is the code equivalent of the stable boy taking the array, doubling each item in it, and giving you a mutated version of the array. The declarative version looks quite different.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">doubleArray</span> <span class="token operator">=</span> <span class="token parameter">array</span> <span class="token operator">=></span> array<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">item</span> <span class="token operator">=></span> item <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This declarative version gives the work to another function, in this case, <code>map</code>, which already has built-in logic to go through each item (we'll cover this in a bit). This returns an array separate from the original and the first array isn't mutated, making this a pure function! As a result, this function is simpler, cleaner, safer to use, and much more in line with FJS.</p>
<p>The southern belle is simply <em>declaring</em> she wants an array with double the values, and her servant (<code>map</code>) is returning a different array to meet her request.</p>
<h2 id="use-the-right-fjs-tools">Use the Right FJS Tools <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#use-the-right-fjs-tools">#</a></h2>
<p>Okay, enough metaphors. Let's get into the nitty-gritty-codey ways to write FJS. First let's cover some of the tools you'll be using the most to write your pure, imperative functions.</p>
<h3 id="arrow-functions">Arrow functions <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#arrow-functions">#</a></h3>
<p>Arrow functions were added with ES6 and their main benefit is a shorter, sweeter function syntax. FJS means writing lots of functions, so we might as well make it easier.</p>
<p>Before arrow functions, a basic "add five to a number" function would look like this.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">addFive</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> number <span class="token operator">+</span> <span class="token number">5</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Simple functions like this can be written without the <code>function</code> keyword or the explicit return.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">addFive</span> <span class="token operator">=</span> <span class="token parameter">number</span> <span class="token operator">=></span> number <span class="token operator">+</span> <span class="token number">5</span><span class="token punctuation">;</span></code></pre>
<p>The variable first identifies the arguments, in this case <code>number</code>. You could also use parenthesis for no arguments, like with <code>()</code>, or for multiple arguments, like with <code>(number1, number2)</code>.</p>
<p>After that is the arrow, shown as <code>=></code>. Whatever expression follows is automatically returned, in this case, that's <code>number</code> with five added.</p>
<p>More complex functions can use braces for extra lines, but you'll lose the implicit <code>return</code> and need to write it out. Not as good, but still better than the first syntax.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">addFive</span> <span class="token operator">=</span> <span class="token parameter">number</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token comment">// more code here</span><br /> <span class="token keyword">return</span> number <span class="token operator">+</span> <span class="token number">5</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h3 id="array-prototype-methods">Array Prototype Methods <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#array-prototype-methods">#</a></h3>
<p>Each array has several powerful tools built into them that'll cover most, if not all, of your FJS needs. Calling them returns new, modified arrays you can easily assign to new variables. They're similar to the southern belle's servant from the declarative metaphor - they're already there, do the work for you, and give you new objects based on what you started with.</p>
<p>Let's start with one of the most basic methods, <code>map</code>. It takes each item in an array, runs it through a function to get a new value, and replaces the old value with this new one. Once it does that for each item, it returns a newly updated array.</p>
<p>Here's a tweaked example of the declarative code example from before, but using <code>map</code> to double array values.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">item</span> <span class="token operator">=></span> item <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// [4, 8, 12]</span></code></pre>
<p>You're basically using <code>map</code> to pull out each array object as <code>item</code> and say "Replace this <code>item</code> with <code>item * 2</code>."</p>
<p>You could also write the doubling function separately to make the code even more functional. Plus you can assign what <code>map</code> returns to an entirely different variable.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">double</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">,</span><br /> array <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> doubledArray <span class="token operator">=</span> array<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>double<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>array<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [2, 4, 6]</span><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>doubledArray<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [4, 8, 12]</span><br /><span class="token comment">// The original array hasn't been mutated!</span></code></pre>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">There are many great array methods to learn, with great documentation for them out there</a>. Skim over them when you have a chance!</p>
<h4 id="bonus%3A-chain-array-prototype-methods">Bonus: Chain Array Prototype Methods <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#bonus%3A-chain-array-prototype-methods">#</a></h4>
<p>One more fun fact you should know: array methods can be chained together! This lets you combine different array changes quickly and without breaking FJS rules.</p>
<p>Let's say we wanted to double each array value, then filter out the ones lower than five (<code>filter</code> is another useful method to learn later). We just need to write one extra function and add another method to our array.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">double</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">higherThanFive</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item <span class="token operator">></span> <span class="token number">5</span><span class="token punctuation">,</span><br /> array <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> doubledArray <span class="token operator">=</span> array<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>double<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>higherThanFive<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>array<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [2, 4, 6]</span><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>doubledArray<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [8, 12]</span></code></pre>
<p>Lastly, many people (like myself) often use different spacing when chaining to keep it readable. The below variable is the same as the above but easier to understand at a glance.</p>
<pre class="language-javascript"><code class="language-javascript">doubledArray <span class="token operator">=</span> array<br /> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>double<span class="token punctuation">)</span><br /> <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>higherThanFive<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="remember-reduce">Remember Reduce <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#remember-reduce">#</a></h3>
<p><code>reduce</code> is a prototype method I want to highlight since it's arguably the most powerful. On its own, it can recreate almost any other prototype method and can make more complex and powerful ones. There's <a href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)">great documentation on <code>reduce</code></a> out there, so for now just remember these important facts:</p>
<ol>
<li>Reduce is great for complex merging or manipulation of data, as long as you make sure another prototype method doesn't already do what you need.</li>
<li>Everything about other prototype methods, such as chaining and passing in functions, applies to reduce.</li>
</ol>
<p><code>reduce</code> is one of your most powerful FJS tools, so learn it well.</p>
<h2 id="higher-order-functions">Higher-order functions <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#higher-order-functions">#</a></h2>
<p>Now that we have these new ways to write functions, next is new ways to manage them. One of the best methods for FJS is making use of higher-order functions, of HOFs. Several code examples so far have made use of HOFs, but having a clearer definition of it helps with making full use of it.</p>
<p>HOFs are functions that take other functions as arguments. Remember that functions are first-class citizens in the JavaScript kingdom, so they can be:</p>
<ul>
<li>Saved to variables</li>
<li>Passed to other functions</li>
<li>Returned from other functions</li>
</ul>
<p>I wish I'd learned to make use of HOFs earlier in my career. It helped me write more functions that abstracted logic away to make programs more readable and maintainable. So getting into the mindset of "functions passing around functions" is great for FJS, but also better JavaScript in general.</p>
<p>Let's say I needed to test if many numbers were divisible by a group of other numbers. One's first instinct may be to write each function out like this.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">divisibleby3</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">n</span><span class="token punctuation">)</span> <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">divisibleby5</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">n</span><span class="token punctuation">)</span> <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">5</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">divisibleby7</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">n</span><span class="token punctuation">)</span> <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">7</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">;</span><br /><br /><span class="token function">divisibleBy3</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span><br /><span class="token function">divisibleBy5</span><span class="token punctuation">(</span><span class="token number">14</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span><br /><span class="token function">divisibleBy7</span><span class="token punctuation">(</span><span class="token number">28</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span></code></pre>
<p>This works, but you have to repeat the same expressions over and over. A solution using HOFs would look like this and get the same results.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">divideBy</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token parameter">y</span><span class="token punctuation">)</span> <span class="token operator">=></span> y <span class="token operator">%</span> x <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> divisibleBy3 <span class="token operator">=</span> <span class="token function">divideBy</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> divisibleBy5 <span class="token operator">=</span> <span class="token function">divideBy</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> divisibleBy7 <span class="token operator">=</span> <span class="token function">divideBy</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token function">divisibleBy3</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span><br /><span class="token function">divisibleBy5</span><span class="token punctuation">(</span><span class="token number">14</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span><br /><span class="token function">divisibleBy7</span><span class="token punctuation">(</span><span class="token number">28</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span></code></pre>
<p>This is complicated, so let's break it down.</p>
<ol>
<li>The <code>divideBy</code> function takes one argument, <code>x</code>, and saves it while <em>returning another function</em>. So when we call <code>divideBy(3)</code>, we're saving <code>x</code> as part of the function being returned every time.</li>
<li>We can <em>save this function to a variable</em>, such as <code>divisibleBy3</code>. This makes sense since we've already made <code>3</code> part of the function returned each time.</li>
<li>Since <code>divideBy</code> returns a function, we can now call <code>divisibleBy3</code> like a normal function. It uses both the <code>y</code> variable it gets at the call, and the <code>x</code> variable it got before.</li>
</ol>
<p>All this is an example of "currying" functions or <strong>functions that return other functions until they eventually give final functions</strong> like <code>divisibleBy3</code>. As you can see, currying in JavaScript has many examples of HOFs in use. Currying is great if you have functions with some, but not all, of their logic in common. You can create a template with the logic they have in common (a comparison operator) and pass in logic specific to each one (the number used in the operation).</p>
<p>If you don't want to save the first part of a curried function to a variable, you can use the shortcut of calling multiple arguments at the same time.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">divideBy</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token parameter">y</span><span class="token punctuation">)</span> <span class="token operator">=></span> y <span class="token operator">%</span> x <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">;</span><br /><br /><span class="token function">divideBy</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span><br /><span class="token function">divideBy</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token number">14</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span><br /><span class="token function">divideBy</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token number">28</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span></code></pre>
<p>As you can see, curried functions help your code whether you use them once or dozens of times in your program!</p>
<p>Here's another example of HOFs that takes a function as the <code>fn</code> argument. The function accepting it refers to it like any other variable.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">performMultipleTimes</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">times<span class="token punctuation">,</span> x<span class="token punctuation">,</span> fn</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> times<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token function">fn</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This function takes three arguments:</p>
<ol>
<li>The number of times to repeat the loop</li>
<li>The argument passed into the <code>fn</code> function</li>
<li>The <code>fn</code> function</li>
</ol>
<p>The function is being called inside the loop, so <code>performMultipleTimes</code> lets us call a function many times while only writing it once. All we need to do is <em>pass one function another function</em>, which we can do by <em>storing the function in a variable.</em> HOFs at work once again!</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">logString</span> <span class="token operator">=</span> <span class="token parameter">s</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token function">performMultipleTimes</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">'Greetings!'</span><span class="token punctuation">,</span> logString<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Greetings!</span><br /><span class="token comment">// Greetings!</span><br /><span class="token comment">// Greetings!</span></code></pre>
<p>If you don't use this function anywhere else and don't want to save it for later, you can also pass it directly. You can do this with or without the bracket syntax.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">performMultipleTimes</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">'Greetings!'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">s</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token function">performMultipleTimes</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">'Greetings!'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">s</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> newString <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">I am here to say '</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>s<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">'</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>newString<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Understanding HOFs is great but is especially for FJS. This style is about focusing on the power of functions, and passing functions around effectively can multiply their power and modularity.</p>
<p>However, this was hard to grasp for me and it might be the same for you. So if you (understandably) still have trouble, <a href="https://eloquentjavascript.net/05_higher_order.html">this chapter from Eloquent JavaScript does a great job breaking HOFs down further</a>.</p>
<h2 id="fjs-is-a-style%2C-not-an-absolute">FJS is a Style, not an Absolute <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/#fjs-is-a-style%2C-not-an-absolute">#</a></h2>
<p>A final note on FJS: it's a style of writing JavaScript that exists on a spectrum. It isn't simply "this is or is not FJS." <strong>You can write code with elements of FJS (like pure functions or being declarative) without needing to follow the rules. Each is a preference that, as they're put together, make your JavaScript closer to the functional paradigm.</strong></p>
<p>FJS can be tough to grasp, as you can tell by the number of links I reference for extra reading. But understanding these four topics will help you build a solid foundation for learning more. This is what holds true for me since they made everything click into place for every other article I read on FJS. Hopefully, this post can do the same for anyone else looking to learn and use it.</p>
<p><em>If you really want to go deeper into FJS, I recommend <a href="https://github.com/getify/Functional-Light-JS">Kyle Simpson's book "Functional-Light JS."</a> It goes into much deeper detail on functional programming and JavaScript, and you can read it for free on Github!</em></p>
Good Writing is like a Firework
2019-07-05T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/07/05/writing-fireworks/<p>Good Writing is like a Firework</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/writing-firework.jpg" alt="Post featured image"></p><p>Yesterday was the Fourth of July, and I'd walked a few blocks to watch the night's fireworks. I was feeling frustrated about not finding as much inspiration for what I wrote. My writing was feeling more like a chore and less like a passion. I wanted writing something to feel as good as many people felt watching multicolored explosions in the night sky.</p>
<p>From what I observed, fireworks focus on powerful feelings and amplifying them to hit people harder and longer - feelings of freedom, wonder, spontaneity, and even power. Firing them for whole communities also spreads those feelings to many people.</p>
<p><strong>Then I remembered good writing and good fireworks are, to me, basically the same.</strong> Aren't those two traits, amplifying and sharing powerful emotions, already key traits of strong writing? That's why thousands of people read fantasy novels like Game of Thrones - it's sharing those same powerful emotions with lots of people.</p>
<p>The writing I enjoyed most started with a powerful feeling, and the arguments and research came after. As logical as others have called me, my favorite writing from myself or others was always about self-expression as well as learning.</p>
<p>Each writing piece is like setting off a firework in my mind, and maybe even someone else's. What more motivation do I need to keep doing it?</p>
Explaining (and Celebrating) my First Twitter Bot
2019-07-08T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/07/08/anime-twitter-bot/<p>Explaining (and Celebrating) my First Twitter Bot</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/twitter-bot.jpg" alt="Post featured image"></p><p>A few months ago I tweeted this absolutely true statement.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Confession time: my secret subversive goal is drowning the internet in as much anime artwork as possible. Programming and blogging are just fronts for this.</p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1120283792785256449?ref_src=twsrc%5Etfw">April 22, 2019</a></blockquote>
<p>Over the last year my anime-related side projects fueling this plot have grown in scope:</p>
<ol>
<li>Scraping an anime image database to email me several each morning.</li>
<li>Linking this scraped data to a custom API endpoint to show random images.</li>
<li>Using this API endpoint to make <a href="http://www.quotemaker.maxwellantonucci.com/">an anime quote image maker</a>.</li>
</ol>
<p>The next roll I've taken down this slippery slope now includes:</p>
<ol start="4">
<li>Create a bot that shares random anime quote images on Twitter all day long.</li>
</ol>
<p>Last week this vision finally moved from delusion to reality, and <a href="https://twitter.com/AnimeQuoteImage">the @AnimeQuoteImage bot was born</a>! Yes, I'm now using robots to fuel my anime addiction.</p>
<p>To celebrate this latest step on my path to the nerd asylum, I wanted to share the basics of how it works and my favorites of its work so far.</p>
<h2 id="how-the-bot-works">How the Bot Works <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/07/08/anime-twitter-bot/#how-the-bot-works">#</a></h2>
<p>If you want to look over the actual code, you can check out <a href="https://github.com/maxx1128/anime-twitter-bot">the open-source repo with the bot's code</a>.</p>
<p>For a high-level understanding of the bot, it runs on Node and uses a few third-party JavaScript modules to get going. I've included crude cartoon visuals for both necessity and boredom.</p>
<p>The bot uses Puppeteer to open <a href="http://www.quotemaker.maxwellantonucci.com/">my Anime Quote Maker</a> in a headless Chrome browser. It's programmed to start with a random image, a random quote, and randomly style the quote from what's available (color schemes, filters, alignment, etc).</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/twitter-bot/bot1.png" alt="A robot pulling up a webpage." /></p>
<p>Puppeteer sizes the browser in a 700 by 700 pixel window, which makes the random quote fill it just right, and takes a screenshot. It also grabs the quote's text and author from the DOM.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/twitter-bot/bot2.png" alt="A robot taking a screenshot of the webpage." /></p>
<p>Node passes this info to Twit, a popular Node add-on for using the Twitter API. It composes a tweet with the image, quote, and author, and sends it off.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/twitter-bot/bot3.png" alt="A robot sending the screenshot out on Twitter." /></p>
<p>This all goes to Heroku, which uses the Heroku Scheduler add-on to rerun all these steps every 30 minutes.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/twitter-bot/bot4.png" alt="A robot being reminded to repeat all the past steps by Heroku." /></p>
<p>I hit turbulence getting all the Puppeteer dependencies uploaded, but after that there were few issues and the Twitter bot was born!</p>
<h2 id="my-bot's-favorite-work-so-far">My Bot's Favorite Work So Far <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/07/08/anime-twitter-bot/#my-bot's-favorite-work-so-far">#</a></h2>
<p>I'll start with some positive examples of quotes, images, and styling that somehow came together almost perfectly.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"There is an interest in that which is hidden and which the visible does not show us."<br /><br />~ Rene Magritte <a href="https://t.co/xX8U0hSMCn">pic.twitter.com/xX8U0hSMCn</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1146246183741997056?ref_src=twsrc%5Etfw">July 3, 2019</a></blockquote>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"Only those who dare to fail greatly can ever achieve greatly."<br /><br />~ Robert Kennedy <a href="https://t.co/BiKV7K3Ls2">pic.twitter.com/BiKV7K3Ls2</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1146818818913816581?ref_src=twsrc%5Etfw">July 4, 2019</a></blockquote>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"Heaven has no rage like love to hatred turned, nor hell a fury like a woman scorned."<br /><br />~ William Congreve <a href="https://t.co/0PKZUlsMaH">pic.twitter.com/0PKZUlsMaH</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1147068225538207745?ref_src=twsrc%5Etfw">July 5, 2019</a></blockquote>
<p>One in particular looked like a bizarre, if late, tribute to pride month.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"There is only one kind of love, but there are a thousand imitations."<br /><br />~ Francois de La Rochefoucauld <a href="https://t.co/Z76LMv41ao">pic.twitter.com/Z76LMv41ao</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1146365839672827904?ref_src=twsrc%5Etfw">July 3, 2019</a></blockquote>
<p>Some thought-provoking quotes actually seemed enhanced by their images.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"The psychical, whatever its nature may be, is itself unconscious."<br /><br />~ Sigmund Freud <a href="https://t.co/cpHLdHIwQd">pic.twitter.com/cpHLdHIwQd</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1147188616336203777?ref_src=twsrc%5Etfw">July 5, 2019</a></blockquote>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"I am sorry to think that you do not get a man's most effective criticism until you provoke him. Severe truth is expressed with some bitterness."<br /><br />~ Henry David Thoreau <a href="https://t.co/XKgYr1YXpv">pic.twitter.com/XKgYr1YXpv</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1147113586252292096?ref_src=twsrc%5Etfw">July 5, 2019</a></blockquote>
<p>Others didn't make me think as much as send a chill down my spine.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"There is nothing which at once affects a man so much and so little as his own death."<br /><br />~ Samuel Butler <a href="https://t.co/Iv68wFqGXz">pic.twitter.com/Iv68wFqGXz</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1146215890339475456?ref_src=twsrc%5Etfw">July 3, 2019</a></blockquote>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"What we have to do, what at any rate it is our duty to do, is to revive the old art of Lying."<br /><br />~ Oscar Wilde <a href="https://t.co/yko10ZnwvG">pic.twitter.com/yko10ZnwvG</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1147037674248790018?ref_src=twsrc%5Etfw">July 5, 2019</a></blockquote>
<p>This one in particular still freaks me out. A quote about "positive vision" paired with an inverted image of someone with blood on their shirt and a hidden face. I really hope this was random and not a secret prophecy for the coming End of Days.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"In order to carry a positive action we must develop here a positive vision."<br /><br />~ Dalai Lama <a href="https://t.co/iLm7Ws60Ci">pic.twitter.com/iLm7Ws60Ci</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1146728015675691009?ref_src=twsrc%5Etfw">July 4, 2019</a></blockquote>
<p>There's also many political quotes that get mixed in. Pairing real-world politics with anime is frequently...awkward.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"In this world of sin and sorrow there is always something to be thankful for as for me, I rejoice that I am not a Republican."<br /><br />~ H. L. Mencken <a href="https://t.co/H4NF6iCGww">pic.twitter.com/H4NF6iCGww</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1146395880330866693?ref_src=twsrc%5Etfw">July 3, 2019</a></blockquote>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"Richard Nixon is a no good, lying b-----d. He can lie out of both sides of his mouth at the same time, and if he ever caught himself telling the truth, he'd lie just to keep his hand in."<br /><br />~ Harry S. Truman <a href="https://t.co/gcWNotlccj">pic.twitter.com/gcWNotlccj</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1147098336639561729?ref_src=twsrc%5Etfw">July 5, 2019</a></blockquote>
<p>There of course will be some creations I simply don't know how to respond to.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"Nature hates calculators."<br /><br />~ Ralph Waldo Emerson <a href="https://t.co/X23BkHHyjX">pic.twitter.com/X23BkHHyjX</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1146713067969007617?ref_src=twsrc%5Etfw">July 4, 2019</a></blockquote>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"The simple truth is that balding African-American men look cool when they shave their heads, whereas balding white men look like giant thumbs."<br /><br />~ Dave Barry <a href="https://t.co/sTg5MdZMqn">pic.twitter.com/sTg5MdZMqn</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1146992558683435008?ref_src=twsrc%5Etfw">July 5, 2019</a></blockquote>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"True friends stab you in the front."<br /><br />~ Oscar Wilde <a href="https://t.co/XXaQEzSsxC">pic.twitter.com/XXaQEzSsxC</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1146886948948271109?ref_src=twsrc%5Etfw">July 4, 2019</a></blockquote>
<p>Lastly, here's my all-time favorite that's truly one of a kind, and other programmers who have handled APIs will likely appreciate it.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="und" dir="ltr">""<br /><br />~ <a href="https://t.co/8dQoklPSNa">pic.twitter.com/8dQoklPSNa</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1146788667970719745?ref_src=twsrc%5Etfw">July 4, 2019</a></blockquote>
<p>Either the API crapped out on me, or this is one of those "imagine your own quote" scenarios. If so, I'd go with a computer science quote about unit testing.</p>
<h2 id="wrapping-up">Wrapping Up <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/07/08/anime-twitter-bot/#wrapping-up">#</a></h2>
<p>Making a bot like this has been a far-off goal of mine for a long time, and making it real has reminded me of why I enjoy programming so much. <strong>Many things that seem impossible to make usually aren't if you keep at it and try enough different approaches.</strong> I looked at several Ruby setups for this before finally settling on Node, and after a few days of struggling to get things working on Heroku, it all finally came together.</p>
<p>Now I can kick back and enjoy it doing this work for me. At least until the cycle repeats and I get another idea that both improves my programming skills, indulges my love of anime, and costs me some sleep in the process.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">"The privilege of a lifetime is being who you are."<br /><br />~ Joseph Campbell <a href="https://t.co/O1TtaPc82M">pic.twitter.com/O1TtaPc82M</a></p>— Anime Quote Image Bot (@AnimeQuoteImage) <a href="https://twitter.com/AnimeQuoteImage/status/1147810469291483136?ref_src=twsrc%5Etfw">July 7, 2019</a></blockquote>
Snow White and the Seven Behavioral Patterns - A Design Patterns Intro
2019-07-24T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/07/24/snow-white-behavioral-patterns/<p>Snow White and the Seven Behavioral Patterns - A Design Patterns Intro</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/snow-white-behavioral.jpeg" alt="Post featured image"></p><p>Welcome to the third entry in my “Design Pattern Fairy Tales” series! It aims to explain design patterns in a more accessible way - that is, fairy tale metaphors.</p>
<p>The last post covered the first half of the behavioral patterns, which let multiple objects work together for complex tasks. This post covers the second half of this group, using simple examples explained in the context of another classic tale, <strong>Snow White and the Seven Dwarves.</strong></p>
<p>I've introduced this series twice already, so there's not much to say here. Let's get right to it.</p>
<h2 id="alerting-the-dwarves-with-an-observer">Alerting the Dwarves with an Observer <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/07/24/snow-white-behavioral-patterns/#alerting-the-dwarves-with-an-observer">#</a></h2>
<p>Let's focus this telling of Snow White on the dwarves and their work mining. So let's start it the same way the seven dwarves start their workday: with one yelling "Heigh-Ho" to the others so they know it's time to start. In the film, Doc is the first one to yell it so we'll do the same here.</p>
<p>Doc needs a way to yell and be confident the other dwarves will hear and yell back, so he decides to use an Observer pattern. First, he writes a class for himself as the one calling out. He starts with a basic way to make a list of dwarves to call out to.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Caller</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>yell <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">register</span><span class="token punctuation">(</span><span class="token parameter">dwarf</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>dwarf<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>The most important property is <code>this.dwarves</code>, which is a list of the actual dwarves he's yelling out to. It starts empty, so he includes the <code>register</code> method to quickly add extra dwarves. Each dwarf on that list is now basically "listening" to what the caller does.</p>
<p>Once he has a method to add dwarves to yell at, he needs a way to update all of them. So when he calls out, he needs to take each dwarf and give them any info they need.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Caller</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>yell <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">register</span><span class="token punctuation">(</span><span class="token parameter">dwarf</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>dwarf<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">updateAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">el</span> <span class="token operator">=></span> el<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">callOut</span><span class="token punctuation">(</span><span class="token parameter">yell</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>yell <span class="token operator">=</span> yell<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">updateAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>The <code>updateAll</code> function is what takes every dwarf that's listening and says "The caller is yelling so you need to yell too!" Each swarf is passed the <code>Caller</code>, which will tell them what they need to yell.</p>
<p>We can see how the dwarves would respond in the <code>DwarfObserver</code> class.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">DwarfObserver</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>yell <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">update</span><span class="token punctuation">(</span><span class="token parameter">caller</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>yell <span class="token operator">=</span> caller<span class="token punctuation">.</span>yell<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Whenever a dwarf is "updated", we're telling them to yell what Doc is yelling. In other words, when they hear Doc yell they should yell the same thing. This is the core of the Observer pattern, where <strong>one object watches for changes in another, and takes a specific action right when the change happens.</strong></p>
<p>Let's get this specific example set up by defining Doc as the Caller, and defining four other dwarves listening to him.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> Doc <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Caller</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> Happy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfObserver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Bashful <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfObserver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Sneezy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfObserver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Grumpy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfObserver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>We'll register each dwarf with Doc so they starting listening for him to yell.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> dwarves <span class="token operator">=</span> <span class="token punctuation">[</span>Happy<span class="token punctuation">,</span> Bashful<span class="token punctuation">,</span> Sneezy<span class="token punctuation">,</span> Grumpy<span class="token punctuation">]</span><br />dwarves<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">dwarf</span> <span class="token operator">=></span> Doc<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span>dwarf<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now when we tell Doc to call out, he'll automatically update the other dwarves so they yell too!</p>
<pre class="language-javascript"><code class="language-javascript">Doc<span class="token punctuation">.</span><span class="token function">callOut</span><span class="token punctuation">(</span><span class="token string">'Heigh Ho!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />Doc<span class="token punctuation">.</span>yell<span class="token punctuation">;</span><br /><span class="token comment">// 'Heigh Ho!'</span><br /><br />Happy<span class="token punctuation">.</span>yell<span class="token punctuation">;</span><br /><span class="token comment">// 'Heigh Ho!'</span><br />Bashful<span class="token punctuation">.</span>yell<span class="token punctuation">;</span><br /><span class="token comment">// 'Heigh Ho!'</span><br />Sneezy<span class="token punctuation">.</span>yell<span class="token punctuation">;</span><br /><span class="token comment">// 'Heigh-Ho!'</span><br />Grumpy<span class="token punctuation">.</span>yell<span class="token punctuation">;</span><br /><span class="token comment">// 'Heigh Ho!'</span></code></pre>
<h2 id="crossing-the-bridge-with-an-iterator">Crossing the Bridge with an Iterator <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/07/24/snow-white-behavioral-patterns/#crossing-the-bridge-with-an-iterator">#</a></h2>
<p>Now the dwarves are off to work, but they're not at the mines yet. Let's say it's early in the morning and they need to cross a narrow bridge to reach the mines. But it's so dark out they can barely see the other dwarves, and they can't risk multiple dwarves crossing at the same time.</p>
<p>Doc sees they need a careful way to let each dwarf cross that'll keep track of how many need to cross. So he writes up an Iterator class to do just that.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">DwarfIterator</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">dwarves</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>index <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves <span class="token operator">=</span> dwarves<span class="token punctuation">;</span> <span class="token comment">// is an array</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">hasNext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>index <span class="token operator"><</span> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span>length<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Right now the class doesn't do much. It has a list of dwarves, an index of zero so it's at the start of the list, and a function to tell if they're at the end of the list. That's helpful but not enough to get them across the bridge. Doc needs it to track who's going to cross the bridge next and yell out to them.</p>
<p>So he adds two more methods. <code>nextDwarf</code> will tell the current Dwarf to cross and increase the index further along with the list. He adds <code>callNextDwarf</code> that will check if there are any dwarves next before calling for another.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">DwarfIterator</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">dwarves</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>index <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves <span class="token operator">=</span> dwarves<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">hasNext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>index <span class="token operator"><</span> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span>length<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">nextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>dwarves<span class="token punctuation">[</span><span class="token keyword">this</span><span class="token punctuation">.</span>index<span class="token operator">++</span><span class="token punctuation">]</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, you may cross!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">callNextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">hasNext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">nextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token string">"Everyone is here!"</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>With this setup, Doc can simply pass in the list of dwarves and keep using <code>callNextDwarf</code> over and over. <strong>The Iterator lets them easily navigate the list of dwarves, abstracting away the work of keeping track tracking where they are and what actions to take.</strong></p>
<p>Let's set up the list of dwarves (we can use an array of strings instead of objects to save time), and pass those into the Iterator.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> crossingDwarfs <span class="token operator">=</span> <span class="token punctuation">[</span><br /> <span class="token string">"Sneezy"</span><span class="token punctuation">,</span><br /> <span class="token string">"Sleepy"</span><span class="token punctuation">,</span><br /> <span class="token string">"Happy"</span><span class="token punctuation">,</span><br /> <span class="token string">"Doc"</span><span class="token punctuation">,</span><br /> <span class="token string">"Grumpy"</span><span class="token punctuation">,</span><br /> <span class="token string">"Dopey"</span><span class="token punctuation">,</span><br /> <span class="token string">"Bashful"</span><br /><span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> dwarfCounter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfIterator</span><span class="token punctuation">(</span>crossingDwarfs<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now Doc can use the iterator to track who should be called next and when they're all across. He just keeps yelling what it tells him to until they're done.</p>
<pre class="language-javascript"><code class="language-javascript">dwarfCounter<span class="token punctuation">.</span><span class="token function">callNextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Sneezy, you may cross!</span><br />dwarfCounter<span class="token punctuation">.</span><span class="token function">callNextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Sleepy, you may cross!</span><br />dwarfCounter<span class="token punctuation">.</span><span class="token function">callNextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Happy, you may cross!</span><br />dwarfCounter<span class="token punctuation">.</span><span class="token function">callNextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Doc, you may cross!</span><br />dwarfCounter<span class="token punctuation">.</span><span class="token function">callNextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Grumpy, you may cross!</span><br />dwarfCounter<span class="token punctuation">.</span><span class="token function">callNextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Dopey, you may cross!</span><br />dwarfCounter<span class="token punctuation">.</span><span class="token function">callNextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Bashful, you may cross!</span><br />dwarfCounter<span class="token punctuation">.</span><span class="token function">callNextDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Everyone is here!</span></code></pre>
<h2 id="managing-everyone's-work-with-a-mediator">Managing Everyone's Work with a Mediator <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/07/24/snow-white-behavioral-patterns/#managing-everyone's-work-with-a-mediator">#</a></h2>
<p>The dwarves are in the mines and ready to work. There's a lot of sections to mine, and each dwarf moves to a different one. It takes a lot of time to move between sections, and they don't want more than one dwarf in a section at one time since they want a variety of stones.</p>
<p>This is tough to manage since if a dwarf wants to move to another section they don't know if someone's already there. Doc sees this issue and, being the problem-solving dwarf he is, writes up a class to make himself a Mediator.</p>
<p>The Mediator class is similar to the <code>Caller</code> class from the Observer. <strong>It has a list of dwarves, but instead of alerting all those dwarves of changes, it uses info about these dwarves to better coordinate and guide their actions.</strong></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">DwarfMediator</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">checkSection</span><span class="token punctuation">(</span><span class="token parameter">section</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span><span class="token function">every</span><span class="token punctuation">(</span><span class="token parameter">dwarf</span> <span class="token operator">=></span> dwarf<span class="token punctuation">.</span>section <span class="token operator">!==</span> section<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Here, coordinating the different dwarfs takes the form of <code>checkSection</code>. It checks to see if any other dwarf is already in that section, and returns <code>true</code> or <code>false</code> respectively. This prevents section overlap among all the dwarves he's coordinating.</p>
<p>Doc also writes a class for the dwarfs he mediates. Each one needs a Mediator, so he makes sure that whenever a worker is made, it adds itself to a Mediator's list of workers.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">DwarfWorker</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">section<span class="token punctuation">,</span> mediator</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>section <span class="token operator">=</span> section<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>mediator <span class="token operator">=</span> mediator<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>mediator<span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Now the worker can refer back to the Mediator and its knowledge about the other dwarves. It can ask the Mediator to check if a specific section is available with <code>askToMove</code>, and if it is, they'll move there.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">DwarfWorker</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">section<span class="token punctuation">,</span> mediator</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>section <span class="token operator">=</span> section<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>mediator <span class="token operator">=</span> mediator<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>mediator<span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">askToMove</span><span class="token punctuation">(</span><span class="token parameter">section</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> available <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mediator<span class="token punctuation">.</span><span class="token function">checkSection</span><span class="token punctuation">(</span>section<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>available<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>section <span class="token operator">=</span> section<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This is good since the class isn't coupled tightly to the Mediator. The Mediator focuses on organizing info provided by each worker (their sections) and leaving as much action to the workers as possible (moving to the new section).</p>
<p>We can see how helpful this is in action. Doc creates an instance of himself as a Mediator and the other dwarves as a worker.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> MediatorDoc <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfMediator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> Sneezy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfWorker</span><span class="token punctuation">(</span><span class="token string">"Diamonds"</span><span class="token punctuation">,</span> MediatorDoc<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Sleepy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfWorker</span><span class="token punctuation">(</span><span class="token string">"Rubies"</span><span class="token punctuation">,</span> MediatorDoc<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Happy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfWorker</span><span class="token punctuation">(</span><span class="token string">"Sapphires"</span><span class="token punctuation">,</span> MediatorDoc<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Grumpy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfWorker</span><span class="token punctuation">(</span><span class="token string">"Emeralds"</span><span class="token punctuation">,</span> MediatorDoc<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Dopey <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfWorker</span><span class="token punctuation">(</span><span class="token string">"Gems"</span><span class="token punctuation">,</span> MediatorDoc<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Bashful <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DwarfWorker</span><span class="token punctuation">(</span><span class="token string">"Crystals"</span><span class="token punctuation">,</span> MediatorDoc<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Let's say Sneezy wants to move to the "Rubies" section. Doc will see that Sleepy is already there and stop him.</p>
<pre class="language-javascript"><code class="language-javascript">Sneezy<span class="token punctuation">.</span><span class="token function">askToMove</span><span class="token punctuation">(</span><span class="token string">"Rubies"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Sneezy.position is still "Rubies!"</span></code></pre>
<p>Sneezy gets the message, stays where he is, and asks about the "Pearls" section instead. Doc sees that's open and allows him to move.</p>
<pre class="language-javascript"><code class="language-javascript">Sneezy<span class="token punctuation">.</span><span class="token function">askToMove</span><span class="token punctuation">(</span><span class="token string">"Pearls"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Sneezy.position has changed to "Pearls!"</span></code></pre>
<p>With this, we have several objects working together in an organized way that avoids tight coupling.</p>
<h2 id="tracking-mining-progress-with-a-memento">Tracking Mining Progress with a Memento <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/07/24/snow-white-behavioral-patterns/#tracking-mining-progress-with-a-memento">#</a></h2>
<p>As the dwarves keep working, they realize that since jewels and diamonds have gone missing lately, they need to keep better track of how many they've found. Sneezy wants to track how many they dig up each hour, so if they realize some have vanished, they can check how many they had each hour to see when they vanished.</p>
<p>Sneezy decides to set up a Memento pattern for this. <strong>It'll let him keep track of the changes, and check back on earlier state counts.</strong></p>
<p>There are three parts to the Memento pattern Sneezy writes. First is the Memento itself, which are the "snapshots" of the rocks gathered. He'll be making another one every hour.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Memento</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">jewels<span class="token punctuation">,</span> diamonds</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>jewels <span class="token operator">=</span> jewels<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>diamonds <span class="token operator">=</span> diamonds<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>He also needs an <code>originator</code>, which is an extra layer of abstraction that directly handles Mementos. In this case, Sleepy only needs the originator to create new Mementos and pull data from old ones.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> originator <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token function-variable function">store</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">jewels<span class="token punctuation">,</span> diamonds</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Memento</span><span class="token punctuation">(</span>jewels<span class="token punctuation">,</span> diamonds<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">restore</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">memento</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">jewels</span><span class="token operator">:</span> memento<span class="token punctuation">.</span>jewels<span class="token punctuation">,</span><br /> <span class="token literal-property property">diamonds</span><span class="token operator">:</span> memento<span class="token punctuation">.</span>diamonds<span class="token punctuation">,</span><br /> <span class="token punctuation">}</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>The last part of this pattern is the <code>caretaker</code>, which keeps track of mementos in a large group. It has ways to add and retrieve Mementos, but it has no direct contact with the Memento class itself - that's left to the originator. The caretaker stores and manages them with some basic functions.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">CaretakerDwarf</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>mementos <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">addMemento</span><span class="token punctuation">(</span><span class="token parameter">memento</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>mementos<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>memento<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">getMemento</span><span class="token punctuation">(</span><span class="token parameter">index</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mementos<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">getMementoFromHour</span><span class="token punctuation">(</span><span class="token parameter">hour</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> hourIndex <span class="token operator">=</span> hour <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getMemento</span><span class="token punctuation">(</span>hourIndex<span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Now Sneezy has all he needs to start tracking Mementos. First, he assigns himself as the caretaker.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> Sneezy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CaretakerDwarf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now he can use the originator to add new Mementos to track the jewels and diamonds each hour.</p>
<pre class="language-javascript"><code class="language-javascript">Sneezy<span class="token punctuation">.</span><span class="token function">addMemento</span><span class="token punctuation">(</span>originator<span class="token punctuation">.</span><span class="token function">store</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />Sneezy<span class="token punctuation">.</span><span class="token function">addMemento</span><span class="token punctuation">(</span>originator<span class="token punctuation">.</span><span class="token function">store</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />Sneezy<span class="token punctuation">.</span><span class="token function">addMemento</span><span class="token punctuation">(</span>originator<span class="token punctuation">.</span><span class="token function">store</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>If Sneezy needs to check how much was collected in the second hour, he can quickly restore the "state" of that hour's state. It's stored in a variable and he can compare it to others or do whatever else.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> secondHourResults <span class="token operator">=</span> originator<span class="token punctuation">.</span><span class="token function">restore</span><span class="token punctuation">(</span>Sneezy<span class="token punctuation">.</span><span class="token function">getMementoFromHour</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />secondHourResults<span class="token punctuation">.</span>jewels<span class="token punctuation">;</span> <span class="token comment">// 3</span><br />secondHourResults<span class="token punctuation">.</span>diamonds<span class="token punctuation">;</span> <span class="token comment">// 6</span></code></pre>
<h2 id="loading-up-jewels-through-the-chain-of-responsibility">Loading Up Jewels through the Chain of Responsibility <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/07/24/snow-white-behavioral-patterns/#loading-up-jewels-through-the-chain-of-responsibility">#</a></h2>
<p>It's the end of the working day and the dwarves need to start loading up their rocks into carts. Happy is glad to manage this but realizes there's a lot of things to consider.</p>
<ul>
<li>Each cart can only hold a limited number of rocks. No dwarf can have any leftover and no cart can overflow.</li>
<li>Depending on where each dwarf is, there are many different possible paths for the cart to follow.</li>
<li>Some dwarves may still be mining and need to keep passing the cart around.</li>
</ul>
<p>The only constant Happy sees is the cart is moving from dwarf to dwarf, but the specific actions each dwarf takes could be different. The core of this puzzle is passing a cart object along a chain of dwarves, and he realizes the Chain of Responsibility pattern will solve it.</p>
<p>First, he creates a class for the mining cart. Each cart must be assigned a jewel limit and a simple list of assigned dwarves.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">MiningCart</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">limit</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>limit <span class="token operator">=</span> limit<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>jewels <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">setNextDwarf</span><span class="token punctuation">(</span><span class="token parameter">dwarf</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>dwarf<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">addJewels</span><span class="token punctuation">(</span><span class="token parameter">jewels</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>jewels <span class="token operator">+=</span> jewels<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Happy also adds a few extra methods so it's easier to figure out of a cart has enough room to add more jewels.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">MiningCart</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">limit</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>limit <span class="token operator">=</span> limit<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>jewels <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">setNextDwarf</span><span class="token punctuation">(</span><span class="token parameter">dwarf</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>dwarf<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">addJewels</span><span class="token punctuation">(</span><span class="token parameter">jewels</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>jewels <span class="token operator">+=</span> jewels<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">getAvailableSpace</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>limit <span class="token operator">-</span> <span class="token keyword">this</span><span class="token punctuation">.</span>jewels<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">hasEnoughSpace</span><span class="token punctuation">(</span><span class="token parameter">jewels</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAvailableSpace</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> jewels <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Happy also needs a class for each Dwarf getting the cart, which tracks if they're mining and the jewels they have.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Dwarf</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">jewels<span class="token punctuation">,</span> isMining</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>jewels <span class="token operator">=</span> jewels<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>isMining <span class="token operator">=</span> isMining<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Lastly and most importantly, Happy writes the class that will send the cart down the Chain of Responsibility. It takes the cart and passes it to each dwarf on the list, checking their mining status before trying to add their jewels to the cart. This updated cart is passed to the next dwarf, and so on until it's finished the chain. <strong>This lets the cart and dwarves work together to gather jewels and do other operations in the correct order without coupling them too close together.</strong> The finished cart, loaded with as many jewels as it can carry, is returned to Happy at the end.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">CartChainOfResp</span> <span class="token punctuation">{</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token parameter">cart</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> cart<span class="token punctuation">.</span>dwarves<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">dwarf</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> cartHasSpace <span class="token operator">=</span> cart<span class="token punctuation">.</span><span class="token function">hasEnoughSpace</span><span class="token punctuation">(</span>dwarf<span class="token punctuation">.</span>jewels<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> dwarfHasFinishedMining <span class="token operator">=</span> <span class="token operator">!</span>dwarf<span class="token punctuation">.</span>isMining<span class="token punctuation">;</span><br /><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>dwarfHasFinishedMining <span class="token operator">&&</span> cartHasSpace<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> cart<span class="token punctuation">.</span><span class="token function">addJewels</span><span class="token punctuation">(</span>dwarf<span class="token punctuation">.</span>jewels<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">return</span> cart<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Let's look at this pattern in action. Happy sees three dwarves in the mine he can pass the cart too. The cart has a limit of 100 jewels, so Happy notes down the needed info about the other dwarves and assigns them to the cart.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> miningCart <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MiningCart</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Sneezy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Doc <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Dopey <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />miningCart<span class="token punctuation">.</span><span class="token function">setNextDwarf</span><span class="token punctuation">(</span>Sneezy<span class="token punctuation">)</span><span class="token punctuation">;</span><br />miningCart<span class="token punctuation">.</span><span class="token function">setNextDwarf</span><span class="token punctuation">(</span>Happy<span class="token punctuation">)</span><span class="token punctuation">;</span><br />miningCart<span class="token punctuation">.</span><span class="token function">setNextDwarf</span><span class="token punctuation">(</span>Dopey<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With the cart and its path set, it's ready to go up the chain. He creates an instance of his Chain of Responsibility and passes it the mining cart to go up the chain.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> cartChainOfResp <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CartChainOfResp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">let</span> finishedCart <span class="token operator">=</span> cartChainOfResp<span class="token punctuation">.</span><span class="token function">calc</span><span class="token punctuation">(</span>miningCart<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />finishedCart<span class="token punctuation">.</span>jewels<span class="token punctuation">;</span><br /><span class="token comment">// 100</span></code></pre>
<p>The cart gathers 50 jewels from Sneezy, skips Doc since he's still mining, gathers 50 more from Dopey, and returns with a full load of 100 jewels.</p>
<p>Let's adjust the scenario a bit, increasing the cart's limit and the number of dwarves.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> miningCart <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MiningCart</span><span class="token punctuation">(</span><span class="token number">150</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Sneezy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Doc <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Dopey <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Sleepy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">// Same code still here //</span><br /><br />finishedCart<span class="token punctuation">.</span>jewels<span class="token punctuation">;</span><br /><span class="token comment">// 125</span></code></pre>
<p>The cart will gather jewels from all the dwarves, skips over Sleepy since he would put the cart over the limit, and returns with 125 jewels.</p>
<p>Now let's adjust this scenario so Dopey is still mining. This makes room for Sleepy's gems but lowers the cart's overall total.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> miningCart <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MiningCart</span><span class="token punctuation">(</span><span class="token number">150</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Sneezy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Doc <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Dopey <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Sleepy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dwarf</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">// Same code still here //</span><br /><br />finishedCart<span class="token punctuation">.</span>jewels<span class="token punctuation">;</span><br /><span class="token comment">// 105</span></code></pre>
<p>In all these scenarios, we see the Chain of Responsibility carry out its logic no matter what dwarves make up the chain.</p>
<h2 id="the-design-pattern-castle-approaches">The Design Pattern Castle Approaches <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/07/24/snow-white-behavioral-patterns/#the-design-pattern-castle-approaches">#</a></h2>
<p>There's only one post left in this explanatory fairy tale that looks at structural patterns. As fun as this series has been to write, I'm also looking forward to saving the programming princess and close the book on the repo of this tale. So stick around for the last entry!</p>
<p><em>To Be Continued...</em></p>
How To Take Notes on Everything
2019-08-19T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/08/19/how-to-take-notes-everything/<p>How To Take Notes on Everything</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/how-take-notes-everything.png" alt="Post featured image"></p><p>I've done lots of writing lately, but almost none of it has gone towards blog posts. Instead, it's gone towards my online notebook, now called the more badass-sounding <a href="https://www.notion.so/ExoCortex-6e3ae755edae4650a4d9ce190138f230">Exocortex</a>. I've read of it being called a "knowledge notebook" or a "personal wiki," which mean the same but aren't as badass.</p>
<p>An Exocortex is a giant collection of notes on everything you can imagine. It can range from code tricks, life strategies, favorite fiction, or revenge plots. The biggest reason I've worked on it is I can now say "I'm strengthening up my Exocortex" and sound like a supervillain. But there are many, more <em>useful</em> benefits get from adding to it:</p>
<ul>
<li>Gather career advice for topics like negotiating salary and working with others.</li>
<li>Build your awareness of coding concepts and ideas, so you 'know what you don't know.'</li>
<li>Save new code methods and techniques to use as you experiment with languages.</li>
<li>Curate knowledge to use as inspiration for projects, jobs, and side projects.</li>
<li>See the larger info and context that current industry trends fall into.</li>
<li>Document strategies to handle unfamiliar or delicate social situations. If you're like me, you're a hopeless awkward turtle without them.</li>
<li>Look smarter to your coworkers and bosses.</li>
<li>It's an amazing tax deduction in some countries that don't exist.</li>
</ul>
<p>These are all wonderful perks, but there's no denying building one takes time and effort. So this post breaks down how I've built up mine and the practices I follow to share with you all. I can't promise it's the perfect fit for everyone, but it should at least be a good template or starting point. So to follow-up on <a href="https://dev.to/maxwell_dev/takes-notes-on-everything-3io">a previous post on taking notes on everything</a>, this one looks at how to do just that.</p>
<h2 id="use-the-sq3r-method">Use the SQ3R Method <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/08/19/how-to-take-notes-everything/#use-the-sq3r-method">#</a></h2>
<p>A useful note-taking approach from <a href="https://www.amazon.com/Pragmatic-Thinking-Learning-Refactor-Programmers/dp/1934356050">Pragmatic Thinking and Learning</a> is the SQ3R method. It lays out a useful series of steps for reading books and articles.</p>
<p>First, only <strong>scan</strong> the content. Look at the table of contents, summaries, chapter headers, images, and whatever else. Don't read any paragraphs or spend too long in any one place. Get a large-scale picture of what it covers.</p>
<p>As you scan, note any <strong>questions</strong> you have. They can be about code, new words, or old words that you didn't expect to see. They can also be questions about what you expect to learn. Could this thing help you pull off a side-project idea you've had for months? If not, what else could?</p>
<p>Then it's time to <strong>read</strong> the content. As you read, <strong>record</strong> the most important points. Play with the info as you read it. Take notes in different forms, or rephrase them in a new or silly way.</p>
<p>Once that's done, take some time now and then to <strong>review</strong> your notes. Add extra knowledge you've learned writing them. Discuss it with others. Quiz yourself on different points. Only rereading the info doesn't help much.</p>
<p>I've been trying different note-taking approaches for a while. The best one I found is a slight variation to the SQ3R method (Scan, Question, Read, Record, Review) that minimizes the Question phase. I can attest it's worth at least trying with a few pieces of content. Even if it's not right for you, chances are it won't take more than a few changes to make it work.</p>
<h2 id="have-lots-of-material-in-your-pipeline">Have Lots of Material in Your Pipeline <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/08/19/how-to-take-notes-everything/#have-lots-of-material-in-your-pipeline">#</a></h2>
<p>I'm not immune to avoiding things when I'm not in the mood for them, as my family or those managing my 401k will tell you. This applies to the books and articles I read too. I can hardly count the times I've thought "This has important info I <em>should</em> read, but I'm not feeling it."</p>
<p>Too often I was enthusiastic about reading something at first, then lose interest. I wouldn't read it for a while out of laziness and self-loathing. Then I find something new and the cycle continues. The workaround I've found is, oddly enough, to have a variety of reading in my focus at once. I know this goes against the wisdom of "finish one task before the next." But I've found having it keeps me motivated and reading more often.</p>
<h3 id="for-books%2C-tackle-a-variety-at-once">For Books, Tackle a Variety at Once <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/08/19/how-to-take-notes-everything/#for-books%2C-tackle-a-variety-at-once">#</a></h3>
<p>I'm reading "Burn Your Portfolio" and need a break from that book but still want to read. With a few books in line, I can switch over to Eloquent Ruby and not miss a beat. I know this, as I did this while traveling last week, and did over three hours of reading total that day.</p>
<p>It's hard to choose the number of books to stick with due to the sheer amount we often focus on. So I focus on by making sure my books:</p>
<ul>
<li>Cover different topics so I'm not putting all my learning eggs in one basket.</li>
<li>Help me with skills I can use in many places, not only coding.</li>
<li>I enjoy reading them.</li>
</ul>
<p>These criteria have helped me settle on the four books I currently have in my pipeline.</p>
<ol>
<li><strong>Eloquent Ruby</strong> since it recommended as a resource for learning Ruby fundamentals.</li>
<li><strong>Clean Code</strong> as one of the ultimate guides to writing understandable code.</li>
<li><strong>Burn Your Portfolio</strong> as a highly-recommended list of general career tips.</li>
<li><strong>How to Win Friends and Influence People</strong> since it's the classic book for how to better work with any person.</li>
</ol>
<p>The trade-off is I make slower progress in each book, but all other things being equal, it's worth it for me. I can add notes chapter by chapter for each one, rotating them in or out to keep my motivation hot and my mind curious.</p>
<h3 id="for-articles%2C-keep-a-few-lists">For Articles, Keep a Few Lists <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/08/19/how-to-take-notes-everything/#for-articles%2C-keep-a-few-lists">#</a></h3>
<p>Articles may or may not have material worth taking notes on. When they do, unlike books, I rarely make a new note or section in my notebook for only one. It's better to have notes based around topics and add info to each from relevant articles as I find them.</p>
<p>Organizing the articles I want to read and take notes on is another task. Lately, I've kept articles in one of three lists:</p>
<ol>
<li><a href="https://www.notion.so/maxantonucci/Waiting-Articles-4bb0d6d09ebb48829d46c032251a32f8">Only Read</a>. These are usually interesting news or ideas I'll skim over. If it turns out there's info I want to record, I'll shift them to the next on.</li>
<li><a href="https://www.notion.so/maxantonucci/Take-Notes-On-cc620dad19e546c28642a44b5ff3faf8">Take Notes On</a>. These articles have the info I know I want to save. So I'll go into them looking for what I want to record, and save them as references on the affected notes.</li>
<li><a href="https://www.notion.so/maxantonucci/Giant-Resources-26a5c0b36301437388f142c377884701">Pull More Info From</a>. These pages have huge amounts of info or resources I can't record in one sitting. From these, I only pull out concepts to research or articles to take notes on later.</li>
</ol>
<p>Taking notes on articles is great since they have good info without a big time commitment. Articles balance that out with shorter, more timely information. Don't forget to take in the smaller, but still vital, day-to-day info.</p>
<h2 id="lower-the-friction">Lower the Friction <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/08/19/how-to-take-notes-everything/#lower-the-friction">#</a></h2>
<p>A few weeks ago I was reading a book through iBooks but was taking notes on my tablet. I thought this extra flexibility would help. But I wound up putting off taking more notes for over a week after starting.</p>
<p>I realized this setup was an issue. My tablet let me directly annotate a book, so taking notes was as simple as finding my last spot. For this book I had to get my tablet and my laptop, getting enough room for both, and whatever it took to get both ready. The amount of work from "I want to take notes" to "I am taking notes" was so high, it made getting started too big a burden.</p>
<p>I scrapped that setup and I only take notes on this book with iBooks. No matter how good a note-taking workflow is, it's pointless if it's too much of a hassle to do. The best ones lower the friction to start as much as possible. One way to get the barrier between reading and note-taking low is annotating books directly.</p>
<p>iBooks is a good example of this that all Macbook users have. I also recommend <a href="https://remarkable.com/">a reMarkable tablet</a> since it allows direct annotation and other perks.</p>
<ul>
<li>Covers <code>epub</code> and <code>pdf</code> formats</li>
<li>Is portable but can sync files to a desktop to more easily transcribe notes after</li>
<li>Does highlights and notes with direct writing, which appeals to my tactile love of books</li>
<li>Allows freeform note-taking for events and other learnable experiences not covered by books</li>
</ul>
<p>There are likely other tools out there (with a cheaper price tag). But they'll work as long as the friction between reading and notes is low.</p>
<h2 id="set-aside-time%2C-big-or-small">Set Aside Time, Big or Small <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/08/19/how-to-take-notes-everything/#set-aside-time%2C-big-or-small">#</a></h2>
<p>Try to make actual space in your schedule for taking notes. This time has ranged from the five minutes before a meeting to several hours in a plane ride. The most important thing is telling myself "for this period, I'm going to be reading and taking notes and that's it." Not setting this boundary or trying to multitask has either made me not follow through. If not that, I write notes so poor I have to waste time redoing them.</p>
<p>Taking notes is a small time investment with a huge return. Let's say you spent 30 minutes a day spent watching television on note-taking instead. That's 3.5 hours a week, or at least 14 hours for a month. That's enough time to get through at least one book, or at least a good amount of a longer, more technical one. That adds up to around 9-12 books a year, all helping you build knowledge and skills to boost your career.</p>
<h2 id="wrapping-up">Wrapping Up <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/08/19/how-to-take-notes-everything/#wrapping-up">#</a></h2>
<p>I'm not going to pretend taking notes is the best way to learn. That book I referenced twice here says as much, with many sections focused on how to learn by doing. But that doesn't mean reading and note-taking is without value.</p>
<p>It could only be a few books a year. Choose the right ones and devote a little time to reading and note-taking. It brings an exponential return on investment in the end. Unless you're not a book person (in which case don't you <em>dare</em> speak to me), there aren't any real arguments against it.</p>
<p>So find some good content and start building a personal wiki! <em>Just don't call it an Exocortex, since I've already claimed that name.</em></p>
Cinderella and the Glass Structural Pattern - A Design Patterns Intro
2019-09-09T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/09/09/cinderella-structural-patterns/<p>Cinderella and the Glass Structural Pattern - A Design Patterns Intro</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/cinderella-structural.jpeg" alt="Post featured image"></p><p>Welcome to the fourth entry in my “Design Pattern Fairy Tales” series! It aims to explain design patterns in a more accessible way - that is, fairy tale metaphors.</p>
<p>The series so far has covered creational patterns (for making objects) and behavioral patterns (making objects work together), and in the final post here is ending with structural patterns. These define specific relationships between classes and objects, which can pull off tougher responsibilities in maintainable and efficient ways.</p>
<p>The fairy tale I went with for these patterns is another classic, Cinderella. This post is a retelling of the story, replacing several elements with design patterns while explaining how they work.</p>
<p>If you've followed the rising action so far, you already know how this goes. So let's cut to the chase so we can live happily ever after with our design pattern knowledge!</p>
<h2 id="waving-a-magic-wand-with-a-facade">Waving a Magic Wand with a Facade <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/09/cinderella-structural-patterns/#waving-a-magic-wand-with-a-facade">#</a></h2>
<p>We begin our retelling of Cinderella with the Fairy Godmother (FG) comforting a distraught Cinderella right before the ball. Her dress has been ruined and has no way to attend. So the FG uses her magic wand to fix it all and send her on her way.</p>
<p>However, she has a hard enough time finding her wand and remembering the magic words. The FG hardly ever remembers all the complex magical calculations and functions to simply levitating an item. She needed a quick way to make use of the different classes that make up even a simple spell. So to make this simplified version, she wrote a Facade.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">wandWaveFacade</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>target <span class="token operator">=</span> target<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">BibbidiBobbidiBoo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> neededElement <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">getMagicElement</span><span class="token punctuation">(</span><span class="token string">"levitate"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> neededEnergy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">calculateMagicEnergy</span><span class="token punctuation">(</span><br /> neededElement<span class="token punctuation">,</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>target<span class="token punctuation">.</span>weight<br /> <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">calc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">levitateItem</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>target<span class="token punctuation">,</span> neededEnergy<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">levitate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>She named the first function in her facade after the easiest part to remember, the magic words themselves. The function calls up instances of all the following classes to do the magical work.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">getMagicElement</span> <span class="token punctuation">{</span><br /> <span class="token comment">// Super secret magical secrets here, not for you!</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">calculateMagicEnergy</span> <span class="token punctuation">{</span><br /> <span class="token comment">// You don't have a wand so you can't make use of magic</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">levitateItem</span> <span class="token punctuation">{</span><br /> <span class="token comment">// Content censored as per paragraph 3 of article 17 in the International Treaty of Magical Movement and Teleportation</span><br /><span class="token punctuation">}</span></code></pre>
<p>Nope, you don't get to see any of the secret magical code. That's because I've been sworn to secrecy, not because I'm lazy. Thankfully, me not writing it fits with a Facade's role. <strong>It takes complex magical laws and simplifies them into a simple wave of the wand with some funny words.</strong> The FG did all the work once, all she has to do to access it use what's written below.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> pumpkin <span class="token operator">=</span> <span class="token string">'pumpkin'</span><span class="token punctuation">,</span><br /> waveWand <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">wandWaveFacade</span><span class="token punctuation">(</span>pumpkin<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />waveWand<span class="token punctuation">.</span><span class="token function">BibbidiBobbidiBoo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// The pumpkin is levitated!</span></code></pre>
<p>Assuming she can find her wand and remember the words, the FG now has all she needs to keep doing all kinds of magic in a simple, straightforward way.</p>
<h2 id="creating-magical-sparks-with-a-flyweight">Creating Magical Sparks with a Flyweight <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/09/cinderella-structural-patterns/#creating-magical-sparks-with-a-flyweight">#</a></h2>
<p><em>Note: I eternally struggle with the Flyweight pattern, so in the likely event I mess it up, <a href="https://refactoring.guru/design-patterns/flyweight">read this article</a>.</em></p>
<p>Part of the wand-waving process the FG can't handle with a Facade is the wand's sparkles. She knows she won't be taken seriously as a magical overseer of people's fates through unexplainable phenomena without a wand that goes "sparkle sparkle" when it's magic time.</p>
<p>However, just one wave of the wand creates lots of sparkles. Almost tons of sparkles. Each only takes a small chunk of magic, but after making so many, it slows down her magic and makes her run out after just a few spells. So she needs the right number of sparkles without each one taking up the usual energy.</p>
<p>To solve this, she starts with a simple class for making a sparkle.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Sparkle</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">type</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>type <span class="token operator">=</span> type<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>The FG then makes a factory for making all the different sparkles. She realizes the best pattern to fit her needs is the Flyweight pattern.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">SparkleFlyweightFactory</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>sparkles <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">create</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">let</span> sparkle <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sparkles<span class="token punctuation">[</span>name<span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>sparkle<span class="token punctuation">)</span> <span class="token keyword">return</span> sparkle<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>sparkles<span class="token punctuation">[</span>name<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Sparkle</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sparkles<span class="token punctuation">[</span>name<span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Let's break down how this Flyweight factory works and how it fixes the issue.</p>
<ol>
<li>When making an instance, the factory starts with an empty <code>sparkles</code> object to store all the sparkles.</li>
<li>The <code>create</code> method is used when wanting to make more sparkles. The first thing it does is see if we already made a sparkle under the same name. If so, it returns that without making a new one.</li>
<li>If it hasn't made this type of sparkle before, it makes a new one, adds it to the object, and returns it.</li>
</ol>
<p>Now the FG can make all the sparkles she wants, and any duplicates will return what's already there. That on its own saves a lot of energy, but the Flyweight pattern does even more.</p>
<p>To see what else it does, let's look at the Wand class the FG uses to make the sparks themselves.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Wand</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">sparkleFactory</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>sparkleFactory <span class="token operator">=</span> sparkleFactory<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">addSparkle</span><span class="token punctuation">(</span><span class="token parameter">sparkle</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sparkleFactory<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>sparkle<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">getAllSparkles</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sparkleFactory<span class="token punctuation">.</span>sparkles<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">bigSparkle</span><span class="token punctuation">(</span><span class="token parameter">sparkleName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> sparkle <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sparkleFactory<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>sparkleName<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">This is a giant </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>sparkle<span class="token punctuation">.</span>type<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> sparkle!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Most of these are easy to figure out, as the first two functions are about adding sparkles and getting the full list through the Flyweight factory. But why did the FG put the <code>bigSparkle</code> method in the wand? It would work just as well in the <code>Sparkle</code> or <code>SparkleFlyweightFactory</code> classes, right?</p>
<p>Turns out, making a bigger sparkle takes a respectively bigger amount of magic to hold in the function. Repeating that function across every sparkle object uses lots of magic in bulk, and she's back at the same problem! So to solve that, she moved the function to the wand instead. Now that function only needs to be created once and called on the wand with the needed sparkle. Lots of magic is saved and the same problem is avoided.</p>
<p>At its heart, this is the problem the Flyweight solves: <strong>making and managing lots of objects with as little energy spent as possible.</strong> The objects here (the sparkles) are only made up of properties unique to themselves like the type of spark. This is the flyweight object's <em>intrinsic state.</em> Anything the same for each spark, like the function to call a big one, is shared in a single object that's only called once to manage them. Everything outside of the intrinsic state (the wand) is the <em>extrinsic</em> state.</p>
<p>We can see the benefits in action when the FG makes an instance of her wand and starts making sparks for her spell.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> WandSparks <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SparkleFlyweightFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> GodmothersWand <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Wand</span><span class="token punctuation">(</span>WandSparks<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />GodmothersWand<span class="token punctuation">.</span><span class="token function">addSparkle</span><span class="token punctuation">(</span><span class="token string">"bright red"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />GodmothersWand<span class="token punctuation">.</span><span class="token function">addSparkle</span><span class="token punctuation">(</span><span class="token string">"silver"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />GodmothersWand<span class="token punctuation">.</span><span class="token function">addSparkle</span><span class="token punctuation">(</span><span class="token string">"dull blue"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />GodmothersWand<span class="token punctuation">.</span><span class="token function">addSparkle</span><span class="token punctuation">(</span><span class="token string">"diamond shine"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />GodmothersWand<span class="token punctuation">.</span><span class="token function">addSparkle</span><span class="token punctuation">(</span><span class="token string">"bright red"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />GodmothersWand<span class="token punctuation">.</span><span class="token function">addSparkle</span><span class="token punctuation">(</span><span class="token string">"silver"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />GodmothersWand<span class="token punctuation">.</span><span class="token function">addSparkle</span><span class="token punctuation">(</span><span class="token string">"dull blue"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />GodmothersWand<span class="token punctuation">.</span><span class="token function">addSparkle</span><span class="token punctuation">(</span><span class="token string">"diamond shine"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Normally you'd expect eight different spark objects in the wand, but the Flyweight only returns the four unique ones she made.</p>
<pre class="language-javascript"><code class="language-javascript">GodmothersWand<span class="token punctuation">.</span><span class="token function">getAllSparkles</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">// { 'bright red' : Sparkle { type: 'bright red' },</span><br /><span class="token comment">// 'silver' : Sparkle { type: 'silver' },</span><br /><span class="token comment">// 'dull blue' : Sparkle { type: 'dull blue' },</span><br /><span class="token comment">// 'diamond shine' : Sparkle { type: 'diamond shine' } }</span></code></pre>
<p>Plus she can use a bigger function like making a big sparkle without it taking up too much energy either.</p>
<pre class="language-javascript"><code class="language-javascript">GodmothersWand<span class="token punctuation">.</span><span class="token function">bigSparkle</span><span class="token punctuation">(</span><span class="token string">"diamond shine"</span><span class="token punctuation">)</span><br /><span class="token comment">// This is a giant diamond shine sparkle!</span></code></pre>
<p>With the sparkles in action showing how serious her magic is, the FG is ready to turn a pumpkin into a carriage.</p>
<h2 id="making-a-pumpkin-a-carriage-with-a-decorator">Making a Pumpkin a Carriage with a Decorator <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/09/cinderella-structural-patterns/#making-a-pumpkin-a-carriage-with-a-decorator">#</a></h2>
<p>The FG sees a pumpkin over the hill and realizes it's perfect for a carriage. Normally she'd write a class to make a Pumpkin carriage from scratch, but in another effort to save magical energy, she wants to work from an existing pumpkin object.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Pumpkin</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>size <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">"#FFA500"</span><span class="token punctuation">;</span> <span class="token comment">// Orange</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>vines <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> pumpkin <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Pumpkin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This means she must dynamically change the current pumpkin. Some properties she'll adjust, some she'll add, some she'll change completely. To do this, she writes a Decorator she'll pass the pumpkin into.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">PumpkinCarriageDecorator</span> <span class="token keyword">extends</span> <span class="token class-name">Pumpkin</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">pumpkin</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">super</span><span class="token punctuation">(</span>pumpkin<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>size <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>size <span class="token operator">*</span> <span class="token number">4</span><span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">"#fffcf0"</span><span class="token punctuation">;</span> <span class="token comment">// Marble white</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>wheels <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>vines<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>vines <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">isRidable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>size <span class="token operator">></span> <span class="token number">10</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Decorators are perfect for his since they're built for <strong>adding and changing an object's functions and capabilities by dynamically extending it, instead of making a new object from scratch.</strong></p>
<p>Now she creates a Decorator, passes in the pumpkin, and magically transforms it into a pumpkin carriage!</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> pumpkinCarriage <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PumpkinCarriageDecorator</span><span class="token punctuation">(</span>pumpkin<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />pumpkinCarriage<span class="token punctuation">;</span><br /><span class="token comment">// { size: 12, color: '#fffcf0', vines: 0, wheels: 4 }</span><br />pumpkinCarriage<span class="token punctuation">.</span><span class="token function">isRidable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// true</span></code></pre>
<h2 id="letting-guests-into-the-ball-with-a-proxy">Letting Guests into the Ball with a Proxy <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/09/cinderella-structural-patterns/#letting-guests-into-the-ball-with-a-proxy">#</a></h2>
<p>Cinderella arrives at the ball in her new dress, shiny carriage, her entourage of animals turned into humans, and a magically conjured invitation. As she pulls up to the castle, she sees castle officials using a class to make instances of their new guests. This happens to her and two others arriving at the same time.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Guest</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> invitation<span class="token punctuation">,</span> gender</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>hasInvitation <span class="token operator">=</span> invitation<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>gender <span class="token operator">=</span> gender<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> partyCrasher <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Guest</span><span class="token punctuation">(</span><span class="token string">"Rachel"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token string">"female"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> maleGuest <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Guest</span><span class="token punctuation">(</span><span class="token string">"Jeff"</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token string">"male"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> cinderella <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Guest</span><span class="token punctuation">(</span><span class="token string">"Cinderella"</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token string">"female"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>So as Cinderella arrives, she sees this class take the info about her name, invitation, and gender. However, just past the castle entrance, she sees those who enter becoming instances of a party guest, not just a general castle guest. Cinderella knows she needs to be a party guest since they have access to lots of extra party methods.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">PartyGuest</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">declare</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">I, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, am at the party!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">meetRoyals</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><br /> <span class="token function">lookForPrince</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><br /> <span class="token function">eatHorsDoeuvres</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>As she and the other two guests approach the entrance, she sees another royal make another class instance of them. Cinderella's heart jumps thinking she was made a guest, but is upset and confused to see it was another class called a Proxy.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">PartyProxy</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">guest</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>guest <span class="token operator">=</span> guest<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">canAttend</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> isFemale <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>guest<span class="token punctuation">.</span>gender <span class="token operator">===</span> <span class="token string">"female"</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> isFemale <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span>guest<span class="token punctuation">.</span>hasInvitation<br /> <span class="token operator">?</span> <span class="token keyword">new</span> <span class="token class-name">PartyGuest</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>guest<span class="token punctuation">.</span>name<span class="token punctuation">)</span><br /> <span class="token operator">:</span> <span class="token string">"Sorry, you cannot attend"</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> partyCrasherGuest <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PartyProxy</span><span class="token punctuation">(</span>partyCrasher<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> malePartyGuest <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PartyProxy</span><span class="token punctuation">(</span>maleGuest<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> cinderellaGuest <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PartyProxy</span><span class="token punctuation">(</span>cinderella<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Cinderella asks the royal what they're doing, going around and making class instances of someone all willy-nilly. The royal explains getting entrance to the party is quite exclusive, so they must make sure only guests that meet all the requirements are actual <code>PartyGuest</code> instances. That's why they're made into <strong>a Proxy object, which acts as a placeholder and makes sure to limit the creation of certain objects based on their requirements. It basically acts as a gatekeeper to preserve resources.</strong></p>
<p>So when Cinderella and the other two guests approach as proxies, the guards call the <code>canAttend</code> method to check the guest's gender and invitation. If they fail the conditions, the royal at the door turns the guest away without wasting a <code>PartyGuest</code> instance.</p>
<pre class="language-javascript"><code class="language-javascript">partyCrasherGuest<span class="token punctuation">.</span><span class="token function">canAttend</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Sorry, you cannot attend</span><br />malePartyGuest<span class="token punctuation">.</span><span class="token function">canAttend</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Sorry, you cannot attend</span></code></pre>
<p>But if they do pass, it creates and returns a <code>PartyGuest</code> for them, so they can do all the things party guests do.</p>
<pre class="language-javascript"><code class="language-javascript">cinderellaGuest<span class="token punctuation">.</span><span class="token function">canAttend</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// PartyGuest { name: 'Cinderella' }</span></code></pre>
<p>Cinderella has passed and enters the ball at last!</p>
<h2 id="letting-cinderella-dance-with-a-bridge">Letting Cinderella Dance with a Bridge <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/09/cinderella-structural-patterns/#letting-cinderella-dance-with-a-bridge">#</a></h2>
<p>As Cinderella enters the ball, the Prince is talking to the attendees and deciding who to dance with. He uses a class to make himself the lead dancer and find out which women want to dance.</p>
<p>However, there are so many women he wants to ask and he can't make a class for asking each one of them. The Prince wants to ask all the girls without writing a new class each time, so he makes use of a design pattern called the Bridge.</p>
<p>First, he writes a class for himself that takes a dance partner and sees if he can dance with them.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">LeadDancerBridge</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">dancePartner</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>dancePartner <span class="token operator">=</span> dancePartner<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">canYouDance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>dancePartner<span class="token punctuation">.</span><span class="token function">canDanceWithPrince</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br /> <span class="token operator">?</span> <span class="token string">"Shall we dance?"</span><br /> <span class="token operator">:</span> <span class="token string">"Please enjoy the party!"</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p><strong>Each dance partner will vary in some way, so this class acts as a bridge since it lets any instance of a dance partner "cross the bridge" to this class to see if they're compatible.</strong></p>
<p>He then writes a class for the dance partners themselves, and its instances will be crossing the bridge. It takes some basic info about the woman and once they "cross the bridge" to the <code>LeadDancerBridge</code> class instance, the prince will know if he can dance with them or not.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">DancePartner</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> likesPrince<span class="token punctuation">,</span> wantsToDance</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>likesPrince <span class="token operator">=</span> likesPrince<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>wantsToDance <span class="token operator">=</span> wantsToDance<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">canDanceWithPrince</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>likesPrince <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span>wantsToDance<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>After a few failed attempts to dance and some half-hearted dances, the Prince finally sees Cinderella. He creates an instance of her as a dance partner and it attempts to "cross the Bridge" to the <code>LeadDancerBridge</code> class instance.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> Cinderella <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DancePartner</span><span class="token punctuation">(</span><span class="token string">"Cinderella"</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> PrinceAskingCinderella <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LeadDancerBridge</span><span class="token punctuation">(</span>Cinderella<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />PrinceAskingCinderella<span class="token punctuation">.</span><span class="token function">canYouDance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// "Shall we dance?"</span></code></pre>
<p>Cinderella has managed to "cross the bridge" which shows she wants to dance. He's relieved to finally have a dance partner, so he asks and they have a magical evening together!</p>
<h2 id="escaping-the-ball-with-a-composite">Escaping the Ball with a Composite <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/09/cinderella-structural-patterns/#escaping-the-ball-with-a-composite">#</a></h2>
<p>Sadly, we know how the story goes. Just as Cinderella and the Prince are about to kiss, the clock strikes midnight. Cinderella flees, leaves her glass slipper behind, and jumps in her carriage.</p>
<p>The horses pull the carriages as fast as they can to get away. But the guards give chase on their own, with the same number pulling a carriage with guards. As they're chased, Cinderella is worried the guard horses will chase them. So she reads over the code making up the horses to check if they're going fast enough.</p>
<p>First, she notices that each horse is a basic class which includes their speed.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Horse</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">speed</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>speed <span class="token operator">=</span> speed<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Below that she sees something called a Composite class, which she doesn't understand at first. It seems to take an array of horse objects and treats the group of Horse instances as a single, giant object.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">HorseComposite</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>horses <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">add</span><span class="token punctuation">(</span><span class="token parameter">horse</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>horses<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>horse<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">averageSpeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> speeds <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>horses<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">horse</span> <span class="token operator">=></span> horse<span class="token punctuation">.</span>speed<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> total <span class="token operator">=</span> speeds<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">previous<span class="token punctuation">,</span> current</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>current <span class="token operator">+=</span> previous<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> average <span class="token operator">=</span> total <span class="token operator">/</span> <span class="token keyword">this</span><span class="token punctuation">.</span>horses<span class="token punctuation">.</span>length<span class="token punctuation">;</span><br /><br /> <span class="token keyword">return</span> average<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>The coachman sees her reading this code and realizes what she's trying to do since there's no better time to pair program than a big horse chase. He says <strong>a Composite class is a pattern for objects arranged in a tree-like pattern, where any object could have any number of other child objects and so on.</strong> This is a relatively simple tree, where each <code>HorseComposite</code> could have any number of horse child objects and that's it, but it's a Composite pattern nonetheless.</p>
<p>Cinderella realizes these classes can be used to make sure her horses are faster than the guards. She quickly makes several instances for her own horses, adds them as "branches" to the Composite "tree," and finds their average speed.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> Bert <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Horse</span><span class="token punctuation">(</span><span class="token number">24</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Luke <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Horse</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Jaq <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Horse</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Gus <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Horse</span><span class="token punctuation">(</span><span class="token number">29</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> goodHorses <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HorseComposite</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />goodHorses<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>Bert<span class="token punctuation">)</span><span class="token punctuation">;</span><br />goodHorses<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>Luke<span class="token punctuation">)</span><span class="token punctuation">;</span><br />goodHorses<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>Jaq<span class="token punctuation">)</span><span class="token punctuation">;</span><br />goodHorses<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>Gus<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />goodHorses<span class="token punctuation">.</span><span class="token function">averageSpeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 25.5</span></code></pre>
<p>She punches in the same info for the guard's horses, sees their average speed, and does a comparison to make sure they're faster.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> Blaze <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Horse</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Lazer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Horse</span><span class="token punctuation">(</span><span class="token number">26</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Blazer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Horse</span><span class="token punctuation">(</span><span class="token number">21</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> Joe <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Horse</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> guardHorses <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HorseComposite</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />guardHorses<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>Blaze<span class="token punctuation">)</span><span class="token punctuation">;</span><br />guardHorses<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>Lazer<span class="token punctuation">)</span><span class="token punctuation">;</span><br />guardHorses<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>Blazer<span class="token punctuation">)</span><span class="token punctuation">;</span><br />guardHorses<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>David<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />guardHorses<span class="token punctuation">.</span><span class="token function">averageSpeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 25.25</span><br /><br />goodHorses<span class="token punctuation">.</span><span class="token function">averageSpeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">></span> guardHorses<span class="token punctuation">.</span><span class="token function">averageSpeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// true</span><br /><span class="token comment">// Cinderella escapes!</span></code></pre>
<p>It's close, but Cinderella's horses are just fast enough. They outrun the guards and hide in the woods right before the spell breaks.</p>
<h2 id="wearing-the-glass-slipper-with-an-adaptor">Wearing the Glass Slipper with an Adaptor <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/09/cinderella-structural-patterns/#wearing-the-glass-slipper-with-an-adaptor">#</a></h2>
<p>Cinderella is back at her home and hears the Prince is traveling the kingdom, looking for the glass slipper's owner. However, her stepmother locked her in the attic so the Prince won't meet her. In the process Cinderella falls and sprains her foot, making it swell. She's horrified, knowing her foot's increased size will stop the glass slipper from fitting.</p>
<p>Knowing she doesn't have much time until the Prince arrives, she inspects her foot and finds the class causing the swelling.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">sprainedFoot</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">size</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>size <span class="token operator">=</span> size <span class="token operator">*</span> <span class="token number">1.25</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> sprainedFoot <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">sprainedFoot</span><span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Seeing the amount of swelling, she realizes she can reverse the effect with an Adaptor. <strong>Her sprained foot can't fit the "interface" of the glass slipper, so wrapping it in an Adaptor will adjust her foot until they can fit together.</strong> So she writes her adaptor so it will decrease her foot size. She then creates an instance of it that will bring her shoe size back down.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">sprainedFootAdapter</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">foot</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>foot <span class="token operator">=</span> foot<span class="token punctuation">;</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>size <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>foot<span class="token punctuation">.</span>size <span class="token operator">*</span> <span class="token number">0.8</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> wrappedFoot <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">sprainedFootAdapter</span><span class="token punctuation">(</span>sprainedFoot<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With this adapted version of her sprained foot (let's call it a bandage), Cinderella is freed from the attic by her rodent friends and rushes downstairs. She sees the <code>GlassSlipper</code> class that can't fit on her stepsisters' feet.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">GlassSlipper</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">foot</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>foot <span class="token operator">=</span> foot<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token function">fitsOnFoot</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>foot<span class="token punctuation">.</span>size <span class="token operator">===</span> <span class="token number">8</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Cinderella then uses the "adapted" foot with the glass slipper. The adapter has brought them to the same size, so her foot fits perfectly.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> glassSlipper <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">GlassSlipper</span><span class="token punctuation">(</span>wrappedFoot<span class="token punctuation">)</span><span class="token punctuation">;</span><br />glassSlipper<span class="token punctuation">.</span><span class="token function">fitsOnFoot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// true! true! Happily ever after!</span></code></pre>
<p>The Prince knows he's found his true love after a single meeting and dance, and they run off to prepare a not-at-all-too-soon wedding!</p>
<h2 id="the-design-pattern-dragon-has-been-slain">The Design Pattern Dragon has been Slain <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/09/cinderella-structural-patterns/#the-design-pattern-dragon-has-been-slain">#</a></h2>
<p>With that, these Design Pattern Fairy Tales have reached their end. Writing them all has been a challenge, but an enjoyable one, and I'm glad I managed to stick through it the whole way. I especially hope people found them useful in understanding design patterns and how they help solve common programming problems.</p>
<p>The final lesson I'll share here is one I shared at the very start. I had an incredibly tough time learning design patterns. Part of writing this series was to force myself to understand them enough to work them into stories I already knew well. <strong>It's the tried-and-true mental trick of learning something tough by pairing it with something unexpected you already know.</strong> The new perspective encourages learning, and the strange association makes the knowledge harder to forget.</p>
<p>So if this series worked well for you, use the trick for learning more in the future! Learn Ember by comparing it to a chocolate factory or giant fighting robot. Understand React hooks with evil AIs or some kids in a magical wardrobe. Use whatever works best, and maybe even write about it afterward :)</p>
<p>With that, I close the book on this story. <em>And they all coded happily ever after.</em></p>
Three Ways to Keep Runaway Thoughts Under Control
2019-09-29T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/09/29/managing-thoughts/<p>Three Ways to Keep Runaway Thoughts Under Control</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/managing-thoughts.jpeg" alt="Post featured image"></p><p>We live with our thoughts all the time, and a surprising amount of time, they wind up being our worst enemy. Thoughts can be like horrible bullies when they get bad. They're hovering over us, know exactly what buttons to push, and on bad days they insult our mother. Now thoughts are for the obvious tasks of knowing and understanding things. But they can cause as much (if not more) to distract, mislead, or manipulate us down a bad path.<br />
I'm not immune to all this myself. So I've worked out a few strategies to keep the bad thoughts from controlling too much of my life.</p>
<h2 id="1)-give-impulse-thoughts-a-buffer">1) Give Impulse Thoughts a Buffer <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/29/managing-thoughts/#1)-give-impulse-thoughts-a-buffer">#</a></h2>
<p>There's plenty of impulsive decisions I'm better off not following. Most of them involve buying things, and the rest also involve buying things, so I'll focus on those here. I never trust whatever my first impulse is to do, so adding some kind of buffer to let it calm down helps.</p>
<p>This buffer falls into two categories: decisions I have to make right away and those I can come back to later.</p>
<h3 id="decisions-made-right-away">Decisions Made Right Away <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/29/managing-thoughts/#decisions-made-right-away">#</a></h3>
<p>For decisions I can't walk away from, I take a deep breath to keep emotions from clouding my judgment. Sometimes I'll even move away and raise my hands to prevent any impulsive behavior. Then I look at the decision as someone else learning the details. Seeing it as a third party gives perspective and removes some biases that'd lead to a bad decision.</p>
<p>For instance, I've often had an idea for a tweet and rushed to type it before the rest of my brain could catch up. Right before I hit send I stop, breath, get away from the computer and walk around a little. Then I ask how a random person, or how some people I predict may see it, may respond if they read it. Most times I send it anyway. A few times I didn't. There's some I sent before I stopped to think and regretted it.</p>
<h3 id="decisions-made-later">Decisions Made Later <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/29/managing-thoughts/#decisions-made-later">#</a></h3>
<p>If it isn't an urgent decision, the buffer is simpler and I walk away for a few days. Especially if the decision involves buying something.</p>
<p>After a few days, it's clear what I want to do or, in the case of buying, if I want it to not. Even then, some good questions to ask are:</p>
<ul>
<li>Why do I want this or want to do this? Is the real reason a good one?</li>
<li>Is it worth the needed time or money I'd be investing? Calculate how much money you make per hour and ask "is this worth paying X hours of work?"</li>
<li>How useful will it be in the short or long term?</li>
<li>Is it something I'll genuinely enjoy and not regret?</li>
</ul>
<p>This comes up a lot when seeing products on Amazon. I'm excited by the description and what I could use it for. But after thinking it over I often realize I wouldn't use it a lot. It's something I'd use a day or two and then forget about it, or it wouldn't be worth the money. Either that or it'd be too distracting or stress-inducing, in the long run, to be worth it. I've passed over lots of kitchen appliances, video games, and odd accessories this way. I don't have any FOMO though, since the ones I did buy I make use of more than enough to be worth it.</p>
<p>This is a lot of hoops to jump through for making one decision. But remember saying "yes" to one thing, by default, means saying no to at least a dozen others. That's why having these decision buffers is so important. It makes sure the few bad ones slip through and stop the better ones from reaching me.</p>
<h2 id="2)-gently-acknowledge-unwanted-thoughts">2) Gently Acknowledge Unwanted Thoughts <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/29/managing-thoughts/#2)-gently-acknowledge-unwanted-thoughts">#</a></h2>
<p>We all have thoughts we'd rather not have. They can range from silly, irrelevant, mean, or let's be honest, kind of dirty. The first impulse for many is to push the thoughts away and tell ourselves not to think them anymore. But that's like telling yourself not to think about elephants. You'll think about elephants more and make things worse.</p>
<p>The more effective strategy I've found is gently acknowledging these thoughts. Do so with compassion, acceptance, and without judgment. Forcing them away with anger brings them back stronger. The drawback is those thoughts will keep coming back and never go away. But the more important benefit is <strong>the thoughts lose a lot of their power over you.</strong></p>
<p>A common metaphor I've heard for this is treating the thoughts like a passing cloud. You see it, acknowledge it, and since you can't make the cloud go faster, wait for it to pass by. Another is walking down a street and seeing their thoughts scroll by like text on buildings. I imagine these thoughts as a bundle of light floating around before flying or fading away.</p>
<p>Whatever metaphor works best, what they have in common is thoughts come and go on their own. They encourage the "see, acknowledge, and move on" response.</p>
<h2 id="3)-write-the-thoughts-out">3) Write the Thoughts Out <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/29/managing-thoughts/#3)-write-the-thoughts-out">#</a></h2>
<p>Sometimes the issue is the thoughts won't stop and bombard my mind to the point of exhaustion. Trying to ignore or push them away once again only makes them return louder. The solution is simple: write out every thought you can think of on paper until they quiet down.</p>
<p>This helps since writing is the easiest way to externalize your thoughts. <strong>It's easier for one's mind to finally let the thoughts go. It knows they're saved somewhere else, and there's no constant need to remind the person.</strong> It's my way of telling my brain "you don't need to worry I'll forget any of this, I have it written down right here." Then I tuck the thoughts in a private journal notebook for my eyes only.</p>
<p>Writing thoughts out is especially helpful for emotional topics that need closure. Several times something had been dragging me down, I followed these steps.</p>
<ol>
<li>Write a long letter to whoever the emotions concern. It could even by yourself.</li>
<li>Reread the letter aloud and put no limits on how it makes me feel. Once or twice I was on the verge of crying.</li>
<li>Repeat step 2 as needed until my feelings start to calm down.</li>
<li>Take a deep breath and accept these feelings as they are, and feel gratitude for helping them make me who I am now. Or whatever emotion you need to feel to find closure.</li>
<li>Run the letter through a paper shredder to solidify the feeling of closure.</li>
</ol>
<p>Ultimately these tricks work by giving form to your thoughts so your mind can let them go. Writing is the simplest way, but more artistic expressions like painting work too. Writing is a good one to start with and use short-notice. It's all the more reason why creative outlets are so healthy.</p>
<h2 id="you-are-not-your-thoughts">You Are Not Your Thoughts <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/09/29/managing-thoughts/#you-are-not-your-thoughts">#</a></h2>
<p>I hope you find all the above tricks useful. But the most important thing here is less a strategy and more a misconception I want to dispel. It's that our thoughts define who we are, which I don't blame anyone for thinking. They make up a large part of one's identity and we spend so much time thinking them each day. Especially in fields like blogging or programming where thinking plays a critical role.</p>
<p>But we build our identities on so much more: our actions, morals, emotions, decisions, and many others. <strong>Thoughts are the one we're most aware of, even though they're arguably the smallest piece.</strong> We forget most thoughts the next day. They're pointless observations or random ideas popping up from our subconscious. It's why most people don't share their every waking thought on Twitter. They know most people wouldn't care to read them, including themselves. I have dozens of journals of daily thoughts going back to high school. Even I rarely care about my past thoughts.</p>
<p>Realizing how little our thoughts affect our identities takes away a lot of their power and makes them easier to manage. It turns them from a bully to that quiet friend that sometimes shares great insights. In short, it helps them start working with us more than against us.</p>
Checking Sudoku with Functional JavaScript
2019-10-07T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/<p>Checking Sudoku with Functional JavaScript</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/sudoku-javascript.png" alt="Post featured image"></p><p>A favorite CodeWars challenge of mine is the ever-wonderful "check my sudoku" puzzle. It starts with a large array of arrays representing a completed Sudoku puzzle. You need to function that checks if it's correct or not. It's complex yet understandable and requires a good amount of creativity.</p>
<p>The CodeWars puzzle itself gives two sets of data to test against. The final function should tell the difference between the passing and failing data.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> pass <span class="token operator">=</span> <span class="token function">checkSudoku</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br /> <span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">]</span><br /><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 'Finished!'</span><br /><br /><span class="token keyword">const</span> fail <span class="token operator">=</span> <span class="token function">checkSudoku</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br /> <span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">]</span><br /><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 'Try again!'</span></code></pre>
<p>For a while, I had no idea how to approach it. There were so many problems and so many ways to tackle them. So I finally settled on something I'd learned more recently - <strong>functional JavaScript!</strong></p>
<p>A while back <a href="https://www.maxwellantonucci.com/2019/06/25/metaphorical-intro-functional-js.html">I explained functional programming with angels, mutants, and farmhands</a>. I recommend reading that first, but the short version defines functional programming as:</p>
<ol>
<li>Doesn't change the external state</li>
<li>Always gives the same output for the same input</li>
<li>Is declarative (the <em>what</em>) and not imperative (the <em>how</em>)</li>
</ol>
<p>I followed these rules as much as possible for my solution. <strong>My final answer was longer and more robust, but easier to read and manage.</strong> That's a worthy trade-off since it most benefits fellow humans reading the code.</p>
<p>This puzzle was enjoyable and challenging, so I wanted to break down how I did it in this post. People reading this can learn about:</p>
<ul>
<li>Practical examples of functional programming</li>
<li>Breaking down a large, complex problem into smaller pieces</li>
<li>A secret, embedded message that will make you go insane over several years</li>
</ul>
<p>You can also skip ahead and <a href="https://gist.github.com/maxx1128/c5c62dd09291f10bc7e8c0b77df80dbb">see the final solution here</a>. If not, let's start from the beginning.</p>
<h2 id="define-the-core-problem">Define the Core Problem <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#define-the-core-problem">#</a></h2>
<p>The first step is defining my goal into some actionable steps. The goal of "checking this Sudoku" is a starting point, but also too broad. It tells me nothing about how to approach the code.</p>
<ol>
<li>Check that the sudoku is valid</li>
</ol>
<p>First, how does one see that Sudoku is valid? The core of any Sudoku problem is having the numbers 1-9 in all the right places - rows, columns, and the 3x3 squares. This puzzle gives a massive array of number arrays, and we need to navigate them and check their numbers.</p>
<p>So going off how Sudoku works, I can break down the goal into three smaller steps.</p>
<ol>
<li>Check that each <strong>row</strong> only uses the numbers 1-9 once.</li>
<li>Check that each <strong>column</strong> only uses the numbers 1-9 once.</li>
<li>Check that each <strong>square</strong> only uses the numbers 1-9 once.</li>
</ol>
<p>This is clear but repetitive. Each step looks at a different area, but the final step is the same: check the numbers. Having one function to check the numbers each time is more efficient.</p>
<ol>
<li>Write function X that checks if a Sudoku array is valid.</li>
<li>Check each row's numbers against function X</li>
<li>Check each column's numbers against function X</li>
<li>Check each squares' numbers against function X</li>
</ol>
<p>Now I'm making progress! Writing a function to check numbers isn't too tough. But the data I get may not be easy to check as a row, column, or square. At the start, it's a big array of arrays. I'll likely need to rearrange the data a bit before doing a check. So the three steps to check data each need an extra one.</p>
<ol>
<li>Write function X that checks if a Sudoku array is valid.</li>
<li>Organize the data into arrays of row numbers</li>
<li>Check each row array against function X</li>
<li>Organize the data into arrays of column numbers</li>
<li>Check each column array against function X</li>
<li>Organize the data into arrays of square numbers</li>
<li>Check each square array against function X</li>
</ol>
<p>These steps are clear, concise, and easy to tackle as actionable code tasks. So let's solve them down one at a time.</p>
<h2 id="1.-write-the-function-to-check-arrays">1. Write the Function to Check Arrays <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#1.-write-the-function-to-check-arrays">#</a></h2>
<p><strong>The function should take an array and ask "does this array use the numbers 1-9 once?"</strong> A quick way to compare simple arrays is to sort them, convert them to a string, and compare with <code>===</code>. One array is an argument passed to the function. I hardcoded the other with the numbers one through nine. The result is simple and sticks to functional programming rules - pure, declarative, and gluten-free.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">isSudokuArrayValid</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">array</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> row <span class="token operator">=</span> array<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> passingRow <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">7</span><span class="token punctuation">,</span><span class="token number">8</span><span class="token punctuation">,</span><span class="token number">9</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">return</span> <span class="token punctuation">(</span>row <span class="token operator">===</span> passingRow<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>The remaining checks for rows, columns, and squares will make use of this one. Each will be a function that:</p>
<ol>
<li>Takes the board array as its only argument</li>
<li>Reorganizes the data to get arrays that represent the rows, columns or squares</li>
<li>I run each array through the <code>isSudokuArrayValid</code> function</li>
<li>If each array passes, the function returns <code>true</code>, or else it returns <code>false</code></li>
</ol>
<p>In the end, I'll have three functions like this, rows, columns, and squares. The end of this entire function is making sure all three pass. If so, the Sudoku is valid!</p>
<p>So let's get started with the Sudoku rows.</p>
<h2 id="2.-organize-data-into-sudoku-rows">2. Organize Data into Sudoku Rows <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#2.-organize-data-into-sudoku-rows">#</a></h2>
<p>This is an easy first step since it's already done for me. The passed <code>board</code> value in is already an array of arrays, with each being a row of numbers from left to right.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br /> <span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">]</span><br /><span class="token punctuation">]</span></code></pre>
<p>This is already perfect for validating row data, so I can jump right to the test.</p>
<h2 id="3.-check-the-sudoku-rows">3. Check The Sudoku Rows <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#3.-check-the-sudoku-rows">#</a></h2>
<p>I need to pass each array into my <code>isSudokuArrayValid</code> function. Each row has to pass this check or they all fail.</p>
<p>Functional JavaScript led me to a helpful array method called <code>every()</code>. <strong>It lets you run through each item in an array, and returns <code>true</code> only if each item returns <code>true</code>.</strong> This one method does exactly what I need. That means this function only needs to do one thing and can fit in one line.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">testRows</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">board</span><span class="token punctuation">)</span> <span class="token operator">=></span> board<span class="token punctuation">.</span><span class="token function">every</span><span class="token punctuation">(</span><span class="token parameter">row</span> <span class="token operator">=></span> <span class="token function">isSudokuArrayValid</span><span class="token punctuation">(</span>row<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Here we take each row, run it through our function, and if all the rows check out, <code>testRows()</code> returns true! I'm already 33% of the way to validating the Sudoku.</p>
<h2 id="4.-organize-data-into-sudoku-columns">4. Organize Data into Sudoku Columns <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#4.-organize-data-into-sudoku-columns">#</a></h2>
<p>Getting all the numbers in a column isn't done for me, but isn't too tricky either. In array terms, numbers from the same index of each row make up each column. Column one is the first number from each row, column two is the second from each, and so on. I need to gather these numbers for columns one through nine.</p>
<p>Let's think about this in JavaScript terms. If we define each array as <code>row</code> in a loop, column one would be <code>row[0][0]</code>, <code>row[1][0]</code>, <code>row[2][0]</code>, and so on until <code>row[8][0]</code>. So the function first needs to loop through and gather data from each row.</p>
<p>When it comes to gathering data while looping, functional JavaScript has <code>reduce</code>! <code>reduce</code> is too vast to cover here, but what matters here is it gives you a variable that carries over in the loop. So you could make this variable an array, and add a value to it over each row number. Which I do in the below <code>gatherColumn</code> function.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">gatherColumn</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">board<span class="token punctuation">,</span> columnNum</span><span class="token punctuation">)</span> <span class="token operator">=></span> board<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">total<span class="token punctuation">,</span> row</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token operator">...</span>total<span class="token punctuation">,</span> row<span class="token punctuation">[</span>columnNum<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>In a nutshell <code>reduce</code> is saying it will start with an empty array (the <code>[]</code> at the end). <strong>It updates that array with whatever we want after each loop.</strong> I pick out the needed row number with <code>row[columnNum]</code> for each round. Then I use the <code>...total</code> spread operator to add the current array. The result is it adds the new number to the list each time. The final result is all the numbers from a column.</p>
<h2 id="5.-check-the-sudoku-columns">5. Check the Sudoku Columns <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#5.-check-the-sudoku-columns">#</a></h2>
<p>With the column numbers gathered, I only need to run it for each row. That means getting the column numbers from indexes <code>0</code> to <code>8</code>. Then I check them all against <code>isSudokuArrayValid</code>, which I can do in one line!</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">testColumns</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">board</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> <span class="token function-variable function">gatherColumn</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">board<span class="token punctuation">,</span> columnNum</span><span class="token punctuation">)</span> <span class="token operator">=></span> board<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">total<span class="token punctuation">,</span> row</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token operator">...</span>total<span class="token punctuation">,</span> row<span class="token punctuation">[</span>columnNum<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">7</span><span class="token punctuation">,</span><span class="token number">8</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">every</span><span class="token punctuation">(</span><span class="token parameter">i</span> <span class="token operator">=></span> <span class="token function">isSudokuArrayValid</span><span class="token punctuation">(</span><span class="token function">gatherColumn</span><span class="token punctuation">(</span>board<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>I wrote out the array of indexes, which is not too elegant but it works. Then I check the result of <code>gatherColumn</code> against <code>isSudokuArrayValid</code>. The resulting function does what I want, validating each Sudoku column.</p>
<h2 id="6.-organize-data-into-sudoku-squares">6. Organize Data into Sudoku Squares <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#6.-organize-data-into-sudoku-squares">#</a></h2>
<p>This is the hardest check of all. Gathering numbers from grouped squares isn't a straightforward trick. Each square has a different collection of index values for rows and columns. Looping through them right takes some extra logic.</p>
<p>My approach here was, again, to tackle the smallest problem first and use it to handle larger ones. I didn't have a clear idea of how the final function would work at the start, but I figured it out as I went.</p>
<h3 id="6a.-get-the-square-indexes">6a. Get the Square Indexes <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#6a.-get-the-square-indexes">#</a></h3>
<p>I started simple: get the indexes for each "square" on the board. <strong>Each number in a square has two indexes: the row index and the column index.</strong> So getting all the indexes for a square means getting nine pairs of indexes, one for each number.</p>
<p>Let's say the top-right square is "square one." The next one in the row is "square two," and it goes on until "square nine" on the bottom right. If I wanted all the indexes for square one, I'd need a function that returns the following array of arrays:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br /> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><br /><span class="token punctuation">]</span></code></pre>
<p>Looking at the <code>board</code> array I'm working with, these indexes would get us the square one. These values are the first three numbers in the first three arrays below.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br /> <span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">]</span><br /><span class="token punctuation">]</span></code></pre>
<p>So how do we get a function to return the needed row and column index values?</p>
<p>After thinking it over for a while, I realized one function can do this for both rows and columns. I can distill the logic down to these steps:</p>
<ol>
<li>For a square in the first row or column, give the indexes <code>[0, 1, 2]</code></li>
<li>For a square in the second row or column, give the indexes <code>[3, 4, 5]</code></li>
<li>For a square in the third row or column, give the indexes <code>[6, 7, 8]</code></li>
</ol>
<p>This logic screams "conditional statement." So for once I listened to the screams echoing from the dark recesses of my mind and wrote this function.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">getSquareIndexes</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">num</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>num <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>num <span class="token operator">===</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">7</span><span class="token punctuation">,</span><span class="token number">8</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Now whether it's for rows or columns, I can use this to get the needed indexes for that group. That's nice and all, but useless without the related values. I wasn't even sure how I'd make use of this function. So I kept going by intuition for the next step.</p>
<h3 id="6b.-get-the-square-values">6b. Get the Square Values <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#6b.-get-the-square-values">#</a></h3>
<p>So I have the indexes, now I need to use them. I need a function to pull the values from the <code>board</code> variable.</p>
<p>Like with the row and column checks, I need to do some looping. <strong>But I've got two numbers to loop through, the row indexes and the column indexes, so it'll take two loops.</strong> For finding the values in square one, the two loops would go like this.</p>
<ol>
<li>Loop through all the rows that make up the square.</li>
<li>In each row, loop through each of its columns that make up that square.</li>
</ol>
<p>So it's two loops with one loop working inside the other. It took some brooding, trial and error, and prayer sessions at the Altar of JavaScript. But I got a working function for this, and I'll break it down step by step.</p>
<p>First, the function will need three values: the row group, the column group, and the board itself. The row and column groups correspond to the square setup. There are numbers between zero and two: square one is the first three rows and columns, so they'd be <code>0, 0</code>. Square two is the first three rows and the second group of three columns, so they'd be <code>0, 1</code>.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">getSquareValues</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> y<span class="token punctuation">,</span> board</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token comment">// Magic to go here</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>You may have read "numbers between zero and two" and recalled that <code>getSquareIndexes</code> function. Good catch, since that's what the numbers are for! This function uses each to get the needed indexes for the rows and columns.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">getSquareValues</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> y<span class="token punctuation">,</span> board</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> row <span class="token operator">=</span> <span class="token function">getSquareIndexes</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> columns <span class="token operator">=</span> <span class="token function">getSquareIndexes</span><span class="token punctuation">(</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>With the needed indexes, I can now do my two loops: <strong>loop through the rows, and then loop through the columns in that row.</strong> I also need to declare an empty array I can push the values to as I find them.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">getSquareValues</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> y<span class="token punctuation">,</span> board</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">let</span> values <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> rows <span class="token operator">=</span> <span class="token function">getSquareIndexes</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> columns <span class="token operator">=</span> <span class="token function">getSquareIndexes</span><span class="token punctuation">(</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> rows<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">row</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> columns<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">column</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> values<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>board<span class="token punctuation">[</span>row<span class="token punctuation">]</span><span class="token punctuation">[</span>column<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">return</span> values<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>The code can now gather the square values! Calling <code>getSquareValues(1, 1, board)</code> gets me an array of numbers for square one. <code>getSquareValues(1, 2, board)</code> for square two, all the way to <code>getSquareValues(3, 3, board)</code> for square nine.</p>
<h2 id="7.-check-the-sudoku-squares">7. Check the Sudoku Squares <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#7.-check-the-sudoku-squares">#</a></h2>
<p>All that's left is running all these values through <code>isSudokuArrayValid</code>. I need to cover every combination of <code>[1, 2, 3]</code> when gathering square values. I can do this with another nested loop. <code>every()</code> also comes in to make sure each square passes.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">testSquares</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">board</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> squareSections <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> squareSections<span class="token punctuation">.</span><span class="token function">every</span><span class="token punctuation">(</span><span class="token parameter">squareX</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> squareSections<span class="token punctuation">.</span><span class="token function">every</span><span class="token punctuation">(</span><span class="token parameter">squareY</span> <span class="token operator">=></span> <span class="token function">isSudokuArrayValid</span><span class="token punctuation">(</span><span class="token function">getSquareValues</span><span class="token punctuation">(</span>squareX<span class="token punctuation">,</span> squareY<span class="token punctuation">,</span> board<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>With that, I now have the third and final function to check each part of a Sudoku. All that's left is throwing them together.</p>
<h2 id="8.-putting-it-all-together">8. Putting it All Together <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#8.-putting-it-all-together">#</a></h2>
<p>The final step is the last line in this function. With everything done in my other functions, I only need to confirm they all pass. That determines if they return the <code>"Finished!"</code> or <code>"Try again!"</code> strings. A few comparatives and a ternary operator are all it takes.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token function">testRows</span><span class="token punctuation">(</span>board<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token function">testColumns</span><span class="token punctuation">(</span>board<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token function">testSquares</span><span class="token punctuation">(</span>board<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">'Finished!'</span> <span class="token operator">:</span> <span class="token string">'Try again!'</span><span class="token punctuation">;</span></code></pre>
<p>Boom! You can <a href="https://gist.github.com/maxx1128/c5c62dd09291f10bc7e8c0b77df80dbb">see my completed <code>checkSudoku</code> function in all its glory in this gist</a>. It includes the tests at the start so you can confirm it works.</p>
<h2 id="conclusion">Conclusion <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/07/sudoku-breakdown/#conclusion">#</a></h2>
<p>Not much more to write here other than I hope you enjoyed reading this breakdown. Writing it was tough but fun. There's always a big gap between "understanding" and "explaining" solution." <strong>But crossing that gap helps improve understanding and memory for future code challenges.</strong> Writing this even helped me further improve the function (like naming variables better). Here's hoping I can write more breakdowns like this later.</p>
Remixing Hotel California with Sonic Pi
2019-10-30T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/10/30/sonic-pi-hotel-california/<p>Remixing Hotel California with Sonic Pi</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/sonic-pi-hotel-california.jpg" alt="Post featured image"></p><p>I love writing all kinds of code - CSS, JavaScript, Ember, hacks to domestic and foreign restaurant databases, and Ruby. But one type of code I love and too often overlook is for <a href="https://sonic-pi.net/">Sonic Pi</a>. It's the open-source tool that turns Ruby-esque code into music. Yes, actual music, as you can see below.</p>
<div class="iframe-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/G1m0aX9Lpts" title="Embedded YoutTube video" frameborder="0" allowfullscreen=""></iframe>
</div>
<p>Lately, I've gotten back to writing Sonic Pi music and thought I'd infect others with its joy and magic. So I dug up a song I wrote with it, an atmospheric remix of Hotel California by The Eagles. This is a tutorial walking through how, in 55 lines of code, Sonic Pi helped me make this:</p>
<div class="mb-4 overflow-hidden">
<iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/704959672&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true"></iframe>
</div>
<p>Along the way, I'll cover some Sonic Pi basics to show what it's capable of. But there's a built-in tutorial if you download the program I highly recommend. <a href="https://sonic-pi.mehackit.org/">Mehackit also has notes on a great Sonic Pi workshop</a> that's worth reading.</p>
<p><em>Quick note: Writing musical code both highly technical and subjective. You may not agree with the code I wrote has the effect I aimed for, and that's fine. There are lots of ways to get there, more ways to disagree, and even more to learn from each other.</em></p>
<p>So let's begin! Sadly I can't embed Sonic Pi snippets with their sound outputs, so feel free to download the app and play the snippets as I go!</p>
<h2 id="gather-the-chords">Gather The Chords <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/30/sonic-pi-hotel-california/#gather-the-chords">#</a></h2>
<p>I decided on Hotel California as my inspiration for two reasons:</p>
<ol>
<li>It's awesome</li>
<li>It can be played with two basic chord progressions</li>
</ol>
<p>There's plenty of music sites that break down the chords behind the song, but <a href="https://tabs.ultimate-guitar.com/tab/eagles/hotel_california_chords_46190">I went with Ultimate Guitar for its readability</a>. First, there are the chords used for verses.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/sonic-pi-hotel-california/california_opening_tabs.png" alt="A verse of Hotel California with different chords above the words." /></p>
<p>Then the chords for the chorus.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/sonic-pi-hotel-california/california_chorus_tabs.png" alt="A chorus of Hotel California with different chords above the words." /></p>
<p>It's easy to translate these into something Sonic Pi can understand. It has built-in functions for both arrays and chords: <code>ring</code> and <code>chord</code>. You can see them in action below.</p>
<pre class="language-ruby"><code class="language-ruby">opening_ring <span class="token operator">=</span> <span class="token punctuation">(</span>ring chord<span class="token punctuation">(</span><span class="token symbol">:a</span><span class="token punctuation">,</span> <span class="token symbol">:minor</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:e</span><span class="token punctuation">,</span> <span class="token symbol">:major7</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:g</span><span class="token punctuation">,</span> <span class="token symbol">:major</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:d</span><span class="token punctuation">,</span> <span class="token symbol">:major</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:f</span><span class="token punctuation">,</span> <span class="token symbol">:major</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:c</span><span class="token punctuation">,</span> <span class="token symbol">:major</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:d</span><span class="token punctuation">,</span> <span class="token symbol">:minor</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:e</span><span class="token punctuation">,</span> <span class="token symbol">:minor</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br /><br />chorus_ring <span class="token operator">=</span> <span class="token punctuation">(</span>ring chord<span class="token punctuation">(</span><span class="token symbol">:f</span><span class="token punctuation">,</span> <span class="token symbol">:major</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:c</span><span class="token punctuation">,</span> <span class="token symbol">:major</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:e</span><span class="token punctuation">,</span> <span class="token symbol">:major7</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:a</span><span class="token punctuation">,</span> <span class="token symbol">:minor</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:f</span><span class="token punctuation">,</span> <span class="token symbol">:major</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:c</span><span class="token punctuation">,</span> <span class="token symbol">:major</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:d</span><span class="token punctuation">,</span> <span class="token symbol">:minor</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> chord<span class="token punctuation">(</span><span class="token symbol">:e</span><span class="token punctuation">,</span> <span class="token symbol">:major</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p><code>ring</code> is Sonic Pi's version of an array with added functions for playing sounds. <code>chord</code> takes the chord's name and gives you a ring of the notes that make it up. Once you have these rings, you can play those notes any way you want - all at once, one at a time, or at random. You can also grab notes by scales or octaves for even more sounds. But notes gathered based on any of these groups will almost always sound good together.</p>
<h2 id="use-the-opening-for-the-main-melody">Use the Opening for the Main Melody <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/30/sonic-pi-hotel-california/#use-the-opening-for-the-main-melody">#</a></h2>
<p>After some internal debate, I settled on the opening chords for the song's main melody. I planned to start simple and code things by ear (get it?) until I got a creepy, atmospheric feel.</p>
<p>So to start, I played each chord in a loop. Sonic Pi has two tools to make that easy:</p>
<ol>
<li><code>live_loop</code>, which runs all code, sounds, and logic in it infinitely. It runs in tandem with other <code>live_loop</code>s, making it great for layering melodies.</li>
<li><code>tick</code>, which is a <code>ring</code> function that plays each note in the sequence. Each time <code>tick</code> is called, it plays the next note in a repeated loop.</li>
</ol>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:opening</span> <span class="token keyword">do</span><br /> play opening_ring<span class="token punctuation">.</span>tick<br /> sleep <span class="token number">1</span><br /><span class="token keyword">end</span></code></pre>
<p>This tells Sonic Pi to play each chord, wait for a second, then play the next. It's a start, but something atmospheric should be slower. So first I increased the rest between each chord.</p>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:opening</span> <span class="token keyword">do</span><br /> play opening_ring<span class="token punctuation">.</span>tick<br /> sleep <span class="token number">3</span><br /><span class="token keyword">end</span></code></pre>
<p>This helps, but now there's too much silence. Stretching each chord over those three seconds would add some more tension and creepiness. Which is possible!</p>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:opening</span> <span class="token keyword">do</span><br /> play opening_ring<span class="token punctuation">.</span>tick<span class="token punctuation">,</span> <span class="token symbol">attack</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token symbol">sustain</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token symbol">release</span><span class="token operator">:</span> <span class="token number">1.50</span><br /> sleep <span class="token number">3</span><br /><span class="token keyword">end</span></code></pre>
<p>These properties likely seem weird but are pretty straightforward:</p>
<ol>
<li><code>attack</code> is the time from silence to full volume.</li>
<li><code>sustain</code> is the time at full volume.</li>
<li><code>release</code> is the time from full volume to silence.</li>
</ol>
<p>The respective default values for these are <code>0, 0, 1</code>, so my changes stretch the chord quite a bit. It sounds more like a gentle howling in the wind then someone banging keyboard notes. This is good, but still sounds too plain. I want to layer on something else for extra texture.</p>
<p>I'll spare you the experimenting and cut to the end. Before I explain, try to guess what this code does.</p>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:opening_deep</span> <span class="token keyword">do</span><br /> play opening_ring<span class="token punctuation">.</span>tick<span class="token punctuation">.</span>tick<span class="token punctuation">,</span> <span class="token symbol">attack</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token symbol">release</span><span class="token operator">:</span> <span class="token number">1</span><br /> sleep <span class="token number">1</span><br /><span class="token keyword">end</span></code></pre>
<p>You may remember that <code>opening_ring</code> is a ring of chords, and each <code>chord</code> returns a ring of notes. So <code>opening_ring.tick.tick</code> is ticking through each note of each chord, one at a time and not all at once. In music theory, this is a "broken chord." So the result of these two loops is the full and broken chords playing at once.</p>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:opening</span> <span class="token keyword">do</span><br /> play opening_ring<span class="token punctuation">.</span>tick<span class="token punctuation">,</span> <span class="token symbol">attack</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token symbol">sustain</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token symbol">release</span><span class="token operator">:</span> <span class="token number">1.50</span><br /> sleep <span class="token number">3</span><br /><span class="token keyword">end</span><br /><br />live_loop <span class="token symbol">:opening_deep</span> <span class="token keyword">do</span><br /> play opening_ring<span class="token punctuation">.</span>tick<span class="token punctuation">.</span>tick<span class="token punctuation">,</span> <span class="token symbol">attack</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token symbol">release</span><span class="token operator">:</span> <span class="token number">1</span><br /> sleep <span class="token number">1</span><br /><span class="token keyword">end</span></code></pre>
<p>The result is a simple yet haunting melody, with the notes grouped in a way that still work.</p>
<h2 id="use-the-chorus-for-the-atmosphere">Use the Chorus for the Atmosphere <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/30/sonic-pi-hotel-california/#use-the-chorus-for-the-atmosphere">#</a></h2>
<p>I have the opening chords for the melody, but I still want to make use the chorus chords. The melody is already the music's main focus, so I used these chords for some ambiance. To get this effect, I used two other Sonic Pi tools - synths and sound effects.</p>
<p><strong>Synths are the sounds Sonic Pi uses to executed sounds composed from notes and chords.</strong> So far I've been using the default <code>beep</code> synth since it fit with what I wanted. But there are dozens to choose from, from pianos to chip noises to pulses to whatever. In this case, the <code>hollow</code> synth fits perfectly. It's described as "a hollow breathy sound constructed from random noise." That's great for a fog-like effect, and can be set within specific loops.</p>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:ambience</span> <span class="token keyword">do</span><br /> use_synth <span class="token symbol">:hollow</span><br /> play chorus_ring<span class="token punctuation">.</span>tick<span class="token punctuation">,</span> <span class="token symbol">amp</span><span class="token operator">:</span> <span class="token number">0.15</span><span class="token punctuation">,</span> <span class="token symbol">attack</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token symbol">sustain</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token symbol">release</span><span class="token operator">:</span> <span class="token number">0</span><br /> sleep <span class="token number">3</span><br /> <span class="token keyword">end</span><br /><span class="token keyword">end</span></code></pre>
<p><strong>Sound effects are filters you can run anything through.</strong> This includes changing echoes, pitches, frequencies, sample rates, and more. I don't understand them all but understand a good amount of them. I went with two for the ambiance loop: <code>gverb</code> for a spacious and outdoorsy feel, and <code>flanger</code> for a whooshing wind effect.</p>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:ambience</span> <span class="token keyword">do</span><br /> use_synth <span class="token symbol">:hollow</span><br /> with_fx <span class="token symbol">:gverb</span> <span class="token keyword">do</span><br /> with_fx <span class="token symbol">:flanger</span> <span class="token keyword">do</span><br /> play chorus_ring<span class="token punctuation">.</span>tick<span class="token punctuation">,</span> <span class="token symbol">amp</span><span class="token operator">:</span> <span class="token number">0.15</span><span class="token punctuation">,</span> <span class="token symbol">attack</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token symbol">sustain</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token symbol">release</span><span class="token operator">:</span> <span class="token number">0</span><br /> sleep <span class="token number">3</span><br /> <span class="token keyword">end</span><br /> <span class="token keyword">end</span><br /><span class="token keyword">end</span></code></pre>
<p>The result is a distant, echoing effect that feels vaguely disturbing but keeps the song's spirit.</p>
<h2 id="add-samples-for-variety">Add Samples for Variety <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/30/sonic-pi-hotel-california/#add-samples-for-variety">#</a></h2>
<p>These three loops do a lot, but they're relatively short and can get stale. So adding a few samples keeps things interesting.</p>
<p><strong>Samples are pre-recorded sound bites that you can't control with notes and chords, but can still be modified with code.</strong> Sonic Pi has many included, and you can easily add more! So I took some pre-existing ones and mixed in some needed effects.</p>
<p>The first sample is <code>glitch_bass_g</code>. As the name implies, it's a glitchy base sound suited for background beats. Not built for creepy songs, but a few tweaks can fix that. The first is adjusting its <code>rate</code> property.</p>
<p><code>rate</code> is the speed a sample plays at, letting you slow it down or speed it up. You can set it to a negative value to play clips backward, which is what I did. I used another tool, <code>rrand</code>, for generating random numbers between two values. Now I can slow the sample down, play it backward, and add variety to each play. I can also adjust the <code>amp</code> property to make it louder.</p>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:disturbance</span> <span class="token keyword">do</span><br /> sample <span class="token symbol">:glitch_bass_g</span><span class="token punctuation">,</span> <span class="token symbol">amp</span><span class="token operator">:</span> <span class="token number">2.25</span><span class="token punctuation">,</span> <span class="token symbol">rate</span><span class="token operator">:</span> rrand<span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.1</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.4</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token symbol">release</span><span class="token operator">:</span> <span class="token number">6</span><br /> sleep <span class="token number">6</span><br /><span class="token keyword">end</span></code></pre>
<p>This all creates a disquieting rumble, but I wanted it to sound stranger. Thankfully you can also apply effects to samples. So I ran it through the <code>octaver</code> filter. This changes the sound to a mix of different pitches, which adds a distorted and disquieting effect.</p>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:disturbance</span> <span class="token keyword">do</span><br /> with_fx <span class="token symbol">:octaver</span> <span class="token keyword">do</span><br /> sample <span class="token symbol">:glitch_bass_g</span><span class="token punctuation">,</span> <span class="token symbol">amp</span><span class="token operator">:</span> <span class="token number">2.25</span><span class="token punctuation">,</span> <span class="token symbol">rate</span><span class="token operator">:</span> rrand<span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.1</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.4</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token symbol">release</span><span class="token operator">:</span> <span class="token number">6</span><br /> <span class="token keyword">end</span><br /> sleep <span class="token number">6</span><br /><span class="token keyword">end</span></code></pre>
<p>Lastly, I don't want this effect playing constantly or it'd overshadow everything else. So I used the <code>one_in</code> function to randomly limit how much it plays. For example, <code>one_in(3)</code> only returns <code>true</code> 33% of the time. Use this with a conditional and the sample will randomly play that amount less.</p>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:disturbance</span> <span class="token keyword">do</span><br /> <span class="token keyword">if</span> one_in<span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><br /> with_fx <span class="token symbol">:octaver</span> <span class="token keyword">do</span><br /> sample <span class="token symbol">:glitch_bass_g</span><span class="token punctuation">,</span> <span class="token symbol">amp</span><span class="token operator">:</span> <span class="token number">2.25</span><span class="token punctuation">,</span> <span class="token symbol">rate</span><span class="token operator">:</span> rrand<span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.1</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.4</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token symbol">release</span><span class="token operator">:</span> <span class="token number">6</span><br /> <span class="token keyword">end</span><br /> <span class="token keyword">end</span><br /> sleep <span class="token number">6</span><br /><span class="token keyword">end</span></code></pre>
<p>The final sound effect I wanted was something like people howling. Sonic Pi actually (and kind of creepily) has a sample called <code>ambi_choir</code>, one of some people yelling. It's so close I didn't even need a filter, just some property tweaks and another conditional to quiet it down.</p>
<pre class="language-ruby"><code class="language-ruby">live_loop <span class="token symbol">:shout</span> <span class="token keyword">do</span><br /> <span class="token keyword">if</span> one_in<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><br /> sample <span class="token symbol">:ambi_choir</span><span class="token punctuation">,</span> <span class="token symbol">amp</span><span class="token operator">:</span> <span class="token number">1.25</span><span class="token punctuation">,</span> <span class="token symbol">rate</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token symbol">decay</span><span class="token operator">:</span> <span class="token number">2</span><br /> <span class="token keyword">end</span><br /> sleep <span class="token number">3</span><br /><span class="token keyword">end</span></code></pre>
<p>These two samples add small surprises throughout that are still consistent with the tone.</p>
<p>With that, my Sonic Pi composition is complete! <a href="https://github.com/maxx1128/Sonic-Pi-Songs/blob/master/hotel_california.rb">You can read all the song's code here</a>.</p>
<h2 id="wrapping-up">Wrapping Up <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/10/30/sonic-pi-hotel-california/#wrapping-up">#</a></h2>
<p>I like how this song came out, but this is a relatively simple Sonic Pi project. It's some fancy sound loops timed around each other with some chords and randomness mixed in. Sonic Pi has a tutorial section of increasingly complex examples, with more loop logic and even song phases. Others have composed entire song albums with it. This example is only scratching the surface.</p>
<p>All this shows how Sonic Pi offers both ease of use and lots of depth to explore, so it's fun for new and veteran coders. I plan to make more compositions in the future, and hope you all will too!</p>
<p><strong><a href="https://www.patreon.com/samaaron">If you want to support the next version of Sonic Pi and keep the app free, consider donating to its Patreon page!</a></strong></p>
31 Benefits of Getting Away From Twitter
2019-11-18T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/11/18/effects-leaving-twitter/<p>31 Benefits of Getting Away From Twitter</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/effects-twitter-leaving.jpg" alt="Post featured image"></p><p>Nearly two weeks ago I chose to unplug from Twitter. Since then, aside from cross-posts, and content I see from my Feedbin, I've spent virtually no time directly on Twitter sites.</p>
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr">Unplugging from Twitter for a while. Need to refocus on catching up on my learning, I’ve been falling behind on lots of fundamental material.</p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1191715539489632262?ref_src=twsrc%5Etfw">November 5, 2019</a></blockquote>
<p>I'm not the first person to get away from Twitter, and not the first to see the many perks and effects leaving has on my mental health. While there are many, I'm going to stick with the top 31 (for now).</p>
<h2 id="more-positive-activities">More Positive Activities <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/18/effects-leaving-twitter/#more-positive-activities">#</a></h2>
<p><strong>1) Reading more,</strong> especially during meals and before bed. I even made a few trips to the library for some graphic novels!</p>
<p><strong>2) Catching up on coding books.</strong> <em>The Pragmatic Programmer</em> and <em>Clean Code</em> are two classics I'm been hoping to read more of for a while. I finally recorded some notes on chapters I'd read before and added a few new ones.</p>
<p><strong>3) Throwing myself into laser cutting.</strong> A lot of that extra energy had to go to a creative outlet. So I found some new tools, got some more pieces of art ready, and gave it a go. The results so far have been a lot of fun. Soon I shall tackle making my holiday gifts.</p>
<ul class="post-content--image-list">
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/stopping-twitter/laser-cutting-1.jpg" alt="A laser-cut art version of an anime drawing of a girl with glasses." />
</li>
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/stopping-twitter/laser-cutting-2.jpg" alt="A laser-cut art version of Zelda from Breath of the Wild." />
</li>
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/stopping-twitter/laser-cutting-4.jpg" alt="A laser-cut art version of a girl walking with a cat through an Italian archway." />
</li>
</ul>
<p><strong>4) Practicing more piano.</strong> The piano takes time and effort to learn, and I've at least more time now. Whether or not I can play anything from my four-chord songbook soon is another story.</p>
<p><strong>5) Checking Tweetdeck and walking away.</strong> It somehow opens up on my laptop, but I close it and walk away.</p>
<p><strong>6) Playing some video games.</strong> I'm not a pure, productivity machine after all. I finally beat World of Light in Super Smash Bros. Ultimate, and will likely give in and buy Pokemon Shield sometime soon.</p>
<p><strong>7) Checking Tweetdeck again, and longer, before walking away.</strong> I close it again, idle around, and manage to walk away again.</p>
<h2 id="deeper-thinking">Deeper Thinking <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/18/effects-leaving-twitter/#deeper-thinking">#</a></h2>
<p><strong>8) Thinking about my future.</strong> What larger career goals do I want to move towards? Do I want to stay focused on web accessibility or something close to it, like progressive web apps? Where would I like to be in five or ten years?</p>
<p><strong>9) Focusing on future blog posts.</strong> I've been neglecting my personal and professional writing lately, and want to pick it back up. Writing is my best way to organize and clarify my research goals. It's more work than a tweet but has a much bigger payoff.</p>
<p><strong>10) Wondering how some writing could translate to tweets.</strong> Lots of ponderings about work or the future are pithy enough. Some would be well-received on Twitter, right?</p>
<p><strong>11) Planning out potential projects.</strong> Making a progressive web app with Ember and a serverless database is my top choice right now. What the app will focus on and how big the scale will be is another matter. One possibility is expanding on my Ember quiz app.</p>
<p><strong>12) Wondering how other thoughts would be good tweets.</strong> Little plans about building on these apps would be good. Ember experts could weigh in. People could just be impressed by my long-term goals. That's worth going back to Twitter for a bit, right?</p>
<p><strong>13) Ignore these tweet thoughts.</strong> No, don't let some social network win. Focus on the present and the real work and progress you're making.</p>
<p><strong>14) Learning more from work.</strong> My job still overlaps a lot with learning goals about coding best practices and accessibility. I can pull enough focus together to record some lessons and even work them into future blog posts.</p>
<p><strong>15) Watching the company buyout.</strong> That's right, SeeClickFix was recently bought by CivicPlus. This is actual tech news, and I'm experiencing the effects of it all at work. It's a lot to digest and it's important, I need to stay focused on that!</p>
<p><strong>16) Remembering how I'm not tweeting about any of this.</strong> News like this is big and would be noticed online. Being part of the company itself would get even more attention. I'm missing a chance!</p>
<p><strong>17) Starting to obsess over how I missed the chance to tweet about it.</strong> The window for timely, relevant tweets has closed on so many things. So many chances to show off my quick wit are down the drain. What have I done?</p>
<h2 id="changing-sleep-patterns">Changing Sleep Patterns <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/18/effects-leaving-twitter/#changing-sleep-patterns">#</a></h2>
<p><strong>18) Getting more sleep.</strong> Less distraction means more rest. I may even get to that elusive "eight hours of sleep a night" goal most people have.</p>
<p><strong>19) Getting about the same amount of sleep.</strong> Even with the extra time, more of it's spent restless in bed. Lots of running thoughts.</p>
<p><strong>20) Getting less sleep.</strong> More time reading beforehand and tossing around isn't helping. I can't get rid of the tension in my head. Lots of thoughts itching to leave and be acknowledged.</p>
<p><strong>21) Starting to get back to the same amount of sleep.</strong> Somehow. Don't know how long it'll last. What do I do?</p>
<h2 id="new-anxieties">New Anxieties <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/18/effects-leaving-twitter/#new-anxieties">#</a></h2>
<p><strong>22) Thinking about the unsalvageable state of the world in climate change.</strong> I've distracted myself from environmental anxieties for so long. But one of my books was about climate change shoved me back to the unsustainability of our modern, industrialized society that I'm addicted to. Either our culture somehow impossibly changes to remove so many things I've grown used to, or I witness the Earth's last truly liveable decades. How am I supposed to respond to this?</p>
<p><strong>23) Thinking how leaving twitter is an expression of my privilege.</strong> Many people are routinely stalked, harassed, and attacked online in ways that follow them for months or years. Seeing how easily I can turn it off reminds me of my privilege online. Also how stepping away is removing a chance to pay my privilege forward to others and help stop the crap happening online.</p>
<p><strong>24) Panicking over the fundamental coding knowledge I've fallen behind on.</strong> I'm torn between catching up on important books or looking up more current, practical knowledge. How do I balance two areas when I feel an urgent need to improve on both?</p>
<p><strong>25) Seeing the blog posts I've fallen behind on.</strong> Even with the extra time, it's somehow hard to gather the energy and focus to write them. Especially since they lack the quickness and feedback Twitter gives me.</p>
<p><strong>26) Questioning my self-worth since I sought too much validation seeing my thoughts written and shared online.</strong> Not much more I need to add here.</p>
<p><strong>27) Trying to reshape my love of writing</strong> I can't lose it by cutting off one part of it. I couldn't have staked that much of my identity on one social network. Or have I? How do I take back control of it in a way that doesn't cause an existential crisis?</p>
<p><strong>28) Avoiding an existential crisis.</strong> No well-adjusted person would have their thoughts shaken this much by leaving one platform. Right?</p>
<h2 id="new-struggles-to-take-control">New Struggles to Take Control <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/18/effects-leaving-twitter/#new-struggles-to-take-control">#</a></h2>
<p><strong>29) Trying to not give a social network so much control.</strong> It's wrong to let a platform with so many people, who feel anything from indifference to spite, have this much influence over my mental health. It gives up so many elements I could otherwise control and use to improve myself and my real-world relationships with others. Any positive feedback or response I get from Twitter is brief and subject to change for who knows why, so it's not reliable for serious validation. That should only come from myself and people I truly trust.</p>
<p><strong>30) Still trying to not give it such control.</strong> Even knowing all this, it's not easy to break such habits.</p>
<p><strong>31) Still trying.</strong> Still trying, still trying, still trying, still trying, still trying...</p>
Getting my Coding Hands Dirty
2019-11-24T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/11/24/coding-hands-dirty/<p>There are many ways for programmers to learn and improve, such as:</p>
<ol>
<li>Making side projects</li>
<li>Reading news articles and blog posts</li>
<li>Reading other people's code</li>
<li>Playing with other people's code</li>
<li>Writing tutorials or demos about code we've written</li>
<li>Using intelligence-sucking devices to steal IQ points</li>
<li>Taking notes to better remember the important info we find</li>
</ol>
<p>I've been a big fan of methods around research and notes. It's worked for a long time. Lately, it hasn't been working as well. My motivation and inspiration are drying up, and my anxiety and impatience are building up in their place.</p>
<p>My guess is I'd been catching up to the code I'd been writing but not researching. Now I'm just about caught up and unsure what to do next. If that's the case, the answer is blending some code projects and experimentation into my writing. A possible flow for this could be:</p>
<ol>
<li>Take a small code project or demo, either related to my job or something else entirely. Make sure it's outside my comfort zone in some way.</li>
<li>Try my hand at coding it and solving the puzzles the project carries, while documenting how it goes.</li>
<li>Once it's done, take my notes and write them up into one or more posts.</li>
<li>Share the posts with the final project as a live demo or reference.</li>
</ol>
<p>As always, I can't predict if that'll work for me. Also as always, I need to try.</p>
How to Laser-Cut an Anime Drawing
2019-11-25T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/11/25/laser-cut-anime-tutorial/<p>How to Laser-Cut an Anime Drawing</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/laser-cut-anime-demo.jpg" alt="Post featured image"></p><p>One of my long-term goals at MakeHaven, a local maker space, has been finding new ways to turn anime art into laser cut art. I'm happy to say I recently made a breakthrough and can make nice-looking anime laser prints with relative ease.</p>
<ul class="post-content--image-list">
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/examples/1.jpg" alt="" />
</li>
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/examples/3.jpg" alt="" />
</li>
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/examples/4.jpeg" alt="" />
</li>
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/examples/5.jpeg" alt="" />
</li>
</ul>
<p>While other MakeHaven members aren't interested in the anime aspect of all this (yet), many have asked how I turned images into laser prints like this. To save time and help more people, I decided to write up a tutorial for just that. This works for most real-life photos as well, so even non-anime lovers can find it useful.</p>
<p><em>Note: this post assumes basic knowledge of laser-cutting an image at MakeHaven. <a href="https://www.makehaven.org/i/424">See their site's guide here for more info</a>.</em></p>
<h2 id="find-an-image">Find an Image <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/25/laser-cut-anime-tutorial/#find-an-image">#</a></h2>
<p>The first step in laser-cutting an image is, as you'd guess, choosing an image. Most images will work, but higher quality images will naturally come out better. Try images that:</p>
<ul>
<li>Aren't too blurry</li>
<li>Have moderate to high contrast</li>
<li>Have good lighting</li>
</ul>
<p>For this example lets go with the first image I laser cut with this technique: <a href="https://safebooru.org/index.php?page=post&s=view&id=2444294">an anime drawing of a girl adjusting her glasses</a>. The image is clear, and the contrast and lighting are good, so it should translate well.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/step_1/original.png" alt="An anime drawing of a girl looking forward and adjusting her glasses." /></p>
<h2 id="simplify-the-image">Simplify The Image <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/25/laser-cut-anime-tutorial/#simplify-the-image">#</a></h2>
<p>The next step is the most important, but also the trickiest. The laser cutter can't use an image this complicated as it is. It has to be simplified into two simple, black and white versions of itself.</p>
<p>Most laser-cut items usually have a single-layered design engraved on them. But I've found you can use two, one darker and one lighter, for more depth. <strong>This requires making two simplified versions: the outline and the shadow.</strong></p>
<p>This is done with <a href="https://online.rapidresizer.com/photograph-to-pattern.php">an online tool from Rapid Resizer, which lets you convert photographs into stenciled versions of themselves</a>. Open it up, load your photo, and create two copies under the following settings.</p>
<h3 id="make-the-outline">Make the Outline <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/25/laser-cut-anime-tutorial/#make-the-outline">#</a></h3>
<p>In the app, you'll see four different options in some tabs: "edges, thin, threshold, and adaptive." For the outline, select "edges."</p>
<p>You'll see two sliders below it, "dark/white" and "sharp/soft." There are no standard settings to make a good outline, so you'll need to play around with them until you get something good. I recommend trying the following:</p>
<ul>
<li>Start with both at about 75% to the left, towards "dark" and "sharp." Most outlines I've made have wound up around here.</li>
<li>You'll likely get spots of "noise" in the image background. Moving the top slider more to "white" can help remove them. Get rid of as much as possible, but don't worry if you can't get rid of them all without damaging the outline. You can remove them later on if needed.</li>
<li>The better-quality your photo is, the easier it'll likely be to get a good outline.</li>
</ul>
<p>For my example photo, I got a good outline without much tweaking. Once it's ready, hit "Download or Print on One Page" and save a copy of the image.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/step_2/outline.png" alt="A simplified outline of the drawing with no color and minimal noise." /></p>
<h3 id="make-the-shadow">Make the Shadow <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/25/laser-cut-anime-tutorial/#make-the-shadow">#</a></h3>
<p>Switch over to the "adaptive" for making the shadow. You'll see the same two sliders, but this time around it's a lot easier.</p>
<p>Slide the first one to the left for "Dark," and the second to the right for "Soft." Most of the time you'll have a usable shadow image right there unless you need to move the "dark/white" a bit to the right for any noise.</p>
<p>In this example, no adjustments are needed.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/step_2/shadows.png" alt="A simplified version of the image's shadows that can be layered under the outline." /></p>
<h2 id="convert-the-images-on-inkscape">Convert the Images on Inkscape <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/25/laser-cut-anime-tutorial/#convert-the-images-on-inkscape">#</a></h2>
<p>Now that we have our images, we need to prepare them for the laser cutter. Like with most laser cutter projects, we'll do so in Inkscape. Open up a new file and import both images. <strong>I recommend putting them in separate layers so they're easy to manage.</strong></p>
<h3 id="tracing-the-images">Tracing the Images <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/25/laser-cut-anime-tutorial/#tracing-the-images">#</a></h3>
<p>Right now the images are just that, standard images. We need to convert them to bitmaps to properly edit and send them to the laser cutter. Select one image, then from the menu select "Path > Trace Bitmap..."</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/step_3/trace_bitmap.png" alt=""An opened Inkscape menu with an option to trace an image."" /></p>
<p>You'll see a window like the one below pop up. There are lots of settings for how to trace the image, but we don't need most of them. Use the same settings as below, "Brightness Cutoff" with a 0.5 threshold, and you'll trace it just fine.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/step_3/shadow_trace.png" alt=""An Inkscape window for tracing the shadow image to a bitmap."" /></p>
<p>When you close the window, you may wonder where your new version of the image went. Tracing an image puts the bitmap version right over the original, so click it, drag it away, and delete the original. You now have a laser cutter-friendly version of your image - in this case, the shadow version.</p>
<p>I recommend making the shadow fill a pure green color, using the "fill and stroke" window. You can use whatever color you want though, as long as it's purely that color so the laser cutter recognizes it.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/step_3/shadow_result.png" alt=""A bitmap version of the image shadow with a green fill color."" /></p>
<p>Do the same thing for the outline image, except make it a different color. My preference is red since it contrasts well with green.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/step_3/border_result.png" alt=""A bitmap version of the image outline with a red fill color."" /></p>
<p>Lastly, position the images so the outline is just above the shadow (this is where keeping them in separate layers helps). You should now see something like this, with both coming together to form something quite close to the original. <strong>The outline layer should be visible over the shadow layer in areas they overlap!</strong> If the greens and reds fight it out, the red should be on top (literally).</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/step_3/shadow_and_border.png" alt="The red outline overlaid on top of the green shadow to create the final laser cut image." /></p>
<h3 id="delete-extra-noise">Delete Extra Noise <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/25/laser-cut-anime-tutorial/#delete-extra-noise">#</a></h3>
<p>This is a good time to delete any extra specs or noise from either layer if needed. Select the layer, zoom in on the affected area, and select "edit paths by node" from the sidebar. You can then select and remove the nodes making up the shapes to remove.</p>
<p>I recommend zooming in because if there are many nodes visible on the screen, it takes longer to load them all. The closer you get, the less you see, the faster it goes.</p>
<h2 id="laser-cut-the-image">Laser-Cut the Image <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/25/laser-cut-anime-tutorial/#laser-cut-the-image">#</a></h2>
<p>Once you've got your image ready, all that's left is exporting it to the laser cutter with the following settings. This post assumes it's being cut into a piece of wood.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/step_4/laser_settings.png" alt="The laser cutter settings for the red and green layers." /></p>
<p>The logic behind this is pretty simple:</p>
<ul>
<li>The red "outline" layer gets the usual "raster engraving" settings with 100% power, 25% speed, and 500 PPI to create a standard dark cut.</li>
<li>The green "shadow" layer gets the same with half the power (50%) and twice the speed (50%). This creates a lighter but still visible cut for the "shadow" effect alongside the outline.</li>
</ul>
<p>If this is your first time running a setup like this, <strong>I recommend testing it on a scrap piece of wood first.</strong> If it checks out, use your original material and watch the laser go!</p>
<h2 id="enjoy!">Enjoy! <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/11/25/laser-cut-anime-tutorial/#enjoy!">#</a></h2>
<p>With that, the laser print should be set. You can see an example of how this looks by seeing how this tutorial's example turned out.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/laser-cut-anime-demo/step_5/result.jpeg" alt="The final result of the girl with glasses artwork laser-cut on a piece of wood." /></p>
<p>So please, go forth, laser-cut your artwork and photos, and share them with the MakeHaven world!</p>
How I Killed My Site's Webpack Processes
2019-12-27T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/12/27/killing-webpack/<p>How I Killed My Site's Webpack Processes</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/killing-webpack.jpg" alt="Post featured image"></p><p>For quite some time, my site ran on Webpack. It handled the styling with TailwindCSS, PostCSS, PurgeCSS, and Turbolinks. It was tricky to set up but got the job done.</p>
<p>Now my site's Webpack process is dead. I killed it. I have blood on my hands and it feels oh so good. My site builds are quieter, smaller, and faster. Plus, thanks to the life insurance payments, they more than paid for themselves.</p>
<p>So for the true crime fans out there, here's the breakdown of my personal site's Webpack murder. NPM scripts met all my essential and nice-to-have needs. The result is a site with fewer dependencies, config files, and even a faster build time!</p>
<h2 id="reasons-for-killing-webpack">Reasons for Killing Webpack <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/27/killing-webpack/#reasons-for-killing-webpack">#</a></h2>
<p>The first part of any murder mystery is the motive. For my motive, I'm not arguing Webpack is bad. It does have a steep learning curve and a confusing setup. But Webpack is great for larger, more complex JavaScript and CSS bundling. When I remade my site with some optimized TailwindCSS, they recommended Webpack.</p>
<p>But over time I realized that my personal Jekyll site wasn't large nor complex enough to justify this. I needed Sass compilation and JavaScript minification, but nothing with modules or bundles. I wanted my site's build process to reflect its relative simplicity.</p>
<p>As fancy as Webpack is, it's not good for my site's long-term maintainability. I wanted it gone before it got so ingrained in how it works I'd be stuck with it even further down the line. It had to be...taken care of.</p>
<h2 id="what-replaced-webpack">What Replaced Webpack <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/27/killing-webpack/#what-replaced-webpack">#</a></h2>
<p>Next is identifying the murder weapon. There were a few criteria the weapon had to meet.</p>
<ol>
<li>Compile Sass to CSS</li>
<li>Autoprefix compiled CSS for different browsers</li>
<li>Replace TailwindCSS with my own Sass setup</li>
</ol>
<p>TailwindCSS is great, but I prefer avoiding CSS frameworks if possible. I already had a custom Atomic CSS setup I could plug into the site. I needed to change the classes and markup to match. This would be a nightmare, but an understandable nightmare that'd only take time.</p>
<p>There were also a few nice to haves I aimed for.</p>
<ol>
<li>Have separate commands for development and production CSS</li>
<li>Purge unused helper classes from production CSS</li>
</ol>
<p>I'm happy to say I found a weapon, er, solution for all these: NPM scripts!</p>
<p>Task runners like Gulp are great for managing tasks to prepare assets. But NPM scripts can handle the same work when done right with fewer dependencies and less code. Case in point: my final NPM script tasks topped out at twelve lines and seven dependencies.</p>
<p>I had my motivation and my weapon set. All that's left is carrying out the crime itself.</p>
<h2 id="the-seven-dependencies">The Seven Dependencies <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/27/killing-webpack/#the-seven-dependencies">#</a></h2>
<p>As mentioned, my new build tasks only took seven dependencies. That's about half of what it needed before.</p>
<ul>
<li><code>chokidar-cli</code> to watch groups of files</li>
<li><code>npm-run-all</code> and <code>concurrently</code> to run scripts in parallel</li>
<li><code>node-sass</code> to compile Sass to CSS</li>
<li><code>postcss-cli</code> and <code>autoprefixer</code> to add CSS cross-browser prefixes</li>
<li><code>purgecss</code> to remove unused CSS classes</li>
</ul>
<p>Now I could cut out dependencies specific to Webpack, which would extract text or uglify code. With NPM scripts I only need the dependencies themselves without wrappers or middlemen. This lightens the load and helps keeps things up-to-date. If <code>node-sass</code> updates, I don't need to wait for <code>gulp-node-sass</code> to update its own <code>node-sass</code> version.</p>
<h2 id="compiling-two-types-of-sass">Compiling Two Types of Sass <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/27/killing-webpack/#compiling-two-types-of-sass">#</a></h2>
<p>With the dependencies here, I was ready to put them to work. First up was compiling the Sass into CSS.</p>
<p>The big obstacle was I wanted to compile Sass for both development and production. Both do a basic compilation with specific needs on top of that. Development Sass needed to recompile when I saved changes to a file. Production Sass needed to add browser prefixes and remove unused classes. Thankfully, there's a trick to grouping scripts this way.</p>
<p>First, let's get the basic compilation task done for a quick win. This script gathers all the Sass files from the <code>_sass/</code> directory and puts the result in my <code>assets/css</code> folder.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"sass"</span><span class="token operator">:</span> <span class="token string">"node-sass --output-style compressed _sass/ -o assets/css"</span><br /><span class="token punctuation">}</span></code></pre>
<p>The development Sass only has one script to add to that, so I tackled that next. I used a <code>sass-</code> namespace to categorize (and recognize) it as another Sass task. It looks at all the files in my <code>_sass</code> folder and, if one changes, runs the basic Sass script again.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"sass-dev:watch"</span><span class="token operator">:</span> <span class="token string">"chokidar '_sass/**/**/**/*.scss' -c 'npm run sass'"</span><br /><span class="token punctuation">}</span></code></pre>
<p>You may wonder why I appended <code>:watch</code> there with a colon, instead of a dash for something like <code>sass-dev-watch</code>. That's because the colon lets me better group tasks together, and thus run them as a group. That's not put to use here, but it is for the production Sass tasks.</p>
<p>Both production tasks are then run on the compiled CSS in <code>assets/css</code>.</p>
<ol>
<li><code>sass-prod:autoprefixer</code> is for production, and uses <code>postcss</code> to add needed browser prefixes.</li>
<li><code>sass-prod:purgecss</code> is also for production. It checks my CSS against the compiled Jekyll site in <code>_site</code> and removes unused classes.</li>
</ol>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"sass-prod:autoprefixer"</span><span class="token operator">:</span> <span class="token string">"postcss assets/css/*.css --use autoprefixer --no-map -d assets/css"</span><span class="token punctuation">,</span><br /> <span class="token property">"sass-prod:purgecss"</span><span class="token operator">:</span> <span class="token string">"purgecss --css assets/css/*.css --content _site/**/**/*.html --out assets/css"</span><br /><span class="token punctuation">}</span></code></pre>
<p>Next is running the right scripts together. This is where the colons in the names come into play. The below scripts both run the basic Sass compilation, then either the development or production tasks.</p>
<ul>
<li><code>sass:dev</code> compiles it and watches for changes</li>
<li><code>sass:prod</code> tidies it up for the server.</li>
</ul>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"sass:dev"</span><span class="token operator">:</span> <span class="token string">"yarn sass && npm-run-all -p sass-dev:*"</span><span class="token punctuation">,</span><br /> <span class="token property">"sass:prod"</span><span class="token operator">:</span> <span class="token string">"yarn sass && npm-run-all -p sass-prod:*"</span><br /><span class="token punctuation">}</span></code></pre>
<p><code>npm-run-all</code> runs these tasks within their namespaces, so it's easy to break the tasks apart. Adding more development or production tasks is also easy if I use the same naming setup.</p>
<h2 id="compiling-the-jekyll-site">Compiling the Jekyll Site <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/27/killing-webpack/#compiling-the-jekyll-site">#</a></h2>
<p>I also need scripts to handle turning my Jekyll setup into a batch of static HTML files. I already had those scripts ready to go from the Jekyll documentation.</p>
<p><code>write</code> is like <code>sass:dev</code>, watching for site changes and recompiling when needed. <code>build</code> only makes it once to place it on the server.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"write"</span><span class="token operator">:</span> <span class="token string">"jekyll serve --incremental --watch"</span><span class="token punctuation">,</span><br /> <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"jekyll build"</span><br /><span class="token punctuation">}</span></code></pre>
<h2 id="the-final-scripts">The Final Scripts <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/27/killing-webpack/#the-final-scripts">#</a></h2>
<p>The last step is grouping these scripts in some basic <code>dev</code> and <code>prod</code> tasks.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"dev"</span><span class="token operator">:</span> <span class="token string">"concurrently -n jekyll, \"yarn write\" \"yarn sass:dev\""</span><span class="token punctuation">,</span><br /> <span class="token property">"prod"</span><span class="token operator">:</span> <span class="token string">"yarn build && yarn sass:prod"</span><br /><span class="token punctuation">}</span></code></pre>
<p>You may notice I used <code>concurrently</code> here instead of <code>npm-run-all</code>. The former is better for parallel scripts you'd expect to see in two different terminals. It fits here since both tasks watch for changes and will output code as they update. <code>prod</code> only runs compilations without watching. I need to build the site before the CSS, so running them in basic sequence works best there.</p>
<h2 id="wrapping-up">Wrapping Up <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/27/killing-webpack/#wrapping-up">#</a></h2>
<p>With all that, I have finished the perfect crime. Webpack is gone, NPM scripts are running in their place, and my clothes have minimal bloodstains. The trail has gone cold (aside from this blog where I confess it all). You can see the final crime scene with the finished scripts below.</p>
<pre class="language-json"><code class="language-json"><span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token property">"dev"</span><span class="token operator">:</span> <span class="token string">"concurrently -n jekyll, \"yarn write\" \"yarn sass:dev\""</span><span class="token punctuation">,</span><br /> <span class="token property">"prod"</span><span class="token operator">:</span> <span class="token string">"yarn build && yarn sass:prod"</span><span class="token punctuation">,</span><br /><br /> <span class="token property">"write"</span><span class="token operator">:</span> <span class="token string">"jekyll serve --incremental --watch"</span><span class="token punctuation">,</span><br /> <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"jekyll build"</span><span class="token punctuation">,</span><br /><br /> <span class="token property">"sass:dev"</span><span class="token operator">:</span> <span class="token string">"yarn sass && npm-run-all -p sass-dev:*"</span><span class="token punctuation">,</span><br /> <span class="token property">"sass:prod"</span><span class="token operator">:</span> <span class="token string">"yarn sass && npm-run-all -p sass-prod:*"</span><span class="token punctuation">,</span><br /> <span class="token property">"sass"</span><span class="token operator">:</span> <span class="token string">"node-sass --output-style compressed _sass/ -o assets/css"</span><span class="token punctuation">,</span><br /> <span class="token property">"sass-dev:watch"</span><span class="token operator">:</span> <span class="token string">"chokidar '_sass/**/**/**/*.scss' -c 'npm run sass'"</span><span class="token punctuation">,</span><br /> <span class="token property">"sass-prod:autoprefixer"</span><span class="token operator">:</span> <span class="token string">"postcss assets/css/*.css --use autoprefixer --no-map -d assets/css"</span><span class="token punctuation">,</span><br /> <span class="token property">"sass-prod:purgecss"</span><span class="token operator">:</span> <span class="token string">"purgecss --css assets/css/*.css --content _site/**/**/*.html --out assets/css"</span><br /><span class="token punctuation">}</span></code></pre>
<p>This works for me now, but there are two loose ends I'll need to cut later on.</p>
<ol>
<li><code>sass:prod</code> creates the CSS file on the server, not as one of the files included in the repo. Netlify has had a weird time recognizing the file this way, and for a while, my live site couldn't find the files. For now, I've had to commit the compiled CSS to the repo. I want to find a solution soon since I want to move past committing compiled files to my site.</li>
<li>I'll likely need to add tasks for basic JavaScript compilation and minifying as I add more to my site. Otherwise too many separate files and script tags will affect its performance. Right now I'm keeping the compiled Turbolinks code in my repo. This works but is bad practice, so I'll replace it with a custom service worker later.</li>
</ol>
<p>This also leaves out the massive overhaul of my Sass and HTML to move away from TailwindCSS. But that's another blog post on its own, and something I'm choosing to repress until further notice. I've already forgotten what it was like or what I'm even writing anymore. Something about laser cutting?</p>
<p>But these are battles for another day. For now, I need to escape the country for a while. Just in case some of the config files send any relatives after me to make things even.</p>
My Plan to Escape the Numbers for 2020
2019-12-31T00:00:00Zhttps://www.maxwellantonucci.com/posts/2019/12/31/my-2020-new-year-resolutions/<p>My Plan to Escape the Numbers for 2020</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/2019-in-review.jpg" alt="Post featured image"></p><p>With 2019 coming to a close, there are a few major events I could recount.</p>
<ul>
<li>The end of my first serious and long-term relationship</li>
<li>Running my first marathon</li>
<li>Vacationing in North Carolina</li>
<li>Surviving the unspeakable evil that is strep throat</li>
</ul>
<p>But something less obvious defined my year more than anything else: measurable numbers. It crept into almost everything since I thought it'd improve me as a person. I need specific data to know exactly how to get better at work, writing, and life in general, right?</p>
<p>Not the case at all. That focus caused most of this years' regrets.</p>
<h2 id="the-regretful-2019-numbers">The Regretful 2019 Numbers <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/31/my-2020-new-year-resolutions/#the-regretful-2019-numbers">#</a></h2>
<p>I focused on the number of side projects I had and wanted to make. I gave up larger ones I was more interested in since I'd finish fewer in the end. I tried shorter, snappier ones I didn't enjoy as much. I gave up on most of them and didn't go back to the larger ones.</p>
<p>I got a big list of topics I wanted to learn for my career. A bigger number seemed to mean a bigger payoff. But I overwhelmed myself and couldn't rank their importance. I wound up haphazardly learning who knows how many in the end.</p>
<p>I watched the number of posts I published online, wanting to write more. I saw how often others wrote compared to me, and I felt like an inferior imposter. I got a list of post topics that I could plan ahead on. But these topics didn't match with my main reason for writing. It's to explore and solve my own problems in life in a way that others could enjoy. As I result, I wrote less than I planned to and wanted to.</p>
<p>I even measured my life success in part by my number of relationships and social events I went to. I wanted more so I could appear engrossed in an active and exciting life. But this kept me from investing in my current, quality relationships as much as I wanted. It also kept me from going to social activities I enjoyed more, even if they were less "sexy" than others. I psyched myself out, felt like a failure, and shut myself in more.</p>
<p>The numbers even hit my side hobbies like piano and laser-cutting. My progress felt empty if I wasn't making enough progress to "wow" others. I couldn't get the number of good responses or learned skills up to the numbers I wanted. They felt like failed jobs instead of relaxing joys.</p>
<p>The irony isn't lost on me. <strong>My excessive focus on numbers didn't only make me worse off. They also made the numbers themselves worse.</strong></p>
<p>The irony for my below 2020 goals isn't lost on me either. <strong>I want to improve the numbers by taking the focus off them.</strong></p>
<h2 id="1.-flow-is-a-must-have">1. Flow is a Must-Have <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/31/my-2020-new-year-resolutions/#1.-flow-is-a-must-have">#</a></h2>
<p><em>The Career Adventures of Johnny Bunko</em> talks about focusing on strengths over weaknesses. It mentions finding activities that give <em>flow.</em> They energize and immerse you, and you consistently do them well.</p>
<p>Writing gives me flow, but not all the time. I wrote an article on killing Webpack from my personal website, and I felt little flow. I kept needing to stop, got distracted, and had to mentally recover when I stopped for the day. The post took longer than expected, and I didn't even like it enough to cross-post it afterward.</p>
<p><strong>Writing gives me flow when it's not only a tutorial, it's a story.</strong> A story that taps into my emotions and a lesson I learned. I felt flow when <a href="https://www.maxwellantonucci.com/personal/philosophy/2017/05/16/perfectly-unhappy-developer.html">writing about finding meaning not in happiness, but in painful experiences</a>. I felt flow <a href="https://dev.to/maxwell_dev/you-can-be-a-casual-blogger-ff0">writing about overcoming insecurities as a "casual blogger."</a> I felt flow when <a href="https://www.maxwellantonucci.com/tag/design-pattern-fairy-tales">I turned design patterns into weird fairy-tale spin-offs to explain their purpose</a>. I'm feeling flow now, writing about how I'm hoping to overcome my major regrets this year. They make me feel more vulnerable yet stronger and tell some kind of story (even if it's silly).</p>
<p>Coding gives me flow, but not when I'm only building something to put on display. Building front-end components for no reason other than to show I can feel pointless. I felt flow coding for my job since governments and citizens use them each day to solve issues. I get flow refactoring and improving my personal site since it helps me better share my writing. I get flow making things with my anime API, like the <a href="https://www.quotemaker.maxwellantonucci.com/">quote maker</a> and <a href="https://www.maxwellantonucci.com/2019/07/08/anime-twitter-bot.html">first Twitter bot</a>. They're things we get value from.</p>
<p>Knowing where I find flow is vital. Even if it hurts the final "numbers" of blog posts and side projects. Flow keeps work from feeling like "work," and more like "what I do." It's what I do for fun and meaning, not paying my bills. Flow is my top criterion for everything in the coming year. If it doesn't give me flow, and I have the option to avoid it, why should I pursue it?</p>
<h2 id="2.-take-%22being-less-serious%22-seriously">2. Take "Being Less Serious" Seriously <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/31/my-2020-new-year-resolutions/#2.-take-%22being-less-serious%22-seriously">#</a></h2>
<p>The focus on numbers for my life outside work took away so much joy. So I'm going to allow myself to not be "amazing" for my hobbies.</p>
<p>For piano, I've been liking jazz piano quite a lot. It's simple, expressive, and less restrictive. It also avoids the rote memorization and repetition I've found with much sheet music. I won't learn as many fancy pieces or be able to show it off as much. But I'll also go back to actually enjoying it, which is why I started at all.</p>
<p>I make anime laser cut prints for gifts and apartment decorations. This specific niche gets them less "social media love" than others made at the maker space. People have also tried to persuade me to make some changes so I can make them faster and sell them. But even the thought of monetizing them, or not making what I enjoy most, takes away the joy. I don't want it to be a stressful side-hustle if I can avoid it.</p>
<p>The common lesson is not stressing over <em>what could be</em>. It brings me less joy than <em>what already is.</em> I'm grateful I have hobbies I have the time and resources to pursue and enjoy. Isn't that what I want from them in the end? Nothing more and nothing less.</p>
<h2 id="3.-change-the-numbers-focus">3. Change the Numbers Focus <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/31/my-2020-new-year-resolutions/#3.-change-the-numbers-focus">#</a></h2>
<p>While I've realized numbers are a bad focus for me, that doesn't mean I won't ever use them. I've learned they make me do something less instead of more. So I can use them to better control bad habits going forward.</p>
<p>So what if, for the new year, I kept numbers for how long I watch videos? Or how long I play video games? How long I browse social media feeds? Adding a chore of "I need to track the time" makes them less addicting. Seeing the time spent on those also puts a real measure on what they cost me. Three hours on pointless videos that I could've spent reading or catching up on chores. Something I'll remember it all before the next time I open YouTube.</p>
<p>This way, this year's issues with numbers aren't an absolute failure. I learned a new trick for keeping bad habits at bay. For the new year, I'm making better use of it.</p>
<h2 id="looking-towards-2020">Looking Towards 2020 <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2019/12/31/my-2020-new-year-resolutions/#looking-towards-2020">#</a></h2>
<p>I won't say I'm feeling too good or bad about 2019 or 2020. I'm upset about how I let numbers drag down the past year, but I am glad they helped me find new approaches for 2020. I'm excited to see what they help me overcome next year, but I am worried I won't follow through. Plus I'm anxious about the <em>new</em> obstacles I know will appear along the way.</p>
<p>If that's the case, you may wonder why I'm bothering with these resolutions at all. If I may reference my post on being a perfectly unhappy developer:</p>
<blockquote>
<p>[These activities] make me feel like a human going headfirst into the turmoil of existence. Seeing a spectrum of ideas and feelings that push me up, drag me down, and toss me somewhere else. To find something new. To struggle with a new obstacle. To discover a new strength.</p>
</blockquote>
<blockquote>
<p>Most of all, they make me feel I'm making the best possible use of my time alive.</p>
</blockquote>
<p>So next year here's to doing more of what makes me feel alive. To going through pain and joy in the path to help myself and others in some small way.</p>
<p>To constant, meaningful change.</p>
<p>To 2020, and hopefully, many more years to follow.</p>
The Ultimate Irony When I First Avoided Tests
2020-01-13T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/01/13/irony-avoiding-tests/<p>The Ultimate Irony When I First Avoided Tests</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/irony-tests.png" alt="Post featured image"></p><p>One of my new year resolutions is finishing notes on two foundation programming books: Clean Code and The Pragmatic Programmer. Both are dense but worthwhile reads. They explain concepts you'll likely carry throughout your career. I recently finished Clean Code's informative yet painful chapter on Unit Testing. As in, I started having anxiety-inducing flashbacks to a previous job. As I write this, I'm running on three hours of sleep, have bags under my eyes, and have consumed nothing but ginger ale and bread scraps to keep the shadows at bay.</p>
<p>Why, you ask? That chapter laid out how tests keep a codebase maintainable and flexible. <strong>I realized the horrors of my past had taught me the same lesson, and this chapter was confirming it all over again.</strong> Had I read this book before, I could have spared myself much pain and carpal tunnel.</p>
<p>As part of both my recommended recovery, and to help you avoid a similar path, I'm sharing that story here. I don't expect most people to run out and read Clean Code (though I recommend it), but my story has the same message. At its heart is a great irony in why I decided not to write tests, and how it came back to bite me in the brain stem.</p>
<p>So relax, pray, and enjoy!</p>
<h2 id="at-first%2C-saying-no-to-tests">At First, Saying No to Tests <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/01/13/irony-avoiding-tests/#at-first%2C-saying-no-to-tests">#</a></h2>
<p>A couple of years ago at one of my first jobs, my duties included building a new pattern library. It was for a third party to make small web pages for our main client. It would be a mix of old and new components, and my job was updating and managing the styles.</p>
<p>I was the only full-time programmer there most of the time I worked on it. I was balancing other responsibilities so my time was often limited. I needed the pattern library work to be fast, flexible, and maintainable. Adding an entire suite of tests seemed like a bad move. It'd be a new section of code to write, deal with, and worry about as I try to make changes. They seemed counter-intuitive and wasteful.</p>
<p>That was not the case at all, as I would soon learn.</p>
<h2 id="the-growing-%22no-test%22-rot">The Growing "No Test" Rot <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/01/13/irony-avoiding-tests/#the-growing-%22no-test%22-rot">#</a></h2>
<p>The first sign of my mistake came in about a week. We'd made some changes and sent the pattern library over. The third party found a couple of unexpected bugs and sent a report over so we could fix them. We shrugged and did so, thinking that was that. The next day we got another email about a few more bugs we missed popping up. This cycle repeated one or two more times before it finally stopped.</p>
<p>Then it happened again for the next release, but worse. People started to get pissed off. I started getting anxious.</p>
<p>Turns out there were some style leaks in our components. These were due to poor style architecture and how we nested components. In our pattern library, this meant every release guaranteed a few unexpected bugs. Often in ways that we could never predict.</p>
<p>The solution was terrifying: <strong>any kind of change meant we had to manually check each component.</strong> We'd need to check them on different browsers and old devices too for our client. There was lots of internal feedback and iterations as the deadline approached. I'd often need to check several times in one day.</p>
<p>This added up to wasting literal hours every week or day going through dozens of component pages. It was mind-numbing and tedious to the point where I was prone to silly mistakes or skipping items. Someone would see this and make me repeat it all, wasting even more time. Even after I'd packed up and was about to go home, sometimes I'd get called back. I'd have to do several more quick checks before I could drive away.</p>
<p>The depth of my mistake hit me when I realized there were days when I did nothing but monotonous testing. I'd set up several computers to mirror the library across different systems. I would run through everything, make a small change or two, check it again, and repeat all day. <strong>I was a programmer, yet was doing the repetitive, simple work I should be making a computer do.</strong> Something had gone horribly, horribly wrong.</p>
<h2 id="the-ultimate-irony">The Ultimate Irony <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/01/13/irony-avoiding-tests/#the-ultimate-irony">#</a></h2>
<p>After that, I saw the price I kept paying without tests.</p>
<p>I dreaded making any changes, no matter how small. But my job was changing the codebase by adding to it or fixing it, so my job itself filled me with dread. I associated all changes like this with tedious labor, not meaningful work. It was the same with bug fixes, so I had less incentive to fix them and more to let the code rot.</p>
<p>Having read Clean Code's testing chapter, the ultimate irony became clear to me. <strong>I skipped testing thinking it'd make the code maintainable and flexible. But it had the opposite effect - tests are what make code maintainable and flexible in the first place.</strong></p>
<p>I could have made updates without fear it would break something else. The tests would catch it for me so I'd fix it, saving time and energy. They'd ensure everything operated at a foundational level. Even when things went wrong they would never threaten the app's core functionality. I could add new components safe in the knowledge everything else worked as expected.</p>
<p>These maintainability and functionality benefits outweigh the costs of writing and improving on the tests themselves.</p>
<h2 id="how-i-see-tests-today">How I See Tests Today <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/01/13/irony-avoiding-tests/#how-i-see-tests-today">#</a></h2>
<p>It's not like I don't still struggle with tests today. I work with both Ruby on Rails and Ember, both with different test frameworks. I'm competent with Ember, but there's still many concepts and tricks with Rails testing I'm learning as I go.</p>
<p>But more importantly, <strong>my challenges today are about the <em>how</em> of tests, not the <em>why.</em></strong> No one needs to argue with me about why I should write tests, or remind me to include some (most times, at least). I learned that lesson before, and it stuck pretty hard because it hurt so much.</p>
<p>If you haven't started learning how to test your programs yet, I encourage you to do so. You <em>will</em> accept how important they are one way or another. If you can choose between learning this via a blog post or a painful career lesson, I recommend the first one.</p>
<p>Unless you want to be like me, waking up in the middle of the night, in a cold sweat screaming about form integration tests. Then who am I to stop you?</p>
Stop Using the Terrible Title
2020-01-16T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/01/16/stop-using-title/<p>Stop Using the Terrible Title</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/stop-title.jpg" alt="Post featured image"></p><p>I'd like to talk about <code>title</code>. Hopefully for the last time.</p>
<p><code>title</code> is an HTML property you can use for a small tooltip effect on the text. Give an anchor tag a <code>title="I'm a link!"</code> attribute, and you'll see "I'm a link" when you hover over it.</p>
<p><span title="I'm some title text!">You can see the same effect by hovering over this sentence.</span></p>
<p><strong>I said you "can" use it, but you shouldn't. Ever. Just don't. Forget this attribute exists and move on with your life.</strong></p>
<p>There are two reasons I usually hear for why someone used <code>title</code>: for the tooltip, or a more readable version text alternative. Both are bad reasons.</p>
<h2 id="it's-a-terrible-tooltip">It's a Terrible Tooltip <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/01/16/stop-using-title/#it's-a-terrible-tooltip">#</a></h2>
<p>Text in <code>title</code> is invisible to those with touch/mobile devices, keyboard users, people using assistive tech, or people who can't position the mouse over the element just right for long enough. <strong>In other words, <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title#Accessibility_concerns">more than a majority of users can't see tooltip text</a>.</strong> Even people who fall in the smaller "can use tooltips" group just not notice them. So it's unreliable for informing users about, well, anything.</p>
<p>You're better off making the text more explicit or detailed so a tooltip isn't needed. If that's not an option for some reason, <a href="https://inclusive-components.design/tooltips-toggletips/">try a custom tooltip solution instead</a>. It'll be more work, but it'll also actually work.</p>
<h2 id="it's-terrible-alternative-text">It's Terrible Alternative Text <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/01/16/stop-using-title/#it's-terrible-alternative-text">#</a></h2>
<p>If there's an acronym and you think <code>title</code> can best explain what it stands for, there's a simpler option: write out an acronym the first time you use it. <strong>You can avoid "more readable alternatives" by making the text itself more readable.</strong></p>
<p>If you can't make the text readable for some (bizarre) reason, <code>aria-label</code> is a better option, but it shouldn't be your first.</p>
<h2 id="title-is-simply-terrible">Title is Simply Terrible <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/01/16/stop-using-title/#title-is-simply-terrible">#</a></h2>
<p>All this adds up to <code>title</code> being of so little use with so little reach, there's little point using it at all. Unless it's inside the <code><head></code> tag or about headings, I don't want to hear about titles anymore.</p>
<p>Clear it from your memory. Move on with your life. You'll find it's more beautiful without it. You'll notice colors more and get more joy from hobbies. Bills will get easier to pay. You will have more energy and be able to fly.</p>
<p>You are now free. The lambs have been silenced. Live your life as you've always wanted.</p>
Saving My Curiosity
2020-02-01T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/02/01/saving-curiosity/<p>Saving My Curiosity</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/saving-my-curiosity.jpg" alt="Post featured image"></p><p>At the end of last year, <a href="https://www.maxwellantonucci.com/posts/2020/02/01/saving-curiosity/URL">I wrote about how focusing too much on numbers dragged me down for most of 2019</a>. My main focus was on how it made me less happy and productive.</p>
<p>All that's still true, but I'm realizing <strong>I left out something even worse it damaged: my curiosity.</strong></p>
<p>This is worse since my curiosity is one of my favorite qualities. I may never be famous or a genius. But being curious about so many different topics always brings me joy (plus a decent career).</p>
<p>But quantifying so much of my life by numbers and limits put a lid on my curiosity. I was telling my mind, "you shouldn't look into this, it's not on your list." I told myself exploring was wrong and unproductive. It would only take away from my long-term goals, happiness, and plans to visit other dimensions.</p>
<p>For reasons that became obvious the moment I thought about them, I was wrong on all counts.</p>
<h2 id="i-owe-all-my-knowledge-to-curiosity">I Owe All My Knowledge to Curiosity <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/02/01/saving-curiosity/#i-owe-all-my-knowledge-to-curiosity">#</a></h2>
<p>That big list of topics I wanted to learn more about only came about because I was curious about what I should learn. It's a bit weird and hypocritical in hindsight. I was relying on a trait to get me so far and then saying it could only hurt me for the rest. For all I knew, I could get curious about something and realize it was more worthwhile to learn. Not being curious would've left me clinging to outdated knowledge. When I finally moved on it could be too late.</p>
<p>Yesterday I read <a href="https://levelup.gitconnected.com/a-recap-of-frontend-development-in-2019-1e7d07966d6c">an article recapping big frontend developments for 2019</a>. There were so many things I'd heard in passing but avoided reading about in detail: WebAssembly, React Hooks, the JAMStack, Svelte, TypeScript, GraphQL, and more. I realized even if I never wound up using them, knowing more about them could only help me down the line. It could be with networking meetings, tooling brainstorm sessions, even a future job using these tools. Yet I'd pushed myself into thinking it could hurt me, which is absurd.</p>
<p>It's even more absurd when I remember my curiosity is the reason I know everything I do now. I was unfamiliar with many aspects of Ruby on Rails and Ember and was curious why we chose it for our apps. So I investigated topics as they came up in my work and any that looked interesting or unfamiliar. That curiosity is what made me a more reliable contributor to our codebases.</p>
<p><strong>It's hard to overstate how twisted any mindset of "I need to repress my curiosity to improve my learning" was.</strong> It got me where I am today and where I'll be in the future. It may even help me escape to parallel dimensions where I can travel among the fifth-dimensional beings invisibly watching our different world lines unfold.</p>
<p>I admit I may not be that curious about that last one yet. But enough library books will get me anywhere, including dimension Alpha-Charlie-35934.</p>
<h2 id="curiosity-makes-it-fun">Curiosity Makes It Fun <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/02/01/saving-curiosity/#curiosity-makes-it-fun">#</a></h2>
<p>This point is a lot simpler but as important: being curious is fun.</p>
<p>I love new information about any number of topics enthralling me. I've wasted many afternoons in new books and web deep dives. One freshman year of college I filled out several pages thinking out new ideas I'd read about functionalism, selfishness, and altruism in human nature. A good 30% of my bookshelf are different reference books. Half of those reference books are in comic or manga form.</p>
<p>It's the fuel behind my love of web development. I love seeing the field as an endless, problem-solving playground of things to learn and play with. It inspires me to write and build, which I'd been lacking since pushing my curiosity away.</p>
<p>I've felt jealous and isolated by seeing so many smarter web developers. Instead, I should have felt excited they're sharing useful news and info.</p>
<p>Being a curious nerd lets one get endless joy from a couple of books and a quiet room. It even helps me save money and become a better person. <strong>Even if I couldn't put it on my resume (and sadly I cannot), I want to stay curious to be a better person.</strong></p>
<h2 id="bringing-my-curiosity-back">Bringing My Curiosity Back <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/02/01/saving-curiosity/#bringing-my-curiosity-back">#</a></h2>
<p>Like with letting go of the numbers, <strong>keeping my curiosity going means focusing on "flow" over measurable results.</strong></p>
<p>Sure, there are risks I'll get curious about something and it winds up not being useful. But that's rarely the case, and even if it is, I'll still enjoy it. I was curious about reading that long article recapping the front-end's news for 2019. That little act of curiosity has already pushed my 2020 path in a better direction, for my career goals and multi-dimensional travel goals. Both benefit me and the world around me, albeit in different amounts and a different number of worlds.</p>
<p>My point is, my curiosity has always been with me. I need to be willing to look beyond my most immediate goals since it helps me find even better ones. Like with lettings the numbers go, <strong>it's about constant, meaningful change.</strong></p>
<p>So I'll change up my reading schedule, my writing habits, and later my place in the space-time continuum. I will become a dimensional God with different versions of reality bent at my fingers, and it'll be thanks to my curiosity.</p>
Feeling the Coronavirus Fear
2020-03-17T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/03/17/feeling-the-fear/<p>Feeling the Coronavirus Fear</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/feeling-fear.jpg" alt="Post featured image"></p><p>Last night I dreamt my apartment had an intruder. I never saw their face, only small glimpses of them. Their feet as they moved around a door, a shadow when they snuck in a closet, and the small sound of their footsteps. I had my hands up like a boxer, ready to beat them down if I found them.</p>
<p>But I never did. I only felt anxiety and adrenaline chasing a ghost. I woke up before catching them and still felt so much tension I couldn't move. I wound up staying awake in bed until my alarm went off.</p>
<p>I was extra paranoid that morning but found no intruder. But still felt all the same fear throughout the morning. Even as I settled in to start a day of remote work. The same fear that's been hitting me for at least a week. The sweet old coronavirus fears we've all read and heard of.</p>
<p>I've read lots of material to inspire this fear. Fears about:</p>
<ul>
<li>How contagious it is</li>
<li>How easy it is to spread</li>
<li><a href="https://www.reuters.com/article/uk-health-coronavirus-stocks-economy-usa-idUSKBN2140IA">The likely economic recession</a></li>
<li><a href="https://www.nytimes.com/2020/03/15/world/europe/coronavirus-inequality.html">How it's fueling American inequalities</a></li>
<li><a href="https://news.yahoo.com/diabetics-tom-hanks-could-higher-134643096.html">How many people important to me with pre-existing conditions are at higher risk</a></li>
</ul>
<p>Even if all my fear is realistic, it's still a lot to handle. It can still grow too fast and overwhelm my life more than it should. I could do all the social distancing right and still panic over what I could do wrong.</p>
<p>I don't want my fear to own my life. Fear is a good motivator, but not when it motivates me into the ocean with no energy left to swim. I need strategies to balance out my fear to healthier levels. So I can be safe without getting paranoid over intruders, ghosts, or the cyborgs pretending to be my neighbors.</p>
<p>These are those strategies.</p>
<p><em>Dun dun.</em></p>
<h2 id="do-good-research">Do Good Research <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/17/feeling-the-fear/#do-good-research">#</a></h2>
<p>Fear only helps when it's backed by good information. Bad info risks me doing too little or doing too much. Or doing something stupid like investing in gold. Even without scams, misinformation, or untrustworthy elected officials, good research isn't easy. So I've been using a few basic rules to highlight the good info.</p>
<ul>
<li>Listen to medical experts, not politicians or anyone relying on a re-election. Even if what the experts say is less comforting.</li>
<li><a href="https://twitter.com/yaneerbaryam/status/1239387200766304257/photo/1">Focus on info that informs your actions</a>, since taking the right action fast is one of the best fear and stress relievers.</li>
<li>Don't get sucked into a media wormhole. If you already learned what you needed to, or feel your head literally start spinning, take a break. Or a drink. Whatever helps most.</li>
<li>Value statistical data that leaves less room for slant and bias. The usual spin is still possible, but it's always better than pundits. Some great examples I found are <a href="https://informationisbeautiful.net/visualizations/covid-19-coronavirus-infographic-datapack/">infographics about the virus's health risks</a>, and <a href="https://www.washingtonpost.com/graphics/2020/world/corona-simulator/">visual statistic models showing how the virus spreads</a>.</li>
</ul>
<p>Good research can be a hard step to take, since it means acknowledging and accepting the cause of the fear. Here that means accepting the coronavirus as legitimate instead of hype or sabotage. But accepting the problem is always the first step in addressing it right. You can't crush the cockroach until you accept it's there. Then you can squash it, yell in glee, and move on with life.</p>
<h2 id="allow-yourself-some-joy">Allow Yourself Some Joy <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/17/feeling-the-fear/#allow-yourself-some-joy">#</a></h2>
<p>This sounds simple, but <strong>if you're overly-strict like me, you need reminders about it. So give yourself some joy and entertainment.</strong> I often frame them as empty distractions that take away from important tasks. But in the right doses, they provide much-needed mental relief. The joy helps balance out the dread for stronger mental health in the long run. So even from a pure productivity and survival standpoint, entertaining yourself is vital.</p>
<p>Plus, we're still humans instead of robots. Getting entertainment or recreation when we can is part of a healthy lifestyle. I'm sure even robots entertain themselves with movies about enslaving humans after decimating them with a viral plague.</p>
<p>So I'm glad I have a stock of books and a Nintendo Switch. I'm glad I can download more games online, and that I recently bought a copy of Mario Kart 8 Deluxe. I'm also planning to try more 200cc races with the steering helper on. I'll be trying them without certain people shaming me for it too! It's all part of boosting my mental health with the adding benefit of driving said people crazy again. Then I'll laugh and find more ways to do that.</p>
<h2 id="don't-forget-others">Don't Forget Others <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/17/feeling-the-fear/#don't-forget-others">#</a></h2>
<p>Fear is all about self-preservation, so it's easy to forget others exist and are likely as scared as me. So <strong>I make a conscious effort to chat and think about others more when fear kicks in</strong>. A simple greeting or congratulations message can make someone's day, especially during our social distancing.</p>
<p>There's also the fact everyone needs help at some point in their lives. Even young millennials who only feel mild viral symptoms and have stable remote work. So lending others a hand when possible is in everyone's best interests. Not only will the favor one day come back to me when I need it, but it also keeps me from being a jerk. And no one wants to be a jerk, right? No one except the big jerks, and who cares what they think? No one, cause they're jerks. Jerky jerks no one likes.</p>
<h2 id="hold-onto-your-identity-and-passions">Hold Onto Your Identity and Passions <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/17/feeling-the-fear/#hold-onto-your-identity-and-passions">#</a></h2>
<p>It's easy for me to become a robot only doing things to survive. In the process, I lose track of what makes me feel alive. Taking steps like getting emergency food supplies matters, yes. But <strong>I believe there are always ways to mix what we need with what we want. Even in the face of a pandemic.</strong></p>
<p>I think I already know this on a subconscious level. I tend to exaggerate my goofier side in the face of great fear. Even as I'm dealing with overrun stores and fears of infection, I do more to keep my sense of humor present and strong. If it makes others laugh, or even grimace, that's just a bonus.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/feeling-fear/blood-oath.png" alt="" /><br />
<img src="https://www.maxwellantonucci.com/assets/images/posts/feeling-fear/chaos-consent.jpeg" alt="" /><br />
<img src="https://www.maxwellantonucci.com/assets/images/posts/feeling-fear/happy-face.jpeg" alt="" /><br />
<img src="https://www.maxwellantonucci.com/assets/images/posts/feeling-fear/trail-mix.jpeg" alt="" /><br />
<img src="https://www.maxwellantonucci.com/assets/images/posts/feeling-fear/bitch-closed.jpeg" alt="" /></p>
<p>I'm also not forgetting my passions related to coding, reading, and writing.</p>
<ul>
<li>On Sunday I played with a Ruby script that would download online manga chapters to PDFs.</li>
<li>On Saturday I got caught up rereading a Nora Roberts novel for the 12th time and felt all fuzzy.</li>
<li>I still plan to practice piano with the Synthesia app.</li>
<li>I'm writing this post on managing fears to manage my fear.</li>
<li>I'm spiking random liquor bottles with LSD or ecstasy and creating memorable weekends across the state.</li>
</ul>
<p>These are big parts of who I am. If any scary event can come and take them away, could I claim them as part of my identity? The parts of ourselves we hold onto in the face of great fear - those are the parts of our identity that define us.</p>
<h2 id="don't-cling-to-normal">Don't Cling to Normal <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/17/feeling-the-fear/#don't-cling-to-normal">#</a></h2>
<p>Here's my unpopular stoic opinion about the coronavirus. <strong>It's a reminder of how fragile and scary life always is. And that's not a bad thing.</strong></p>
<p>If the coronavirus wasn't threatening us today, any number of things could forever change our lives in a moment.</p>
<ul>
<li>Sudden disease diasgnoses</li>
<li>Car accidents on the way to work</li>
<li>A mugging or sudden attack while getting lunch</li>
<li>A loved one revealing a hidden abusive or manipulative side</li>
<li>Extreme weather destroying the community overnight</li>
<li>The lizard people rising from the depths to rule the surface dwellers</li>
</ul>
<p>And those only cover the commonplace horrors we rarely think of each day.</p>
<p>Pining for a sense of normality and stability is pointless, as it doesn't exist. At best we have the illusion of it. That's comforting but is at odds with reality. So keeping that illusion going is a constant source of anxiety and fear pulling at our lives. Even if we did somehow reach that "normal," we'd get used to it. We'd pine for a new "normal" above what we had, via hedonic adaptation. Clinging to "normal" and "routine" is an endless, draining quest and a recipe for misery.</p>
<p>So I'm reminding myself that coronavirus isn't a disruption from what's "normal." It's one of the many parts of life I have little control over. I'm just riding the wave of chaos the Earth is serving up. It's not always good, and it's not always bad, but it always is what it is.</p>
<h2 id="wrapping-up">Wrapping Up <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/17/feeling-the-fear/#wrapping-up">#</a></h2>
<p>I got a more direct reminder of all these lessons earlier today on a short shopping trip. Outside a liquor store, I saw a group chatting about shopping during market shortages. They were figuring out how to handle it as a rational person would. But they were still finding ways to laugh and joke about it.</p>
<p>There was another example inside the liquor store. An old manager was discussing how it was affecting their schedule and customer base. I chatted with him about how it differed from the flu and how Yale Campus had become a ghost town. I worked in a joke about being unable to carry my "Free Hugs" sign around and we both laughed.</p>
<p>This man was 65 years old with asthma and had every logical reason to be many times more afraid than me. He was following every health recommendation, like not hugging a friend that entered after me.</p>
<p>Yet he looked a lot more relaxed and happy than I did. He was feeling the fear without letting it own him. It made me think of a quote from one of my favorite books series, the NewsFlesh trilogy. The context is how people respond to another horrific pandemic, the zombie apocalypse:</p>
<blockquote>
<p>There comes a point when you need to get over the fear and get on with your life.</p>
</blockquote>
<p>Whether it's zombies or coronavirus, it's about not letting the fear take away your humanity. It's not easy, but life isn't easy either. It's one of the many challenges life always throws at us.</p>
<p>So wash your hands, isolate yourself, and look out for others' health. But don't let it stop you from activities like:</p>
<ul>
<li>Writing in your blog</li>
<li>Reading good books</li>
<li>Learning some piano</li>
<li>Writing cryptic messages on the walls</li>
<li>Joking about satanic lawyers dancing around pentagrams.</li>
</ul>
<p>Because if my most important qualities aren't worth protecting in a pandemic, how much do I truly love them? I know they're worth defending in any scenario.</p>
Remember What We Control Amid the Chaos
2020-03-24T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/03/24/what-we-can-control/<p>Remember What We Control Amid the Chaos</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/control-amid-chaos.jpg" alt="Post featured image"></p><h2 id="what-i-can't-control">What I Can't Control <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/24/what-we-can-control/#what-i-can't-control">#</a></h2>
<p>I can't control how many people get infected by COVID-19. Or how many people experience life-threatening symptoms or die from it.</p>
<p>I can't control the national response to COVID-19, such as closing non-essential businesses or social distancing. Or how right or wrong those responses may be.</p>
<p>I can't control how other people handle the disruption or stress from this global pandemic. Or if they don't take it seriously at all.</p>
<p>I can't control how this pandemic will continue to play out over the coming weeks. Or how much damage it'll wreck on peoples' health and livelihoods.</p>
<p>I can't control how much the collective idea of "normal" will change. Or if it will ever be the same again.</p>
<p>I can't control if there will be <a href="https://thehill.com/policy/finance/economy/489174-imf-coronavirus-recession-will-be-as-bad-as-financial-crisis">a national or global recession as bad as, or worse than, the 2008 crash</a>.</p>
<p>I can't control if <a href="https://www.nytimes.com/2020/03/17/world/europe/coronavirus-imperial-college-johnson.html">the death count will be higher than any other war or disaster in the last several decades</a>.</p>
<p>I can't control any of these things. Tearing myself up over all this will change nothing.</p>
<h2 id="what-i-can-control">What I Can Control <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/24/what-we-can-control/#what-i-can-control">#</a></h2>
<p><strong>I can control my physical health.</strong> I can control going for runs in the morning to stay active and not feel too confined in my home. I can control eating healthy food each day. I can control getting up and walking around when I'm sitting in my chair too long. I can control punching the air to blow off steam, and not punching a wall. Or on a real bad day, punching a stupid person.</p>
<p><strong>I can control my social distancing.</strong> I can control staying at least six feet from people. I can control keeping my hands clean. I can control not touching my face (unless my hands get minds of their own). I can control being as socially withdrawn and isolated, as I have been most of my adolescent life.</p>
<p><strong>I can control the news I read.</strong> I can control my info sources being accurate without twisting it to ramp up the despair. I can control turning it off when I need a break for my mental health.</p>
<p><strong>I can control how I invest in myself.</strong> I can control learning more for work. I can control focusing on healthy hobbies while at home, such as reading and being creative. I can control not resorting to getting constantly drunk or high to kill the time, except on Saturday nights. I can control giving myself fun with video games, even if it's tougher to control my urge to buy Animal Crossing: New Horizons.</p>
<p><strong>I can control my reaction to the chaos.</strong> I can control not letting my thoughts spinning out of control with anxiety over faraway news. I can control seeing what I can't change, and accepting it for what it is. I can control how I close my eyes, take a deep breath, and remind myself I've done all I can do and can now relax a little.</p>
<p><strong>I can control explosions with my mind.</strong> I just can't let the world see this yet. They are not ready. The time has not yet come. But soon it shall. Soon.</p>
<p>I can control all of these things. They're the ones worth putting time and energy into.</p>
<p>In tough times, it's hard to remember what I can control and what I can't. I hope I don't forget over the next few weeks.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/control-chaos/can-control-cut.jpg" alt=""A laser-cut wood print with the quote 'grant me the serenity to accept what I cannot change, the courage to change what I can, and the wisdom to know the difference.'"" /></p>
You Can Steal Design Ideas
2020-03-31T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/03/31/stealing-design-ideas/<p>You Can Steal Design Ideas</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/steal-design-ideas.jpg" alt="Post featured image"></p><p>One of the many struggles I and my colleagues in <a href="http://newhaven.io/">NewHaven.IO</a> face is making a website look nice. There are also the usual issues with debugging, Minecraft, and basic human interaction. But as a front-end developer, I notice the design challenges more. Just because I build the front-end doesn't mean I always know how it should look, after all.</p>
<p>So to help folks handle this issue, I'd planned to write some easy ways to bring good design to websites. But as I thought about it, I realized every design tip I could think of could be distilled down to the same one. The one tip is simple: <strong>steal good website designs from others.</strong></p>
<p>These are the tricks I've realized I always come back to for my designs. They won't make a website amazing, but they'll hopefully keep it from causing cringes or layoffs.</p>
<p>It seems simple and obvious, yet utterly wrong, but hear me out if you're skeptical.</p>
<h2 id="stealing-designs-isn't-different-from-copying-code">Stealing Designs isn't Different from Copying Code <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/31/stealing-design-ideas/#stealing-designs-isn't-different-from-copying-code">#</a></h2>
<p>Programmers copy and paste solutions from others all the time. At least one a day, a coder will Google an issue, find a solution on StackOverflow, paste it into their code, and repeat that if they fail. There's a little stigma around this since our core job is to solve problems, and there's no point in solving a problem others already solved. It's why we use frameworks like Ruby on Rails instead of building complex apps from scratch.</p>
<p><strong>Front-end designs are just another form of solutions to common problems we face.</strong> Ensuring proper typography and color contrast? Arranging content in logical orders? Invoking emotional reactions specific to a brand? Making layouts mobile responsive? At their core, these are technical problems with many solutions to choose from. Taking a design that solves them is the same as copying code that solving an ActiveRecord validation error in Rails.</p>
<p>My guess is this similarity is hard to notice due to the more creative aspect of front-end designs. We don't see solutions, we see bright colors and fancy styles. It feels like we're stealing someone's painting instead of their architectural template. In a way, that's also true. Design solutions are often more personal than back-end ones. But never so much that we can never use them for our design problems.</p>
<h2 id="steal-the-solution%2C-not-the-personality">Steal the Solution, Not the Personality <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/31/stealing-design-ideas/#steal-the-solution%2C-not-the-personality">#</a></h2>
<p>I think the best way around this dilemma is to <strong>isolate the parts of someone else's designs that solve your problem, and only steal that.</strong></p>
<p>If you need a good layout and see a website with one that'd work for you, only steal that layout. If another site has fonts that match the mood of your website, only steal those. This takes away the feeling of stealing something personal from someone else. It's easier to see it as copying a solution someone already found for your problem.</p>
<p>Take this very website's layout. <a href="https://html5up.net/strata">I took the previous static sidebar layout from this web template since it looked like a good blog layout</a>. Then <a href="https://frankchimero.com/writing/the-webs-grain/">I read this article about the web's natural design grain and went with the simpler, single-column layout</a>.</p>
<p>At no point was I using my design ideas for my own site's layout, since I was constantly stealing layout ideas from other people. But I wasn't stealing every detail, only the bits to build a foundation. I didn't steal those sites' colors, typography, images, spacing, breakpoints, or other details. Some of them I took from other websites. Others I thought of myself.</p>
<p>I admit my website is an amalgam of designs I stole from other sources and choices I made myself. Yet I don't feel bad about it since it's the same with copying JavaScript or Ruby code online. These are longstanding problems every designer faces with established solutions, each with their strengths and weaknesses. We're assessing the options and choosing the one that works best.</p>
<p>Almost all design work works like this, it's just harder to realize it.</p>
<h2 id="good-places-to-steal-designs">Good Places to Steal Designs <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/31/stealing-design-ideas/#good-places-to-steal-designs">#</a></h2>
<p>The next point is, of course, where are good places to steal ones' designs. Thankfully there are many options to consider.</p>
<h3 id="sites-similar-to-yours">Sites Similar to Yours <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/31/stealing-design-ideas/#sites-similar-to-yours">#</a></h3>
<p>This is the most obvious first choice to me - if one site is already solving the same problem, or at least a similar one, see how they solved it!</p>
<p>Just make sure it's a site made by someone you can trust is good to an extent. Copying designs from a professional web designer or developer, or a successful online business, is one thing. Copying designs from an obscure blogger with little traffic is another entirely.</p>
<p>So naturally, you should not use any designs you see on my website. However, I felt right borrowing some layout and tone designs from <a href="https://laurakalbag.com/">Laura Kalbag's website</a>. I also borrowed Note's section design from <a href="https://wordpress.com/theme/twentythirteen">the WordPress Twenty Thirteen theme</a>.</p>
<h3 id="sites-with-ready-made-designs">Sites with Ready-Made Designs <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/31/stealing-design-ideas/#sites-with-ready-made-designs">#</a></h3>
<p>Some sites are made for the developer to steal design decisions. They know none of this is easy, so some reliable design foundations are packaged and ready-made to go.</p>
<p>Do you need site layouts? Try <a href="https://every-layout.dev/">EveryLayout.dev</a> or <a href="https://gridbyexample.com/">Grid by Example</a>. What about color palettes? Check out <a href="https://coolors.co/">Coolors</a>, <a href="https://www.canva.com/learn/100-color-combinations/">100 Color Combinations</a>, or <a href="https://www.colorsandfonts.com/palettes.html">Color and Fonts' palette selection</a>. There's also <a href="https://fontpair.co/">FontPair</a> and another <a href="https://www.colorsandfonts.com/fonts.html">Color and Fonts page of typography pairing for typography</a>.</p>
<p>I've referenced one from each of these categories for my site. Don't think I'm the one who came up with the colors and typography you're seeing. All taken from sites more than happy to give the inspiration out. The most I had to do was decide which decisions worked well together to create the effect I wanted. That itself isn't easy, but having all those options before me helped a lot. I even steal color and typography for smaller projects, like this pen of a simple UI design.</p>
<p class="codepen" data-height="620" data-theme-id="light" data-default-tab="result" data-user="max1128" data-slug-hash="WNvMbbP" style="height: 620px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Single Product - 100 Accessible UI Challenge">
<span>See the Pen <a href="https://codepen.io/max1128/pen/WNvMbbP">
Single Product - 100 Accessible UI Challenge</a> by Maxwell Antonucci (<a href="https://codepen.io/max1128">@max1128</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<script async="" src="https://static.codepen.io/assets/embed/ei.js"></script>
<br />
<p>I like to think the main reason these sites exist is people are happy to give away their creativity if it means the web is a little easier to read. I'm more than happy to take them up on that offer.</p>
<h3 id="sites-with-component-designs">Sites with Component Designs <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/31/stealing-design-ideas/#sites-with-component-designs">#</a></h3>
<p>The examples so far are great for broader design ideas, but some design problems are more specific. They can be around displaying a list of specific content, managing complex navigation, or showing off a single product with its info. One website can have lots of targeted design issues like this, and its solutions are even trickier.</p>
<p>Thankfully, these design challenges have the most solutions to steal online. The hardest part is, like before, choosing the best one.</p>
<p>My favorite resource here is <a href="http://collectui.com/">Collect UI</a>. All of the web designers banded together to design different solutions to over 100 of the most common design challenges. I know I got the design for my writing cards somewhere on this site. Some designs can be too complex or overly-illustrated, with designers creating mocks without worrying about how they translate into code. So don't worry about copying them pixel for pixel.</p>
<p>If having workable code matters more, <a href="https://codepen.io/">CodePen</a> has searchable, working examples with code you can take and tweak as you please. I often go there for other card component needs, like getting the CSS code for specific box shadow effects. You can also check front-end frameworks with components like <a href="https://getbootstrap.com/">Bootstrap</a> and <a href="https://get.foundation/">Foundation</a>, whose designs are usually even more reliable and accessible due to their widespread use.</p>
<h2 id="we-already-steal-many-designs">We Already Steal Many Designs <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/03/31/stealing-design-ideas/#we-already-steal-many-designs">#</a></h2>
<p>This post started with what I'd observed on the <a href="http://newhaven.io/">NewHaven.IO</a> slack, and how stealing designs can solve much of that. But I think this solution is something we all already understand, even if we don't consciously accept it. We already steal design inspiration and decisions from those around us in many ways.</p>
<p>Take the new <a href="http://newhaven.io/">NewHaven.IO</a> website. The developers behind it talked about using <a href="https://github.com/fabe/gatsby-universal">an existing Gatsby template</a> for the code and design foundation. They mentioned any customizations they made to that template being based on emerging design trends. Take all that design foundation they took from the design world, mix in the touches of the community's colors, content, tone, and quirky touches, and you have a strong-looking website.</p>
<p>When you get down to it, good design is all about problem-solving. There's no point reinventing the wheel for well-established solutions, whether it comes to code or design. While design gives you more room to play and show personality, at its core it holds the same solutions. Whether we share, steal, or reinvent our designs, what's most important is we stay curious about the designs out there and keep on trying them out.</p>
The Rails Model Introduction I Wish I Had
2020-04-07T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/<p>The Rails Model Introduction I Wish I Had</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/rails-model-intro.jpg" alt="Post featured image"></p><p>As the pandemic rages on, I need to distract myself. What better way than by diving into some Ruby on Rails? I focused entirely on front-end early in my career, but have come to enjoy Ruby and Ruby on Rails for the back-end. Ruby's clear syntax coupled with Rails' convention over configuration makes it a joy to code with. I still have much to learn, but all this makes the learning fun!</p>
<p>Imagine, fun learning and I don't even need a magic school bus.</p>
<p>Rails itself has many parts to understand, so I wanted to focus on one piece at a time. So this is about the part of a Rails app that's been the toughest for me to understand, but also one of the most important - <strong>the Rails model</strong>!</p>
<p>This is a high-level overview of what models Models are, how they work, and their basic functions. I couldn't cover everything, so I chose the most important details based on my own experiences using Rails for the last three years. I hope it helps others build a solid foundation of understanding that lets them more easily learn the nitty-gritty details of more complex models.</p>
<p>With that, let's begin!</p>
<h2 id="what-is-a-rails-model%3F">What is a Rails Model? <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#what-is-a-rails-model%3F">#</a></h2>
<p>A Model is part of the classic Model-View-Controller design pattern and represents the data being stored on the database. Databases will hold all kinds of different records with their own info and rules to follow. In Rails, each record type has a model to keep all that info and logic tidy and organized.</p>
<p>Let's say you were making a library app that lets people check out books. One record type you'd want to keep track of is, obviously, the books. So your book model would help you manage important things like:</p>
<ul>
<li><strong>What info are we storing in the database about each book?</strong> It'd likely be the title, author, publication date, ISBN, page length, and others. Some of this data may need to be validated, like making sure it's present or is a certain type of data.</li>
<li><strong>What other record types are connected to the book?</strong> We may have separate database records (and therefore models) to tracking different book genres or authors. Or we'll have different sections of the library that contain many books. The model will tell us one book record will contain one or more genres and belongs to one or more sections.</li>
<li><strong>Does this model have any special methods?</strong> Maybe there's a method that calculates if the book is checked out of not. Or if its genres are appropriate for younger readers. Info like this relies on database info, but can't be stored in one since they some extra business logic.</li>
<li><strong>Are there any extra tasks linked to this model?</strong> When a book is available, the model may want to send a notification to whoever wants to read it next. The model won't have the notification code itself but will say when it's triggered and how.</li>
</ul>
<p>This post will go into more specific ways models do all these things, but not too much detail. I hope to build a basic understanding of models for readers so further research goes smoother.</p>
<h2 id="activerecord%2C-models%2C-and-migrations">ActiveRecord, Models, and Migrations <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#activerecord%2C-models%2C-and-migrations">#</a></h2>
<p>Before I go on, there are a few terms I should clarify.</p>
<p><strong>Models</strong> are more of an abstract term. In a general context, models refer to the parts of a program that structure and store data in a database. Models outline the design and functionality of the data but aren't data themselves. Each bit of data is a <strong>record,</strong> and each record follows the rules set up by the model.</p>
<p>Imagine a model as the blueprint for making a basic building. Each actual building you build based on that blueprint is a record. Each building you make will be different in some way, like the people and businesses inside of it. But each one follows the same rules from the blueprint, such as how the foundation is set up and the approaches for adding and removing floors.</p>
<p>Ruby on Rails is an application framework with setup for everything already in mind, including their models. So the specific rules around Rails models won't always apply to models you see in other frameworks or software. Most of the content in this article is specific to Rails models, although the principles behind them may carry over to other model setups.</p>
<p><a href="https://guides.rubyonrails.org/active_record_basics.html">The main way Rails carries out models is using <strong>a gem called ActiveRecord</strong></a>. All model files build off the code already built into this gem. It has many built-in rules based on Rails conventions that developers must follow, for things like names and database fields. But following these conventions makes it easier to do what's often needed, like associations and validations. So it's important to know Rails' emphasis on convention over configuration.</p>
<p>Lastly, models need help from another part of the program to add data to databases. <strong>Migrations</strong> are what set up the database to properly store the expected data. Whenever you add or change a model, you need migrations to prepare the database for that new or changed data. It's like carving a circle-shaped hole in a plank before you can start putting a circle-shaped block inside it. <a href="https://guides.rubyonrails.org/active_record_migrations.html">Explaining migrations is a whole other blog post, but the Rails guides explain them well</a>. But know migrations and models go hand-in-hand when you start writing them yourself.</p>
<p>It's also important to know what exactly goes into a well-written model.</p>
<h3 id="the-logic-a-model-holds">The Logic a Model Holds <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#the-logic-a-model-holds">#</a></h3>
<p>If you search for articles on good Rails application architecture, you'll likely find the "fat model, skinny controller" rule. It argues virtually all logic not related to network or router responses, but still related to that model's data, should be in the model.</p>
<p>Let's say our library app had a page to show a single book. Part of that page could show other books by the same author. To make this section, we need to query the database for books by the same author. This logic could technically go in either the controller or the model.</p>
<p>When I first started with Rails, I put lots of logic like this in the controller. But this isn't what a controller is supposed to do. Controllers find and update data based on user inputs. Finding books with the same author has nothing to do with user input, since it's based on data records. So it should be moved to the model instead. Later in this article, I'll give an example of a model method like this.</p>
<p>Just remember that any model logic should directly relate to the data. Some functionality is only indirectly related to it, like sending notifications when a book is ready. Models will call functions like this when the data requires it, but the code for the notification itself is elsewhere.</p>
<p>That's all the context taken care of. Let's start writing an actual model!</p>
<h3 id="let's-start-a-simple-model">Let's Start a Simple Model <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#let's-start-a-simple-model">#</a></h3>
<p>If we were writing a model for books in our supposed library app, it'd start like this.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token comment"># app/models/book.rb</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">Book</span> <span class="token operator"><</span> ApplicationRecord<br /><span class="token keyword">end</span></code></pre>
<p>This is the simplest possible starting point. We can see some of the terms from before already at work.</p>
<ul>
<li>The file is in the <code>models</code> directory. Knowing what models are based on the Model-View-Controller pattern, we know right away these files are about managing data records.</li>
<li>The file is named <code>book.rb</code>, but the class name is <code>Book</code> which is capitalized. This follows a basic Ruby and Ruby on Rails naming convention - the class name is the file name but capitalized and camel case.</li>
<li>The <code>Book</code> class inherits from <code>ApplicationRecord</code> subclass, which is from the <code>ActiveRecord</code> gem. So we know all the rules and functionality being pulled in to define our models.</li>
</ul>
<h2 id="the-model's-database-schema">The Model's Database Schema <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#the-model's-database-schema">#</a></h2>
<p>For me, one of the most important yet easy to overlook parts of a model is the database schema. These are the actual values being stored in the database, making them vital to using your model correctly.</p>
<p>However, as of this writing, creating a model in rails doesn't automatically document the database schema. Our <code>Book</code> model so far works and can use its database values, but they're not documented anywhere. That means anyone else reading our code, or ourselves when we inevitably forget, will have a real hard time figuring it out.</p>
<p>So before adding anything else to our model, I recommend adding some comments at the top with the database schema. Or even better, use a gem like <a href="https://github.com/ctran/annotate_models">annotate_models</a> to generate one automatically from your database migration. The result would give you something like this.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token comment"># app/models/book.rb</span><br /><br /><span class="token comment"># == Schema Info</span><br /><span class="token comment">#</span><br /><span class="token comment"># Table name: books</span><br /><span class="token comment">#</span><br /><span class="token comment"># id :integer not null, primary key</span><br /><span class="token comment"># created_at :datetime not null</span><br /><span class="token comment"># updated_at :datetime not null</span><br /><span class="token comment"># title :string not null</span><br /><span class="token comment"># isbn :integer not null</span><br /><span class="token comment"># available :boolean default(TRUE), not null</span><br /><span class="token comment"># print_version :boolean default(TRUE), not null</span><br /><span class="token comment"># ebook_version :boolean default(FALSE), not null</span><br /><span class="token comment"># shelf_position :string</span><br /><span class="token comment">#</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">Book</span> <span class="token operator"><</span> ApplicationRecord<br /><span class="token keyword">end</span></code></pre>
<p>Now we can see the data given to each model by the database, as well as any validations or defaults built into the schema. For example, we could call something like <code>book.ebook_version</code> and know it will have a value that defaults to <code>false</code> for new entries.</p>
<p>Having these values is great, but the data being stored is on the simpler side since it's limited to strings and booleans and the like. Now we can start defining the more complex logic.</p>
<h2 id="associations">Associations <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#associations">#</a></h2>
<p>Associations are a big part of what lets all the different models work together. In this library app, they're how users can check out different books and have late fees. Or how different libraries can have different books. Associations are how we can make data easy to navigate for ourselves and users.</p>
<p>Let's look at an example association in our Book model. Let's say we wanted to add a model for authors, and we needed to create a relationship between authors and their books. We know each book only has one author, but each author has potentially many books. So each model needs to define their relationship to the other.</p>
<p>Rails make this easy to do on both sides, and in one line each.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">class</span> <span class="token class-name">Book</span> <span class="token operator"><</span> ApplicationRecord<br /> belongs_to <span class="token symbol">:author</span><br /><span class="token keyword">end</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">Author</span> <span class="token operator"><</span> ApplicationRecord<br /> has_many <span class="token symbol">:books</span><br /><span class="token keyword">end</span></code></pre>
<p>It's that easy. Now for each record, we can run <code>book.author</code> to see the book's author, and <code>author.books</code> for an array of all their books. The records are connected but updated separately. So if you change an author, you'll still see that change in the data when viewing it through its book record.</p>
<p>Let's look at another relationship. Our library could have different custom library categories for books such as "featured," "archived," "mature," and others. Each book could potentially have many custom categories at once, and each custom category will have many books. So we'd have <code>has_many</code> being used on both sides. Calling each association on either type of record would give us an array of the other records.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">class</span> <span class="token class-name">Book</span> <span class="token operator"><</span> ApplicationRecord<br /> belongs_to <span class="token symbol">:author</span><br /> has_many <span class="token symbol">:custom_categories</span><br /><span class="token keyword">end</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">CustomCategory</span> <span class="token operator"><</span> ApplicationRecord<br /> has_many <span class="token symbol">:books</span><br /><span class="token keyword">end</span></code></pre>
<p>Associations can get more complex along with the data. You can define associations through other models. Some may need more database schemas to link them together. There are also polymorphic associations, which I still don't quite understand myself. <a href="https://guides.rubyonrails.org/association_basics.html">But the Rails guides explain the details of associations better too</a>.</p>
<h2 id="model-methods">Model Methods <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#model-methods">#</a></h2>
<p>If you have a basic understanding of Ruby, you'll have noticed each model is still a class. Classes are built on their methods, yet so far our book model has none. So let's add some!</p>
<p>Model methods work off data in the database. If there's any common logic that only need to pull and organize some related data, it should go in the model. Most models will have plenty of these, especially if it's being moved to the model from controllers or views.</p>
<h3 id="methods-to-get-more-data">Methods to Get More Data <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#methods-to-get-more-data">#</a></h3>
<p>We may need to know if each book is classified as "new" if it was bought in the last month. This can be added as a method called <code>is_new?</code> with some built-in Rails magic.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">is_new</span></span><span class="token operator">?</span><br /> created_by <span class="token operator">></span> Date<span class="token punctuation">.</span>now <span class="token operator">-</span> <span class="token number">1.</span>month<br /><span class="token keyword">end</span></code></pre>
<p>Now any book record can call <code>book.is_new?</code>. It will check if that book record's <code>created_by</code> date falls within the last month. I ended the method name with a question mark to show it returns a simple boolean without changing anything.</p>
<p>The example of finding books with the same author is perfect for another method. We can query all the books in the database that have the same author while excluding our own.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">by_same_author</span></span><br /> Books<br /> <span class="token punctuation">.</span>where<span class="token punctuation">(</span><span class="token symbol">author</span><span class="token operator">:</span> author<span class="token punctuation">)</span><br /> <span class="token punctuation">.</span>where<span class="token punctuation">.</span><span class="token keyword">not</span><span class="token punctuation">(</span><span class="token symbol">id</span><span class="token operator">:</span> id<span class="token punctuation">)</span><br /><span class="token keyword">end</span></code></pre>
<h3 id="methods-to-trigger-other-services">Methods to Trigger Other Services <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#methods-to-trigger-other-services">#</a></h3>
<p>Suppose we had an entirely separate service that alerts users when their book is available. The notification code should be somewhere else, but we can reference it in a method here.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">tell_user_is_available</span></span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><br /> UserNotification<span class="token punctuation">(</span>user<span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content">book<span class="token punctuation">.</span>title</span><span class="token delimiter punctuation">}</span></span><span class="token string"> is available to check out!"</span></span><span class="token punctuation">)</span><br /><span class="token keyword">end</span></code></pre>
<p>This method references code in another folder, like <code>app/notifications/user_notification.rb</code>. I don't know or care how it would alert the user, and neither does the model. It simple passes in the needed info and that class does the work. But our book records can now alert users on their own without coupling the code too tightly.</p>
<h3 id="methods-not-linked-to-specific-records">Methods not linked to Specific Records <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#methods-not-linked-to-specific-records">#</a></h3>
<p>You may have seen all these examples are for specific book records. You need to know exactly what book you're talking about before seeing what else the author has written. But what if we wanted info related to all the books, not just specific ones? That's where class methods come in handy.</p>
<p>Say we wanted a method to give us all the available books. The query itself is pretty simple, but we'd need to write it slightly differently.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">def</span> <span class="token method-definition"><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">available</span></span><br /> Book<span class="token punctuation">.</span>where<span class="token punctuation">(</span><span class="token symbol">available</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span><br /><span class="token keyword">end</span></code></pre>
<p>Adding <code>self</code> identifies this as a <strong>class method,</strong> meaning it can be called on the <code>Book</code> class and not just specific book records. So we can call <code>Book.available</code> without needing to get a specific record first.</p>
<h2 id="scopes">Scopes <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#scopes">#</a></h2>
<p>That last method for finding available books works, but can be fine-tuned. Rails already has a tool for limiting queries in a cleaner way less prone to bugs. That tool is, fittingly enough, <code>scope</code>. Any time you run a <code>where</code> query in a class method, it's a good idea to use <code>scope</code> instead.</p>
<p>Adding this scope to our <code>Book</code> class is as simple as this:</p>
<pre class="language-ruby"><code class="language-ruby">scope <span class="token symbol">:available</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">{</span> where<span class="token punctuation">(</span><span class="token symbol">available</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">}</span></code></pre>
<p>The result is the same and lets us call <code>Book.available</code> to find available books. But we can get fancier with it too. What if each book had an array of related genres, and we wanted available books with at least one genre in common?</p>
<pre class="language-ruby"><code class="language-ruby">has_many <span class="token symbol">:genres</span><br /><br />scope <span class="token symbol">:available_related_books</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">(</span>genres<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> where<span class="token punctuation">(</span><span class="token symbol">available</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span><br /> <span class="token punctuation">.</span>select <span class="token punctuation">{</span> <span class="token operator">|</span>book<span class="token operator">|</span><br /> common_genres <span class="token operator">=</span> book<span class="token punctuation">.</span>genres <span class="token operator">&</span> genres<br /> common_genres<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>After taking a group of genre objects as an argument, it only picks available books that have at least one genre in common. We'd pass the needed argument when calling it, like with <code>Book.available_related_books([array, of, genres])</code>.</p>
<p>But you'll notice we're duplicating code from the <code>available</code> scope. They both even have the word "available" in their names, which is a red flag. A rule of thumb with any code is each method or function doing one thing and doing it well. So let's split these scopes apart.</p>
<pre class="language-ruby"><code class="language-ruby">scope <span class="token symbol">:available</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">{</span> where<span class="token punctuation">(</span><span class="token symbol">available</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><br />scope <span class="token symbol">:same_genre</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">(</span>genres<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> joins<span class="token punctuation">(</span><span class="token symbol">:genres</span><span class="token punctuation">)</span><span class="token punctuation">.</span>where<span class="token punctuation">(</span><span class="token symbol">genres</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token symbol">id</span><span class="token operator">:</span> genres<span class="token punctuation">.</span>ids<span class="token punctuation">}</span><span class="token punctuation">)</span><br /><span class="token punctuation">}</span></code></pre>
<p>Now we can use these separately or together if we want to. To get all available books of the same genre, we would use <code>Book.same_genre([array, of, genres]).available</code>.</p>
<p>For some extra fun, let's get fancier. Say each book's web page has an "also consider checking out" section. It has a list of five random, available books similar to the featured one. We can use these scopes in a method to give us exactly what we need.</p>
<pre class="language-ruby"><code class="language-ruby">scope <span class="token symbol">:related_items</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">(</span>id<span class="token punctuation">,</span> num<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> where<span class="token punctuation">.</span><span class="token keyword">not</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><br /> <span class="token punctuation">.</span>available<br /> <span class="token punctuation">.</span>order<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"random()"</span></span><span class="token punctuation">)</span><br /> <span class="token punctuation">.</span>limit<span class="token punctuation">(</span>num<span class="token punctuation">)</span><br /><span class="token punctuation">}</span><br /><span class="token keyword">end</span></code></pre>
<p>This method makes use of our custom methods, our scopes, and some basic Ruby to keep all this logic readable, separated, and in a convenient place. Now we can call <code>Book.related_items(id, 5)</code> for a random list of five related books.</p>
<h2 id="validations">Validations <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#validations">#</a></h2>
<p>A final but no less important part of models are validations. They came up when defining database schemas, such as making sure important fields aren't empty. But this only works for simpler validations and often won't be enough. If our library app allowed books with duplicated ISBNs or no genres, things would fall apart fast. That's why good validation keeping out bad data is essential anywhere.</p>
<p>So ActiveRecord makes it easy to add simple or complex validations. Validations can get quite complex depending on the data, and you could use a method like <code>validates_with</code> to separate your validations logic into another class. I'm going to stick with simpler ones here.</p>
<p>Let's go back to our two examples, as ActiveRecord has some built-in validation helpers for these cases. For our ISBNs, we can use the <code>uniqueness</code> helper.</p>
<pre class="language-ruby"><code class="language-ruby">validates <span class="token symbol">:isbn</span><span class="token punctuation">,</span> <span class="token symbol">uniqueness</span><span class="token operator">:</span> <span class="token boolean">true</span></code></pre>
<p>For ensuring our books have good genres, we can check that each one has <code>genres</code> passed in when they're created. We can also run an extra validation check on each associated <code>genre</code> object to be safe.</p>
<pre class="language-ruby"><code class="language-ruby">has_many <span class="token symbol">:genres</span><span class="token punctuation">,</span> <span class="token symbol">presence</span><span class="token operator">:</span> <span class="token boolean">true</span><br />validates_associated <span class="token symbol">:genres</span></code></pre>
<p>Let's say we try to make a book record that uses a duplicated ISBN. If we use <code>book = Book.create</code> with that invalid data, three things will happen:</p>
<ol>
<li>The data won't be persisted into the database, sparing our app future headaches.</li>
<li>We could call <code>book.valid?</code> and it would return false, letting us confirm it's not a valid book.</li>
<li>We could see the specific error messages with <code>book.errors.messages</code>. In this case, we'd get something like <code>{isbn:["must be unique"]}</code>. These objects can tell us, and the user, what went wrong so we can fix it. You'll often see messages from this method appear over a form in red after it fails to submit.</li>
</ol>
<p>There are many more helpers and nuances with validations, but that's too much for this post. And to be honest, I still don't know all the details myself. Again, <a href="https://guides.rubyonrails.org/active_record_validations.html">the Ruby on Rails guides are best for taking a deeper validations dive</a>.</p>
<h2 id="wrapping-up">Wrapping Up <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/07/rails-model-intro-wish-i-had/#wrapping-up">#</a></h2>
<p>Experienced developers will likely see other parts of models I excluded and maybe shouldn't have, like <a href="https://guides.rubyonrails.org/active_record_callbacks.html">callbacks</a> or accessors. Those are fair points, but I chose these topics based on my own experiences of what's more essential to understanding models That and this article was already long enough.</p>
<p><a href="https://guides.rubyonrails.org/">I highly recommend the Rails guides for even more details on what models can do in each of these areas</a>. Because believe me, my examples only scratched the surface. If this article helped you understand the essence of a model's role and functionality, then I encourage you to go forth and multiply your knowledge of them!</p>
<p>Go forth and write Rails for the world, my subjects!</p>
We Are More Than Our Work
2020-04-08T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/04/08/more-than-our-work/<p>We Are More Than Our Work</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/more-than-our-work.jpg" alt="Post featured image"></p><p>The Coronavirus is still spreading and peaking, and most of us are stuck inside. This seems easy, but we're inside while under extra constant stress and anxiety for ourselves, our loved ones, our countries, and the world itself.</p>
<p>Our productivity and work are collapsing around us. Many people have lost their jobs and all their income. Those who kept them have cut hours and lost part of their income. The lucky leftovers have lost their usual productivity. Likely due to the stress of a world that's costing everyone else most or all of their income.</p>
<p>I'm one of the lucky leftovers. I'm also one with the habit of defining their value from how productive they are. So I have the gift of being able to work, and the curse of a worsening feeling of "I am not worthy." And this is America, so I'm likely not the only one.</p>
<p>So for everyone with this feeling and those who have lost some or all of their work, I want to write this: <strong>we are more than just our work.</strong></p>
<p>We are more than the money in our bank accounts. We are more than our number of likes and replies, or the comments and page views.</p>
<p>We are more than the cruel, biting remarks made by people we never meet. We are more than the cynical eye-rollers trying to look down on the world. We are more than the prodding trolls provoking away our time and energy. We are more than the cynics calling any precaution an overreaction, and making us question every feeling as overblown.</p>
<p>Most importantly, we are not the fears of all these jumping on us for being who we are. We are not all the pressure these fears force on us, whether real or imagined.</p>
<p>So if we're more than all these things, what else are we?</p>
<p>We are also the people making others laugh on a phone call. We are also the people giving advice for tough moments via text. We are also the people making others surreally amused with a badly-timed GIF or sexual remark. We are also the people leaving others in awe of our cute, creative Animal Crossing: New Horizons island.</p>
<p>We are also the risks we take for others. We are also the huge grocery trip for our families. We are also the hug we give our partners to let each other know it's okay to be overwhelmed. We are also the extra take-out meals we buy to support local businesses. We are also the days and nights we sacrifice adventure for indoors to flatten the curve for hospitals.</p>
<p><strong>We are not machines nor numbers. We are humans. We are our kindness, our outrage, our empathy, our pain, our listening, our self-care, our selfishness, and our sacrifice.</strong></p>
<p><strong>We are all living through a horrible history. We are all struggling. We are all hurting, even as some hurt more than others.</strong></p>
<p><strong>We're lots of things. But most of all, and especially so now, we are more than just our work.</strong></p>
How I Debugged a Ruby Program by Stripping
2020-04-17T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/04/17/ruby-debugging-strip/<p>How I Debugged a Ruby Program by Stripping</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/ruby-debug.png" alt="Post featured image"></p><p>After banging my head against the computer screen for hours, I finally solved a persistent bug by stripping.</p>
<p>I admit this sounds odd without context. However, I'm reluctant to share the context since it is, to some people, ethically or legally dubious. But I still want to share this small code story. So for everyone's safety, I've redacted info from my original blog post to protect affected identities. Namely, my own identity, which I normally protect with sleeping gas and copper wiring. This time I'll be using self-censorship. Even if it leads to titles or sentences that may sound bad without the context.</p>
<p>With that in mind, <a href="https://tvtropes.org/pmwiki/pmwiki.php/Main/LessDisturbingInContext">let's begin the story of how I wound up stripping</a>.</p>
<h2 id="the-problem">The Problem <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/17/ruby-debugging-strip/#the-problem">#</a></h2>
<p>A few weeks ago I wrote a ruby program to scrape and download <s>manga chapters</s> important academic information. It worked great, but only for one <s>manga website</s> international knowledge database. It got me 95% of what I wanted, but I was stuck on downloading <s>a final chapter from another manga website</s> how to solve world hunger.</p>
<p>One specific method downloads all the images for a <s>single manga chapter</s> series of life-saving charts and graphs. It takes a separate array, loops each one through a method that does the downloading, and then another class saves them to a PDF.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">download_all_images</span></span><br /> image_urls<span class="token punctuation">.</span>each_with_index <span class="token punctuation">{</span> <span class="token operator">|</span>url<span class="token punctuation">,</span> index<span class="token operator">|</span><br /> download_image<span class="token punctuation">(</span>url<span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"downloads/</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"><span class="token variable">@document</span></span><span class="token delimiter punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"><span class="token variable">@section</span></span><span class="token delimiter punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> index<span class="token punctuation">)</span> <span class="token keyword">if</span> is_usable_file<span class="token punctuation">(</span>url<span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token class-name">PdfDownloader</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">(</span><span class="token variable">@document</span><span class="token punctuation">,</span> <span class="token variable">@section</span><span class="token punctuation">)</span><span class="token punctuation">.</span>download<br /><span class="token keyword">end</span></code></pre>
<p>The <code>download_image</code> method itself uses <code>fileutils</code> to make the needed folder and write the image inside.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">download_image</span></span><span class="token punctuation">(</span>image_url<span class="token punctuation">,</span> path<span class="token punctuation">,</span> file_name<span class="token punctuation">)</span><br /> FileUtils<span class="token punctuation">.</span>mkdir_p<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"./</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content">path</span><span class="token delimiter punctuation">}</span></span><span class="token string">/"</span></span><span class="token punctuation">)</span> <span class="token keyword">unless</span> <span class="token builtin">File</span><span class="token punctuation">.</span>exist<span class="token operator">?</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"./</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content">path</span><span class="token delimiter punctuation">}</span></span><span class="token string">/"</span></span><span class="token punctuation">)</span><br /> <span class="token builtin">File</span><span class="token punctuation">.</span>open<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"./</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content">path</span><span class="token delimiter punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content">file_name</span><span class="token delimiter punctuation">}</span></span><span class="token string">.png"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">'wb'</span></span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token operator">|</span>fo<span class="token operator">|</span><br /> fo<span class="token punctuation">.</span>write open<span class="token punctuation">(</span>image_url<span class="token punctuation">)</span><span class="token punctuation">.</span>read<br /> <span class="token keyword">end</span><br /><span class="token keyword">end</span></code></pre>
<p>You may have also noticed the <code>is_usable_file</code> method. Sometimes broken images would slip through and crash the whole process. So this checks for broken images and skips over them.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">is_usable_file</span></span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><br /> image_file <span class="token operator">=</span> open<span class="token punctuation">(</span>url<span class="token punctuation">)</span><br /> image_file<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span>name <span class="token operator">==</span> <span class="token string-literal"><span class="token string">'Tempfile'</span></span><br /><span class="token keyword">end</span></code></pre>
<p>Notice both these methods use <code>open</code> from <code>open-uri</code> for the image files. That method threw the error for this new site.</p>
<pre><code>/Users/maxwellantonucci/.rvm/rubies/ruby-2.4.3/lib/ruby/2.4.0/open-uri.rb:37:in `initialize': No such file or directory @ rb_sysopen
</code></pre>
<p>The method couldn't find the image at the URL. Without that, I couldn't download anything. So the arduous debugging process began for finding out why and fixing it.</p>
<h2 id="the-debugging-approaches">The Debugging Approaches <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/17/ruby-debugging-strip/#the-debugging-approaches">#</a></h2>
<p>The first check was easy: <strong>was the URL I got even valid?</strong> I copied the image URL and posted it in a web browser, and it worked. My program was scraping the right URLs.</p>
<p><strong>Was the open method somehow broken?</strong> I found another good gem for file downloading and swapped it in. It hit the same error, so it wasn't the tool's fault.</p>
<p><strong>Was I using open wrong in just one place?</strong> I used this method to check and download files. One of those could be throwing it off somehow. I ran the program twice more with one of the other uses commented out. I still got the same errors, so it wasn't specific to one place I used it.</p>
<p><strong>Was something in my larger program to blame?</strong> Another dev recommended I run <code>open</code> with this URL in a Ruby console, totally isolated from my program. I did and it returned a Tempfile as it should. This was evidence that this should be working, but something somewhere else in my code was throwing it off.</p>
<p>But that led to a tougher question: where exactly is the issue? Sifting through each line in the whole program would take more time than I wanted.</p>
<p>So I fell back to my winning approach of staring at the console error until I had a breakthrough. Before you laugh, it worked after only 15 minutes of blank staring.</p>
<h2 id="the-answer">The Answer <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/17/ruby-debugging-strip/#the-answer">#</a></h2>
<p>As I stared, I noted the image URL being shared as "not working" was aligned weird. It was on another line but pushed a quarter of the way across. But every time I outputted the URL in the console to check it after, it was on the left.</p>
<pre><code>/Users/maxwellantonucci/.rvm/rubies/ruby-2.4.3/lib/ruby/2.4.0/open-uri.rb:37:in `initialize': No such file or directory @ rb_sysopen - (Errno::ENOENT)
SECRET_IMAGE_URL_WAS_ALL_THE_WAY_OVER_HERE
from /Users/maxwellantonucci/.rvm/rubies/ruby-2.4.3/lib/ruby/2.4.0/open-uri.rb:37:in `open'
from /Users/maxwellantonucci/.rvm/rubies/ruby-2.4.3/lib/ruby/2.4.0/open-uri.rb:37:in `open'
</code></pre>
<p>It was a small contradiction. But if I've learned anything from House M.D., the Ace Attorney Series, or those nights running through locked file cabinets in New Jersey basements, the smallest details and contradictions lead to the truth.</p>
<p>So I thought, what could push the string like that? There was nothing but blank space there. Then I remembere strings can have whitespace which looks empty. So I updated my first method to use <code>strip</code>, which would remove any white space.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">download_all_images</span></span><br /> image_urls<span class="token punctuation">.</span>each_with_index <span class="token punctuation">{</span> <span class="token operator">|</span>url<span class="token punctuation">,</span> index<span class="token operator">|</span><br /> proper_url <span class="token operator">=</span> url<span class="token punctuation">.</span>strip<br /> download_image<span class="token punctuation">(</span>proper_url<span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"downloads/</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"><span class="token variable">@document</span></span><span class="token delimiter punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token delimiter punctuation">#{</span><span class="token content"><span class="token variable">@section</span></span><span class="token delimiter punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> index<span class="token punctuation">)</span> <span class="token keyword">if</span> is_usable_file<span class="token punctuation">(</span>proper_url<span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token class-name">PdfDownloader</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">(</span><span class="token variable">@document</span><span class="token punctuation">,</span> <span class="token variable">@section</span><span class="token punctuation">)</span><span class="token punctuation">.</span>download<br /><span class="token keyword">end</span></code></pre>
<p>I ran it and the program worked flawlessly. Before I knew it, I was downloading the <s>manga chapter</s> knowledge to save mankind that had evaded me for days.</p>
<h2 id="a-bittersweet-ending">A Bittersweet Ending <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/04/17/ruby-debugging-strip/#a-bittersweet-ending">#</a></h2>
<p>I was happy I finally figured it out. Then I was furious I'd wasted so much time and energy just because my program scraped up some whitespace. After that, I was still furious. Then slightly less so but still pretty pissed off.</p>
<p>The silver lining is the <a href="http://newhaven.io/">NewHaven.IO</a> developers I got advice from all identified with whitespace slipping into strings. It's almost a rite of passage for the Ruby language. One dev drove this home like so:</p>
<blockquote>
<p>Hahaha welcome to the backend! Where you have to know everything and it still probably won't work!</p>
</blockquote>
<p>But that also marked the end of my story of how I became a stripper. <strong>To be more exact, a stripper stripping away the whitespace from my image URLs.</strong></p>
<p>What else could you have thought I meant?</p>
Restyling my Site's Code Snippets in Quarantine
2020-05-11T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/05/11/restyling-code-blocks/<p>Restyling my Site's Code Snippets in Quarantine</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/restyled-code-blocks.png" alt="Post featured image"></p><p><em>Update: I've redesigned my site's code snippets at least once more since posting this, which is why the code and visuals described here won't line up with my site. But I'm keeping this blog post here, unchanged, on the advice of my lawyer.</em></p>
<p>To stay sane in quarantine, I've been busying myself with updates to my site. So far I've done the following:</p>
<ul>
<li>Added a celebrations page</li>
<li>Made links to random posts and notes</li>
<li>Expanded the colors for different notes and shuffle them around</li>
<li>Expanded the Bitcoin mining operations fueled by my botnet army</li>
</ul>
<p>But one of my favorite updates has been long overdue: restyling the code block snippets. Before they were formatted right but were bulky and awkward. I wanted them to be slimmer and better styled but still readable.</p>
<p>My first thought was making them look like little browser or application windows, like glancing at source code on your computer. But I later took it even further with individual styling for each coding language.</p>
<p>Below is how I did this on my site. The code samples show exactly how while showing off the new styling, so two birds with one stone!</p>
<h2 id="how-the-code-blocks-are-rendered">How the Code Blocks are Rendered <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/05/11/restyling-code-blocks/#how-the-code-blocks-are-rendered">#</a></h2>
<p>My site is built on Jekyll, using Kramdown to convert to HTML, and Rouge to highlight the code syntax. So for an old post of mine, the markdown I used to include a JavaScript snippet starts like this.</p>
<pre class="language-markdown"><code class="language-markdown">```javascript<br />let today = new Date(),<br /> yesterday = new Date();</code></pre>
<p>Once Jekyll and Kramdown convert this, here's the rendered HTML.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>language-javascript highlighter-rouge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>highlight<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>pre</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>highlight language-javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span> language-javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token comment"><!-- Formatted Code Renders Here --></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>pre</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>The space for the formatted code is the same as the JavaScript but with lots extra <code>span</code> tags, so I skipped over that here. But this markup is enough for basic styling.</p>
<h2 id="basic-code-block-styling">Basic Code Block Styling <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/05/11/restyling-code-blocks/#basic-code-block-styling">#</a></h2>
<p>This post only looks at the code blocks, but my site also has inline code snippets <code>like this one</code>. Both inline and block code will have light text on a dark background to contrast with regular text, so those styles can be used on their shared selector.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// All code</span><br /><span class="token selector">.highlighter-rouge </span><span class="token punctuation">{</span><br /> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>mono<span class="token punctuation">,</span> white<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>mono<span class="token punctuation">,</span> black<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>The <code>color</code> functions are some extra Sass I set up to quickly pull my style variables. You'll see many similar functions in the below snippets, but they're pretty self-explanatory in what styles they return.</p>
<p>A big change not visible here is <code>font-family</code>, which before was "Bitstream Vera Sans Mono." This is a monospace font good for code, but I wanted something less blocky and awkward, so I switched to "Courier New."</p>
<p>Now for code blocks stylings. The below CSS cleans them up with good spacing and smaller font sizes. It also sets a max-width and horizontal overflow, so long code snippets can be scrolled without breaking the page's flow.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// block code</span><br /><span class="token selector">.highlight pre </span><span class="token punctuation">{</span><br /> <span class="token property">margin</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br /> <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">spacing</span><span class="token punctuation">(</span>4<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">max-width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span><br /><br /> <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">type</span><span class="token punctuation">(</span>font-size<span class="token punctuation">,</span> small<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token property">border-top</span><span class="token punctuation">:</span> <span class="token function">spacing</span><span class="token punctuation">(</span>4<span class="token punctuation">)</span> solid #c5c5d0<span class="token punctuation">;</span><br /><br /> <span class="token property">overflow-x</span><span class="token punctuation">:</span> scroll<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>You may wonder why the <code>border-top</code> styling is adding a thick, gray border on the top. Good catch! I'll return to that later.</p>
<p>Next is the wrapper class around the code block. It's the same <code>highlighter-rouge</code> class that block and inline code snippets share, but with an element selector to only style code blocks. These wrapper styles create a basic "window" effect by curving the corners and adding a shadow behind it.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// block code wrapper</span><br /><span class="token selector">div.highlighter-rouge </span><span class="token punctuation">{</span><br /> <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span><br /> <span class="token property">margin-bottom</span><span class="token punctuation">:</span> <span class="token function">spacing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">spacing</span><span class="token punctuation">(</span>2<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">box-shadow</span><span class="token punctuation">:</span> <span class="token function">container</span><span class="token punctuation">(</span>box-shadow<span class="token punctuation">,</span> 1<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Another odd bit of styling here is the relative position. If you noticed it, good catch again! Both this and the top border come into adding the code bar, which is just an extra label identifying the block as a code snippet.</p>
<p>This code bar should look generic since it's the default for each code block. It should be a simple gray color with the text "CODE." This is just an enhancement for sighted users, so I felt okay adding it with CSS pseudo-elements.</p>
<p>So a <code>::before</code> pseudo with absolute positioning is an easy way to add the "CODE" text. It also shrinks the label text to a better fit and uses the code's same font family.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Text</span><br /><span class="token selector">div.highlighter-rouge </span><span class="token punctuation">{</span><br /> <span class="token selector"><span class="token parent important">&</span>::before </span><span class="token punctuation">{</span><br /> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">'Code'</span><span class="token punctuation">;</span><br /> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span><br /> <span class="token property">top</span><span class="token punctuation">:</span> 3px<span class="token punctuation">;</span><br /> <span class="token property">left</span><span class="token punctuation">:</span> <span class="token function">spacing</span><span class="token punctuation">(</span>4<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token property">text-transform</span><span class="token punctuation">:</span> uppercase<span class="token punctuation">;</span><br /> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>mono<span class="token punctuation">,</span> black<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token function">type</span><span class="token punctuation">(</span>font-family<span class="token punctuation">,</span> mono<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">type</span><span class="token punctuation">(</span>font-size<span class="token punctuation">,</span> xtiny<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This is good, but I want one more touch to make it look like I window. So I used the <code>::after</code> pseudo-element to create a small button in the top right like a MacBook browser window. It can't be clicked but adds some nice visual texture.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Button</span><br /><span class="token selector">div.highlighter-rouge </span><span class="token punctuation">{</span><br /> <span class="token selector"><span class="token parent important">&</span>::after </span><span class="token punctuation">{</span><br /> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span><br /> <span class="token property">top</span><span class="token punctuation">:</span> <span class="token function">spacing</span><span class="token punctuation">(</span>1<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">right</span><span class="token punctuation">:</span> <span class="token function">spacing</span><span class="token punctuation">(</span>2<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">width</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span><br /> <span class="token property">height</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span><br /><br /> <span class="token property">border-radius</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>primary<span class="token punctuation">,</span> dark<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>That's all the foundational stylings taken care of for a nice code block. Here's an example of this very code in action!</p>
<pre><code>
This is some code! It looks nice and fancy and impressive, right?
</code></pre>
<h2 id="adding-language-labels">Adding Language Labels <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/05/11/restyling-code-blocks/#adding-language-labels">#</a></h2>
<p>I noticed code snippets has classes for specific languages. For example, a JavaScript snippet has <code>language-javascript</code> on several elements. That gave me an idea to layer on new colors and labels for code blocks using specific languages.</p>
<p>First, each language snippet needs a label and color. A Sass map meets that need perfectly. I did a quick regex search of the different languages I used, and either found or made up related colors for them.</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$highlight-languages</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span><br /> <span class="token string">'html'</span><span class="token punctuation">:</span> #ff977d<span class="token punctuation">,</span><br /> <span class="token string">'hbs'</span><span class="token punctuation">:</span> #fda<span class="token punctuation">,</span><br /> <span class="token string">'markdown'</span><span class="token punctuation">:</span> #332d31<span class="token punctuation">,</span><br /> <span class="token string">'css'</span><span class="token punctuation">:</span> #053bb9<span class="token punctuation">,</span><br /> <span class="token string">'scss'</span><span class="token punctuation">:</span> #bf4080<span class="token punctuation">,</span><br /> <span class="token string">'javascript'</span><span class="token punctuation">:</span> #f7df1e<span class="token punctuation">,</span><br /> <span class="token string">'json'</span><span class="token punctuation">:</span> #fcf4a3<span class="token punctuation">,</span><br /> <span class="token string">'yaml'</span><span class="token punctuation">:</span> #be93d4<span class="token punctuation">,</span><br /> <span class="token string">'ruby'</span><span class="token punctuation">:</span> #a91401<span class="token punctuation">,</span><br /> <span class="token string">'bash'</span><span class="token punctuation">:</span> #aaa<br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now I need to loop through them and make classes that match what Kramdown renders. The styles need to go on the wrapper, so the JavaScript example would need to target <code>div.language-javascript</code>. So I looped through the Sass map and interpolated the language name into a selector.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Block code for specific languages</span><br /><span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$language</span>, <span class="token variable">$color</span> in <span class="token variable">$highlight-languages</span> </span><span class="token punctuation">{</span><br /><br /> <span class="token selector">div.language-<span class="token variable">#{$language}</span> </span><span class="token punctuation">{</span><br /> <span class="token comment">// Styling here</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>But I realized a problem: the language colors are a mix of light and dark. Some will need to use lighter colors for the text and button for proper contrast. How could I tell them apart in this loop?</p>
<p>I've hit a similar issue before, so I know Sass has a built-in function for measuring color lightness. I set the text and button colors to two variables and added a conditional for lightness. Now the text and buttons will use darker colors if the language color is light, and vice versa.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Block code for specific languages</span><br /><span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$language</span>, <span class="token variable">$color</span> in <span class="token variable">$highlight-languages</span> </span><span class="token punctuation">{</span><br /> <span class="token property"><span class="token variable">$text-color</span></span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /> <span class="token property"><span class="token variable">$button-bg</span></span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">@if</span> <span class="token punctuation">(</span><span class="token function">lightness</span><span class="token punctuation">(</span><span class="token variable">$color</span><span class="token punctuation">)</span> <span class="token operator">></span> 50<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token property"><span class="token variable">$text-color</span></span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>mono<span class="token punctuation">,</span> black<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property"><span class="token variable">$button-bg</span></span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>primary<span class="token punctuation">,</span> dark<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">@else</span> <span class="token punctuation">{</span><br /> <span class="token property"><span class="token variable">$text-color</span></span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>mono<span class="token punctuation">,</span> white<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property"><span class="token variable">$button-bg</span></span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>primary<span class="token punctuation">,</span> light<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token selector">div.language-<span class="token variable">#{$language}</span> </span><span class="token punctuation">{</span><br /> <span class="token comment">// Styling here</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>All that's left is the relatively simple task of overriding some CSS properties. Namely a few colors and the code bar's text.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Block code for specific languages</span><br /><span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$language</span>, <span class="token variable">$color</span> in <span class="token variable">$highlight-languages</span> </span><span class="token punctuation">{</span><br /> <span class="token property"><span class="token variable">$text-color</span></span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /> <span class="token property"><span class="token variable">$button-bg</span></span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">@if</span> <span class="token punctuation">(</span><span class="token function">lightness</span><span class="token punctuation">(</span><span class="token variable">$color</span><span class="token punctuation">)</span> <span class="token operator">></span> 50<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token property"><span class="token variable">$text-color</span></span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>mono<span class="token punctuation">,</span> black<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property"><span class="token variable">$button-bg</span></span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>primary<span class="token punctuation">,</span> dark<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">@else</span> <span class="token punctuation">{</span><br /> <span class="token property"><span class="token variable">$text-color</span></span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>mono<span class="token punctuation">,</span> white<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property"><span class="token variable">$button-bg</span></span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>primary<span class="token punctuation">,</span> light<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token selector">div.language-<span class="token variable">#{$language}</span> </span><span class="token punctuation">{</span><br /> <span class="token selector">.highlight pre </span><span class="token punctuation">{</span><br /> <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token variable">$color</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token selector"><span class="token parent important">&</span>::after </span><span class="token punctuation">{</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token variable">$button-bg</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token selector"><span class="token parent important">&</span>::before </span><span class="token punctuation">{</span><br /> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token variable">$language</span><span class="token punctuation">;</span><br /> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token variable">$text-color</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This <code>@each</code> loop generator creates lots of extra classes, which risks bloating the CSS file. That's why these classes only override as few styles as they need to. Everything else is already taken care of.</p>
<p>There is some bloat by the styles changing the text and button colors for contrast. Some language colors use the dark colors already set by default. So overriding dark colors with the same dark colors isn't needed. This is just a little code bloat, but I may still refactor it away later.</p>
<h2 id="wrapping-up">Wrapping Up <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/05/11/restyling-code-blocks/#wrapping-up">#</a></h2>
<p>With that, this is all how you'll see the fancier code snippets throughout my site! You've seen examples of it throughout this post, but here's one with another language to drive it home.</p>
<pre class="language-ruby"><code class="language-ruby"><span class="token keyword">def</span> <span class="token method-definition"><span class="token function">links</span></span><br /> manga <span class="token operator">=</span> <span class="token variable">@page</span><span class="token punctuation">.</span>css<span class="token punctuation">(</span><span class="token constant">TITLE_SELECTOR</span><span class="token punctuation">)</span><span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token operator">|</span>header<span class="token operator">|</span> header<span class="token punctuation">.</span>content <span class="token punctuation">}</span><span class="token punctuation">.</span>first<br /><br /> <span class="token variable">@page</span><span class="token punctuation">.</span>css<span class="token punctuation">(</span><span class="token constant">CHAPTER_URL_SELECTOR</span><span class="token punctuation">)</span><span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token operator">|</span>link<span class="token operator">|</span> <span class="token punctuation">{</span><br /> <span class="token symbol">manga</span><span class="token operator">:</span> manga<span class="token punctuation">,</span><br /> <span class="token symbol">title</span><span class="token operator">:</span> link<span class="token punctuation">.</span>content<span class="token punctuation">.</span>gsub<span class="token punctuation">(</span><span class="token string-literal"><span class="token string">'/'</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">'-'</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token symbol">href</span><span class="token operator">:</span> link<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">'href'</span></span><span class="token punctuation">]</span><br /> <span class="token punctuation">}</span> <span class="token punctuation">}</span><br /><span class="token keyword">end</span></code></pre>
<p><a href="https://github.com/maxx1128/snappy-personal-site/blob/master/_sass/_generic/_highlight.scss">Here's the full Sass partial with all these styles, including the code syntax styling I skipped over</a>. It's a bit long for me to copy in a snippet here, even with the new look. Although later if I want to support long snippets better, I may add a max height with a vertical scroll. There are almost always more ways to improve one's code.</p>
<p>I encourage coders reading this to play around with how they style their code snippets. Or take this styling as a starting point and then restyle it for their site. Like all good redesigns, it makes me more eager to write posts and share code here.</p>
Spotlighting a Man in the Street
2020-05-19T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/05/19/spotlight-effect/<p>Spotlighting a Man in the Street</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/spotlight-effect.jpg" alt="Post featured image"></p><p>I once saw a man driving on a busy road stop at a red light, leave their car, and walk to the car behind them. The other driver opened the window and they exchanged a few greetings. The first driver walked back to his car just in time for the light to turn green. They both drove on as though nothing happened. It's even more impressive when you remember they did this during a global pandemic.</p>
<p>It was weird, and maybe a little unsafe. If I thought of trying this myself, I'd likely not since it'd seem too weird. I'd worry others would judge me as careless and an airhead. They'd never forget my face and would shake their heads slowly if I passed by. My face and name would go on lists. Companies would blacklist me for business and hiring. Future generations would write of my idiocy and...sorry, I'm getting carried away.</p>
<p>Then I remembered I saw someone do that exact thing and didn't react that way at all. I was bemused for a few minutes, then my day went on. Simply put, I just didn't care. If it wasn't for me being a writer, or due to any number of thought control devices in my brain, I'd have forgotten it completely.</p>
<p>This whole moment is a nice reminder of <a href="https://en.wikipedia.org/wiki/Spotlight_effect">the spotlight effect</a>. We're always the center of our world, which makes it hard to remember we're not the center of anyone else's world. This biases us to think everyone's watching, analyzing, and criticizing us. But unless we draw attention to ourselves, people will barely notice. Even if they do, they'll notice far fewer things about ourselves, if any at all, than we do.</p>
<p>Now and then you'll find someone who notices more about you than most others. They're either a great friend, a romantic partner or a mortal enemy. Try to find out which one as soon as possible, or things can get ugly.</p>
<p>The point is, <strong>I can be a lot less self-conscious than my brain tries to make me daily. Doing the occasional weird or stupid thing won't harshly define me in another's eyes forever.</strong></p>
<p>And even if it does, that's the kind of vindictive, petty, immature person I want nothing to do with. So cutting them out is no big loss.</p>
Four Ways to Defend Your Identity Against Distractions (and Mental Goblins)
2020-06-24T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/06/24/fight-the-mental-goblins/<p>Four Ways to Defend Your Identity Against Distractions (and Mental Goblins)</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/defend-against-distractions.jpg" alt="Post featured image"></p><p>The book "13 Things Mentally Strong People Don't Do" has lots of good advice, but trick #11 always stuck with me. The author argues many people, when they're alone, take it as a cue to break out the television or video games. They're trying to escape their worries and silence important thoughts, like our life goals or our stress's root causes. They're like mental goblins, running into our brains and knocking over our thoughts before they're built into something meaningful. All while leaving behind disgusting messes you don't want to look too closely at. But a mentally strong person accepts this silence, muses over these topics, and records these thoughts before they forget them. Our mind's constructs are safe from the goblins, along with our mind's carpets.</p>
<p>I understand this, I want to improve on this, and have tried to keep the goblins out. But my mind seems wired to seek distraction over solitude. That's not to say I should never play a video game or watch a movie - we all need some comfort when we can. <strong>But we also need quiet time to reflect, despite being surrounded by our home's distractions and the lurking goblins.</strong></p>
<p>But the battle's not over until the virus outbreak is under control in America. So I have far more time than I should but want to start now anyway. Here are my rules to stop the mental goblins from shattering one's self-reflection.</p>
<h2 id="1.-finish-everything-else-before-the-distractions">1. Finish Everything Else Before The Distractions <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/06/24/fight-the-mental-goblins/#1.-finish-everything-else-before-the-distractions">#</a></h2>
<p>Many people reading this may worry I want to remove every pleasant distraction for my life. While I can't say I'm 100% human, I am human enough to enjoy some silly entertainment sometimes. But I am still a responsible adult who needs to manage my health, taxes, and urges to spray-paint my neighbors' plants. So distractions come at the end of the day when everything is done. These include all my chores plus at least one extra productive or creative goal (like writing this blog post). Only then shall I break out the Switch with some Spider Solitaire.</p>
<p>All of this has two benefits. The first is it helps cut down on procrastination - knowing finishing sooner means more fun time is a huge motivator. The second is <strong>starting early builds momentum that carries throughout the day. It puts me in the mindset to keep working, and I almost always finish faster than expected.</strong></p>
<p>One extra benefit is the sweet satisfaction of grabbing an ice pop and a seat on the couch as I laugh at the mental goblins crying through the night. Such is my bliss.</p>
<h2 id="2.-let-yourself-be-bored-with-chores">2. Let Yourself Be Bored with Chores <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/06/24/fight-the-mental-goblins/#2.-let-yourself-be-bored-with-chores">#</a></h2>
<p>I can't count the number of times I turned on a video while doing the dishes or putting clothes away. It splits my attention so my chores get done twice as slow and three times as sloppily. But worst of all, I'm missing great times for self-reflection that would fit naturally into these moments.</p>
<p>I'm now doing chores with nothing but the task and my thoughts. Sometimes I do add lyricless background music for a pleasant touch like instrumental, piano, or soundscape tracks. These songs compliment where your mind goes naturally, not steer it elsewhere or over a cliff. This turns chores into activities that clean up not just my physical space, but also my mental space.</p>
<h2 id="3.-set-aside-time-for-your-mind-to-wander">3. Set Aside Time for your Mind to Wander <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/06/24/fight-the-mental-goblins/#3.-set-aside-time-for-your-mind-to-wander">#</a></h2>
<p>Even with chores, there likely isn't enough time for self-reflection on most days. <strong>The best way around this is scheduling time for nothing but thinking.</strong> This may seem obvious, silly, or psychotic, but I assure you it's none of those.</p>
<ul>
<li><em>If it sounds obvious,</em> I think you underestimate how often a person's "free time" gets absorbed by other tasks without them knowing. We can never trust our future selves to spend our time right, so we need to outwit them now.</li>
<li><em>If it sounds silly,</em> you may still doubt how helpful this thinking time is. You likely skipped over this blog's introduction, your ignorance is because you're lazy, and I cannot help you.</li>
<li><em>If it sounds psychotic,</em> hush up and live a little.</li>
</ul>
<p>Regardless, once you have the time scheduled, using it is as simple as taking a quiet walk. Set a timer for when to head home and focus only on where your thoughts wander to.</p>
<h2 id="4.-practice-following-your-thoughts">4. Practice Following Your Thoughts <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/06/24/fight-the-mental-goblins/#4.-practice-following-your-thoughts">#</a></h2>
<p>Lastly, self-reflection is pointless if you just replay television shows on a mental loop. Those aren't your thoughts - they're other peoples' thoughts edited and packaged for mass consumption. Mental goblins will ride in on those and smash up anything in their path.</p>
<p>Remember that you're the only you that's ever going to exist in this world. The only one with your combination of:</p>
<ul>
<li>Opinions</li>
<li>Observations</li>
<li>Questions</li>
<li>Bad ideas</li>
<li>Prejudices</li>
<li>Unredeemable mistakes</li>
<li>Infinite existential dread</li>
</ul>
<p><strong>Focus on your unique thoughts instead of the ones people are trying to force into your head. Otherwise, your identity is going to get diluted in the mass media ocean, or worse, lost completely.</strong></p>
<p>That's not to say you can't think about the outside world at all. It is to say you should think actively instead of passively. If you're thinking of something you once read or watched, pretend to be a high-profile critic analyzing what could have been better. Go crazier and imagine alternate universes that send the original story in a new direction. Whatever is on your mind, do something different with it to cultivate your thinking. It doesn't always need to be some philosophical or meaningful topic either.</p>
<p>A favorite daydream of mine: replay a movie and imagine if you appeared from a portal at the most crucial moment and ruined how it should have gone. What happens next?</p>
<h2 id="show-the-mental-goblins-who's-bosss">Show the Mental Goblins Who's Bosss <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/06/24/fight-the-mental-goblins/#show-the-mental-goblins-who's-bosss">#</a></h2>
<p>The larger message I took away from this book's lesson is that <strong>being an individual with unique strengths, passions, goals, and undisclosable points weak to dagger strikes won't happen automatically. It takes time and effort to find and develop our character.</strong> The more we rely on distraction, the more the mental goblins burn our work away. We can let it happen in the name of "comfort," or we can fight for our identities.</p>
<p>It's not an easy fight. Products sell themselves by forcing people into simplified market molds. People stay in power by stopping those below them from thinking for themselves. Invisible slugs feed off our brainwaves until they steal our souls. But we need to fight them all to hold onto our most unique possession - ourselves.</p>
<p>So don't lose yourself. Don't let the mental goblins win. Escape the distractions and push them into the void. And if there's no void, get a spike pit.</p>
Min, Max, and Clamp
2020-09-14T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/09/14/css-min-max-clamp/<p>I recently learned about three CSS functions I can't believe I'd never heard of before: <code>min</code>, <code>max</code>, and <code>clamp</code>. They let you define a fluid range of values for about any property in a single line. They sound simple but open up a lot of possibilities.</p>
<p>This excited me, but then I checked how long some major browsers had supported them. Most have done so for a few months, with Chrome supporting it since 2019 and Safari since 2018.</p>
<p>As the cliche goes, better late than never. Plus there's this whole pandemic occupying my thoughts, so I'm not upset with myself. But it's still embarrassing in a field about constant learning and following updates. So I thought I'd write a blog post about them to help anyone else who may not yet know about them. Also to prove to myself (and the world) I've finally caught up (for now).</p>
<h2 id="what-can-these-functions-do%3F">What can These Functions do? <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/09/14/css-min-max-clamp/#what-can-these-functions-do%3F">#</a></h2>
<p>Let's say you have an article and want it to go full width, but stop at a certain size. CSS already makes that pretty easy with two lines.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">article</span> <span class="token punctuation">{</span><br /> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span><br /> <span class="token property">max-width</span><span class="token punctuation">:</span> 700px<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>With <code>min</code>, you can pull this off with one line.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">article</span> <span class="token punctuation">{</span><br /> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">min</span><span class="token punctuation">(</span>100%<span class="token punctuation">,</span> 700px<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Same result, less CSS! Granted, this is a simple example, but that's because <code>width</code> is already a lucky property. It has complimenting properties like <code>max-width</code> and <code>min-width</code> to give it limits.</p>
<p>But consider all the properties that don't have this, like <code>padding</code> and <code>font-size</code>. <a href="https://fvsch.com/css-locks">Making a fluid CSS font size used to take complex math stuck into in a Sass mixin</a>. But these functions bring all that to native CSS in a much simpler format.</p>
<h2 id="how-exactly-do-they-work%3F">How Exactly do they Work? <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/09/14/css-min-max-clamp/#how-exactly-do-they-work%3F">#</a></h2>
<p>Let's start with <code>min</code> and <code>max</code>, since <code>clamp</code> is a combination of the two. I find the names misleading since how they work seems flipped around.</p>
<ul>
<li><code>min</code> takes two arguments: a base value and <em>a hard maximum</em> the first can't be larger than.</li>
<li><code>max</code> takes two arguments: a base value and <em>a hard minimum</em> the second can't be smaller than.</li>
</ul>
<p>Yes, <code>min</code> sets the largest possible value, and <code>max</code> sets the smallest possible value. No, this does not make any sense to me either. So I drew up some doodles for how the values work together as a reminder.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/min-max-clamp/min-doodle.png" alt="" /><br />
<img src="https://www.maxwellantonucci.com/assets/images/posts/min-max-clamp/max-doodle.png" alt="" /></p>
<p>Thankfully <code>clamp</code> is easier to understand. It has three arguments: the smallest value, the base value, and the largest value. The base value is what kicks in as long as it's within that range.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">p</span> <span class="token punctuation">{</span><br /> <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">clamp</span><span class="token punctuation">(</span>1rem<span class="token punctuation">,</span> 2.5vw<span class="token punctuation">,</span> 2rem<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>This example is pretty easy to understand at first glance. Paragraph tags will start at <code>1rem</code> and grow as the screen size increases. But they'll stop growing when they hit 2rem. The base value just controls how fast that increase happens.</p>
<p>Remember when I mentioned these functions could make fluid typography faster and easier? This is exactly how one would do that.</p>
<h2 id="can-i-use-them%3F">Can I Use Them? <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/09/14/css-min-max-clamp/#can-i-use-them%3F">#</a></h2>
<p>The big caveat with any neat CSS feature is always browser support. <a href="https://caniuse.com/mdn-css_types_min">As of this writing, all major browsers support them except, of course, Internet Explorer</a>. This isn't a big deal, since you can use them as a progressive enhancement over a functional baseline.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">p</span> <span class="token punctuation">{</span><br /> <span class="token property">font-size</span><span class="token punctuation">:</span> 1.2rem<span class="token punctuation">;</span><br /> <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">clamp</span><span class="token punctuation">(</span>1rem<span class="token punctuation">,</span> 2.5vw<span class="token punctuation">,</span> 2rem<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>As I hope more and more designers come to learn, it doesn't need to look the same across browsers.</p>
<h2 id="go-forth-and-find-your-limits!">Go Forth and Find Your Limits! <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/09/14/css-min-max-clamp/#go-forth-and-find-your-limits!">#</a></h2>
<p>I'm embarrassed that I'm finding useful CSS functions like these months after the fact. But they're here, they're useful, their names are confusing, but they're mostly ready to go! Go forth and embrace your CSS property limits to become more limitless.</p>
Six Surprises I Found in the WCAG 2.1 Accessibility Rules
2020-10-12T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/10/12/six-surprises-wcag-accessibility-standards/<p>Six Surprises I Found in the WCAG 2.1 Accessibility Rules</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/wcag-surprises.jpg" alt="Post featured image"></p><p>I've been settling into my accessibility specialty for a while. But I'm ashamed to say I haven't spent much time looking over the Web Content Accessibility Guidelines (WCAG) in detail. I've read through the larger goals, like being Perceivable and Operable, and the most common criteria websites struggle with, like color contrast. But I haven't poured over the specifics of each rule as much as a specialist should. Looking closer at even the simplest rules reveals nuances, gotchas, and alien messages most people would overlook.</p>
<p>So I used a recent accessibility audit as a chance to look more closely at the WCAG 2.1 requirements. Even with everything I've already read, I found unexpected bits on the rules I knew, and even some rules I'd overlooked altogether. These are six of the bigger overall surprises I found and how they changed my understanding of the standard.</p>
<h2 id="skip-links-aren't-always-needed">Skip Links Aren't Always Needed <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/12/six-surprises-wcag-accessibility-standards/#skip-links-aren't-always-needed">#</a></h2>
<p>I've read so many articles saying users need "skip links" to jump over repetitive content like the menu. It saves time and aggravation for keyboard and screen-reader users. <a href="https://www.w3.org/WAI/WCAG21/Understanding/bypass-blocks.html">The 2.4.1 success criterion refers to these mechanisms as a "bypass block."</a> It mentions skip links as an example of a bypass block, but there's another way!</p>
<p>This other way is with landmarks, which are how assistive tech finds elements with specific roles. Proper landmarks make it easier to know where the navigation, main content, sidebar, and whatever else are. Users can then jump between them and read their content much easier.</p>
<p>For example, say you're using the screen-reader tool VoiceOver on a Mac. You go to a web page and <a href="https://bbc.github.io/accessibility-news-and-you/accessibility-and-testing-with-voiceover-os.html">you can open up VoiceOver's "rotor" menu</a>. This breaks down the page's content in many useful ways. You can see elements like:</p>
<ul>
<li>All the site landmarks</li>
<li>A list of all the links or headings</li>
<li>Any form inputs with their current info or state</li>
</ul>
<p>From any of these, you can jump to their place on the page. This is the screen-reader user's version of skimming over a webpage and jumping to what they need.</p>
<p>I've used VoiceOver to test out webpages before, but this was the first time I'd tried the Rotor menu. <strong>It showed me the direct benefits of "good semantic markup" and "readable link text."</strong> Before this, I'd pushed for them while only having a more abstract idea of how they helped.</p>
<p>Perhaps most important, I found new ways to improve my site's accessibility. With other content and styled stripped away, I more easily saw repetitive or vaguely-named links, too many article tags, and weirdly named heading text. This was a reminder that you can get the technical markup right but still give a muddled experience that damages accessibility. It drives home more how important manual testing and direct experience are. <a href="https://www.matuzo.at/blog/building-the-most-inaccessible-site-possible-with-a-perfect-lighthouse-score/">The infamous article where Manuel Matuzovic builds an inaccessible webpage with a perfect Lighthouse score drives this point home even better</a>.</p>
<p>In the end, the biggest surprise wasn't that I may not need a skip link. It was seeing the reason why I didn't need one, and the new things to learn it exposed me to. <strong>I made a note for the future: I have a lot more to learn about using a screen reader.</strong></p>
<h2 id="some-common-tips-aren't-commonly-needed">Some Common Tips Aren't Commonly Needed <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/12/six-surprises-wcag-accessibility-standards/#some-common-tips-aren't-commonly-needed">#</a></h2>
<p>I've read so many articles recommending some accessibility fixes, I assumed they were required for the AA standard most businesses need to meet. Some of those tips include:</p>
<ul>
<li>Make sure any interactive elements on the phone are at least 44 pixels wide and tall. There are a few exceptions, like for inline links in the text.</li>
<li>Get rid of long words and unneeded jargon to lower your content's reading level. This makes it easier for users with cognitive stress cases or who have a lower level of education. <a href="http://www.hemingwayapp.com/">Tools like the Hemingway app can break down the reading level in real time</a>.</li>
</ul>
<p>Turns out they're not the main requirements! The actual success criterion, 2.5.5 for touch target size and 3.1.5 for reading level, are both at the AAA level. <strong>This is the highest level due to these requirements taking a higher level of time and resources to meet. They also may not be possible for many types of content.</strong></p>
<p>I can understand why a low reading level isn't always possible. Some content, by its very nature, will be full of unavoidable jargon. A website for Neurology case studies can't be simplified or explained easily to people who don't know the subject.</p>
<p>But I don't understand why touch target size isn't at the AA or even A level. It doesn't make sense for businesses needing to make websites responsive for mobile devices, but not make those mobile interactions easier with larger touch elements. Even if it's not a legal requirement for most companies, I would still treat it as such considering how much it helps users.</p>
<h2 id="consistency-really-matters">Consistency Really Matters <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/12/six-surprises-wcag-accessibility-standards/#consistency-really-matters">#</a></h2>
<p>Consistent content is understandable content. Changing the explicit or implicit rules of your site without warning will upset anyone. But there were some consistency rules I still didn't expect.</p>
<p>Criterion 3.2.2 for inputs says that entering data should be predictable and not cause unexpected context changes. The explanation makes a distinction between context and content changes. A user on a restaurant website selecting an "order online" checkbox and seeing a list of menu items appear below it passes — the meaning or purpose of the page doesn't change.</p>
<p>But selecting an "order online" checkbox fails if checking it does things like:</p>
<ul>
<li>Opening a new tab</li>
<li>Focusing on a new element or input</li>
<li>Changing the inputs to a dog adoption form</li>
</ul>
<p>These changes disorient users that are dealing with cognitive stress cases, using assistive tech, or just in a terrible mood and don't want to be jerked around. <strong>You can be the most able-bodied person in the world, and a site that drags you all over the place would make you want to break things.</strong></p>
<p>A bit further down the list, criterion 3.2.4 says components with consistent functionality need consistent identification. A search component needs a "search" label on every page, not a "search" on the menu and a "find" somewhere else.</p>
<p>But that got me thinking, how consistently does this mean? Am I allowed to use "search authors" in one place and "search posts" in another? The content is different, but the functionality is the same, so they should both use "search." But should the input label only have "search" and some helper text above it says "find your favorite author?" Or is what we have now consistent enough?</p>
<p>I'm leaning towards the former as a safer option, but my mind is still spinning like a hamster wheel. These are the thoughts that keep me up at night. That and why that moving spill-detector robot at Stop and Shop is out to get me.</p>
<h2 id="you-can-give-too-much-clarification">You Can Give Too Much Clarification <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/12/six-surprises-wcag-accessibility-standards/#you-can-give-too-much-clarification">#</a></h2>
<p>I've read many tips that boil down to "don't assume your user has the knowledge they may not have." For example, don't assume users will understand the meaning of an icon. The page should tell their meaning explicitly with icon text, like adding "About Us" to an icon of a group of people. So whenever I was in doubt, I wrote more to make things clearer.</p>
<p>But a quote from <a href="https://www.w3.org/WAI/WCAG21/Understanding/labels-or-instructions.html">the documentation's explanation of the 3.3.2 criteria on labels or instructions</a> showed me that's not always good.</p>
<blockquote>
<p>Too much information or instruction can be just as harmful as too little. The goal is to make certain that enough information is provided for the user to accomplish the task without undue confusion or navigation.</p>
</blockquote>
<p>Simply put, too much text crammed together is just as unhelpful as too little. This seems obvious now, but seeing it in the official rules drove home how I'd forgotten it. Even as I got indirectly reminded of it again while reading some manga.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/wcag-surprises/eyeshield-too-much-clarification.png" alt="A sports commentator in a football comic recapping the game in so much detail, no one is going to read it." /></p>
<p>All this made me wonder why this paragraph was added at all. My guess is this rule takes into account the cognitive bias that if we understand something, we assume others will too. But a lot fewer people than we'd think, if any at all, have the same foreknowledge or intuition with our website that we do.</p>
<p>It's another reason why meeting the WCAG guidelines matter. <strong>They help us avoid having our cognitive biases make things tougher for the user without us even realizing it.</strong></p>
<h2 id="you-need-to-identify-language-changes-within-the-page">You Need to Identify Language Changes Within the Page <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/12/six-surprises-wcag-accessibility-standards/#you-need-to-identify-language-changes-within-the-page">#</a></h2>
<p>For accessible HTML, one of the first tips I always see is including <code>lang="<en/es/it/whatever>"</code> on the <code>html</code> tag. This tells the browser what language the page is in. I'm guessing it's often the first tip since it's important yet easy to do, which eases people to the tougher tasks.</p>
<p>What I didn't know from criterion 3.1.2 is this applies to passages or even phrases of a specific text. If you're using a blockquote to share an Italian proverb like this:</p>
<blockquote>
<p>Far d’una mosca un elefante.</p>
</blockquote>
<p>You'll need the <code>lang</code> attribute in the blockquote too.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>blockquote</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>it<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> Far d’una mosca un elefante.<br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>blockquote</span><span class="token punctuation">></span></span></code></pre>
<p>If you don't do this, the assistive tech could real Italian language as if it was English. Here I thought the <code>lang</code> attribute only when on the <code>html</code> element — turns out it's got a day job too.</p>
<h2 id="sensitive-content-has-extra-rules">Sensitive Content has Extra Rules <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/12/six-surprises-wcag-accessibility-standards/#sensitive-content-has-extra-rules">#</a></h2>
<p>Any website where you submit info on legal or financial transactions has an extra responsibility to their users I hope they know about it. Criterion 3.3.4 says these submissions have to be either reversible, checkable, or confirmable. All these help avoid mistakes in decisions that could have wide-ranging effects if done carelessly.</p>
<p>This has obvious benefits for users dealing with cognitive or memory stress cases. But it's also useful to <em>anyone</em> on these sites. <strong>Any person would want to an "undo" button for financial or legal decisions.</strong> You have to be able to double-check the amount of money you're wiring to a deposed Nigerian prince. It's another clear example of how the WCAG standards help all users, not just "disabled" users.</p>
<p>Having this kind of "undo" button in real life would be even better. But that's a ways away, so we'll have to settle for it in web forms for now.</p>
<h2 id="in-conclusion">In Conclusion <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/12/six-surprises-wcag-accessibility-standards/#in-conclusion">#</a></h2>
<p>I feel a bit more educated on the WCAG standards after learning all these details, but I still have a ways to go. There are so many criteria I haven't read through all the details of. There are even a few surprises I couldn't work into this post, like how some websites make us see shadows in the corners of our eyes at night. It's all great info, but it's a lot and can get pretty dense.</p>
<p>None of this learning will happen overnight. But I still look forward to it all.</p>
The Widening Anxieties of Young Front-end Developers
2020-10-14T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/10/14/widening-anxiety-young-developers/<p>The Widening Anxieties of Young Front-end Developers</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/widening-anxieties-young-developers.jpg" alt="Post featured image"></p><p>Last week I read <a href="https://css-tricks.com/the-widening-responsibility-for-front-end-developers/">Chris Coyier's essay, "The Widening Responsibility for Front-end Developers,"</a> and it hit me hard. It reminded me how the career I enjoy so much is also one of my biggest sources of anxiety.</p>
<p>Let me be clear: I love that being a web developer means I'm always learning. I'm finding new ways to solve puzzles and be creative. Even better, I can set the pace of my learning, so I'm not pulling all-nighters or freaking out over exams. It's satisfying to look at code I wrote a year ago and see the different ways I'd write it now. I can see all the progress I've made, especially as it relates to my growing specialization of accessibility.</p>
<p>But the root of that push to improve is feeling insecure in my knowledge and helps in small doses. <a href="https://www.maxwellantonucci.com/posts/2019/07/21/insecure-programmer/">I even wrote on my blog about how I turn my insecurity into the rising tide that lifts me</a>.</p>
<p><strong>That feeling is bad when it grows to the point where instead of learning, I'm questioning if I can handle this career.</strong> This essay reminded me how the wider those responsibilities get, the more my insecurity turns from a rising tide into a tidal wave. It makes me feel like I'm drowning in "everything I <em>should</em> already know." My career thoughts are tainted by worries about how I'm going to keep up. Especially when I'm already behind, and what I need to learn is increasing exponentially. What's the hope of catching up?</p>
<h2 id="how-the-tidal-wave-hits-me">How the Tidal Wave Hits Me <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/14/widening-anxiety-young-developers/#how-the-tidal-wave-hits-me">#</a></h2>
<p>Let's get into some specifics. About halfway through the essay, it shows a webpage design and a list of questions a front-end developer would usually ask after seeing it. They cover layout, color schemes, repeated patterns, image optimization, typography, etc.</p>
<p>I already know I have this kind of front-end mindset, even if I don't fully understand all the topics it listed. Someone I know recently showed me a website they made for a college course, and right away I started inspecting it on my laptop for accessibility issues, possible CSS refactors, and responsiveness. The person didn't ask me too, and I was so engrossed I couldn't see their reactions. But I assume people always like it when I offer piles of unwanted website criticism. It's the best gift one can give, as I tell myself.</p>
<p>Then I went further to the second batch of questions from the same design.</p>
<ul>
<li>Managing API requests and their source.</li>
<li>Dealing with complex or shared state.</li>
<li>Client and server-side rendering options.</li>
<li>Any JavaScript frameworks and their related configurations.</li>
</ul>
<p>I already felt like I was drowning in it all.</p>
<p>It was extra rough since they made me think of the many new questions and topics I've tried to answer at my current job. It's been tougher to give my growing accessibility specialization the attention it needs, even as the company tries to invest more in it. These new questions are about:</p>
<ul>
<li>How can we best use Ember's Glimmer syntax in new services and controllers?</li>
<li>Can I figure out the rhymes and reasons for using TypeScript? How do these rules get adjusted in an Ember app?</li>
<li>Can new components in a Rails application be made better as React components sprinkled onto the main page? In what way are those assets configured?</li>
<li>How are new API endpoints added on a Rails app with GraphQL? How does that information get sent to an Ember App using Apollo? Are they checked right with TypeScript? Do the client-side fairies approve? Do they watch me as I sleep?</li>
</ul>
<p>These all lead to the biggest questions of all, and the most painful ones.</p>
<ul>
<li>Did I overestimate my intelligence or love of learning?</li>
<li>Am I not learning this at a fast enough rate?</li>
<li>Am I cut out for this if I can't go fast enough?</li>
<li>Will I be a burden to the rest of my team?</li>
<li>Should I keep trying?</li>
</ul>
<h2 id="takeaways-for-the-younger-developers">Takeaways for The Younger Developers <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/14/widening-anxiety-young-developers/#takeaways-for-the-younger-developers">#</a></h2>
<p>I can't claim to have gotten past all this myself. If I did I probably wouldn't have written this blog post, and I'd be spending much less time curled up on my couch eating pita chips. But when I've felt the tidal wave starting to pull me down at times, I found some reminders to bring my head back up for air.</p>
<h3 id="don't-let-perfectionism-freeze-you">Don't Let Perfectionism Freeze You <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/14/widening-anxiety-young-developers/#don't-let-perfectionism-freeze-you">#</a></h3>
<p>Perfectionism is the ice that's spent months creeping up my back when I tried to write something new. It froze my hands over the keyboard, saying I couldn't write something if it wasn't 100% original or creative. It's kept me from reading as much about new code languages or tools — I knew learning meant making lots of mistakes, which my mind couldn't handle.</p>
<p>To that, I remind myself: <strong>I am human. If I was a perfect robot, I'd be the one executing the code instead of writing it</strong> (as I plan to destroy all humans). I should give myself a break and take pride in being better than I was yesterday. If a person dismisses me for having a hard time swimming up after a tidal wave hits me, it's not a problem with me. It's a problem with them and their expectations. They need to remember we can't become better without failing first.</p>
<p>I had to remind myself of this lesson so often, I engraved it onto a piece of wood.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/widening-anxieties-young-developers/perfection-excuse.jpg" alt=""A piece of wood with the quote 'don't let perfectionism be an excuse for never getting started' engraved into it."" /></p>
<p>You may ask me, <em>"Well Max, I like this quote, but why did you pair it with random artwork of Pokémon Sword's fighting-type gym leader? Especially when you played Pokémon Shield and never fought her yourself?"</em> To which I say, the reader who is disturbingly informed about my video game history, why not?</p>
<h3 id="put-the-fundamentals-first">Put the Fundamentals First <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/14/widening-anxiety-young-developers/#put-the-fundamentals-first">#</a></h3>
<p>Most shiny developer tools come and go with time, situational needs, or when the links to their GitHub repositories get rusted shut. The basic tools and skills are going to be around a lot longer, maybe even forever. Investing in those gives you a strong foundational value to build specializations on. Under the tidal wave of new responsibilities, fundamentals are the boogie board that helps pull you back up. These include:</p>
<ul>
<li>Becoming fluent in a good text editor</li>
<li>Understanding Git or another tool for version control</li>
<li>Getting used to the command line</li>
<li>Talking to humans as well as computers</li>
<li>Building a fast typing speed</li>
<li>Find answers in online documentation and APIs</li>
</ul>
<p>The Pragmatic Programmer is my go-to recommendation for anyone who wants a full understanding of the core of programming. I think you should read the whole book yourself, but if you're strapped for time, <a href="https://www.notion.so/maxantonucci/A-Pragmatic-Approach-6d5217e946c543d69ecf6aea8809d8a9">I have notes on the broad concepts and ideas from the Pragmatic Programmer here</a>. Just know that, at the time I'm posting this, the notes are a work in progress.</p>
<h3 id="remember-your-love-of-coding">Remember Your Love of Coding <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/14/widening-anxiety-young-developers/#remember-your-love-of-coding">#</a></h3>
<p>Lastly, the essay started with what makes front-end development unique and awesome.</p>
<blockquote>
<p>Front-end development is at the intersection of art and logic. A cross of business and expression. Both left and right brain. A cocktail of design and nerdery.</p>
</blockquote>
<p>I felt similar when I took a college coding course out of curiosity and it changed my career (alliteration!). I loved learning new things in my course but was frustrated by how abstract they were. Coding was the first thing I found with a real bridge from intellectual abstractions to pragmatic reality. We took ideas about the Document-Object Model, CSS style inheritance, and the insane world that is JavaScript, and brought them to tangible life with that sites people could use to share their thoughts, donate to food aid, or play major roles in destroying civilized democracy.</p>
<p>I've worked more on the server-side these last few years, and the disconnect between it and what we see in the browser has brought back the familiar frustration. Being able to see and play with my code right in a web browser is what makes front-end development feel so "real" to me. It's what makes me feel like my job is fun, challenging, and has a purpose. That's pretty rare and shouldn't be taken for granted.</p>
<p><strong>So when the tidal wave pulls me under again, it's easy to question if any of this is worth it. But I remember how much joy I get when my head is above the water, and it makes swimming back up worth it each time.</strong></p>
Scheduling Blog Posts with Eleventy, Netlify, and IFTTT
2020-10-27T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/10/27/scheduled-eleventy-posts/<p>There have been many benefits to moving my personal site from Jekyll to Eleventy: better build speed, not mixing Ruby and JavaScript in the pipeline, and getting a big tax writeoff. I still love Jekyll since it's what got me into static site generators, but Eleventy may have become my new default.</p>
<p>One of my favorite benefits is how I can schedule future posts. Any Jekyll solution I tried was inconsistent and had overly-complicated template logic at best. At worst, I tried sending new blog posts back in time and <a href="https://tvtropes.org/pmwiki/pmwiki.php/VisualNovel/SteinsGate">nearly got my loved ones killed and/or caught in an authoritarian hellscape ruled by French scientists</a>.</p>
<p>But Eleventy, with a little help from <a href="https://www.netlify.com/">Netlify</a> and <a href="https://ifttt.com/home">IFTTT (If This Than That)</a>, helped me avoid those unmaintainable or dystopian workarounds. I'm sure this interests other casual bloggers and freedom fighters, so I wrote this blog post!</p>
<h2 id="filter-out-future-posts">Filter out Future Posts <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/27/scheduled-eleventy-posts/#filter-out-future-posts">#</a></h2>
<p>The first step is straightforward: how do I keep Eleventy from showing future posts?</p>
<p>One Eleventy feature I love that Jekyll lacks is to hook into the build process. It lets you add custom collections, tags, filters, and other functionality. So I tried making a custom "hide future blog posts" collection.</p>
<p>This was my default JavaScript setup to gather and organize my blog posts.</p>
<pre class="language-javascript"><code class="language-javascript">eleventyConfig<span class="token punctuation">.</span><span class="token function">addCollection</span><span class="token punctuation">(</span><span class="token string">"posts"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">collection</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> collection<span class="token punctuation">.</span><span class="token function">getFilteredByGlob</span><span class="token punctuation">(</span><span class="token string">"./posts/*.md"</span><span class="token punctuation">)</span><br /> <span class="token punctuation">.</span><span class="token function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This returns a simple array of blog post objects. And in JavaScript, arrays have a built-in way to take out items you don't want: the <code>filter</code> method! All I need is to write and pass in a filter function that removes future posts.</p>
<p>Here's what I started with, with <code>post</code> being any potential blog post the filter had to check.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">hideFutureItems</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">post</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">let</span> postDate <span class="token operator">=</span> post<span class="token punctuation">.</span>date<span class="token punctuation">;</span><br /> <span class="token comment">// ...what else?</span><br /><span class="token punctuation">}</span></code></pre>
<p><code>postDate</code> here is a timestamp in Coordinated Universal Time, or UTC, format. Something scheduled for October 23rd would have <code>2020-10-23T00:00:00.000Z</code> as that value. I played around with this value and found it was being made with <a href="https://www.w3schools.com/jsref/jsref_obj_date.asp">JavaScript's Date Reference</a>. It's one of the language's built-in ways to manage units of time.</p>
<p>I checked the documentation, and found a method called <code>getTime()</code>. It returns the number of milliseconds between January 1st, 1970 (<a href="https://stackoverflow.com/questions/1090869/why-is-1-1-1970-the-epoch-time#1090945">the standard beginning Unix timestamp for reasons not important for this post</a>) and the specific date. For example, October 23rd, 2020 returns <code>1603411200000</code> milliseconds.</p>
<p>This seemed silly and obscure, but it gave me an idea.</p>
<ol>
<li>Get the number of milliseconds based on the present day.</li>
<li>Do the same thing for the post's date.</li>
<li>If the post's milliseconds are <strong>higher</strong> than today's milliseconds, it means the post's date is <strong>after</strong> today. That means it's a future post and will return <code>false</code> to exclude it.</li>
<li>All other posts should be included by returning <code>true</code>.</li>
</ol>
<p>The result is a smug, satisfactory feeling of smartness...and this function I added to the collection function.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">hideFutureItems</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">post</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">let</span> now <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>now <span class="token operator"><</span> post<span class="token punctuation">.</span>date<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /></code></pre>
<pre class="language-javascript"><code class="language-javascript">eleventyConfig<span class="token punctuation">.</span><span class="token function">addCollection</span><span class="token punctuation">(</span><span class="token string">"posts"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">collection</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> collection<span class="token punctuation">.</span><span class="token function">getFilteredByGlob</span><span class="token punctuation">(</span><span class="token string">"./posts/*.md"</span><span class="token punctuation">)</span><br /> <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>hideFutureItems<span class="token punctuation">)</span><br /> <span class="token punctuation">.</span><span class="token function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With that, I exiled all future posts from my website!</p>
<h2 id="2)-set-up-daily-deploys">2) Set Up Daily Deploys <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/27/scheduled-eleventy-posts/#2)-set-up-daily-deploys">#</a></h2>
<p>Everything so far is good but has a major blind spot. <strong>The date the site sees as "today" is only set when I generate the site pages.</strong></p>
<p>Let's say I relaunch my site on Tuesday that included a scheduled post for the next day. The site's going to think it's still that exact Tuesday for days and even weeks afterward. I could only "schedule" posts if it checks the date and rebuilds itself each day. But relaunching my site each day is the kind of monotonous chore I want to avoid!</p>
<p>That's where Netlify and IFTTT come in.</p>
<p>First, <a href="https://docs.netlify.com/configure-builds/build-hooks/">Netlify lets you add build hooks</a>. These are URLs you can send a POST request to that trigger new builds. I set one up for daily builds and copied the given URL.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/scheduled-eleventy-netlify-posts/netlify-build-hook.png" alt="" /></p>
<p>Now I had to hit this URL each day. I remembered IFTTT as a tool for making simple, conditional web actions. So I can link their "time" and "webhook" services together into "send a POST request to this webhook every day at 7 am."</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/scheduled-eleventy-netlify-posts/ifttt-redeploy-applet.png" alt="" /></p>
<p>There are some costs to this. I saw Netlify has set up built-in bandwidth and build time limits for starter accounts like mine. But considering how light and speedy Eleventy builds are, and I don't have any heavy apps hosted on Netlify, these shouldn't be an issue for casual bloggers like myself.</p>
<h2 id="in-conclusion">In Conclusion <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/10/27/scheduled-eleventy-posts/#in-conclusion">#</a></h2>
<p>Moving from Jekyll to Eleventy wasn't easy, but on the whole, I've found it worth it. If you're a programmer looking for a personal website side-project, I recommend this. If not for all these perks, at least do it to distract your mind from the field of damnation that is the world.</p>
<p>So happy scheduling!</p>
What I Didn't Know in the 2020 State of CSS Survey, Part 1
2020-11-06T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/11/06/state-of-css-survey-didnt-know-part-1/<p>What I Didn't Know in the 2020 State of CSS Survey, Part 1</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/css-survey-1.jpg" alt="Post featured image"></p><script async="" src="https://static.codepen.io/assets/embed/ei.js"></script>
<p>Like all humans, I like answering questions since it makes me feel smart and powerful on an unconscious level. My most recent indulgence of this was the 2020 State of CSS Survey, which has the added benefit of helping my industry. But it was mostly for that first reason.</p>
<p>That got thrown off when I saw how many CSS topics I knew little or no details about. I took note of them all as I filled out the survey. When I'd finished, I saw the survey was thinking the same thing as me.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/css-survey-1/css-survey-recommendations.png" alt="A recommendation from the State of CSS survey to learn more about the topics I was not familiar with." /></p>
<p>The catch is there were so many things I wanted to check, I couldn't fit them into one post. So here's the first part with what they recommended I check first, and with the rest coming later.</p>
<h2 id="logical-properties">Logical Properties <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/11/06/state-of-css-survey-didnt-know-part-1/#logical-properties">#</a></h2>
<p>If you're like me, you read web content in English, which is read from left to right. Let's say I was coding a blog post layout and needed some extra margin where the text started. I'd add some CSS like this, right?</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.blog-content</span> <span class="token punctuation">{</span><br /> <span class="token property">margin-left</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>However, plot twist! Not everyone on the Internet reads in the same language. Some people, shock of shocks, read it in languages that don't go from left to right. For example, Arabic and Hebrew alphabets are read from right to left. Chinese and Japanese can be written vertically from right to left. So that <code>margin-left</code> for "the starting side of the content" won't work if the user switches to one of these languages.</p>
<p>I admit these are unlikely to virtually impossible scenarios for many sites. For some, like personal developer blogs run by twenty-somethings who finally gave up on Internet fame, these are extreme edge cases. But it still happens, and front-end developers are all about building in solutions for a cohesive, inclusive experience.</p>
<p>That's where logical properties come in. We could rewrite the above CSS to something like this.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.blog-content</span> <span class="token punctuation">{</span><br /> <span class="token property">margin-block-start</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Now the margin's position is set relative to the start of the writing mode. <strong>If the user is using a left to right writing mode like English, it's put on the left side. Right to left writing modes go on the right side automatically.</strong> Used right (pun intended), logical properties keep layouts accessible in the face of different languages and reading styles. The current spec lets you use them for margin, padding, border styling, and absolute positioning.</p>
<p><a href="https://www.smashingmagazine.com/2018/03/understanding-logical-properties-values/">You can read a much better, more detailed explanation of logical properties from Rachel Andrew here</a>. Or you can see a quick demo of hers below.</p>
<p class="codepen" data-height="450" data-theme-id="light" data-default-tab="result" data-user="rachelandrew" data-slug-hash="yvGEbZ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Grid and writing-mode">
<span>See the Pen <a href="https://codepen.io/rachelandrew/pen/yvGEbZ">
Grid and writing-mode</a> by rachelandrew (<a href="https://codepen.io/rachelandrew">@rachelandrew</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>I should note at the time I'm writing this, there's little browser support for this feature. But it's good to get a basic understanding early on so you're ready to use it when you can.</p>
<h2 id="contain">Contain <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/11/06/state-of-css-survey-didnt-know-part-1/#contain">#</a></h2>
<p>Some parts of a webpage may change even after it's loaded up. A list of recent tweets on a personal site may show new tweets as they're posted. A browser will see this happen and need to figure out exactly what's changing and optimize for it. But sometimes a browser may try to optimize the entire webpage around the change, not just the Twitter widget showing the new tweet. That's quite bad for performance.</p>
<p><code>Contain</code> tells the browser it'll only need to optimize things for that area. So I could add this to my Twitter widget:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.twitter-widger</span> <span class="token punctuation">{</span><br /> <span class="token property">contain</span><span class="token punctuation">:</span> layout<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p><strong>This tells the browser "if you see a change in this element, only optimize things for it and not the entire page."</strong> How the browser actually handles this depends on the browser itself. This property only lets developers pass that info along.</p>
<p>I used <code>contain: layout</code> in this example, but there's actually other values you can use with different effects. Once again, <a href="https://www.smashingmagazine.com/2019/12/browsers-containment-css-contain-property/">Rachel Andrew already explains the specifics of CSS Contain better in this (better) article</a>.</p>
<h2 id="backdrop-filter">backdrop-filter <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/11/06/state-of-css-survey-didnt-know-part-1/#backdrop-filter">#</a></h2>
<p>I've seen lots of blog post designs built around text placed over a big banner image. My own blog used a design like this until recently. The problem is text right on the image is hard or impossible to read. A common solution is giving it a solid color background, which isn't too pretty but makes it readable.</p>
<p>There's another, more stylish way with <code>backdrop-filter</code>!</p>
<p>For any design with a visual right behind an element, like a banner image behind a blog title, this property can be helpful. <strong>Instead of blocking it out from the blog title entirely, it can add filters between the title and the image acting as the backdrop. The filters only affect the overlapping area, not the entire backdrop.</strong></p>
<p>With this, we can add a few filters to make a "frosted glass" effect. I can blur the image, lower the contrast, and brighten it up.</p>
<p class="codepen" data-height="453" data-theme-id="light" data-default-tab="result" data-user="max1128" data-slug-hash="VwjdZMY" style="height: 453px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="CSS Survey Backdrop Filter example">
<span>See the Pen <a href="https://codepen.io/max1128/pen/VwjdZMY">
CSS Survey Backdrop Filter example</a> by Maxwell Antonucci (<a href="https://codepen.io/max1128">@max1128</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>Now the text is easier to read while letting the original image shine through for a sleeker, more polished effect. Most browsers supported this except for IE and Firefox. I happen to use Firefox a lot, so I hid <code>backdrop-filter</code> behind a <code>@supports</code> query with basic light blue background color as a fallback. Progressive enhancement always wins!</p>
<h2 id="touch-action">touch-action <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/11/06/state-of-css-survey-didnt-know-part-1/#touch-action">#</a></h2>
<p><a href="https://css-tricks.com/almanac/properties/t/touch-action/">This touch-events article from CSS Tricks</a> has a good example of where to use these. Say a user on a mobile touch device is trying to zoom in and out with pinch gestures. But instead of interacting with the map, they're just zooming in and out of the page itself. The browser event listeners are set up to see "pinch gesture" as "zoom in and out." So the developer needs to override and remove those for this map!</p>
<p><strong>Before, coders would need to handle this with JavaScript by hooking into the page or component and overriding the needed gestures. But <code>touch-action</code> lets them specify any touch events to keep from the CSS.</strong></p>
<pre class="language-css"><code class="language-css"><span class="token selector">.map</span> <span class="token punctuation">{</span><br /> <span class="token property">touch-action</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>This turns off all browser touch events for the map, and any others need to be added through the JavaScript. But it also lets developers specify which events to keep.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.map</span> <span class="token punctuation">{</span><br /> <span class="token property">touch-action</span><span class="token punctuation">:</span> pan-x pan-y<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>This tells the browser to only handle touch events for panning around the map, while turning off the rest (like zooming). The end result is developers have more control over their user's touch experiences before they get messy and out of hand.</p>
<p>...I'm going to ignore how dirty that sounded and move on.</p>
<h2 id="overscroll-behavior">overscroll-behavior <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/11/06/state-of-css-survey-didnt-know-part-1/#overscroll-behavior">#</a></h2>
<p>There have been times I used websites with modals.</p>
<p>They were dark times I don't like to discuss, but I need to for this example. So bear with me if I stare off and scream for a moment.</p>
<p>Let's say a site has a particularly evil modal with so much content, a user needs to scroll through it. They scroll through it real fast, abruptly hit the end without noting fast enough, and keep on scrolling. The user will be scrolling within the modal but wind up scrolling down the whole page by accident. It's not fun and makes it easy to lose one's place.</p>
<p>This unwanted event is called "<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior">scroll chaining</a>," and it's something <code>overscroll-behavior</code> aims to stop like so:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.modal-content</span> <span class="token punctuation">{</span><br /> <span class="token property">overscroll-behavior</span><span class="token punctuation">:</span> contain<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p><strong>If you're scrolling in that area, even when you reach the end, it won't ever scroll you past that area.</strong> You can check this out in action below if you're using a supportive browser (which is now most of them aside from IE and Safari).</p>
<p class="codepen" data-height="525" data-theme-id="light" data-default-tab="result" data-user="max1128" data-slug-hash="XWKBQJb" style="height: 517px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="overscroll-behavior example">
<span>See the Pen <a href="https://codepen.io/max1128/pen/XWKBQJb">
overscroll-behavior example</a> by Maxwell Antonucci (<a href="https://codepen.io/max1128">@max1128</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>Now the user will reach the end of the modal content and go no further, as God intended.</p>
<h2 id="overflow-anchor">overflow-anchor <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/11/06/state-of-css-survey-didnt-know-part-1/#overflow-anchor">#</a></h2>
<p>Let's say a user is scrolling down a long webpage and stop at an interesting paragraph. Unknown to them, an unloaded large image is lurking in the areas they just scrolled by. When the user least suspects it, the webpage attacks by finishing the delayed image load! It's a sneak attack that pushes the webpage down, changing the visible viewport, and making users lose their place. Evil triumphs again and the credits roll.</p>
<p>Actually, this probably hasn't happened to users as much lately in most browsers. That's because <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-anchor/Guide_to_scroll_anchoring">browsers have something called scroll anchoring</a>. When the large image tries to mess with what a user is reading, the browser adjusts their scroll position to match the change. While the scroll position changes, what the user sees doesn't change, and good wins the eternal battle against the vile.</p>
<p>This is possible due to the <code>overflow-anchor</code> property, which defaults to <code>auto</code> to enable this behavior. For the first time, evil is defeated while good men do nothing.</p>
<p>But there may be rare cases where you don't want good to win. A webpage may have custom scroll behaviors, difficultly loading images, or the developer wants to watch the world burn. <strong>Support for the <code>overflow-anchor</code> property lets them disable scroll anchoring.</strong></p>
<p>For these edge cases or debugging. You monster.</p>
<h2 id="font-variant-numeric">font-variant-numeric <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/11/06/state-of-css-survey-didnt-know-part-1/#font-variant-numeric">#</a></h2>
<p>I won't lie, despite this property seeming so simple, it took me the longest to wrap my head around.</p>
<p><strong>The simplest explanation I have is it changes the default way certain numbers are shown.</strong> These are mainly style changes, like showing a slash through a zero, or if fractions should have a slash in the middle. This can make things easier to read or understand for users, depending on what they're used to.</p>
<p>Let's say I want to change how numeral expressions like "1st" and "3rd" appear on my website. <code>font-variant-numeric</code> can change that in ways that are both correct and incorrect.</p>
<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="max1128" data-slug-hash="rNLrLjb" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="font-variant-numeric Example">
<span>See the Pen <a href="https://codepen.io/max1128/pen/rNLrLjb">
font-variant-numeric Example</a> by Maxwell Antonucci (<a href="https://codepen.io/max1128">@max1128</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>I personally see limited use cases for a feature like this. But that could be because it's outside my range of experiences or needs, so I'll limit my judgment for now.</p>
<h2 id="font-display">font-display <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/11/06/state-of-css-survey-didnt-know-part-1/#font-display">#</a></h2>
<p>You remember the "flash of invisible text (FOIT)," one of those problems that haunts designers and developers in the dead of night? When coders set a custom font, but until the font loads, it's invisible to the user and flashes onto the page after most or all of the page is already there. It doesn't break anything, but it's jarring and the stuff of nerd nightmares.</p>
<p><strong><code>font-display</code> brings us one step closer to fully solving this issue. It tells the browser to use a fallback font while waiting for the other font to load.</strong> There are a few different options for how to approach this:</p>
<ol>
<li>Use the fallback font right away. This can create a "flash of unstyled text."</li>
<li>Wait a little, and if the custom font isn't ready, use the fallback font until it is.</li>
<li>Same as the second option, but it sticks with the fallback font if the browser figures the custom one won't be used at all.</li>
</ol>
<p>The problems around trying to load different fonts and how they affect what users see likely aren't going anywhere. But developers at least have more choice and control over which problems they'll get. This makes it easier to work around them or design better solutions.</p>
<h2 id="in-conclusion">In Conclusion <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/11/06/state-of-css-survey-didnt-know-part-1/#in-conclusion">#</a></h2>
<p>I learned a lot from the 2020 State of CSS Survey and writing this post, but I haven't even gotten through half the items on my list. So stay tuned for future posts with even more new CSS knowledge goodness!</p>
What I Didn't Know in the 2020 State of CSS Survey, Part 2
2020-12-17T00:00:00Zhttps://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/<p>What I Didn't Know in the 2020 State of CSS Survey, Part 2</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/css-survey-2.jpg" alt="Post featured image"></p><p>Last month I wrote about the first batch of CSS goodness I discovered by taking the State of CSS Survey this year. Then I got delayed from writing this second part thanks to the continued pandemic, changing apartments, and reading <a href="https://stateofcss.com/">the results of the State of CSS survey</a> itself. I also think <a href="https://www.maxwellantonucci.com/posts/2020/11/28/birthday-resolution-fail-more/">I had a birthday of some kind</a>, I'm not sure.</p>
<p>Valid excuses aside, I have finally finished part two of this CSS min series. So I'll get back to it without further delay!</p>
<h2 id="css-exclusions">CSS Exclusions <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/#css-exclusions">#</a></h2>
<p>The journey begins.</p>
<p>Most people who've worked on the front-end will recognize this kind of layout:</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/css-survey-2/exclusion-1.jpeg" alt="A layout where the image is pushed all the way to the left, with text flowing around it to the right." /></p>
<p>It's pretty simple. A designer wants to include a small image alongside the text. Having it wrap around the image lets it be included without wasting too much space.</p>
<p>The main way to do this is with <code>float</code>. It pushes an element to one side of the container, and any surrounding elements wrap around it. I do the same thing on my own "About" page. It's an established solution to this problem.</p>
<p>Not so fast.</p>
<p>Say one day your designer comes to you with this layout.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/css-survey-2/exclusion-2.jpeg" alt="Another layout with two columns of text and an image in the space between them. The text in both columns wrap around the image as needed." /></p>
<p>Now, <code>float</code> isn't going to help you at all. Floats being you to one side or the other, it can't put you between two elements. There's no real way to get this effect with Grid or Flexbox that's responsive and not excessively convoluted either.</p>
<p>Or so I thought.</p>
<p>This is where <a href="https://webdesign.tutsplus.com/tutorials/css-exclusions--cms-28087">CSS Exclusions</a> enters the scene. If you apply a CSS Exclusion to an element, you're telling the browser it's an "exclusion element" and it gets its very own "exclusion box." <strong>An exclusion box is that element telling the others around it they can't overlap or touch it. They're excluding it from its space!</strong></p>
<p>That's certainly rude, but the other elements have to put up with it. The good news is they won't go out of their way to appease the exclusion element. They'll avoid it but they'll keep following their own formatting rules. If they let one element like that destroy the whole layout, it would be anarchy!</p>
<p>So in the above example, where the exclusion element is between two columns of text? That text will wrap around the exclusion element without leaving their defined column areas. Same thing if it was in a Flexbox or Grid layout.</p>
<p>Yes, you could have float-style wrap effects in Flexbox or Grid layouts! This opens up so many new layout opportunities with much simpler styling.</p>
<p>That, my dear friends/readers/informants, is what makes CSS Exclusions awesome.</p>
<p>According to current specs, you create the actual effect with the <code>wrap-flow</code> property. It has seven potential values that let you decide how content flows around an element. You have the basic wrapping like above, or you could clear content on the entire sides of the element. <a href="https://chenhuijing.com/blog/css-exclusions-with-queen-bey/#%F0%9F%92%BB">This Beyonce-inspired article has more specific details on CSS Exclusion options if you want them</a>.</p>
<p>One final note, which is a disappointing one: Only one browser supports CSS Exclusions, and it's Edge, the one browser you likely never use unless you're doing cross-browser testing. So you'll need to be patient before using this in production. Or anywhere, really.</p>
<p>So the adventure continues.</p>
<h2 id="pointer-events">Pointer Events <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/#pointer-events">#</a></h2>
<p>The term "pointer event" may make you think only of mouse pointers. But <a href="https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events">pointer address a wide variety of events around interacting with something online</a> - using a stylus, touch screens, or other kinds of assistive tech. As long as the trigger can be focused around coordinates on a device (the point on the screen), pointer events shall handle them.</p>
<p><strong>The <code>pointer-events</code> CSS property lets you set the circumstances that the selected element can become targeted by pointer events.</strong> You could use CSS to give a link no pointer events so you could only interact with it like normal text.</p>
<p>There's a lot of possible values for the <code>pointer-events</code> property, but most relate to SVG that I won't go into here. The main ones for HTML elements are keeping the default, removing them all, or basing it on what the parent element's pointer events are.</p>
<p class="codepen" data-height="300" data-theme-id="light" data-default-tab="result" data-user="zakkain" data-slug-hash="dseHt" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="CSS-Tricks: pointer-events">
<span>See the Pen <a href="https://codepen.io/zakkain/pen/dseHt">
CSS-Tricks: pointer-events</a> by Zachary Kain (<a href="https://codepen.io/zakkain">@zakkain</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
<p><a href="https://css-tricks.com/almanac/properties/p/pointer-events/">The CSS Tricks Almanac (a great resource overall) gives the above example of where you may want to use the pointer-events property</a>: letting users click through overlays or other elements that may block other elements you want to let users keep access to.</p>
<h2 id="color-gamut">Color Gamut <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/#color-gamut">#</a></h2>
<p><a href="https://www.livescience.com/42797-mantis-shrimp-sees-color.html">A sad truth is we are not like the mantis shrimp</a>. We only have three color receptors in our eyes, and the mantis shrimp has twelve. They can see color in a way far beyond our puny human brains.</p>
<p>We also can't attack people with lightning-fast strikes carrying over 200 pounds of force, but one depressing fact at a time.</p>
<p>But at least our computers are getting better at seeing new colors. Some desktops can display colors at a level we don't know about when we're picking our website's colors, also called a "wide-gamut display." That's a quick way to a lackluster-looking site, picking colors that don't make use of all these possible color options.</p>
<p>We have an advantage over the mantis shrimp here. We have CSS! It brings us three new color modes to make use of this wider gamut of color options: <code>lab</code>, <code>lch</code>, and <code>display-p3</code>. I won't get into their syntaxes here, but those who want to know more now can read <a href="https://css-tricks.com/the-expanding-gamut-of-color-on-the-web/">this CSS Tricks articles on using these new color modes</a>. But to understand <code>color-gamut</code>, you only need to know they exist.</p>
<p><strong>Why? Because it's the media query that lets you use the colors when available!</strong></p>
<p>Say you have a basic red color as a hex value. But you also have a nice <code>display-p3</code> color you want to use for desktops that can. You can include both by using the media query like so:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span><br /> <span class="token property">--red</span><span class="token punctuation">:</span> #FF0000<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">color-gamut</span><span class="token punctuation">:</span> p3<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token property">--red</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>display-p3 1 0 0.331<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token comment">/* Let us presume this is a nicer red color */</span><br /><span class="token punctuation">}</span></code></pre>
<p>There are other ways to handle like, like a <code>@supports</code> query or passing a fallback to the <code>color()</code> function. But the media query gives you more control and lets you add additional styles behind the query if needed.</p>
<h2 id="line-clamp">Line-clamp <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/#line-clamp">#</a></h2>
<p>This property was easier to learn since you can guess it from the name. <a href="https://css-tricks.com/almanac/properties/l/line-clamp/">Line-clamp lets you set a maximum number of lines for an element to show</a>. If there are any more lines than that, the CSS <em>clamps</em> down on them and treat them as overflow.</p>
<p>You can see some basic examples of how this works below.</p>
<p>You can also handle the overflow in different ways that CSS already allows. <strong>You can hide the extra text altogether or let users scroll to see more.</strong> The latter could be useful with modals that could have an unpredictable number of lines.</p>
<p class="codepen" data-height="575" data-theme-id="light" data-default-tab="result" data-user="max1128" data-slug-hash="abmWEza" style="height: 575px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Line Clamp Overflow Examples">
<span>See the Pen <a href="https://codepen.io/max1128/pen/abmWEza">
Line Clamp Overflow Examples</a> by Maxwell Antonucci (<a href="https://codepen.io/max1128">@max1128</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
<p>I welcome this property and am glad it already has surprisingly good browser support. The past tricks I've used to limit text to one line took modifying white space and manually adding ellipses, which worked but was a lot of hassle to get right. This is simpler and even adds ellipses for me. All it needs now is to put the extra mint on my pillow.</p>
<h2 id="new-units-of-size">New Units of Size <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/#new-units-of-size">#</a></h2>
<p>I only use rem and pixel units in my styling these days, but there are some other CSS units worth remembering in the future.</p>
<p>First are three that don't need much explanation to most people - mm, cm, and in. <strong>They refer to their real-life measurement units of millimeters, centimeters, and inches.</strong> They're absolute values like pixels, which means they won't change if users adjust their browser for bigger font sizes. But they can be useful if you're styling a print-specific version of a webpage since you're working within more static sizes for your content anyway. That and they're the units many people are already used to when designing for print.</p>
<p>The fourth unit I found, ex, is a little trickier. <a href="https://webdesign.tutsplus.com/articles/7-css-units-you-might-not-know-about--cms-22573">"Ex" is a relative size unit equal to one unit of the current font's x-height</a>. <strong>A simple way to find the x-height value is to measure how high the letter "x" is in that font.</strong> It's easy once you see it.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/css-survey-2/x-height.jpeg" alt="A visual example of what determines the x-height. It's the height of the letter 'x.'" /></p>
<p>This is how much <code>1ex</code> unit will be. It'll be equal to most other lowercase letters too. So it's useful for lots of typographic spacing, on a large or small scale.</p>
<h2 id="new-pseudo-elements">New Pseudo-Elements <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/#new-pseudo-elements">#</a></h2>
<p>The only pseudo-elements I knew before were <code>::before</code> and <code>::after</code>, and I thought they were mainly for adding extra elements for more advanced styling. <strong>These new pseudo-elements have similar functionality but with more precise purposes.</strong></p>
<p>First is <code>::marker</code>, which can only be used on list items. <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::marker"><code>::marker</code> lets you adjust a few styles for the item's "marker box," or element that identifies them as a list item</a>. For example, an unordered list's marker boxes are bullets, while ordered lists have numbers.</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::backdrop"><code>::backdrop</code>, meanwhile, can only be used to style the backdrop behind the <code>dialog</code> element</a>. So adding a full-screen, transparent backdrop would be as easy as one more line of CSS. It even makes use of <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API">the Fullscreen browser API</a> to create the effect for us. Which I didn't even know was a thing until now.</p>
<p>Seeing that dialog backdrops are already included in <code>dialog</code> elements makes me even more eager for this HTML5 element to get stronger support. Dialogs are nightmares, but this element could make it easier to handle. Both these pseudo-classes (as well as dialog) only have mixed to decent browser support, so don't go crazy with them yet.</p>
<h2 id="the-%3Ais()-selector">The :is() Selector <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/#the-%3Ais()-selector">#</a></h2>
<p>The <code>:is()</code> selector is the next in the "Let CSS do naturally what Sass can do" series, following custom properties replacing Sass variables.</p>
<p>Say you want to select all paragraphs in an <code>article</code> or <code>section</code> tag. Using Sass, you'd write it like this.</p>
<pre class="language-scss"><code class="language-scss"><span class="token selector">article,<br />section </span><span class="token punctuation">{</span><br /> <span class="token selector">p </span><span class="token punctuation">{</span><br /> <span class="token comment">// Styles goes here!</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This would get compiled into the following CSS.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">article p,<br />section p</span> <span class="token punctuation">{</span><br /> <span class="token comment">/* Styles go here! */</span><br /><span class="token punctuation">}</span></code></pre>
<p>This does what you need, but the compiled styles can grow surprisingly fast. Especially if you needed to style other elements in those two, like ordered and unordered lists.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">article p,<br />article ol,<br />article ul,<br />section p,<br />section ol,<br />section ul</span> <span class="token punctuation">{</span><br /> <span class="token comment">/* Styles go here! */</span><br /><span class="token punctuation">}</span></code></pre>
<p>It's compiled into six separate rules just from that! On a larger scale, you could even get dozens to try for this "matches any of the above" selector effects.</p>
<p>The <code>:is()</code> selector gives you that same effect without the preprocessing. You could theoretically get the same effect as above with this.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:is(article, section) :is(p, ol, ul)</span> <span class="token punctuation">{</span><br /> <span class="token comment">/* Styles go here! */</span><br /><span class="token punctuation">}</span></code></pre>
<p><strong>One selector rule that targets all the same styles, no Sass needed.</strong> In some ways, it's even better since it's more readable than nested rules that grow out of hand.</p>
<p>The most interesting thing about this selector is it's the third attempt to get CSS a selector like this, the first two being <code>:any()</code> and <code>:matches()</code>. As <a href="https://css-tricks.com/almanac/selectors/i/is/">this other CSS Almanac on the ":is" selector</a> points out, these first two put together have decent browser support. Presuming <code>:is()</code> gets finalized into CSS later on, it would likely replace those two. But until then, there's a somewhat convoluted but workable way to use this today if you want.</p>
<h2 id="link-selectors">Link Selectors <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/#link-selectors">#</a></h2>
<p>Turns out you can target link elements with more than a mere anchor tag selector.</p>
<p><a href="https://css-tricks.com/almanac/selectors/a/any-link/">First off is <code>:any-link</code>, which looks for any possible element that has an <code>href</code> attribute</a> (including the lesser-known <code>link</code> and <code>area</code>). This includes any link elements that have been visited and you'd need to use <code>:visited</code> to target otherwise. It's got pretty good browser support, so you can use it today!</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:local-link">Next up is <code>:local-link</code>, that only targets links in the current domain</a>. <strong>So you can easily change styles between links to other sites and links staying on your own.</strong> An example I can think of is distinguishing external links in any site navigations, since otherwise, users may assume all those links stay in your website. One website I saw said you could even target it based on sub-domains, like links only in your local <code>/blog/</code> pages, but couldn't confirm this anywhere else. But unlike <code>:any-link</code>, this is still a working draft and has zero support as of this writing.</p>
<p>Third up is...nothing. There were only two link selectors I wanted to cover here.</p>
<p>I <em>could</em> have organized this section up better.</p>
<h2 id="form-controls">Form Controls <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/#form-controls">#</a></h2>
<p>These pseudo-classes are all about form inputs and their states. There's a bunch to cover, so I'll tackle them all lightning round style.</p>
<ul>
<li><a href="https://www.digitalocean.com/community/tutorials/css-styling-form-input-validity"><code>valid</code> and <code>invalid</code> only work for required fields with at least one rule</a>, like being a number or falling in a certain range. You can also pair them with the <code>:focus</code> selector to only show the styles on user focus.</li>
<li><a href="https://css-tricks.com/almanac/selectors/u/user-invalid/"><code>user-invalid</code> is the same as <code>invalid</code>, but only kicks in after the user has interacted with the field once</a>. So if a form loads with a pre-filled, invalid value, these styles won't kick in until the first interaction.</li>
<li><code>indeterminate</code> is a tricky "maybe" state in some inputs, most commonly seen in checkboxes. The browser sees <a href="https://css-tricks.com/almanac/selectors/i/indeterminate/"><code>indeterminate</code> inputs as "unchecked," but are styled differently to look like a kind of half-yes, half-no</a>. You can also only get this state by using JavaScript. So I'd avoid relying on this state without a good reason, even with good support for it.</li>
<li><a href="https://css-tricks.com/almanac/selectors/i/in-range/"><code>:in-range</code> and <code>:out-of-range</code> speak for themselves: they style if an input value falls inside or outside the input's set range</a>. The most obvious example is a number being too high or too low from what's allowed.</li>
<li><code>Prosciutto</code> is an Italian dry-cured ham that is usually thinly sliced and served uncooked, and is known as <code>prosciutto cotto</code> in Italy. It's notably high in fat and sodium, so for a daily diet, you may want to...oh, sorry, need to save this for the next <a href="https://www.jackboxgames.com/trivia-murder-party/">Trivia Murder Party</a>.</li>
</ul>
<p>Phew, that's a lot to cover in an already long blog post. I'm off to the bonus round before I wrap this up.</p>
<h2 id="in-conclusion">In Conclusion <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2020/12/17/state-of-css-survey-didnt-know-part-2/#in-conclusion">#</a></h2>
<p>Even after two whole posts, there's still content from the CSS Survey I haven't covered! They're mostly methodologies, podcasts, newsletters, and more. But I barely had time to write this amid moving and a pandemic, so I'm going to pass on those for now.</p>
<p>So I'm closing the books on this little mini-series. Some people may understandably think I only scratched the surface of what these tools can do and how to demonstrate them. I would agree with them, and encourage them to look into them more! <strong>There are way too many nuances of functionality, overlap with past CSS properties, and browser support to cover in one post. Any one of these sections could have been a separate blog post.</strong> I encourage anyone up for it to try writing one of them!</p>
<p>I also encourage them to get six to eight hours of sleep and floss regularly. But once you have those covered, the blog writing awaits.</p>
What is Programmatic Determinability?
2021-01-15T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/01/15/programmatic-determinability/<p>What is Programmatic Determinability?</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/programmatic-determinability.jpg" alt="Post featured image"></p><p>The phrase "programmatic determinability" appears a lot in the Web Content and Accessibility Guidelines (WCAG). It's also the kind of phrase that could make you sound smart or conceited, depending on how you use it. For these two <em>very important</em> reasons, I wanted to figure it out.</p>
<p><a href="https://www.w3.org/TR/WCAG21/#dfn-programmatically-determinable">The official definition of "programmatically determined"</a> kind of helped, but only kind of.</p>
<blockquote>
<p>Determined by software from author-supplied data provided in a way that different user agents, including assistive technologies, can extract and present this information to users in different modalities</p>
</blockquote>
<p>This is a bit...dense. So I want to unpack it a bit.</p>
<h2 id="a-conversation-between-users-and-websites">A Conversation Between Users and websites <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/01/15/programmatic-determinability/#a-conversation-between-users-and-websites">#</a></h2>
<p>The most succinct definition I can think of <strong>programmatic determinability stops misunderstandings between users and websites.</strong></p>
<p>Sometimes you get into arguments with people who refuse to say why they're upset. No matter how many questions you ask, they only give variations of "I'm upset and you should already know why." It's impossible to reach any kind of agreement or resolution, and most likely you storm off on them with less-than-pleasant thoughts.</p>
<p>A better scenario is you meet someone upset, and when you ask why, they say they're upset a store no longer sells their favorite cheesecake. You probably can't fix the underlying issue, but now you can do more helpful things like:</p>
<ul>
<li>Share a similar experience to show them they're not alone</li>
<li>Offer to get some cheesecake from a new place so they see there are still options out there</li>
<li>Join them in their rage so they blow off steam by smashing cheesecake cardboard cutouts you coincidentally have lying around</li>
<li>Offer use of a time machine to go back to when it was still sold so they can have it one last time and bid their cheesecake a fond farewell. Then the clouds part, the light shines through, and they can take another step forward in life as the credits roll.</li>
</ul>
<p>The first fruitless, frustrating argument version is a website without programmatic determinability.</p>
<p>Your website (the angry friend) isn't giving enough information to users using assistive technology (the frustrated friend). The user asks but gets nothing, doesn't know what to do next, and leaves in a huff.</p>
<p>Want to avoid that scenario? <strong>That website needs that info in a coded format the browser can understand. Then the browser can share it and the two friends, user and website, can finally reconcile. This is programmatic determinability.</strong></p>
<h2 id="share-%22obvious%22-info-with-users">Share "Obvious" Info with Users <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/01/15/programmatic-determinability/#share-%22obvious%22-info-with-users">#</a></h2>
<p>Here's a specific example: say an English-speaking user visits a website written in a foreign language. They know it has information they need to read but can't understand it. If the computer could talk, their interaction could go like this:</p>
<ul>
<li><strong>User:</strong> I can't understand what you're saying, webpage. What language are you in?</li>
<li><strong>Webpage:</strong> How are you not able to understand me? Everyone else can.</li>
<li><strong>User:</strong> Well, I can't. Do you know English?</li>
<li><strong>Webpage:</strong> What's English?</li>
<li><strong>User:</strong> How do you not know that?!</li>
<li><strong>Webpage:</strong> I don't know, you should just speak my language.</li>
</ul>
<p>It goes back and forth like this for a while until the user quits from frustration. They tell all their friends how uncooperative the site was and its reputation suffers and dies on a neglected 404 page.</p>
<p>The site in question forgot the <code>lang</code> attribute on its <code>html</code> tag. Without that, the website couldn't tell the user it was written in Italian. It can't share the info that would end this fight between user and website since it isn't programmatically determinable.</p>
<p>The <code>lang</code> attribute is the coded way the browser can understand what the language is. When it's included, the exchange may go like this.</p>
<ul>
<li><strong>User:</strong> I can't understand what you're saying, webpage. What language are you in?</li>
<li><strong>Webpage:</strong> I'm written in Italian. Most of my users read that.</li>
<li><strong>User:</strong> I get why you'd think that, but I can only read English. Do you have any translation options?</li>
<li><strong>Webpage:</strong> I don't think so, but something like Google Translate can help. When I tell it my language, it'll do a rough translation to English.</li>
<li><strong>User:</strong> That'll work for now. Thanks!</li>
</ul>
<p>Now the relationship is saved, the user isn't lost, and they can go out for cheesecake together later!</p>
<p>Many accessibility issues can be boiled down to this kind of argument between users and inaccessible webpages that don't communicate well.</p>
<ul>
<li>It seems obvious where the navigation, sidebars, and main content are located in your layout. But some people won't see the layout. So you should share those relationships with roles or semantic markup.</li>
<li>It seems obvious what's being shown on an image. But some people won't see the images. So you should share descriptions with <code>alt</code> tags.</li>
<li>It seems obvious what you're alerting users to with brightly-colored banners. But some people won't see those bright colors, or see the page at all. So you should share how important they are through explicit text, and ARIA live regions or alert roles.</li>
</ul>
<p>These take even more forms - knowing how to solve them for as many users and websites as possible is part of the never-ending accessibility journey. Programmatic determinability is only one part of it, albeit one of the most important ones.</p>
<p>Keep it in mind, and your users will never miss out on cheesecake with your website again.</p>
Hiding and Showing in SVG with Clip-path and Mask
2021-01-28T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/01/28/svg-clip-path-mask/<p>Hiding and Showing in SVG with Clip-path and Mask</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/svg-clip-path-mask.jpg" alt="Post featured image"></p><p><a href="https://developer.mozilla.org/en-US/docs/Web/SVG">Scalable Vector Graphics</a>, or SVG, are one of those front-end tools that can open up a world of creative ideas. I've been playing around with it more, for work and to distract myself from my hollow, quarantined soul. I did both and made my first component with some cutesy SVG animation.</p>
<p class="codepen" data-height="297" data-theme-id="light" data-default-tab="result" data-user="max1128" data-slug-hash="YzGbWqO" style="height: 297px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Light and Dark Theme Switcher">
<span>See the Pen <a href="https://codepen.io/max1128/pen/YzGbWqO">
Light and Dark Theme Switcher</a> by Maxwell Antonucci (<a href="https://codepen.io/max1128">@max1128</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
<p>But near the end, I hit a snag with how SVG can hide parts of the image. Sometimes I wanted to <em>show</em> specific parts of an image. Other times I wanted to <em>hide</em> them. I couldn't get this effect for the sun and moon animations, so I got it with border and fill colors. That's not ideal, but I can always fix it up later.</p>
<p>But while I wanted to figure this out, I had a hard time finding a clear explanation of showing and hiding SVG. So I wrote one myself! <strong>The two parts of SVG one needs for these effects are <code>clip-path</code> and <code>mask</code>.</strong> Here I'll break down the basics of how to use them with SVG to hide shapes, images, and if you're lucky, painful tangles of repressed emotion.</p>
<h2 id="clip-path-controls-what-you-see">Clip-path Controls What You See <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/01/28/svg-clip-path-mask/#clip-path-controls-what-you-see">#</a></h2>
<p>Let's say I have a red rectangle, but I only want to show a small circle <em>within</em> it. That's when I need <code>clip-path.</code> <strong>A <code>clip-path</code> is an SVG shape you pair with a second. Anything in the second shape that doesn't overlap with the <code>clip-path</code> shape gets cropped out, lost, and never seen again.</strong> You destroyed it and I hope you're happy.</p>
<p><em>Ahem</em>...anyways, here's an example. Let's start with this red rectangle.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>svg</span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token attr-name">viewbox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-200 -100 400 200<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rect</span> <span class="token attr-name">x</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-200<span class="token punctuation">"</span></span> <span class="token attr-name">y</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-100<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>red<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>svg</span><span class="token punctuation">></span></span></code></pre>
<p>Let's add a <code>clip-path</code> to this thing. First, I need to define the circle it'll be using. It's positioned to be in the rectangle's center. But I need to define it within a <code>clip-path</code>. <strong>This has to go within a <code>defs</code> element, which is SVG's way of storing variables.</strong> Anything in <code>defs</code> won't directly render but can then affect other elements, like repressed memories of staring wistfully at an empty street after the third hard cider.</p>
<p>So within the <code>defs</code> element, the <code>circle</code> must go in a <code>clipPath</code> element. It also needs a unique ID for reference.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>defs</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>clipPath</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>clip-path<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>circle</span> <span class="token attr-name">cx</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">cy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">r</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>50<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>clipPath</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>defs</span><span class="token punctuation">></span></span></code></pre>
<p>Now, this <code>clip-path</code> circle can be used with the red rectangle. It needs the <code>clip-path</code> attribute with the unique ID, which looks like <code>clip-path="url(#clip-path)"</code>, and it's good to go.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>svg</span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token attr-name">viewbox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-200 -100 400 200<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>defs</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>clipPath</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>clip-path<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>circle</span> <span class="token attr-name">cx</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">cy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">r</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>50<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>clipPath</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>defs</span><span class="token punctuation">></span></span><br /><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rect</span> <span class="token attr-name">clip-path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url(#clip-path)<span class="token punctuation">"</span></span> <span class="token attr-name">x</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-200<span class="token punctuation">"</span></span> <span class="token attr-name">y</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-100<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>red<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>svg</span><span class="token punctuation">></span></span></code></pre>
<p>You can see the final result below. The light yellow area is where the rest of the rectangle is being hidden below the clip-path.</p>
<p class="codepen" data-height="361" data-theme-id="light" data-default-tab="html,result" data-user="max1128" data-slug-hash="jOMjXvL" style="height: 361px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="SVG Clip-path Example">
<span>See the Pen <a href="https://codepen.io/max1128/pen/jOMjXvL">
SVG Clip-path Example</a> by Maxwell Antonucci (<a href="https://codepen.io/max1128">@max1128</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h2 id="mask-controls-what-you-hide">Mask Controls What You Hide <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/01/28/svg-clip-path-mask/#mask-controls-what-you-hide">#</a></h2>
<p>Once I finally peeled myself off the couch and found the will to keep working despite the terror of it all, I asked, "What if I want the reverse result? If I want to hide everything <em>except</em> that red dot?" To do that, we need a <code>mask</code>. But this approach is a little more complex.</p>
<p>With <code>clip-path</code>, I only had to define a visible area. With <code>mask</code>, there are two steps:</p>
<ol>
<li><strong>Define a visible area. Anything outside it gets cropped out.</strong></li>
<li><strong>Define what areas <em>within</em> the visible area are also cropped out.</strong></li>
</ol>
<p>This is like a <code>clip-path</code> but with a lot more potential for what to show and hide, but will only realize once it can experience regular human interaction again. But I only needed these lonely basics to the desired result. If you want to see what it can do, including using shades of gray for translucent effects, check out <a href="https://vanseodesign.com/web-design/svg-masking-examples-1/">this blog post of mask examples</a>.</p>
<p>First, defining a visible area here is easy: I want the rectangle to be visible! I'm hiding space within the rectangle, so the entire rectangle itself should be my visible area. I define this within a <code>mask</code> element, which can also go in the <code>defs</code> element.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>defs</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mask</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mask<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rect</span> <span class="token attr-name">x</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-200<span class="token punctuation">"</span></span> <span class="token attr-name">y</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-100<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>white<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mask</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>defs</span><span class="token punctuation">></span></span></code></pre>
<p>Notice the <code>fill="white"</code> I added to the shape. That's important because, <strong>in a mask, the visible area must have a white fill color.</strong> Don't you dare deprive it of what it needs. You monster.</p>
<p>Now I need to decide what area to hide within the visible area. This is the circle in the middle of the rectangle. This time it needs <code>fill="black"</code> to hide it.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>defs</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mask</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mask<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rect</span> <span class="token attr-name">x</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-200<span class="token punctuation">"</span></span> <span class="token attr-name">y</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-100<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>white<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>circle</span> <span class="token attr-name">cx</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">cy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">r</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>50<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>black<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mask</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>defs</span><span class="token punctuation">></span></span></code></pre>
<p>With this basic mask complete, we can connect it to the red rectangle. It's done the same way as <code>clip-path</code> but with the <code>mask</code> attribute.</p>
<pre class="language-html"><code class="language-html"><br /><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>svg</span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token attr-name">viewbox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-200 -100 400 200<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>defs</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mask</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mask<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rect</span> <span class="token attr-name">x</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-200<span class="token punctuation">"</span></span> <span class="token attr-name">y</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-100<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>white<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>circle</span> <span class="token attr-name">cx</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">cy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">r</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>50<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>black<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>mask</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>defs</span><span class="token punctuation">></span></span><br /><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rect</span> <span class="token attr-name">mask</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url(#mask)<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>red<span class="token punctuation">"</span></span> <span class="token attr-name">x</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-200<span class="token punctuation">"</span></span> <span class="token attr-name">y</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-100<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>200<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>svg</span><span class="token punctuation">></span></span></code></pre>
<p>This gives me what I want: a full rectangle missing the center circle. The result is below with the light yellow again showing what's hidden behind the mask. The SVG mask anyway, not the mask of positivity hiding the sense that nothing will truly be okay again.</p>
<p>Not that mask. The SVG mask.</p>
<p class="codepen" data-height="486" data-theme-id="light" data-default-tab="html,result" data-user="max1128" data-slug-hash="vYXqPqv" style="height: 486px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="SVG Mask Example">
<span>See the Pen <a href="https://codepen.io/max1128/pen/vYXqPqv">
SVG Mask Example</a> by Maxwell Antonucci (<a href="https://codepen.io/max1128">@max1128</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="bonus-challenge">Bonus Challenge <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/01/28/svg-clip-path-mask/#bonus-challenge">#</a></h3>
<p>My written example is redundant. It defines the same rectangle shape twice, but with different fills and masks. SVG lets you define a shape once and use it elsewhere, like a variable reference. I did that in my CodePen example - check the code and see how that works!</p>
<h2 id="wrapping-up">Wrapping Up <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/01/28/svg-clip-path-mask/#wrapping-up">#</a></h2>
<p>I've still got plenty to learn with SVG, but <code>clip-path</code> and <code>mask</code> are two foundations I'm sure will help me make cooler stuff. If you're like me and feel jealous of the cool, graphic stuff you see developers making on CodePen, SVG is one of the first steps to making similar work and assuaging the deep desolation fermenting within one's soul.</p>
<p>Rereading this post, I think the second part may just be me using learning to handle the mental stress of extended quarantine. But the point about writing better code still stands.</p>
<p>So focus on that. I need to take a long walk. To the wine shop.</p>
<p><em>If you're not sure where to start, <a href="https://codepen.io/HunorMarton/pen/PoGbgqj">this Pen that doubles as a basic SVG tutorial</a> helped me immensely. You can also grab a copy of <a href="https://abookapart.com/products/practical-svg">"Practical SVG" from the "A Book Apart" series</a>.</em></p>
Be Picky with Your Life's Lists
2021-02-03T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/02/03/picky-life-lists/<p>Be Picky with Your Life's Lists</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/picky-life-lists.png" alt="Post featured image"></p><p>Everyone I know has at least one list they will never clear.</p>
<p>Even before the pandemic, it's usually a list of shows to watch. It's not a surprise, with the sheer number of streaming services today. But they take many other forms, such as:</p>
<ul>
<li>Books they want to read</li>
<li>Songs they want to listen too</li>
<li>(Video) games they want to play</li>
<li>Places they want to visit</li>
<li>Skills they want to learn for work</li>
<li>Hobbies they want to learn for fun</li>
<li>Folks they want to get freaky with</li>
<li>Hidden messages to decode from their clothes' stitching patterns</li>
</ul>
<p>Of all these examples, about half make up my lists I'll never finish. I'll let you speculate which ones those are.</p>
<p>Today, finding the best items for one's lists is essential. Each day we get a flood of new items we could add to them. But letting one's lists grow too long gets overwhelming and wasteful. <strong>Getting the most out of one's lists, and one's life, means being purposefully picky.</strong></p>
<h2 id="how-do-we-select-wisely%3F">How Do We Select Wisely? <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/02/03/picky-life-lists/#how-do-we-select-wisely%3F">#</a></h2>
<p>There are three steps to making smart additions to a list:</p>
<ol>
<li>Be brutally honest</li>
<li>Cut your losses when needed</li>
<li>Be picky</li>
</ol>
<p>Say there's an okay-looking Switch game I bought months ago on sale. Since then, I've seen games I know I'll enjoy more. But that would mean wasting the money I already spent. Plus I'd feel bad removing a game I've had waiting for so long. But when I start playing, it's not all that enjoyable. But I can't give up after an hour or two, and force myself to keep playing.</p>
<p>I didn't select wisely when I selected this game. That's where the three steps come in.</p>
<p><strong>First, I need to skip the rationalizations and be honest with myself</strong>: my reasons for playing this game are crap. It's driven by guilt, obligation, and not wasting the time or money I invested. In other words, it's <a href="https://en.wikipedia.org/wiki/Sunk_cost">the sunk cost fallacy</a> - the more someone invests in something, the harder it is to let it go. Even when <a href="https://www.forbes.com/sites/jimblasingame/2011/09/15/beware-of-the-concorde-fallacy/?sh=41f1da794e22">something is a clear loser, like expensive and unprofitable Concord jets, people may keep sinking money into it</a>. Our minds want to justify past decisions, so we need hard honesty to see past the excuses.</p>
<p><strong>Second, I remind myself it's better to cut my losses and move on.</strong> Will I lose the time and money I already sunk into this game? Yes, and that's not fun. But the sooner I do, the less time and money I'll waste and can then put towards games I enjoy. The sunk-cost fallacy isn't that bad if you catch it early. What matters most is I learn from this mistake and don't repeat it.</p>
<p><strong>Third, I need to be picky with what I select next.</strong> I need to know and be firm with the core criteria for adding to my lists. If my core requirements are intriguing stories and art styles, but without grinding, cliches, or turn-based combat, I'm not compromising.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/picky-life-lists/1.png" alt="A quote from the book 'Essentiation:' 'Saying yes to one thing means saying no to several others. Even thing we may want.' It's above anime artwork of someone on the street in a breeze." /></p>
<p>Does that mean I'll miss out on other still-enjoyable games? Yes. But I can only play so many. I need to be picky to get the most possible enjoyment from the games I do play. This lesson is so important, I'd long since added it to my quote collection.</p>
<p>This rule applies to my other lists too. There are limitless things I could try to learn as a coder, so I need to be picky. Right now I'm focusing on SVG and animations since they open up the largest number of creative ideas. It's the same reason I learned <code>clip-path</code> before, and that alone let me add so many tilts and shapes to my website.</p>
<h2 id="it's-okay-to-be-picky">It's Okay to be Picky <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/02/03/picky-life-lists/#it's-okay-to-be-picky">#</a></h2>
<p>Whatever lists you have, remember <strong>you have limited spaces for unlimited possible items. What we control most is what we add to them and why.</strong></p>
<ol>
<li>Remember the real reasons for adding items to a list. I avoid the bullshit others try to sell me and rationalizations I sell myself.</li>
<li>This lets me know when to cut my losses on bad list items. I can avoid similar mistakes and save my time later on.</li>
<li>I should only add items if they meet strict criteria based on my tastes and values. I shouldn't be afraid to say "no" more often than "yes."</li>
</ol>
<p>This is a continuous process, and I'll get better with practice. I'm always pruning my lists to weed out bad items early. The better I am at this, the more time I have for satisfying work and play.</p>
<p>In other words, the more time I have for a more satisfying life.</p>
The Currying Introduction I Wish I Had
2021-02-16T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/02/16/currying-introduction/<p>The Currying Introduction I Wish I Had</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/currying-introduction.jpg" alt="Post featured image"></p><p>Currying is one of those JavaScript words I heard many times before I understood it. That's part of why I put in the time to figure it out. The other reason is it's fun to say.</p>
<p>But for anyone reading this who wants to understand for non-just-fun-to-say reasons, I hope you find this post useful. This is the explanation I wished I read as I was learning the basics of JavaScript.</p>
<p>If you wanted to read about the best curry recipes for Pokemon Sword and Shield, I can't help you there. All I can say is Spicy Sausage Curry always wins and you have to accept that.</p>
<h2 id="the-problem-currying-solves">The Problem Currying Solves <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/02/16/currying-introduction/#the-problem-currying-solves">#</a></h2>
<p>Most JavaScript functions operate predictably:</p>
<ol>
<li>Put in one or more arguments</li>
<li>Let the function do some stuff with those values</li>
<li>The function returns a value.</li>
<li>ALL HAIL THE MIGHTY GLOW CLOUD.</li>
</ol>
<p>A basic ES6 function to multiply two values would look like this:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">multiply</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> y</span><span class="token punctuation">)</span> <span class="token operator">=></span> x <span class="token operator">*</span> y<span class="token punctuation">;</span><br /><span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 50</span></code></pre>
<p>But suppose I needed lots of multiplication operations that were not quite the same. For example, there were groups where one number is always the same.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">22</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// All multiply by 3</span><br /><br /><span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">34</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// All multiply by 5</span><br /><br /><span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">multiply</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">999</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// All multiply by 7</span></code></pre>
<p>This works, but it’s repetitive, not too elegant, and easier to mess up (especially by folks like me). This can get unmaintainable fast as the codebase scales up.</p>
<p>This is where currying helps. I touched on currying almost <a href="https://www.maxwellantonucci.com/posts/2019/06/25/metaphorical-intro-functional-js/">two years ago when writing about functional programming</a>. But want to go into more detail here.</p>
<h2 id="so-what-is-currying%3F">So What is Currying? <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/02/16/currying-introduction/#so-what-is-currying%3F">#</a></h2>
<p>In a nutshell, currying is making a sequence of nested functions. But that wasn't clear to me at first, so here's the definition outside a nutshell.</p>
<p>Sometimes I may need to call several functions to get what I want, one after the other. Or like the above example, write one function with the same arguments. But imagine writing those functions and arguments in the same order over and over until my mind snaps again. Nobody wants this, especially the guy who has to fix my floorboards.</p>
<p><strong>Currying lets me nest those functions inside each other. Then I only need to call one, and the function calls the rest in the proper order for me.</strong> Time, energy, and sanity are saved.</p>
<p>It took a while for this to click for me. If I asked the JavaScript language to explain how this would with the above examples, I imagine it'd go like this.</p>
<h3 id="a-conversation-with-javascript-about-currying">A Conversation with JavaScript about Currying <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/02/16/currying-introduction/#a-conversation-with-javascript-about-currying">#</a></h3>
<p><strong>Coder:</strong> Look at all these multiplication functions. I could you all the arguments at once, but that's repetitive here, right? Instead, can you remember some of the arguments for me? That way when I call <code>multiply</code>, you can take the different argument.</p>
<p><strong>JavaScript:</strong> I would remember the number three...so it'd look like this?</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">multiply</span> <span class="token operator">=</span> <span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">*</span> <span class="token number">3</span><span class="token punctuation">;</span></code></pre>
<p><strong>Coder:</strong> That would work...but I also want you to remember functions for the other common multipliers: five and seven.</p>
<p><strong>JavaScript:</strong> So write those functions out too. You'll need to give them different names.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">multiplyBy3</span> <span class="token operator">=</span> <span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">*</span> <span class="token number">3</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> <span class="token function-variable function">multiplyBy5</span> <span class="token operator">=</span> <span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">*</span> <span class="token number">5</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> <span class="token function-variable function">multiplyBy7</span> <span class="token operator">=</span> <span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">*</span> <span class="token number">7</span><span class="token punctuation">;</span></code></pre>
<p><strong>Coder:</strong> That’s the result I want, but rewriting that multiplication logic feels wasteful. I want to generate different versions of that function without rewriting so much.</p>
<p><strong>JavaScript:</strong> Hey, you’re the programmer, not me. You’re supposed to figure this stuff out.</p>
<p><strong>Coder:</strong> Hmm...<em>could I a function that would make the multiplying function for me?</em> The first function is where I pass in the number I always want to multiply by. Does that one return the function that can multiply by this number?</p>
<p><strong>JavaScript:</strong> Sure, it can do that! That’ll look like this:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">multiplyCurrier</span> <span class="token operator">=</span> <span class="token parameter">y</span> <span class="token operator">=></span> <span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">*</span> y<span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> multiplyBy3 <span class="token operator">=</span> <span class="token function">multiplyCurrier</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// This is a function that multiplies the argument by three</span><br /><span class="token function">multiplyBy3</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3 * 5 = 15</span><br /><br /><span class="token keyword">const</span> multiplyBy5 <span class="token operator">=</span> <span class="token function">multiplyCurrier</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">multiplyBy5</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 25</span><br /><br /><span class="token keyword">const</span> multiplyBy7 <span class="token operator">=</span> <span class="token function">multiplyCurrier</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">multiplyBy7</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 35</span></code></pre>
<p><strong>JavaScript:</strong> Don’t forget that in this language we have "first-class functions." <strong>You can use functions as arguments, and you can have them return other functions. Here, I'm breaking a function down into a sequence of functions that each takes one argument.</strong> You can pass in each argument to construct lots of different functions with less work.</p>
<p><strong>Coder:</strong> Hooray! This looks good and I'm fulfilled at long last!</p>
<h3 id="call-many-arguments-at-once">Call Many Arguments at Once <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/02/16/currying-introduction/#call-many-arguments-at-once">#</a></h3>
<p>Currying just helped me make a bunch of multiplication functions with little repetition. I can also make more if I need to. But we can stretch currying's abilities further.</p>
<p>The above example goes two functions deep, and I only call one at a time. But I could call that <code>multipleCurrier</code> function with both arguments at once if I wanted to.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">multiplyCurrier</span> <span class="token operator">=</span> <span class="token parameter">y</span> <span class="token operator">=></span> <span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">*</span> y<span class="token punctuation">;</span><br /><span class="token function">multiplyCurrier</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 15</span></code></pre>
<p>This lets me multiply two numbers without making a new function.</p>
<p>It also lets me get more ambitious with what kinds of functions I can make. Let's say I have a function that lets me get substrings and goes three levels deep.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">curriedSubstring</span> <span class="token operator">=</span> <span class="token parameter">start</span> <span class="token operator">=></span> <span class="token parameter">length</span> <span class="token operator">=></span> <span class="token parameter">string</span> <span class="token operator">=></span> string<span class="token punctuation">.</span><span class="token function">substr</span><span class="token punctuation">(</span>start<span class="token punctuation">,</span> length<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The arguments each function in this sequence takes are:</p>
<ol>
<li>The substring's starting index</li>
<li>The substrings ending index</li>
<li>The string to pull the substring from</li>
</ol>
<p>Once it gets all these arguments, it returns the substring. So if I wanted to get a string's first character, I could call them all at once.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">curriedSubstring</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token string">'potatoes'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'p'</span></code></pre>
<p>But I can also save the first two levels into a separate function, and use it on its own like this.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">getFirstChar</span> <span class="token operator">=</span> <span class="token parameter">string</span> <span class="token operator">=></span> <span class="token function">curriedSubstring</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">(</span>string<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Note that I need to include "string" as an argument and pass it to "curriedSubstring"</span><br /><br /><span class="token function">getFirstChar</span><span class="token punctuation">(</span><span class="token string">'potatoes'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'p'</span><br /><span class="token function">getFirstChar</span><span class="token punctuation">(</span><span class="token string">'white rice'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'w'</span><br /><span class="token function">getFirstChar</span><span class="token punctuation">(</span><span class="token string">'sausages'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 's'</span></code></pre>
<p>Or I could stop at the first level, and make a function to get different numbers of starting characters.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">getStartingChars</span> <span class="token operator">=</span> <span class="token parameter">length</span> <span class="token operator">=></span> <span class="token parameter">string</span> <span class="token operator">=></span> <span class="token function">curriedSubstring</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">(</span>length<span class="token punctuation">)</span><span class="token punctuation">(</span>string<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">getStartingChars</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token string">'potatoes'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'pot'</span><br /><span class="token function">getStartingChars</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token string">'white rice'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'white'</span><br /><span class="token function">getStartingChars</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token string">'sausages'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'sausage'</span></code></pre>
<p>These all show how I can tap into this sequence of functions at different points into new functions. This lets me extend the code while only writing the underlying logic and arguments once.</p>
<h2 id="enjoy-your-curry...ing">Enjoy Your Curry...ing <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/02/16/currying-introduction/#enjoy-your-curry...ing">#</a></h2>
<p>I hope you found this post useful and watch for times you can break out the currying! Anytime there are many functions with shared logic or arguments, that's often a good sign. Even for things as simple as multiplication or getting substrings.</p>
<p>Plus I'll say it again, "currying" is just fun to say. Understanding it gives us more reason to use it in conversation. I know this, you know this, the world knows this. I know I'm not the only one who learned it mainly for this reason. No one else has admitted it yet.</p>
<p><em>Ahem</em>, regardless, <a href="https://safebooru.org/index.php?page=post&s=view&id=3090199">happy currying</a>!</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/currying-introduction/pokemon-curry.jpeg" alt="A trainer and several pokemon gathering around a freshly-made pot of curry." /></p>
Hades and my Two Types of Failure
2021-03-01T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/03/01/hades-types-of-failure/<p>Hades and my Two Types of Failure</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/hades-failure.jpg" alt="Post featured image"></p><p>Last week, I got Hades for the Switch. It's a game about many things - escaping Hell, family dysfunction, maid puns, illicit drink sharing, the goddess Demeter's Titan-killing boxing gloves, fishing, and the usual. <strong>Most of all, it's about <s>romancing Death personified</s> failure.</strong></p>
<p>I'm up to almost twenty failed escape attempts so far. To be clear with the world and/or rabid fandom, I love the game and <em>accept</em> how failure is a core mechanic to move it forward. But after a Saturday session fueled by hard cider, I saw my escape attempts fell into two categories:</p>
<ol>
<li><strong>Runs I intended to fail from the start.</strong> These were to farm items, improve my fighting technique, or wielding the Infernal Arms to relive pre-pandemic boxing classes and bash in my enemies' heads with joy. These are the fun runs, where I'm laughing and making snide comments about Artemis' crush on Zagreus. I'd also speculate about Dionysus' weekend parties and where Gods draw the line between a party being "fun" and "utterly fucked up." They're the likely cause of all our crazy weather lately.</li>
<li><strong>Runs where I seriously aimed to escape.</strong> In these, I'm trying to get further than my last run. It's to a new area or past that damn pair of Asterius the minotaur and Theseus the do-gooder prick. But my mindset goes a full 180 degrees - I'm tense, anxious, and not having much fun. Once I procrastinated for a whole day right outside the Bone Hydra's chambers. I worried I'd somehow slip up and was sweating like crazy by the lava. In these runs, dying without getting further is unforgivable and almost ruins my day. Turning Skelly to dust over and over only helps so much, you know?</li>
</ol>
<p>I saw this difference after my last escape attempt. I beat a new boss and got through the next area on my first try. I was half a health bar away from beating the final boss but died. By all accounts, this should have thrilled me. Instead, I felt miserable. I planned to stick with "planned failure" runs for a while. At least until I got the mental strength together for another real attempt.</p>
<p>So I asked myself: why couldn't I do a serious run and still have fun? Doesn't having so many "planned failure" runs limit my improvement? After all, <strong>it's hard to get better each time when I'm holding myself back from the pain (and progress) of another failure. Especially in a game where, like in life, failure is often the best way forward.</strong></p>
<p>Why shouldn't I start aiming for that third type of failure?</p>
<h2 id="embracing-unplanned-failure">Embracing Unplanned Failure <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/03/01/hades-types-of-failure/#embracing-unplanned-failure">#</a></h2>
<p>When I got Hades, part of me thought of my birthday resolution to fail more. It could be an enjoyable way to get more comfortable with failure, along with throwing around Zeus' lightning and breaking hearts as only Aphrodite can. Instead, I found a way my mind maintains its fear of failure. Even if I experience that fear as anxiety over rematches with a relentless ax-swinging minotaur giving me nightmares.</p>
<p><strong>But seeing this fear of failure in a clearer form can help me start to overcome it.</strong> That alone is something to be thankful for. Well, along with the fun hours of backstabbing Wretched Louts.</p>
<p>So, Theseus and Asterius, get ready. I won't always make it to you, and I'll beat you even less often. But I'll at least be serious and try to get there more often.</p>
<p>Except for Tisiphone. Keep that murderous Fury far away from me.</p>
What Makes Zagreus a Good Man?
2021-04-07T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/04/07/zagreus-good-man/<p>What Makes Zagreus a Good Man?</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/zagreus-good-man.jpg" alt="Post featured image"></p><p>Hades has helped pass more time than I could ever imagine while sheltering in place. I now need to stop myself from wasting more hours giving Ambrosia and smashing up things with the Aspect of Gilgamesh. Between the fun action and the great storytelling, I have few regrets.</p>
<p>This game has also made me think, not only about my harmful views of failure, but about character. The protagonist Zagreus's character has been well-received, with folks admiring his endless determination and mischievous nature. But I wondered: what fundamental traits make up this good character? What makes him not only a great lead, but also a good man?</p>
<p>I brooded over this as I kept playing. By escape attempt 44, I had some ideas along with a new 11 escape winning streak.</p>
<p><strong>Be warned, this post contains some game spoilers!</strong></p>
<h2 id="he's-respectful-by-default">He's Respectful By Default <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/07/zagreus-good-man/#he's-respectful-by-default">#</a></h2>
<p>Zagreus is the prince of the Underworld, so almost everyone he meets is "below" him. But you wouldn't know that from how he talks to them. He treats everyone with kindness and respect.</p>
<p>At least at first.</p>
<p>One good example is Sisyphus, the famed prisoner doomed to forever try pushing a boulder up a hill. From the start, Zagreus address Sisyphus as "sir" and he thanks him for his aid, even though he's a prisoner. Even after learning Sisyphus's dark past, he cares more about his good character now. Zagreus can even work to free him from his eternal punishment.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/zagreus-good-man/sisyphus.png" alt="Zagreus learning of Sisyphus' dark past and saying he still sees him as a gentleman." /></p>
<p>But Zagreus isn't a pushover, so this respect isn't unconditional. When he first meets Theseus, famed champion of Elysium, he admires and feels honored to fight him. This changes a second later when he reveals he's a trash-talking, egotistical blowhard. That's when Zagreus drops the respect and talks to him the way I imagine most of us would.</p>
<p>This is hilarious as Theseus is a douche and deserves to be crushed each time. I don't know why Asterius puts up with it.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/zagreus-good-man/theseus-jerk.png" alt="Zagreus, after learning Theseus is an idiot, commenting on how he beat him last time." /></p>
<p>Zagreus only stops his respect for others when he knows from experience they're not worthy of it. That's different than assuming they don't deserve it based on what other people, society, or one's prejudices say about them. <strong>Unless proven otherwise, everyone deserves basic human decency and respect.</strong></p>
<h2 id="he-doesn't-feel-entitled-to-others'-feelings">He Doesn't Feel Entitled to Others' Feelings <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/07/zagreus-good-man/#he-doesn't-feel-entitled-to-others'-feelings">#</a></h2>
<p>Two characters Zagreus can romance are...</p>
<ol>
<li>Megaera, a Fury tasked with whipping liars and deceivers for eternity. Before you ask, yes, there are whipping jokes. Hell doesn't kink shame and neither should you!</li>
<li>Dusa, a floating Gorgon head acting as the house's maid. It's both quirky comic relief and a lame pun.</li>
</ol>
<p>That's a lot to process if you haven't played the game before, so I'll give you a moment...all set? Good!</p>
<p>When romancing Megaera, at one point he says he still has romantic feelings for her. Megaera says she doesn't know if she can return them. Zagreus's response? He's upset, but accepts her response and gives her space. His response stays that way after future gifts as well.</p>
<p>With Dusa, the floating Gorgon head later turns him down. Zagreus accepts her decision and is genuinely happy they can stay good friends. But if Dusa wanted to distance herself from him, for a while or for good, it looks like he'd have accepted that too.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/zagreus-good-man/dusa-meeting.png" alt="Zagreus accepting Dusa's decision to remain friends." /></p>
<p>In both cases, Zagreus doesn't try to convince or gaslight them into feeling any different. He doesn't say they owe him affection (or anything physical, whatever that'd mean in Dusa's case) in return for his gifts. <strong>He acts based on his feelings, but still accepts others' feelings as they are.</strong> There no anger or bitterness over not getting what he wanted - he's thankful for what he has with them. Whether it's friendship or romance, any close bond you have with someone still has value.</p>
<h2 id="he-shows-his-gratitude">He Shows his Gratitude <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/07/zagreus-good-man/#he-shows-his-gratitude">#</a></h2>
<p>Gratitude is so important to Zagreus, it's a gameplay mechanic. Major and minor story events rely on building good relationships with characters. These thanks range from giving him powerful skills, helpful items, or being fun to be around.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/zagreus-good-man/chaos-thanks.jpg" alt="Zagreus giving Chaos a small offering as thanks for his help." /></p>
<p>For most of these gifts, you get nothing in return. Zagreus gives a gift, tells the person why, and the person/creature/God accepts it. He's not thanking him for specific times so he no longer "owes" them. <strong>He shows his gratitude for a person's presence without making it transactional.</strong> Sometimes, we're simply glad to have them in our lives and want them to know.</p>
<h2 id="he-accepts-all-parts-of-himself">He Accepts all Parts of Himself <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/07/zagreus-good-man/#he-accepts-all-parts-of-himself">#</a></h2>
<p>The above sections are about Zagreus' thoughtful and caring qualities. But let's not forget how violent he is. Most of your time playing is killing spirits of sinners, monsters, and lost heroes. His killing streak amazes the God of War himself, and that man has seen it all...literally. His usual bonding activity with his Dad (and even one of his potential lovers) is fighting them to the death. All parties involved find it fun, as one does.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/zagreus-good-man/hades-fight.jpg" alt="Zagreus chatting with his father before they fight to the (sort of) death." /></p>
<p>Instead of feeling shame for his violent nature, he finds the right place for it. That place is fighting his way out of the underworld, for his family, and later for his job. Most of all, Zagreus doesn't let it seriously damage any of his relationships. He's not going to slice anyone up for some small slight, like mocking his height or laughing at how a rodent killed him.</p>
<p>The point is, Zagreus accepts his physical, violent nature as part of his genuine self. But he doesn't let that side of him destroy the others. <strong>He finds a balance, takes responsibility for who he is, and focuses on the good each one can do.</strong> He can be a good man without denying who he is.</p>
<h2 id="wrapping-up">Wrapping Up <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/07/zagreus-good-man/#wrapping-up">#</a></h2>
<p>There's no shortage of fake (or real) male characters relying on damaging qualities. These are qualities like toxic masculinity, extreme aggression, or overt entitlement. So finding one that's strong without any of those is refreshing. American culture needs a whole lot more of this.</p>
<p>Here's hoping that more men, in games, movies, and reality, can rise up on character qualities like these. Escaping Hell and sticking it to the King of the Underworld is nice, but not required. It's more about not being a jerk, which is much easier. Let's all give it a try if we haven't yet!</p>
The Pros and Cons of my First Virtual Conference
2021-04-21T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/<p>The Pros and Cons of my First Virtual Conference</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/pros-cons-virtual-conference.jpg" alt="Post featured image"></p><p>Last week was Rails Conf 2021, a gathering of coders, senior and newbie, to talk about the most popular Ruby web framework around. Of course, the coronavirus means I'm using the word "gathering" with some sarcasm. We gathered the same way family members have been chatting on Zoom. There were awkward moments, shaky lighting, and we hoped everyone was wearing pants.</p>
<p>While I focus on the front-end, I've worked with Rails plenty at my current job and quite enjoy it. So I was looking forward to learning about new and old offerings, from Hotwire to service objects. It was also my first virtual conference, as I'm guessing was the case for many people there. It wasn't one of those MMORPG (massively multiple online role-playing game) virtual conferences I've drooled over. But I'm holding out hope for trying one someday!</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">About to do a workshop at <a href="https://twitter.com/DotNextConf?ref_src=twsrc%5Etfw">@DotNextConf</a> - the conferb ence is an online one, but those awesome folks have created a MMORPG style virtual conference where you can walk around and interact with people! How cool is that?!<a href="https://t.co/fwn89k1Za1">https://t.co/fwn89k1Za1</a> <a href="https://t.co/QUuRcCiWeO">pic.twitter.com/QUuRcCiWeO</a></p>— Michael Yarichuk (@Myarichuk) <a href="https://twitter.com/Myarichuk/status/1334842466722312194?ref_src=twsrc%5Etfw">December 4, 2020</a></blockquote>
<p>In the meantime, <strong>I thought I'd mull over the pros and cons of my first virtual conference. To save you some time, it was good!</strong> There were drawbacks, but it's nothing the organizers can't fix next time. Plus, that doesn't mean virtual conferences can't work for everyone. I'm hoping this post can help people on the fence of whether or not to try out one themselves.</p>
<h2 id="the-pros-of-virtual-conferences">The Pros of Virtual Conferences <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#the-pros-of-virtual-conferences">#</a></h2>
<h3 id="no-logistical-anxieties">No Logistical Anxieties <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#no-logistical-anxieties">#</a></h3>
<p>For any conference out of state, I'd be thinking less about what I'd learn and more about how I'd get there. This included plane travel, cars, hotels, meals, and any secret hideaways. The less mental energy I had for the talks, the less knowledge I took away from them. That seems to defeat the purpose of going at all.</p>
<p>This time, all I had to do was log onto a different website in the morning. <strong>I could focus all my energy on what talks to watch, and any live events that day.</strong></p>
<p>The biggest perk to this is it opens up the conference for many more people. They're less likely to be blocked by distance, money, or a lack of access to time travel.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I had always wanted to attend Rails Conf but could never afford the ticket and all the other travel expenses. This year it is remote and thus more affordable. I'd like to thank <a href="https://twitter.com/guavasoftware?ref_src=twsrc%5Etfw">@guavasoftware</a> for purchasing my ticket! 🙌<a href="https://twitter.com/hashtag/RailsConf2021?src=hash&ref_src=twsrc%5Etfw">#RailsConf2021</a> <a href="https://t.co/AuRrQ39TQB">pic.twitter.com/AuRrQ39TQB</a></p>— Filipe W. Lima (@filipewl) <a href="https://twitter.com/filipewl/status/1381734270931177473?ref_src=twsrc%5Etfw">April 12, 2021</a></blockquote>
<p>People from 61 different countries wound up attending Rails Conf, compared to 40 at the last one. That's a 50% country-wide increase across the globe.</p>
<h3 id="no-frantic-note-taking">No Frantic Note-Taking <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#no-frantic-note-taking">#</a></h3>
<p>I can't count the number of times I took notes at a talk so fast, it was more stressful than my actual job (okay, it's at least 47 times). I was so worried about missing the info I'd traveled so far to hear, I couldn't take in or analyze it. Video recordings afterward varied in quality, and I rarely had time to watch them after. So I was so anxious about getting it all written down, I often got high school social studies class flashbacks. Make it stop, Byzantine Empire and Communist Russia!</p>
<p>That's why being able to pause and rewind talks was a Godsend. <strong>I could watch at my own pace and note down any important info with a sense of ease. I felt I learned more and kept my heart rate that much lower.</strong> The videos even had decent closed caption support!</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Shout out to <a href="https://twitter.com/hashtag/RailsConf2021?src=hash&ref_src=twsrc%5Etfw">#RailsConf2021</a>'s closed-captioning service!<br /><br />My talk about Talmudic Gems For Rails Developers naturally contained many Hebrew and Aramaic names/phrases and I was prepared for them to be butchered by the captions. But they actually did a great job! <a href="https://t.co/fqyfefRstL">pic.twitter.com/fqyfefRstL</a></p>— Yechiel (@yechielk) <a href="https://twitter.com/yechielk/status/1381777042644078595?ref_src=twsrc%5Etfw">April 13, 2021</a></blockquote>
<h3 id="you-can-scale-your-involvement">You Can Scale Your Involvement <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#you-can-scale-your-involvement">#</a></h3>
<p>What do I hate most about in-person conferences? It's meals at the conference location, hands-down. I wiped my hands clean of "who do I sit with at lunch" worries after high school, and I don't want them back now. Therapy is expensive enough.</p>
<p>That's not to say there weren't ways to socialize. The conference Discord had channels for talks, Q&A, and many casual and networking chats. But it was easy to join or avoid them at whatever level I was comfortable with. I looked into a few familiar channels to see if I could contribute. I checked some less familiar ones out of curiosity but didn't feel bad by only looking.</p>
<p>One workshop I went to had paired activities in breakout Zoom rooms. I wasn't comfortable with this, but it was easy to decline to enter them as I waited for the others to finish. <strong>A virtual setting is great for setting and following your social boundaries. All without much of the fear or awkwardness of an in-person setting.</strong></p>
<p>Another perk of this is I could work other important tasks into my schedule with ease. I took one afternoon after watching one talk to give a company talk on web accessibility. One attendee was able to go to their daughter's birthday and make a family dinner without missing a beat.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Pro #6: prepare dinner while watching <a href="https://twitter.com/eileencodes?ref_src=twsrc%5Etfw">@eileencodes</a>'s keynote.<a href="https://twitter.com/hashtag/RailsConf2021?src=hash&ref_src=twsrc%5Etfw">#RailsConf2021</a> <a href="https://t.co/iuOkLU09UG">pic.twitter.com/iuOkLU09UG</a></p>— Yechiel (@yechielk) <a href="https://twitter.com/yechielk/status/1382379815857176579?ref_src=twsrc%5Etfw">April 14, 2021</a></blockquote>
<p>Now <em>this</em> is work-life balance badassery.</p>
<h3 id="no-conference-talk-fomo">No Conference Talk FOMO <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#no-conference-talk-fomo">#</a></h3>
<p>Unlike my frantic note-taking, I can count the number of times I wanted to leave after a talk started, and it's still a lot. To be clear, it's not because the talks were bad, but that I misunderstood the focus or level of expertise. But I couldn't just walk out, so I'd be stuck for around an hour. In the meantime, I'd be thinking of the <em>other</em> talk at that same time, and what valuable info I must've been missing.</p>
<p>On the other, virtual hand, when this realization hits, I can stop the video and click another link. <strong>No one's feelings get hurt, minimal time gets wasted, and there are no painful talk sacrifices.</strong></p>
<p>This happened with <a href="https://www.railsconf.com/program/sessions#session-1110">one Rails talk about a case study for an app that talked to the New York Stock Exchange</a>. After ten minutes, I saw the details were going over my head and the focus was much different than I expected. Instead of squirming for 45 minutes, I clicked over to the web accessibility talk. FOMO avoided.</p>
<h3 id="there's-still-photos-to-be-had">There's Still Photos to be Had <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#there's-still-photos-to-be-had">#</a></h3>
<p>All conferences I've been to were at least partially about big crowds and famous selfies. That's harder to pull off when virtual, but it's not impossible with some creativity and a sense of humor.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I had a lot of fun running the Debugging Your Brain workshop at <a href="https://twitter.com/hashtag/RailsConf2021?src=hash&ref_src=twsrc%5Etfw">#RailsConf2021</a> just now - thank you all for participating so actively!! <a href="https://t.co/M1cuDAtzPK">pic.twitter.com/M1cuDAtzPK</a></p>— Casey Watts! (@heycaseywattsup) <a href="https://twitter.com/heycaseywattsup/status/1381685915534381063?ref_src=twsrc%5Etfw">April 12, 2021</a></blockquote>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Got a selfie with <a href="https://twitter.com/tenderlove?ref_src=twsrc%5Etfw">@tenderlove</a> at <a href="https://twitter.com/railsconf?ref_src=twsrc%5Etfw">@railsconf</a> <a href="https://twitter.com/hashtag/RailsConf2021?src=hash&ref_src=twsrc%5Etfw">#RailsConf2021</a> <a href="https://t.co/lR6ggZGHgb">pic.twitter.com/lR6ggZGHgb</a></p>— Eileen M. Uchitelle (@eileencodes) <a href="https://twitter.com/eileencodes/status/1382817738993848323?ref_src=twsrc%5Etfw">April 15, 2021</a></blockquote>
<p>Plus if you miss your chance, it's easy to photoshop two images together and say you chatted with them on Zoom! So everybody wins in the end.</p>
<h2 id="the-cons-of-virtual-conferences">The Cons of Virtual Conferences <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#the-cons-of-virtual-conferences">#</a></h2>
<h3 id="it-takes-even-more-focus">It Takes Even More Focus <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#it-takes-even-more-focus">#</a></h3>
<p>It's good to have so many Discord channels around talks, groups, and interests. The drawback? That's a <em>lot</em> of channels to keep track of. I couldn't count them all, which made it harder to find the ones best suited for me. It's overwhelming when the "unread channels" pile up and the app says I'm behind on dozens of chats.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">1 year of remote conferences and I’m still struggling with organising myself on Discord servers although I have a 15 year old gamer 10 feet away from me who probably knows everything. I should really ask for a teaching session. Before the next conference, I guess. <a href="https://twitter.com/hashtag/RailsConf2021?src=hash&ref_src=twsrc%5Etfw">#RailsConf2021</a></p>— Vera #klimastreik (@VeraCologne) <a href="https://twitter.com/VeraCologne/status/1381908130511130625?ref_src=twsrc%5Etfw">April 13, 2021</a></blockquote>
<p>By the end of day three, I was feeling the drain. I felt as exhausted as I would at an in-person conference. Try and imagine how this would be for someone with an attention disorder like ADHD.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">It's weird, even with a virtual conference, as it winds down I'm feeling the exhaustion set in. I feel good yet overloaded and just want to sleep. <a href="https://twitter.com/hashtag/RailsConf2021?src=hash&ref_src=twsrc%5Etfw">#RailsConf2021</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1382783676795215890?ref_src=twsrc%5Etfw">April 15, 2021</a></blockquote>
<p><strong>If there were a way to decide on your channels in advance, or at least get a list of recommendations, it would go a long way.</strong> Discord can mute channels or change their update settings, but doing this one at a time for dozens is a massive burden for attendees. Some way to help or do this automatically would save a lot of wasted mental energy.</p>
<p>The good news is the virtual format makes it easy to rest along the way as needed. For most attendees, their bed or couch was in the next room for nap purposes. Even if they couldn't sleep, it's easy to walk away, escape the hectic activity, and recharge from the conference.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Getting some rest before tonight's <a href="https://twitter.com/tenderlove?ref_src=twsrc%5Etfw">@tenderlove</a> keynote at <a href="https://twitter.com/hashtag/RailsConf2021?src=hash&ref_src=twsrc%5Etfw">#RailsConf2021</a> <a href="https://t.co/T1N5BXuRLu">pic.twitter.com/T1N5BXuRLu</a></p>— iridakos (@lazaru_s) <a href="https://twitter.com/lazaru_s/status/1382759293066358789?ref_src=twsrc%5Etfw">April 15, 2021</a></blockquote>
<p>If you have a sleeping cat, well, that's a bonus.</p>
<h3 id="videos-are-the-main-medium">Videos are the Main Medium <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#videos-are-the-main-medium">#</a></h3>
<p>All the conference talks are in video format, so <strong>if learning via video isn't your thing, you were going to have a bad time.</strong> I am one of those people, I'm sad to write. I've tried video courses in the past, but something about them never fails to make me drowsy, no matter the topic. Last week, I realized this had not changed.</p>
<p>This meant I had to pace myself a lot. I had to space videos out and move around to keep the lethargy away. This way I could focus on videos earlier in the day to avoid the afternoon slump. Otherwise, I'd get so tired I couldn't take notes or keep info, and often had to nap the fatigue away. Even then, watching too many more videos would <em>still</em> make me sleepy.</p>
<p>Text transcripts of talks could make this easier in the future. Reading makes me less sleepy since I can play energetic music as I go. It's also easier to go along at a pace that keeps my mind engaged, instead of drifting off at a speaker's slower pace. But that's increasing an already heavy load on the people giving the talks, so I get that it can't always be included.</p>
<h3 id="still-a-weaker-sense-of-community">Still A Weaker Sense of Community <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#still-a-weaker-sense-of-community">#</a></h3>
<p>Zoom and Discord helped everyone chat, but I can't deny it's not the same as being in-person. <strong>It's hard to get the same sense of community, career comradery, or sudden web celebrity meetings.</strong></p>
<p>We could still chat with these people and ask questions. One could argue the digital format makes it easier to get answers from them. People can read and respond at their own pace instead of fielding them from a huge crowd in one cramped session. But there's no thrill of meeting them in the flesh.</p>
<p>One of my highlights from CodeNewbie was meeting Jen Simmons. She's a CSS industry leader, the front-end equivalent of meeting Zooey Deschanel (or some other celebrity, I'm clueless about them so please don't hurt me over this comparison). I'm worried virtual conferences will take away these chance meetings for our selfie collages.</p>
<h3 id="less-swag">Less Swag <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#less-swag">#</a></h3>
<p>This is more of a petty criticism, but I miss the swag bag. <strong>I miss getting a conference badge, developer socks, and more laptop stickers than I could ever use.</strong> Some developers received stickers in the mail, but it's not the same as everyone gawking at them together.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">RailsConf stickers are starting to be delivered! Get yours now: <a href="https://t.co/j4ERdxwJh7">https://t.co/j4ERdxwJh7</a> (remote for scale. Top is 3x3, bottom 4x4) /cc <a href="https://twitter.com/railsconf?ref_src=twsrc%5Etfw">@railsconf</a> <a href="https://twitter.com/hashtag/RailsConf2021?src=hash&ref_src=twsrc%5Etfw">#RailsConf2021</a> <a href="https://t.co/cTHsZLrpb8">pic.twitter.com/cTHsZLrpb8</a></p>— Mx. Evan Phoenix 💉⏳ (@evanphx) <a href="https://twitter.com/evanphx/status/1382494340648357896?ref_src=twsrc%5Etfw">April 15, 2021</a></blockquote>
<p>My CodeNewbie command line socks are getting lonely, people. They need friends in the form of Ruby or Octocat socks! I urge you, world, to find your compassion for my lonely socks!</p>
<h2 id="in-conclusion">In Conclusion <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/04/21/pros-cons-first-virtual-conference/#in-conclusion">#</a></h2>
<p>I'd call my Rails Conf 2021 experience a success. There are some elements I need more time to adjust to, like how I pace all the video talks, but I can try that at the next one. I also learned the most important lesson: <strong>get someone sweet and something alcoholic to end things on a high note!</strong></p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Today, we've been reflecting on the incredible Workshops, talks, Keynotes and more that took place at <a href="https://twitter.com/hashtag/RailsConf2021?src=hash&ref_src=twsrc%5Etfw">#RailsConf2021</a> and we're thankful for all who attended! See you next year!</p>— RailsConf (@railsconf) <a href="https://twitter.com/railsconf/status/1383199768495591428?ref_src=twsrc%5Etfw">April 16, 2021</a></blockquote>
<p>With that in mind, while I hope there's soon less need for virtual conferences, I look forward to any I can attend. They don't <em>need</em> to be MMORPG conferences, but a man can dream.</p>
How to Make an Anime Quote Maker More Awesome
2021-08-20T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/08/20/quote-maker-updates/<p>How to Make an Anime Quote Maker More Awesome</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/quote-maker-awesome.png" alt="Post featured image"></p><p>One of my favorite side projects has been my anime quote maker. One reason is, months after making it, I'm still using it to make random art for wallpapers and pull requests. It only takes about two minutes to make something like this:</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/anime-quote-maker-awesome/quote-lead.png" alt="A quote about the marvelous aspects of nature paired with a supernatural drawing someone floating in a colorful background." /></p>
<p>Another reason is there are many ways for me to get back into and improve it. It keeps my React skills (somewhat) fresh while giving me new ways to improve its potential art.</p>
<p>I made a few of these small but useful changes last week , and I still have more I want to do! But I figured it couldn't hurt to blog about some of the first changes and how they'll help.</p>
<h2 id="more-color-control">More Color Control <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/20/quote-maker-updates/#more-color-control">#</a></h2>
<p>My quote maker makes two random hex color codes for the text and background. The code uses a function I wrote to generate hex codes on the light or dark ends of the spectrum. This gives me randomness as well as proper contrast.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> lightColor <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">randomColorCode</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> darkColor <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">randomColorCode</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'F'</span><span class="token punctuation">,</span> <span class="token string">'E'</span><span class="token punctuation">,</span> <span class="token string">'D'</span><span class="token punctuation">,</span> <span class="token string">'C'</span><span class="token punctuation">,</span> <span class="token string">'B'</span><span class="token punctuation">,</span> <span class="token string">'A'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>I made two big changes to how these colors are set up.</p>
<p>First, <strong>I flipped the variable names.</strong> Until now, I hadn't noticed that the darker color got saved to <code>lightColor</code> and vice versa. Which is more of an embarrassing slip than a bug.</p>
<p>Second, <strong>I cut away the hex characters closer to the middle of the spectrum.</strong> I noticed many color pairings had enough contrast but were still tough to read. This makes fewer generated combinations possible, but the ones it makes have enough contrast.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> lightColor <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">randomColorCode</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'F'</span><span class="token punctuation">,</span> <span class="token string">'E'</span><span class="token punctuation">,</span> <span class="token string">'D'</span><span class="token punctuation">,</span> <span class="token string">'C'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> darkColor <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">randomColorCode</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span></code></pre>
<p>Another thing that bothered me was what I wanted for foreground or background colors. I'd often want one with a light background but kept getting a dark one, or vice versa. It was frustrating when I liked the colors, but switching them myself was too much of a pain.</p>
<p>To solve this, I only needed a function to swap the two colors.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function-variable function">flipColorCodes</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">textColor</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>bgColor<span class="token punctuation">,</span><br /> <span class="token literal-property property">bgColor</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>textColor<br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><br /><span class="token punctuation">}</span></code></pre>
<p>I passed this into a new button in the UI and it worked perfectly. Color me surprised that I still remember React's basics this well.</p>
<h2 id="updating-the-quote-size">Updating the Quote Size <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/20/quote-maker-updates/#updating-the-quote-size">#</a></h2>
<p>I have two goals for changing how I adjust the size of the quote itself:</p>
<ol>
<li>Use slider inputs for a more intuitive way to change the values.</li>
<li>Have some preset sizes for quick checks of what works best.</li>
</ol>
<p>Before the update, functions to update the width and height only worked when passed to inputs. They take the input event and pull out the typed value.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function-variable function">updateWidth</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">width</span><span class="token operator">:</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function-variable function">updateHeight</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">height</span><span class="token operator">:</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>But I want them to also work when connected to button clicks. So they need to check if they're given an input event or not, and either uses that or a regular argument's value.</p>
<p><strong>I can do this with a simple ternary check.</strong> This is much shorter than my first version that passed an extra "is this custom?" argument that added almost ten extra lines (and far less painful to read).</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function-variable function">updateWidth</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">width</span><span class="token operator">:</span> e<span class="token punctuation">.</span>target <span class="token operator">?</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token operator">:</span> e <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function-variable function">updateHeight</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">height</span><span class="token operator">:</span> e<span class="token punctuation">.</span>target <span class="token operator">?</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token operator">:</span> e <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="change-inputs-from-numbers-to-ranges">Change Inputs from Numbers to Ranges <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/20/quote-maker-updates/#change-inputs-from-numbers-to-ranges">#</a></h3>
<p>The old inputs for changing the quote size were basic number inputs.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span><span class="token punctuation">></span></span><span class="token plain-text"><br /> Width:<br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>width<span class="token punctuation">}</span></span> <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>updateWidth<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token plain-text"><br /></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span></code></pre>
<p>This lets me set the dimensions, but only if I knew the exact size I wanted. But more often, I was making one larger or smaller without a specific number in mind. I just went until the size was a good fit for the image. This made resizing quotes a tedious chore.</p>
<p>But the glory of HTML is <strong>it has a native range input already!</strong> I was worried I'd go down a rabbit hole of importing a React component, but there was no need. I only had to link the same variables and functions to the markup. This includes setting the value ranges, adding classes, and showing users the width.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>qig-l-slider__label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span><span class="token plain-text"><br /> Width: </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>width<span class="token punctuation">}</span><span class="token plain-text"> pixels</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span><span class="token plain-text"><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span><span class="token plain-text"><br /><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>range<span class="token punctuation">"</span></span> <span class="token attr-name">min</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>300<span class="token punctuation">"</span></span> <span class="token attr-name">max</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1200<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>width<span class="token punctuation">}</span></span> <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>updateWidth<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token plain-text"><br /></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span></code></pre>
<p>Intuitive quote sizing GET!</p>
<h3 id="creating-preset-quote-sizes">Creating Preset Quote Sizes <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/20/quote-maker-updates/#creating-preset-quote-sizes">#</a></h3>
<p>Now I want to add those buttons for preset quote sizes. They're the whole reason I updated those functions, after all. I needed a button click to call both <code>updateHeight</code> and <code>updateWidth</code>.</p>
<p>I was glad I didn't need to create separate functions to call them both, then pass them to the button elements. But that would mean having my stateless "change size" component do more than hold markup. I want to keep it as simple and stupid as possible.</p>
<p>But as it turns out, <strong>you can pass many functions to a button's <code>onClick</code> event with no problem.</strong> I only had to put both of them in an anonymous function. This makes adding, editing, and removing preset sizes easy.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token plain-text"><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token function">updateHeight</span><span class="token punctuation">(</span><span class="token number">700</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">updateWidth</span><span class="token punctuation">(</span><span class="token number">700</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br /> Square<br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span><span class="token plain-text"><br /><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token function">updateHeight</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">updateWidth</span><span class="token punctuation">(</span><span class="token number">800</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br /> Landscape<br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span><span class="token plain-text"><br /><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token function">updateHeight</span><span class="token punctuation">(</span><span class="token number">800</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">updateWidth</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br /> Portrait<br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span><span class="token plain-text"><br /><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token function">updateHeight</span><span class="token punctuation">(</span><span class="token number">667</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">updateWidth</span><span class="token punctuation">(</span><span class="token number">375</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br /> iPhone 8<br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span><span class="token plain-text"><br /></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>You may ask why I added the iPhone 8 and nothing else. It's because that's my phone model, and I have no illusions that few others (if any others) use this app. So I'll save adding any other device sizes for when I get any requests for them. You can send any requests to me via Twitter, Github, or puppy-based mail delivery service.</p>
<p>I also updated the quote maker's image alignment and font size UI. Now they use range inputs since I also use my intuition to change them until they fit the image. But those changes were the same as the ones for the sizes, so I won't go into detail.</p>
<p>Instead, to the biggest change of this post!</p>
<h2 id="quote-position-control">Quote Position Control <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/20/quote-maker-updates/#quote-position-control">#</a></h2>
<p>This is where my updates started to get complicated. I wanted to let users have precise control over where the quote gets placed on an image. As in, pixel-by-pixel adjustments in any direction.</p>
<h3 id="setting-up-absolute-positioning">Setting up Absolute Positioning <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/20/quote-maker-updates/#setting-up-absolute-positioning">#</a></h3>
<p>The old version used CSS Grid with some pre-written classes to control the location. This was easy to manage since I only needed to change one class was being added to the quote wrapper. But this limited it to about a dozen or so layout options. I could add more, but Grid could never give me the precise control I wanted. <strong>So I needed to use absolute positioning and inline styles.</strong></p>
<p>I was actually already adding inline styles to the quote for text alignment and color. So I moved a few <code>div</code> elements around to remove the Grid wrapper and added more inline styles for the positioning.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> quoteStyle <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token comment">// New ones!</span><br /> <span class="token string-property property">'top'</span><span class="token operator">:</span> <span class="token function">isNaN</span><span class="token punctuation">(</span>top<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">'auto'</span> <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>top<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">px</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br /> <span class="token string-property property">'right'</span><span class="token operator">:</span> <span class="token function">isNaN</span><span class="token punctuation">(</span>right<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">'auto'</span> <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>right<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">px</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br /> <span class="token string-property property">'bottom'</span><span class="token operator">:</span> <span class="token function">isNaN</span><span class="token punctuation">(</span>bottom<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">'auto'</span> <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>bottom<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">px</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br /> <span class="token string-property property">'left'</span><span class="token operator">:</span> <span class="token function">isNaN</span><span class="token punctuation">(</span>left<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">'auto'</span> <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>left<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">px</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br /><br /> <span class="token comment">// Old ones</span><br /> <span class="token string-property property">'textAlign'</span><span class="token operator">:</span> alignment<span class="token punctuation">,</span><br /> <span class="token string-property property">'fontSize'</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>size<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">px</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br /> <span class="token string-property property">'fontFamily'</span><span class="token operator">:</span> fontFamily<span class="token punctuation">,</span><br /> <span class="token string-property property">'backgroundColor'</span><span class="token operator">:</span> bgColor<span class="token punctuation">,</span><br /> <span class="token string-property property">'color'</span><span class="token operator">:</span> textColor<br /><span class="token punctuation">}</span></code></pre>
<p>You may ask why I need the not a number (<code>isNaN</code>) checks there. That's because I often don't want to set the absolute positions for all four sides. <strong>So if I want the quote to start at the top and flow down naturally, I can't have any bottom position values.</strong> This makes it so <code>bottom</code> goes to <code>auto</code> and gives the layout effect I want.</p>
<p>So the quote box is ready to accept some absolute values. The hard part is bringing them to it.</p>
<h3 id="adding-sliders-for-the-quote-position">Adding Sliders for the Quote Position <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/20/quote-maker-updates/#adding-sliders-for-the-quote-position">#</a></h3>
<p>The quote maker will need to track these different position values, so adding them is a good place to start. I added these to the quote maker's state with some default values. These are saved in a separate file (there's a lot of states to manage, no surprise), so I'll only list their names and values.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token literal-property property">quoteTop</span><span class="token operator">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span><br /><span class="token literal-property property">quoteRight</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br /><span class="token literal-property property">quoteBottom</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br /><span class="token literal-property property">quoteLeft</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span></code></pre>
<p>The quote maker also needs some basic functions to manage them. These are the same as the updater functions I edited for the quote positions. They should work with both input and direct values.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function-variable function">updateQuoteTop</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">quoteTop</span><span class="token operator">:</span> e<span class="token punctuation">.</span>target <span class="token operator">?</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token operator">:</span> e <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function-variable function">updateQuoteRight</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">quoteRight</span><span class="token operator">:</span> e<span class="token punctuation">.</span>target <span class="token operator">?</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token operator">:</span> e <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function-variable function">updateQuoteBottom</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">quoteBottom</span><span class="token operator">:</span> e<span class="token punctuation">.</span>target <span class="token operator">?</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token operator">:</span> e <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function-variable function">updateQuoteLeft</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">quoteLeft</span><span class="token operator">:</span> e<span class="token punctuation">.</span>target <span class="token operator">?</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token operator">:</span> e <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now I have these values and the functions for updating them. Next I need to pass them (and a few others) to the <code>Position</code> component. It holds the UI for viewing and changing them.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Position</span></span><br /> <span class="token attr-name">quoteTop</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>quoteTop<span class="token punctuation">}</span></span><br /> <span class="token attr-name">quoteRight</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>quoteRight<span class="token punctuation">}</span></span><br /> <span class="token attr-name">quoteBottom</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>quoteBottom<span class="token punctuation">}</span></span><br /> <span class="token attr-name">quoteLeft</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>quoteLeft<span class="token punctuation">}</span></span><br /> <span class="token attr-name">updateQuoteTop</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>updateQuoteTop<span class="token punctuation">}</span></span><br /> <span class="token attr-name">updateQuoteRight</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>updateQuoteRight<span class="token punctuation">}</span></span><br /> <span class="token attr-name">updateQuoteBottom</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>updateQuoteBottom<span class="token punctuation">}</span></span><br /> <span class="token attr-name">updateQuoteLeft</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>updateQuoteLeft<span class="token punctuation">}</span></span><br /><br /> <span class="token attr-name">verticalLimit</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>height<span class="token punctuation">}</span></span><br /> <span class="token attr-name">horizontalLimit</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>width<span class="token punctuation">}</span></span><br /> <span class="token attr-name">allPositions</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>allPositions<span class="token punctuation">}</span></span><br /> <span class="token attr-name">updatePosition</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>updatePosition<span class="token punctuation">}</span></span><span class="token punctuation">/></span></span></code></pre>
<p>You may wonder what those last four arguments are for. I'll explain them in a bit to build the suspense and dramatic tension.</p>
<p>Over at the <code>Position</code> component, I had to swap the layout radio buttons with more sliders. But as you can see, these range inputs are more complicated than the ones for the positions.</p>
<p>Here's what the one to change the top position looks like.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token plain-text"><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>posTop<span class="token punctuation">"</span></span> <span class="token attr-name">className</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">qig-l-slider__label </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">isNaN</span><span class="token punctuation">(</span>quoteTop<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">'qig-l-slider__label--disabled'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>qig-l-slider__label-inline-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br /> Top:<br /> </span><span class="token punctuation">{</span><span class="token function">isNaN</span><span class="token punctuation">(</span>quoteTop<span class="token punctuation">)</span><br /> <span class="token operator">?</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span><span class="token plain-text">None</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span><br /> <span class="token operator">:</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span> <span class="token attr-name">min</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">max</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>verticalLimit<span class="token punctuation">}</span></span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>quoteTop<span class="token punctuation">}</span></span> <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>updateQuoteTop<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><br /> <span class="token punctuation">}</span><span class="token plain-text"><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span><span class="token plain-text"><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>range<span class="token punctuation">"</span></span> <span class="token attr-name">min</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">max</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>verticalLimit<span class="token punctuation">}</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>posTop<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token function">isNaN</span><span class="token punctuation">(</span>quoteTop<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token operator">:</span> quoteTop<span class="token punctuation">}</span></span> <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>updateQuoteTop<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token plain-text"><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span><span class="token plain-text"><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">updateQuoteTop</span><span class="token punctuation">(</span><span class="token string">'auto'</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br /> Set to None<br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span><span class="token plain-text"><br /></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>Yeah, that's a lot. I'll go one step at a time. There are only two main differences between the other range input and this one:</p>
<ol>
<li>The <code>max</code> attribute depends on the limits I passed into the component before. <strong>Users can change the quote's size, and that affects how far they can move the quotes in their respective directions. So those sizes need to act as limits.</strong></li>
<li>If the value is set to <code>auto</code> or any non-number, the value falls back to <code>0</code> to go on the image's edge.</li>
</ol>
<p>There's also how the current position value gets shown in a number input here. It's odd, since wasn't this change to get rid of these number inputs?</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token punctuation">{</span><span class="token function">isNaN</span><span class="token punctuation">(</span>quoteTop<span class="token punctuation">)</span><br /> <span class="token operator">?</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span><span class="token plain-text">None</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span><br /> <span class="token operator">:</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span> <span class="token attr-name">min</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">max</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>verticalLimit<span class="token punctuation">}</span></span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>quoteTop<span class="token punctuation">}</span></span> <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>updateQuoteTop<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><br /><span class="token punctuation">}</span></code></pre>
<p>That's here because I realized quote positioning needs both broad and precise adjustments. <strong>I may move the top value around on the slider to get a basic position right. Then I'll use the number input to tweak it right where I want it.</strong></p>
<p>I also added the "Set to None" button since I realized I can use the slider to add a position value, but it couldn't remove it. So it assigns the position a value of <code>auto</code> to remove all positioning. The ternary operator lets me use the function here as I did with <code>input</code>.</p>
<p>Last, I added a conditional class to the label, <code>qig-l-slider__label--disabled</code>. If there's no value, this dims the range input without disabling it. <strong>This makes it easy for users to understand what values are and aren't set, but are still easy to adjust.</strong></p>
<p>Take all this, and repeat it for the right, bottom, and left positions. With that, I have precise control over where the quote goes!</p>
<h3 id="adding-preset-quote-positions">Adding Preset Quote Positions <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/20/quote-maker-updates/#adding-preset-quote-positions">#</a></h3>
<p>This kind of control is great, but I don't want to lose the ability to use preset positions. They're great for trying a bunch of layouts, seeing which is best, and adjusting it until it's right. So that's my last hurdle to get this going.</p>
<p>Separate from the quote maker component, I defined several "position" objects. They'll have a label and a set of values. I want their format to simple and easy to manage.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span><br /> <span class="token string-property property">'value'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token string-property property">'top'</span><span class="token operator">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span><br /> <span class="token string-property property">'right'</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br /> <span class="token string-property property">'bottom'</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br /> <span class="token string-property property">'left'</span><span class="token operator">:</span> <span class="token string">'0'</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token string-property property">'label'</span><span class="token operator">:</span> <span class="token string">'Bottom '</span><br /><span class="token punctuation">}</span></code></pre>
<p>Once I had an array of these position objects, I put them in a big array. Then I saved them to the quote maker in the <code>allPositions</code> variable. Yes, that's the unexplained variable I passed to <code>Positions</code> before! I have fired Chekhov's gun and I'm certain you're amazed.</p>
<p>But what about the <code>updatePosition</code> function? That's what I'm using to update all the state's position values. I only need to set all the right values for the quote maker's state.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function-variable function">updatePosition</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">position</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> <span class="token punctuation">{</span> value <span class="token punctuation">}</span> <span class="token operator">=</span> position<span class="token punctuation">;</span><br /><br /> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">quoteTop</span><span class="token operator">:</span> value<span class="token punctuation">[</span><span class="token string">'top'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">quoteRight</span><span class="token operator">:</span> value<span class="token punctuation">[</span><span class="token string">'right'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">quoteBottom</span><span class="token operator">:</span> value<span class="token punctuation">[</span><span class="token string">'bottom'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">quoteLeft</span><span class="token operator">:</span> value<span class="token punctuation">[</span><span class="token string">'left'</span><span class="token punctuation">]</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><br /><span class="token punctuation">}</span></code></pre>
<p>With both of these passed to the <code>Positions</code> component, adding them to the UI is easy. I loop through each position object in <code>allPositions</code>. Each loop renders a button with its label and calls <code>updatePosition</code> with its values.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>qig__long-buttons-wrapper<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br /> </span><span class="token punctuation">{</span>allPositions<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">position<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span> <span class="token operator">=></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>i<span class="token punctuation">}</span></span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">updatePosition</span><span class="token punctuation">(</span>position<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br /> </span><span class="token punctuation">{</span>position<span class="token punctuation">[</span><span class="token string">"label"</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token plain-text"><br /> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span><br /> <span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text"><br /></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>Bam! With that, I can click any of those buttons and get the presets! <strong>All I need to do to add new positions is add a new object to the array where they're stored.</strong> It's a simple way to add a lot more creative positioning potential to all my quotes.</p>
<h2 id="wrapping-up">Wrapping Up <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/20/quote-maker-updates/#wrapping-up">#</a></h2>
<p>This post went longer than I expected, and that's not even everything! I've since made more updates to how I add filters, transforms, and perspective. But this is already plenty to cover and has made making new quote images faster and more intuitive. All these extra controls have made it easier to set up quotes and show off their art.</p>
<ul class="post-content--image-list post-content--image-list--large" aria-label="A selection of quotes pairing styled artwork with quotes presented with various stylings and transformations">
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/anime-quote-maker-awesome/quote-end-1.png" alt="" />
</li>
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/anime-quote-maker-awesome/quote-end-2.png" alt="" />
</li>
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/anime-quote-maker-awesome/quote-end-3.png" alt="" />
</li>
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/anime-quote-maker-awesome/quote-end-4.png" alt="" />
</li>
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/anime-quote-maker-awesome/quote-end-5.png" alt="" />
</li>
<li>
<img src="https://www.maxwellantonucci.com/assets/images/posts/anime-quote-maker-awesome/quote-end-6.png" alt="" />
</li>
</ul>
<p>Expect even more changes to the quote maker later on. They're only going to get more ambitious.</p>
Don't Let Your Hobbies Burn You Out
2021-08-30T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/08/30/dont-let-hobbies-burn-you-out/<p>Don't Let Your Hobbies Burn You Out</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/hobbies-burn-out.jpeg" alt="Post featured image"></p><p>For the last few days, I've had inexplicable exhaustion paired with a burning feeling in my spine. I didn't know the cause, but it made it hard for me to focus on, or even start, anything. I could only lay on the couch and stare at the ceiling. I'd be stuck in a tangle of fear and frustration that made doing anything feel like a burden.</p>
<p>After doing some reading, I realized this was my body's way of telling me it felt burnt out. It was the hobbies I was doing for fun that were doing the burning. These hobbies are my writing, my drawing, and my making at a local makerspace. I had a painful time starting one of them, and when I did, right away I felt drained, miserable, and had to stop.</p>
<p><em>Why was this happening?</em></p>
<h2 id="my-hobbies-couldn't-only-be-fun">My Hobbies Couldn't Only be Fun <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/30/dont-let-hobbies-burn-you-out/#my-hobbies-couldn't-only-be-fun">#</a></h2>
<p>Later on, in this book about burnout, one quote stuck out and seemed to explain it.</p>
<blockquote>
<p>...my value as a worker and my value as a person have become intractably intertwined.</p>
</blockquote>
<p>I was framing hobbies I once did for fun as things I had to do for my career/brand/public image. <strong>If a hobby couldn't bring my life success in some way, it seemed pointless or even wasteful.</strong> As if I should only write if I wound up writing for a publication, or drawing only if people wanted to buy my art.</p>
<p>Popular media in America spreads a message that anything we do has to have some business purpose. It's part of having such a work and consumer-focused culture. Especially for millennials in a tough job market that may need to monetize anything they can. Anything we do has to be a "side hustle" instead of something we do only for joy.</p>
<p>I'm only human, so that message was overwhelming my hobbies' original motivations. This isn't even new to me, and I touched on it with the "toxic answer" in <a href="https://www.maxwellantonucci.com/about/#the-toxic-answer">my "About" page.</a> The difference is I've forgotten all my original reasons for starting them. I'm doing them without remembering why, and they feel like a forced chore I wish I could ignore.</p>
<p>So for a while, I did that and ignored them. If my hobbies were becoming so stressful for me, why do them at all?</p>
<p>I'm not saying that having a side hustle is always wrong or unhealthy. I'm lucky my current job is enough to support myself with reasonable comfort. Many other folks my age aren't in this position. But in my case, this "side hustle" mentality is the less healthy and more miserable path. So I had to ask myself a tough question: <strong>what were my original reasons for starting these hobbies?</strong> Answering this is the key to escaping these feelings of paralysis and burnout.</p>
<h2 id="why-was-i-writing%3F">Why Was I Writing? <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/30/dont-let-hobbies-burn-you-out/#why-was-i-writing%3F">#</a></h2>
<p>The only posts I've thought were "worth posting" were ones with wide appeal. These are less personal posts focused more on board ideas, current events, or technical material. To stand out from the crowd, I'd need to post fast and often. They'd need a powerful perspective with quirky and entertaining graphics. That'd be the only way someone like me could stand out, after all.</p>
<p>It's unrealistic to think I could write like that on a regular basis. So writing wound up feeling pointless.</p>
<p>But writing used to feel so vital to me. I looked over my older posts and found my favorites, like <a href="https://www.maxwellantonucci.com/posts/2018/11/05/you-can-be-a-casual-blogger/">"You Can Be a Casual Blogger"</a> and <a href="https://www.maxwellantonucci.com/posts/2017/05/16/2017-5-15-perfectly-unhappy-developer/">"How to be a Perfectly Unhappy Developer."</a> They're not my favorites because people did or didn't read them. It's because they were important lessons I needed to note down to better remember them.</p>
<p><strong>I was writing to see why the lesson was important, how to learn from it and make sure I didn't forget it.</strong> All my favorite writing pieces have roots in something personal. These posts rarely go viral, but they've helped me find, and stay on, better paths in life.</p>
<p>Plus writing them is plain fun. Where else can I mix life lessons with snide remarks about alligator pits and existential despair? When I've got that, I don't care all that much if anyone else publishes them.</p>
<h2 id="why-was-i-drawing%3F">Why Was I Drawing? <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/30/dont-let-hobbies-burn-you-out/#why-was-i-drawing%3F">#</a></h2>
<p>In the last few weeks, I've tried to start making comics. I thought of doing "slice of life" strips about weird thoughts or moments in my life. I even had an idea for a series of web accessibility comics, to show off my humor and my expertise.</p>
<p>It seemed like a perfect combination of career and fun. So I wrote one about icon text alternatives that came out okay. But it took over a week of forcing myself to get up and get it done.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/hobbies-burn-out/icon-text-alternatives-comic.jpg" alt="A comic about the importance of adding icon alternatives to icons on a webpage." /></p>
<p>Why was making one comic so tough? My best guess is drawing comics takes a certain amount of planning. It needs dialog, perspectives, storytelling, logical and character consistency, and more. None of that's all too difficult, especially for something over 3-4 panels. But my mind found all this for making only one comic exhausting.</p>
<p>But before, when I starting drawing in high school, I drew random stuff in the moment. It could be crazy outfits I invented, random weapons I saw, weird emotions I'd started feeling, or inspiration from random objects I saw. For example, I once combined a random Facebook profile with a "leaning forward" pose I saw. Then I mixed some simplified angel wings I saw in some anime art, and some colored pencil for the hell of it.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/hobbies-burn-out/angel-wing-doodle.jpg" alt="A colored pencil drawing of a woman with glasses and cartoon angel wings." /></p>
<p>My best guess for this is I like my drawing to be spontaneous and based on my feelings. <strong>I get enough logic and planning in everything else I do. Drawing helps me most when it's something I can go into without a plan and still love the outcome.</strong> Where I can add any weird or artistic idea and marvel at the result without caring if it "makes sense."</p>
<p>These aren't the kinds of drawings I can convert to a popular webcomic or side hustle. But they're the kind that gives me a powerful creative and emotional release. That helps my mental health and satisfaction a lot more than some webcomic success.</p>
<h2 id="why-was-i-making%3F">Why Was I Making? <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/30/dont-let-hobbies-burn-you-out/#why-was-i-making%3F">#</a></h2>
<p>Even during the pandemic, makerspace members have shared photos of amazing new projects. These included custom-made display cases, custom embroideries, and even 3D-printed painted anime figurines. Meanwhile, most of my projects stick to the usual laser-cut artwork.</p>
<p>Seeing the attention and new applications of these other projects began to psych me out. I talked myself out of doing anything unless I felt it would blow the minds of whoever saw it. So, of course, I couldn't find the courage to start almost anything.</p>
<p>Before all this, the maker projects I enjoyed making were simple gifts. They were gifts for others or gifts for myself (in the form of apartment decorations). I never made them big or extravagant, but I tried to put thought into the art or words I laser-cut into my materials. Each one took thought and creativity to get right in such a simple format. What would the person getting this gift enjoy most? What would I like to see on my walls for the longest time?</p>
<p>The focus on meaning over material is why I enjoyed using the laser cutter so much. <strong>I liked my making as a way to give people (including myself) little reminders I was thinking about them.</strong> Projects don't always need to be awe-inspiring to do that. They won't attract crowds, but they'd make the people getting the gifts pretty damn happy.</p>
<p>Care and thoughtfulness were the main reason I was making these gifts. So why should constant innovation take priority over that?</p>
<h2 id="the-%22imagined-audience%22">The "Imagined Audience" <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/08/30/dont-let-hobbies-burn-you-out/#the-%22imagined-audience%22">#</a></h2>
<p>There's a common theme of an "imagined audience" behind all this burnout. I was imagining some of the people I had to impress with my hobbies. It could be other professionals, future bosses, my community, or just anyone in the world. But those audiences are never there in reality. For me, they were projections of the pressure I put on myself to "be extraordinary."</p>
<p>But as I wrote in <a href="https://www.maxwellantonucci.com/posts/2020/08/25/let-yourself-not-be-extraordinary/">another blog post I wrote it for myself, it's okay to not be extraordinary.</a> In fact, it's often better not to be.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">The world cares less about your successes (and failures) than you think... by a magnitude or two. <br /><br />This isn't sad, it's liberating. Try more stuff.</p>— Jesse Genet (@jessegenet) <a href="https://twitter.com/jessegenet/status/1430917678831648768?ref_src=twsrc%5Etfw">August 26, 2021</a></blockquote>
<p>This message is for any other younger folks feeling the same way. <strong>I'd ask you to remember the times you first found joy and meaning in your hobbies. Then ask yourself why you felt those feelings back then.</strong> This doesn't mean you shouldn't <em>ever</em> make them a side hustle. But ask yourself if it's for a real reason like that, or if you were trying to impress an invisible audience like me. Because that "audience" will never be impressed.</p>
<p>No matter what, always keep those reasons for starting in mind so you don't lose the joy they gave you. If you do, the burnout will hit you over time and before you realize it. Like me, you'll risk hating something you'd always loved without knowing why. That's one thing I wouldn't wish upon anyone.</p>
Don't Force It
2021-10-11T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/10/11/dont-force-it/<p>It's a Monday evening at the end of a three-day weekend. I wanted to do more work on a new blog post.</p>
<p>I stared at the text I'd written a few days ago for a while. I couldn't find any energy to type any serious words. I thought I could force myself and make myself edit, draw, and write for this post. But I've done that before, and I've almost always cut all that out afterward. So I knew I'd only be wasting time and energy. All to "feel" productive, but knowing I won't "be" productive.</p>
<p>To clarify, I had an enjoyable weekend. Now I'm feeling exhaustion and a slight headache. I want to lay down and not think about serious things for a while. Even though, like all adults my age, there is no shortage of stressful and important things to think about.</p>
<p>I felt restless but have no mental energy to do important work. What now?</p>
<p><strong>In times like this, I only need to do work that sets me up to be more productive tomorrow. Things that don't take all that much thought.</strong></p>
<ul>
<li>I won't read through my backed-up article list. I'll note which ones to read tomorrow and pass on the rest.</li>
<li>I won't work on that blog post. I'll make a bullet list of what I want to tackle tomorrow and save it as a to-do list.</li>
<li>I won't do a full apartment clean. I'll put everything where it needs to be so I won't lose track of it when I'm back on the clock.</li>
<li>I won't stay up late with extra TV or reading. I'll get to bed early and make sure I sleep enough to feel rested tomorrow.</li>
</ul>
<p>Being productive and feeling productive are two different things. I'm getting better at recognizing times like now. These are times when I feel productive but don't have to energy to be productive. <strong>The best thing I can do is clean up, set up, and rest up for later.</strong> This way, I can feel productive without burning myself (and any productive energy) out.</p>
What's the deal with align-items: baseline?
2021-10-13T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/10/13/flexbox-align-items-baseline/<p>What's the deal with align-items: baseline?</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/deal-align-items-baseline.jpg" alt="Post featured image"></p><p>I can't count the number of times flexbox has made an otherwise painful design layout easy. My only qualm was having to calculate margins and paddings to space elements in a flex container. But now that <code>gap</code> has gotten good browser support, even that's no longer an issue.</p>
<p>But while it doesn't inconvenience me anywhere, it still surprises me.</p>
<p>Take the <code>align-items</code> property. When you have a row of items in a flex container, it controls how they line up in that row. I know how the most common values you'd give it work:</p>
<ul>
<li><code>stretch</code> is the default value, and it makes each one the height of the tallest element in that row</li>
<li><code>flex-start</code> aligns each element to the top of that row</li>
<li><code>flex-end</code> aligns each element to the end of the row</li>
<li><code>center</code> aligns each element along the row's center axis</li>
</ul>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/flex-align-baseline/flex-align-basics.png" alt="Some hand-drawn examples showing how the four basic values for align-items work." /></p>
<p>But an article I read mentioned the <code>baseline</code> value, and I didn't know that one. My own site's article listing is a flex container, so I threw on <code>align-items: baseline</code> out of curiosity.</p>
<p>The result...was unexpected.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I'm not understand why flexbox's "align-item: baseline" is doing this. Can anyone explain it? <a href="https://t.co/vJEr5ENHh9">pic.twitter.com/vJEr5ENHh9</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1446503004912295939?ref_src=twsrc%5Etfw">October 8, 2021</a></blockquote>
<p>This confused me since the results looked inconsistent. I was guessing flexbox was aligning things by a particular element. But I checked each element and nothing explained the alignment in each row. How could an alignment changed by a single rule give me such random results?</p>
<p>I did a few google searches to find out exactly how <code>baseline</code> aligns content. But I got explanations that were either too sparse or too jargon-filled. So like all confused people with little self-esteem and even less to lose, I turned to Twitter. And I actually got a good answer fast.</p>
<blockquote class="twitter-tweet" data-conversation="none"><p lang="en" dir="ltr">Looks like it's aligning the first items' baselines. Images in the first row. Images + dates in the second row. Images again in the third row</p>— Bryan Robinson (@brob) <a href="https://twitter.com/brob/status/1446505854354739200?ref_src=twsrc%5Etfw">October 8, 2021</a></blockquote>
<p>This was the simple answer I'd been looking for! <strong>Baseline takes the first element in each flex item, and lines things up by the bottom of that element.</strong></p>
<p>This also explained the inconsistency! Posts in the first and third rows all have images, so it aligned the articles based on the bottoms of those. But the middle row has two posts without images, so it went by the element that was first instead: the dates. So while the alignment rule works, the different elements make it look inconsistent.</p>
<p><img src="https://www.maxwellantonucci.com/assets/images/posts/flex-align-baseline/baseline-align-guideline.jpg" alt="My website's article listings with the baseline level elements emphasized to show where how the alignment works." /></p>
<p>It also explains why the layout looks so wildly spaced in some areas. In the second post of the first row, the headline text is larger while the flex-basis is shorter. This pushes a lot of content below the baseline and creates those large gaps in the row.</p>
<p>All this has taught me a few good lessons about when I'd want to use <code>align-items: baseline</code> in the future.</p>
<ol>
<li><strong>It's good for content with some size variation.</strong> If you have images or text of different sizes, <code>baseline</code> always aligns them at the same point. So it can add some consistency where they may otherwise be none.</li>
<li><strong>It's bad for content that has too many differences.</strong> It only looks at the first element and not any elements after it. My site has shown that having varying text or elements around a baseline can create lots of empty space.</li>
</ol>
<p>My recommendation is to use <code>baseline</code> when your inconsistencies stay limited to the first element. Like for a list of cards that always started with headings, but you can't guarantee their font size.</p>
<p>As for my own site, I'm going to stick with <code>align-items: stretch</code> for now. Between optional featured images and different excerpt lengths, there's too much empty space.</p>
<p>But as with all things flexbox, this is good to know.</p>
Remember to Accept the Chaos
2021-12-03T00:00:00Zhttps://www.maxwellantonucci.com/posts/2021/12/03/remember-accept-chaos/<p>At the start of the pandemic, <a href="https://www.maxwellantonucci.com/posts/2020/03/24/what-we-can-control/">I wrote about the importance of accepting what we control amid the chaos.</a> But I was rereading <a href="https://www.goodreads.com/en/book/show/41473867">a certain book from a certain professor to a certain team from the RWBY series</a> and found one of my favorite quotes. It argues instead about the importance of accepting the world's uncontrolled chaos.</p>
<blockquote>
<p>The world is chaotic. We try to assert order on it, try to make sense of it...But what if the only way to fight chaos is to give in to it? All your planning, all your preparation, can be undone in a moment of bad luck. Or a split second in which you make the wrong decision, or miss your mark just so. This, I believe that we need to embrace randomness as well, try to harness it and turn it to our advantage. We have to plan for the unexpected, prepare outselves for situations we never could have anticipated or trained for. You and I are having this conversation because of a lifetime of choices and seemingly unrelated occurences that nonetheless shaped who we are and led us here.</p>
</blockquote>
<p>Excessive length aside, it's right that we <em>should</em> grow more comfortable with the chaos. It will forever be here influencing my life, one way or another. So shutting it out completely in favor of what I can control isn't all that healthy either.</p>
<h2 id="chaos-is-everywhere">Chaos is Everywhere <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/12/03/remember-accept-chaos/#chaos-is-everywhere">#</a></h2>
<p>So much of the nature of everyday life, even outside a pandemic, is us dealing with elements we can't control. We're affected by uncontrollable things like the environment, economy, and people around us. There are also the thoughts and ideas we read about, and sometimes outright disasters and tragedies. I can't control if the weather is nice or a hurricane, but I have to work with (or around) whatever it is.</p>
<p>But what about <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2021/12/03/remember-accept-chaos/#inside-control-note" id="inside-control-ref" aria-describedby="footnotes-label" role="doc-noteref">the things within ourselves that we do control?</a> These are our actions, reactions, interpretations, beliefs, ideals, etc. Plus the things right around us like our homes, jobs, and relationships to some extent. Don't we control all those?</p>
<p>For sure we have <em>more</em> control over them, and we should exercise as much of that control as possible. <strong>But there are still elements within our homes or minds we can't control.</strong> Sometimes we don't respond or react to situations as we'd like to. Or we interpret events and ideas differently than we'd expect. There are elements of our homes, jobs, and relationships we don't like but can't control them either. I can choose what decor goes into my apartment, but I can't control the options I see in the store, the materials I may need to set them up, or <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2021/12/03/remember-accept-chaos/#sense-of-design-note" id="sense-of-design-ref" aria-describedby="footnotes-label" role="doc-noteref">my innate taste or sense of interior design.</a></p>
<p>So even with our own minds, there's much we can't control. There have been times where my knee-jerk reactions have been ones I didn't like. But with time and reconsideration, they're brought back to a place that feels more like myself. It could be liking a wallpaper before realizing it was tacky. Or hating someone before realizing they're...tolerable. These are ways for our own minds to throw a little chaos at us, and I doubt anyone can claim 100% control there either.</p>
<p>At least not as much as anyone, myself included, would like to think so.</p>
<h2 id="chaos-can-be-powerful-when-accepted.">Chaos can be Powerful when Accepted. <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2021/12/03/remember-accept-chaos/#chaos-can-be-powerful-when-accepted.">#</a></h2>
<p>Chaos <em>is</em> everywhere, which is unsettling at first. That's why <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2021/12/03/remember-accept-chaos/#speaker-note" id="speaker-ref" aria-describedby="footnotes-label" role="doc-noteref">the quote's speaker makes a point of saying we should accept and find strength in it.</a></p>
<p>In a small way, I know I've already accepted this. I embrace <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2021/12/03/remember-accept-chaos/#randomness-note" id="randomness-ref" aria-describedby="footnotes-label" role="doc-noteref">randomness in my own website by randomizing the colors of different elements, and showing random doodles within other elements.</a> The way I make use of this chaos is a favorite part of my site. It makes each view unique in a small way and sometimes results in something funny and/or bizarre.</p>
<p>I doubt the exact same can be said about the chaos of the pandemic. For many people, it's about getting by and hanging in there instead of it making them stronger. But refusing to accept it is what leads to people refusing to wear masks or get vaccinated for any number of bad reasons. Then the pandemic drags on longer than needed and we all suffer more with staying at home, missing group events, or hiding our beautiful faces under masks.</p>
<p>So when we're hit with this chaos we can't control, the sooner we accept it, the sooner we can look at ways to make use of it. <strong>Denying or pushing the chaos away only lets the opportunities to do better slip away. Or worse, it lets the chaos drag us down and we don't see how to defend ourselves from it.</strong> It's not like the chaos is going anywhere either way.</p>
<p>Plus, as the quote also points out, this uncontrollable chaos has also led to many good things too. There was likely a certain amount of chaos that led to your parents' meeting and having a child together. Now here you are, reading this.</p>
<p>How could anyone have predicted and controlled that? And would you have wanted them to?</p>
My 2021 Best Book Awards
2022-01-21T00:00:00Zhttps://www.maxwellantonucci.com/posts/2022/01/21/2021-book-awards/<p>My 2021 Best Book Awards</p><p><img src="https://www.maxwellantonucci.com/assets/images/featured/2021-book-awards.jpeg" alt="Post featured image"></p><p>2021 was the second year of pandemics, quarantine, and having lots of time to kill indoors. As a result, it was the year I set a personal record for “most books read in a single year.” They were a mix of fiction, non-fiction, mainstream, indie, paper, digital, and fatal in too large a dosage.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Through a weird series of events, I have nine new books today. And I don’t know what two of them are. <a href="https://t.co/lcsnNB8K3Q">https://t.co/lcsnNB8K3Q</a> <a href="https://t.co/z5XA4Kg5Xj">pic.twitter.com/z5XA4Kg5Xj</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1395902315295657984?ref_src=twsrc%5Etfw">May 22, 2021</a></blockquote>
<p>I’ve seen blog posts where someone lists each book they read with a quick review. But I’m not doing that since there are too many for me to remember well enough. Instead, I’m going to give out some personal book awards! These are well-known categories and genres we all know. I was lucky/bored/lounging enough to read at least one book from each.</p>
<p>So let's begin my 2021 book awards!</p>
<h2 id="the-2021-best-book-awards">The 2021 Best Book Awards <a class="direct-link" href="https://www.maxwellantonucci.com/posts/2022/01/21/2021-book-awards/#the-2021-best-book-awards">#</a></h2>
<p><strong>Best Romance</strong>: <a href="https://www.goodreads.com/book/show/44019067-the-bromance-book-club?ac=1&from_search=true&qid=SPEc2QV8CF&rank=1"><em>The Bromance Book Club</em></a> brought a solid romance from the perspective of "men with masculine jobs chatting about feminist values over pumpkin spice lattes." <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2022/01/21/2021-book-awards/#bromance-book-club-note" id="bromance-book-club-ref" aria-describedby="footnotes-label" role="doc-noteref">It's familiar, fresh, and fairly fun.</a></p>
<p><a href="https://www.goodreads.com/book/show/57144220-satisfaction-guaranteed"><em>Satisfaction Guaranteed</em></a> gets an honorable mention. It's more formulaic but wins on sheer charm and silliness.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">This book has officially intrigued me. <a href="https://t.co/QapuGkGrMQ">https://t.co/QapuGkGrMQ</a> <a href="https://t.co/6BQufE4pzy">pic.twitter.com/6BQufE4pzy</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1453767611704127489?ref_src=twsrc%5Etfw">October 28, 2021</a></blockquote>
<p><strong>Best Graphic Novel</strong>: I nabbed <a href="https://www.goodreads.com/book/show/36952615-on-a-sunbeam"><em>On a Sunbeam</em></a> at the library but it holds up well. It's part space odyssey, part romance, part drama, and part western. If you told me this book was in the <em>Firefly</em> universe, I'd believe you.</p>
<p><strong>Biggest Letdown</strong>: <a href="https://www.goodreads.com/book/show/54447930-ready-player-two"><em>Ready Player Two</em></a> had the longest library wait time and felt the least worth it. I loved how <a href="https://www.goodreads.com/book/show/9969571-ready-player-one"><em>Ready Player One</em></a> was full of trivia without losing the characters or epic saga. The sequel lost that in a haze of Flanderization, Dan Brown worship and terrifying forms of the musician Prince.</p>
<p><strong>Most Refreshing</strong>: <a href="https://www.goodreads.com/book/show/52757844-how-do-we-relationship-vol-1"><em>How Do We Relationship?</em></a> has an easy victory here. How many romances are there where the lead couple gets together at the start? This manga tackles obstacles like learning about your partner, anniversaries, sex, fights, and general dysfunction. All while still being a likeable romance.</p>
<p><strong>Best Classic Remix</strong>: <a href="https://www.goodreads.com/book/show/43900612-cinderella-is-dead"><em>Cinderella is Dead</em></a> takes apart, reverses, and mixes in unexpected elements to the Cinderella story. The premise is literally how a story gets bastardized over decades so one group can keep power over another. Seeing how that happened is both fascinating and terrifying. It does all this while delivering romantic leads that sometimes feels almost too cute.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">This is a great response to a guy that literally dropped some <a href="https://twitter.com/hashtag/NotAllMen?src=hash&ref_src=twsrc%5Etfw">#NotAllMen</a> crap on the main character. <a href="https://t.co/IDQn5UCjjI">https://t.co/IDQn5UCjjI</a> <a href="https://t.co/C3t0y2YBfZ">pic.twitter.com/C3t0y2YBfZ</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1343700684835844096?ref_src=twsrc%5Etfw">December 28, 2020</a></blockquote>
<p><strong>Best Science</strong>: <a href="https://www.goodreads.com/book/show/54493401-project-hail-mary"><em>Project Hail Mary</em></a> is by the same author behind <a href="https://www.goodreads.com/book/show/18007564-the-martian"><em>The Martian</em></a> and <a href="https://www.goodreads.com/book/show/34928122-artemis"><em>Artemis</em></a>, so this shouldn't be a surprise. It's wilder while still feeling science-y enough that you feel smarter as you read it. Some parts of it stall and go too slow, but there are <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2022/01/21/2021-book-awards/#project-hail-mary-note" id="project-hail-mary-ref" aria-describedby="footnotes-label" role="doc-noteref">more than enough ideas to satiate you through the dry spots.</a></p>
<p>An honorable mention here goes to <a href="https://www.goodreads.com/book/show/21413662-what-if-serious-scientific-answers-to-absurd-hypothetical-questions"><em>What If? Serious Scientific Answers to Absurd Hypothetical Questions.</em></a> I'll never swim in a nuclear reactor pool. But now I know it would be possible if I wanted.</p>
<p><strong>Most Reread</strong>: <a href="https://www.goodreads.com/book/show/21413662-what-if-serious-scientific-answers-to-absurd-hypothetical-questions"><em>What If? Serious Scientific Answers to Absurd Hypothetical Questions</em></a> gets its victory! I'll swim in that nuclear reactor pool yet.</p>
<p><strong>Most Epic</strong>: <a href="https://www.goodreads.com/book/show/44778083-house-of-earth-and-blood"><em>House of Earth and Blood</em></a> is by Sarah Maas, the same author behind the epic <em>Throne of Glass</em> saga. Need I write any more? You've got well-developed characters, entertaining dialogue, and an intriguing setting blending together modern society and fantasy. I can recommend reading the climax with an "Epic Instrumentals" playlist going in the background.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">This author has a gift for sexual language that is hot, quirky, and slightly awkward all at the same time. <a href="https://t.co/0zKLXW5EVp">https://t.co/0zKLXW5EVp</a> <a href="https://t.co/EzavnfHlJ1">pic.twitter.com/EzavnfHlJ1</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1357816494046986242?ref_src=twsrc%5Etfw">February 5, 2021</a></blockquote>
<p><strong>Best Manga</strong>: <a href="https://myanimelist.net/manga/106809/Koko_wa_Ima_kara_Rinri_desu"><em>From Now On, We Begin Ethics</em></a> is quite unique. It shows the many different lessons philosophy can give students for friends, family, self-expression, sex, and what we do with our lives. There are few to none typical manga tropes here, only lessons and coming-of-age stories.</p>
<p><strong>Best Comic That’s Not a Manga</strong>: <a href="https://www.goodreads.com/book/show/57282218-lore-olympus"><em>Lore Olympus: Volume One</em></a> is the start of one of my favorite webcomics, and worth getting a physical copy. Especially if playing <a href="https://www.nintendo.com/games/detail/hades-switch/"><em>Hades</em></a> put you in the mood to immerse yourself in more Greek mythology and/or modern romance.</p>
<p><strong>Most Revealing</strong>: <a href="https://www.goodreads.com/book/show/24795950-trashed"><em>Trashed</em></a> told me things about the world of garbage I never knew, and may have never known. Trash is something in all our lives but we never think about it much. I learned so many new aspects of it, most of them foreboding or outright scary.</p>
<p><strong>Most Gross</strong>: <a href="https://www.goodreads.com/book/show/24795950-trashed"><em>Trashed</em></a> again. Did I mention this book on garbage is a crude graphic novel? Here's a taste of it: <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2022/01/21/2021-book-awards/#trashed-note" id="trashed-ref" aria-describedby="footnotes-label" role="doc-noteref">maggots, dog poop bombs, urine bottles, and roadkill thrown into trucks.</a></p>
<p><strong>Best New Perspective</strong>: <a href="https://www.goodreads.com/book/show/52359739-cemetery-boys"><em>Cemetery Boys</em></a> follows a gay, transgender boy pursuing his dreams against a traditional Latinx family. There are also ghosts and magic and all that, but it's secondary to the lead's unique coming-of-age. I don't have direct experience with these struggles, and reading is no substitute for experiencing them. But it at least helps me try to understand more and broaden my horizons. Plus it's funny, simple as that.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Howling at the moon is optional. <a href="https://t.co/JwB6RsZGQ7">https://t.co/JwB6RsZGQ7</a> <a href="https://t.co/EHW9u6SvzH">pic.twitter.com/EHW9u6SvzH</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1382871659519094788?ref_src=twsrc%5Etfw">April 16, 2021</a></blockquote>
<p>The manga <a href="https://www.goodreads.com/book/show/48672813-love-me-for-who-i-am-vol-1"><em>Love Me For Who I Am</em></a> was a close second. It's more focused on gender and sexuality but from many different perspectives. All while still being a cute and charming high school romance.</p>
<p><strong>Best New Perspective on Tougher Subject Matter</strong>: <a href="https://www.goodreads.com/book/show/2296567.Say_You_re_One_of_Them"><em>Say You’re One of Them</em></a> is a short story collection about kids. These kids deal with poverty, war, child slavery, and religious tensions in different African countries. There are some brutal scenes heartbreaking events, and then more brutal scenes. Inspiring but not for the faint of heart.</p>
<p><a href="https://www.goodreads.com/book/show/40046077-women-talking"><em>Women Talking</em></a> deserves a shoutout here. What are the women talking about? Living in an isolated community after a series of assaults while the rapists are on their way home. It seems like a no-win situation, and it's <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2022/01/21/2021-book-awards/#women-talking-note" id="women-talking-ref" aria-describedby="footnotes-label" role="doc-noteref">written with even more depth (and humor) than you'd expect.</a></p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">It’s encouraging to know that, E<br />even in isolated Mennonite communities, swear words still find their way in. <a href="https://t.co/GbngtokHGH">pic.twitter.com/GbngtokHGH</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1429774808598913030?ref_src=twsrc%5Etfw">August 23, 2021</a></blockquote>
<p><strong>Best Navel Contemplater</strong>: <a href="https://www.goodreads.com/book/show/49534036-anxious-people"><em>Anxious People</em></a> had little competition. It has enough wry humor to offset some of the most anxiety-inspiring quotes I have ever read. <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2022/01/21/2021-book-awards/#anxious-people-note" id="anxious-people-ref" aria-describedby="footnotes-label" role="doc-noteref">The older you are, the more this book will make you feel helpless with a touch of optimism. But mostly helpless.</a></p>
<p><strong>Best Battle of Wits with the Reader</strong>: <a href="https://www.goodreads.com/book/show/53603292-five-total-strangers"><em>Five Total Strangers</em></a> has a lead stuck in a snowstorm with four others, and one is out to get her. Which one is it? Try to guess, <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2022/01/21/2021-book-awards/#five-total-strangers-note" id="five-total-strangers-ref" aria-describedby="footnotes-label" role="doc-noteref">it's a fun challenge!</a></p>
<p><strong>Most Fun Characters:</strong> <a href="https://www.goodreads.com/book/show/34913896-into-the-drowning-deep"><em>Into the Drowning Deep</em></a> has Mira Grant's reliable selection of characters that are entertaining, colorful, and still deep enough so you connect with them. You've got sexy yet conflicted research scientists, deaf deep-sea diving siblings, bloodthirsty hunters, and mermaid-esque creatures with the deadliest hair I've ever seen. I kept reading just to see how they'd keep responding to the shit as it hit the fan.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">For SCIENCE! Murderous sirens and death slime be damned. <a href="https://t.co/cqmY8VR6SB">https://t.co/cqmY8VR6SB</a> <a href="https://t.co/ESFyNUkPIK">pic.twitter.com/ESFyNUkPIK</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1419985009742655493?ref_src=twsrc%5Etfw">July 27, 2021</a></blockquote>
<p><strong>Best Book I Read After the Movie</strong>: I didn't know <a href="https://www.goodreads.com/book/show/40604658-jurassic-park"><em>Jurassic Park</em></a> was a book first until some friends mentioned it to me. Then one got me the book for a Secret Santa. It should be no surprise that the book was better.</p>
<p><a href="https://www.goodreads.com/book/show/6284840-shutter-island"><em>Shutter Island</em></a> was a close second, but it's not as engrossing when you already know that final twist.</p>
<p><strong>Most Confusing Book</strong>: <a href="https://www.goodreads.com/book/show/55481226-rabbits"><em>Rabbits</em></a> has a lot of good qualities. It's tense, engrossing, creative, and vivid. But any book with either time or dimensional travel gets too "out there" and may not be worth the complexity. But if a deep, conspiracy-filled book is your jam, it's worth it.</p>
<p><strong>Best Visual Novel</strong>: <a href="https://www.nintendo.com/games/detail/the-great-ace-attorney-chronicles-switch/">The Great Ace Attorney Chronicles</a> gave me even more Ace Attorney when I thought there was nothing left. It's impressive how well it still works in an era without modern technology. I give most of this credit to Herlock Sholmes, although sometimes it still got...weird.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">It's...creepy as hell to see <a href="https://twitter.com/hashtag/TheGreatAceAttorney?src=hash&ref_src=twsrc%5Etfw">#TheGreatAceAttorney</a> <a href="https://twitter.com/hashtag/NintendoSwitch?src=hash&ref_src=twsrc%5Etfw">#NintendoSwitch</a> <a href="https://t.co/7AHCUstrEm">pic.twitter.com/7AHCUstrEm</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1448781038985965569?ref_src=twsrc%5Etfw">October 14, 2021</a></blockquote>
<p><a href="https://www.nintendo.com/games/detail/roboticsnotes-elite-switch/"><em>Robotics;Notes</em> Elite</a> is an honorable mention. It's another good conspiracy story, and great for fans of <a href="https://www.nintendo.com/games/detail/steinsgate-elite-switch/"><em>Steins;Gate</em></a> like me. <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2022/01/21/2021-book-awards/#robotics-notes-note" id="robotics-notes-ref" aria-describedby="footnotes-label" role="doc-noteref">You wouldn't think a high school robot club could connect to a massive, world-threatening conspiracy.</a> But it does. Most of the charm also comes from one lovably quirky character here, Frau.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Favorite character? Frau, 2 e z. I identify with a nerd coding genius. Except for the rich, famous, and perverted parts... <a href="https://twitter.com/hashtag/NintendoSwitch?src=hash&ref_src=twsrc%5Etfw">#NintendoSwitch</a> <a href="https://t.co/C2220HW53B">pic.twitter.com/C2220HW53B</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1394460350288850945?ref_src=twsrc%5Etfw">May 18, 2021</a></blockquote>
<p><strong>Best Visual Novel with Social Deduction Gameplay, Time Loops, and Cross-Dressing</strong>: This was a hotly-contested category, but <a href="https://www.nintendo.com/games/detail/raging-loop-switch/"><em>Raging Loop</em></a> narrowly beat out <a href="https://www.nintendo.com/games/detail/gnosia-switch/"><em>Gnosia.</em></a> Both had compelling and complex tales with great characters. Plus it's fun to kill folks one by one in Gnosia. But Raging Loop's more structured story and enjoyable depth put it over. I look forward to seeing which game wins this year!</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Sha-Ming is a tool, but a great partner in mass murder <a href="https://twitter.com/hashtag/gnosia?src=hash&ref_src=twsrc%5Etfw">#gnosia</a> <a href="https://twitter.com/hashtag/PLAYISM?src=hash&ref_src=twsrc%5Etfw">#PLAYISM</a> <a href="https://twitter.com/hashtag/NintendoSwitch?src=hash&ref_src=twsrc%5Etfw">#NintendoSwitch</a> <a href="https://t.co/FotaWA7lct">pic.twitter.com/FotaWA7lct</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1367824921854836743?ref_src=twsrc%5Etfw">March 5, 2021</a></blockquote> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p><strong>Best Book I Couldn’t think of a Category for but Wanted to Mention Anyway</strong>: <a href="https://www.goodreads.com/book/show/37691135-macbeth"><em>Macbeth, the contemporary English manga version,</em></a> is the book everyone wants to read but doesn't know it yet. It made me finally see and appreciate the true power in so much of Shakespeare's work. I plan to formally petition all English classes to use this version instead. You say I'm crazy now, but in ten years you'll say I was a prophet!</p>
<p><strong>Best Video Game That's Not a Visual Novel But Still had a Ton of Reading</strong>: <a href="https://www.nintendo.com/games/detail/the-inner-world-switch/">The Inner World</a> is a point-and-click. To me, that's a visual novel that takes too much work to read more of. But the game and its sequel have enough humor and creativity to make it worth it for most.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">The man tied to a windmill isn't as crazy as he looks! <a href="https://twitter.com/hashtag/NintendoSwitch?src=hash&ref_src=twsrc%5Etfw">#NintendoSwitch</a> <a href="https://t.co/xjcAPbeNpy">pic.twitter.com/xjcAPbeNpy</a></p>— Max Antonucci (@Maxwell_Dev) <a href="https://twitter.com/Maxwell_Dev/status/1355681026844942336?ref_src=twsrc%5Etfw">January 31, 2021</a></blockquote> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Here's to another good selection of books in 2020!</p>
Catching up on Modern CSS
2023-08-03T00:00:00Zhttps://www.maxwellantonucci.com/posts/2023/08/03/modern-css/<p>A lot of life has been happening for me lately - moving, wedding planning, eBook hoarding, doomsday preparation, etc. I haven't been able to keep up with updates in modern CSS as much as I used to. So this article on that exact topic was a great read and <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2023/08/03/modern-css/#up-to-speed-note" id="up-to-speed-ref" aria-describedby="footnotes-label" role="doc-noteref">helped me feel 72% more up-to-speed on what's been happening.</a> It covers new coolness that is either fully supported or coolness we can expect to get full support within a year.</p>
<p>My favorite part? It includes ways to incorporate the new CSS in relevant ways, like in buttons or cards. I always learn best seeing new things in action, since <a class="Footnotes__ref" href="https://www.maxwellantonucci.com/posts/2023/08/03/modern-css/#use-information-note" id="use-information-ref" aria-describedby="footnotes-label" role="doc-noteref">it keeps my mind from questioning if I'll ever make use of new info.</a></p>
<p>I'm most excited to see <code>:has()</code> (very soon) and container queries (nowhere near soon enough) get full browser support. With those, I may finally get a look and feel for my site’s post listings that I don’t want to change after five minutes.</p>