hey it's violetdeveloper & human in the PNWhttps://vgpena.github.io/2021-05-04T12:47:00-07:00Violet PeñaThrowaway Workhttps://vgpena.github.io/throwaway-work/2021-05-04T12:47:00-07:002021-05-04T13:36:14-07:00Violet PeñaOver the years, I've found that I generate a lot of docs and drawings that aren't part of final deliverables -- throwaway work. Here's why throwaway work is necessary, and how to get comfortable with and even celebrate it.<p>Last week, I walked my mentor through a technical discovery project my team had recently completed. Four weeks of notes, architecture diagrams, flowcharts, checklists, meeting minutes, and mind maps fed into <em>two</em> solitary write-ups which we sent over to our client. In other words, almost all of the artifacts we produced didn't end up being seen by anyone outside of our team, and aren't considered project deliverables. Going through all of these non-deliverables felt bittersweet, and one specific thought bubbled up in my mind: "Wow, that's a lot of throwaway work".</p>
<p>Maybe? But these documents weren't failed deliverables. They came out of a need to ask questions, propose hypotheses, provoke ourselves and our clients. They're an externalized thought process.</p>
<p><div class=" image-primary">
<img src="/images/strange-f.jpg" alt="Three thick stacks of pink sticky notes on a wooden table in front of a window." title="Some throwaway work." width="4032px" height="3024px" />
</div></p>
<p>Which brings me to the other side of this coin: I (you? most people?) <em>need</em> to produce throwaway work in order to arrive at the conclusions that we're on the hook to actually deliver. We we need room to externalize our ideas: to draw and sketch, gather links, connect elements, color-code, develop spatial relationships. Externalizing thoughts is an element of communication, but even more fundamentally, externalization forces us to reckon with and revise our own ideas. (If I'm drawing boxes, why is one larger than another? Are they the same color? <em>What even is reality, man?</em>)</p>
<hr>
<p>For all our talk of prototyping and iterating, I often see developers hesitate to create throwaway work. This hesitation comes from a variety of sources, but one significant factor is: what output are developers expected to create? We generally produce working code, generally with a mouse and keyboard. What can we make if we <em>don't</em> stick to these modes of expression?</p>
<p>Removing these norms opens the door to pseudocode, diagramming, handwriting, highlighting, paper cutouts. Changing modalities lets me shift my expression into the domain that fits the problem at hand and/or my own mind.</p>
<p><div class=" image-secondary">
<img src="/images/whiteboard.jpg" alt="A green-and-orange web application architecture diagram drawn on a whiteboard table." title="More throwaway work." width="3024px" height="4032px" />
</div></p>
<p>That thought I can't put into words — maybe I can articulate it by drawing some boxes. Maybe I have to draw these boxes three times before they look like what I was thinking about. Maybe this drawing leads me to a related question, or shows me that my idea actually isn't viable. Maybe I want to show this drawing to a colleague, use it for my own reference as I work towards a
deliverable, or treat it purely as a lesson learned and never look at it again. But this drawing is doing <em>something</em>.</p>
<hr>
<p>Throwaway work is invisible from the outside. Just as our clients never saw my hand-drawn mind maps, we don't see the rehearsal hours that go into polished conference presentations. We don't know that an experienced colleague has already solved this problem eight times in four different ways. The work may be invisible, may be thrown away, but it's absolutely not <em>lost</em> — rather, it enables everything that <em>does</em> eventually see the light of day.</p>
<p>To zoom back in, throwaway work — alternate, intermediate representations — got me to truly understand design systems, and helped me take my first steps into application architecture. It lets me tackle nebulous (and immensely rewarding) discovery projects. It helps me discuss and understand my teammates' ideas.</p>
<p>Throwaway work is a necessary, invisible, rarely-taught element of working in tech. (I'm dreaming of a future blog post where I break this down more, by the way.) And yes, it can be sad to know that no one else will see a doc that represents a huge breakthrough. But once we have that breakthrough, we can bring it forward to inform our next round of questioning. And we'll do this again, and again, until we have what feels like an answer.</p>
On Prioritieshttps://vgpena.github.io/on-priorities/2020-06-28T12:55:00-07:002021-05-04T13:36:14-07:00Violet PeñaAs corporations renew their equity and inclusion efforts, questioning how these efforts are powered can reveal their authenticity.<p>Over the past few weeks, numerous companies, projects, and working groups have put forth statements outlining their new racial equity efforts. There is a <em>lot</em> to unpack in these corporate initiatives, but I want to focus on the specific dimension of how racial equity work is prioritized.</p>
<p>This post references patterns I have observed in tech and adjacent industries. It does not refer in totality to specific events at any specific company.</p>
<hr>
<p>By default, I reject zero-sum thinking and am most interested in how to get to <code>A && B</code> instead of <code>A || B</code>. This mindset is how I understand and survive in the world and the tech industry. I also see it as the cornerstone to dismantling patriarchal and white supremacist systems which, by nature, thrive on exclusion and on defining the world as zero-sum (e.g., “It’s nice that we want to hire more Black people but then what about all the white candidates who we’ll have to turn down?”)</p>
<aside class="aside">
<p class="aside-body">
Some changes are superficially win-lose (e.g., white peoples’ comfort no longer being centered) but are actually win-win (because EVERYONE will thrive more outside of a white supremacist system)
</p>
</aside>
<p>That said, time and energy are measurable, finite quantities that we can only access a bit at a time. And I respect that. This is where prioritization comes into play.</p>
<hr>
<p>Over time, yes, Virginia, you can have it all. You <strong>can</strong> have an inclusive and safe environment, you <strong>can</strong> raise your profit margin, you <strong>can</strong> win all the work awards, you <strong>can</strong> recruit easily, you <strong>can</strong> operate efficiently. But in the short term, if any of these systems need fixing, you need to figure out where the effort to make the fix is going to come from. If you’re spinning up a task force to improve recruiting, or to guarantee pay equity, where do the group members come from? <a href="https://www.washingtonpost.com/technology/2020/06/26/black-ergs-tech/">Are they current employees who will need to swap this work out for their current 9-5 responsibilities?</a> Then you’re probably taking an efficiency/quality-of-work hit. Are you hiring a third-party consultancy? Then may lessen your coveted profit margins. (And so on.)</p>
<p>Any of these options can be correctly executed on, but my point is that <strong>if you need to fix your white supremacy and you can’t tell me what you will sacrifice to make this possible, then you’re not part of the solution.</strong></p>
<hr>
<p>I have been circling around prioritization for a while now, so I’ll finally come to it directly, in terms many tech workers will find familiar. Some features are launch-critical/P0 (e.g., having a navigation on your website). Other features are nice-to-haves/P1 (adding page transition animations). Articulating priorities makes it OK to lose a P1 in order to complete a P0.</p>
<p>I see many companies claim that equity & inclusion (E&I) is “a priority” or that they intend to “put in the work”, but so far I overwhelmingly see efforts that demand E&I be fixed <strong>at no cost to anything else.</strong> ERG members are not given time within the 9-5 to do this work; companies shy away from third-party consultancies; chains of accountability and empowerment remain as-is.</p>
<p>If E&I is a P0 — if Black employees’ safety and health is a P0 — you are pulling every lever possible that does not compromise other P0s (e.g., job security; keeping the business solvent). You're delaying release dates, reducing ERG members' normal workload, prepping notes for your shareholders on why your profits stayed flat this quarter.</p>
<aside class="aside">
<p class="aside-body">
At time of writing, this blog is hosted on Github Pages, signaling that I prioritize keeping a consistent coding/deployment platform over divesting from a company that works with ICE. I know I need to fix my shit. I’d prefer that Github fixed their shit instead, but I can’t control that.
</p>
</aside>
<p>So, my personal commitment, and what I encourage from the reader, is to ask yourself and your employers: <strong>if we’re making a change, where do these resources come from? What are we giving up, even a little, while we fix our white supremacist M.O.?</strong> (And what are we OK <em>having</em> lost/”lost” once these systems have been fixed? But that’s another blog post.)</p>
<hr>
<p>If there’s no answer to this question, or the answer is “we’re not giving up anything”, reflect on what this implies. And reflect on how powerful this change can possibly be when it’s coming in addition to everything, at the cost of nothing. E&I being a non-prioritized “priority” is one manifestation of the #causeascene guiding principle that <a href="https://hashtagcauseascene.com/">“Intention without strategy is chaos”</a>. </p>
<p>These are reasonable questions to ask of any large-scale effort or project. Articulating them may not be easy, and you may be met with defensive reactions. Stand by your questions. If you can expect priorities out of a software feature list, you can expect the same from a corporate restructuring effort.</p>
<p>Know that I will be here with you, also asking these questions, also evaluating the answers.</p>
<hr>
<p>P.S -- This has <em>always</em> been the question. Whethere it's about encrypting data, hiring women, time off policies, or ad-buying, always look for what is being put on the line to achieve a professed "priority".</p>
Best Practices in JavaScript Array Iterationhttps://vgpena.github.io/js-arrays/2020-05-12T21:22:00-07:002021-05-20T09:28:38-07:00Violet PeñaLearning more about JavaScript Array methods will help you write clean, idiomatic code. Let's look at four essential Array methods and how to use them.<p>Getting your code to run is great, but why not aim for readability, consistency, and flexibility as well? One low-investment, high-reward way to level up your JavaScript is to learn the different ways to iterate over Arrays, and when to use each of them.</p>
<p>In this post, I’ll look at four essential Array prototype methods — <code>forEach</code>, <code>map</code>, <code>filter</code>, and <code>reduce</code> — and discuss best practices.</p>
<aside class="aside">
<p class="aside-body">
My code samples will prioritize explicitness over brevity. There are ways to shorten almost every code sample here.
</p>
</aside>
<h2 class='section-title' id=arrayforeach-take-an-array-give-me-nothing><a href='#arrayforeach-take-an-array-give-me-nothing' class='section-inner'>Array.forEach: take an Array; give me nothing</a></h2>
<p><code>Array.forEach</code> behaves similarly to a <code>for</code> loop incrementing by 1 — all it says is, “walk me through each element in an Array, and I will do <em>something</em> on each step”. Looking at <a href="https://github.com/microsoft/TypeScript/blob/master/src/lib/es5.d.ts#L1135">the TypeScript definition for this method</a>, we see that the return type is <code>void</code>:</p>
<div class="highlight"><pre class="code typescript"><code><span class="nx">forEach</span><span class="p">(</span><span class="nx">callbackfn</span><span class="p">:</span> <span class="p">(</span><span class="nx">value</span><span class="p">:</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">index</span><span class="p">:</span> <span class="kr">number</span><span class="p">,</span> <span class="nx">array</span><span class="p">:</span> <span class="k">readonly</span> <span class="nx">T</span><span class="p">[])</span> <span class="o">=></span> <span class="k">void</span><span class="p">,</span> <span class="nx">thisArg</span><span class="p">?:</span> <span class="kr">any</span><span class="p">):</span> <span class="k">void</span><span class="p">;</span>
</code></pre></div>
<p>This means that <code>forEach</code> is most useful for side effects such as writing to the DOM or making an API call per member of an Array.</p>
<p>In this example, we’re appending text to the DOM but the original Array isn't passed on to other calculations. Great time for a <code>forEach</code>.</p>
<div class="highlight"><pre class="code javascript"><code><span class="p">[</span><span class="dl">"</span><span class="s2">Nita</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Kit</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Dairine</span><span class="dl">"</span><span class="p">].</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">wizardName</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">element</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">span</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">innerText</span> <span class="o">=</span> <span class="nx">wizardName</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">element</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div>
<p>Since <code>forEach</code> returns <code>void</code>, you should <strong>not</strong> use it when you want to generate or build a value to keep using in your JavaScript code.</p>
<p>The most common mistake I see with <code>forEach</code> is when developers it like a <code>for</code> loop to build one Array out of another. For example:</p>
<div class="highlight"><pre class="code javascript"><code><span class="c1">// DO NOT DO THIS!!</span>
<span class="kd">const</span> <span class="nx">capitalized</span> <span class="o">=</span> <span class="p">[];</span>
<span class="p">[</span><span class="dl">"</span><span class="s2">Nita</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Kit</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Dairine</span><span class="dl">"</span><span class="p">].</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">wizardName</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">capitalized</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">wizardName</span><span class="p">.</span><span class="nx">toLocaleUpperCase</span><span class="p">());</span>
<span class="p">});</span>
</code></pre></div>
<p>This misuse means that now you have an extra Array (<code>capitalized</code>) hanging out in possibly global scope, even if you only needed it for that single calculation. Messy, and potentially confusing. A much better way to turn one Array into another is by using <code>Array.map</code>.</p>
<h2 class='section-title' id=arraymap-take-an-array-give-me-an-array-of-the-same-length><a href='#arraymap-take-an-array-give-me-an-array-of-the-same-length' class='section-inner'>Array.map: take an Array; give me an Array of the same length</a></h2>
<p>Array.map walks through each element in an Array, does something to that element, and gives you a new Array back containing the resulting elements.</p>
<p>Check out the <a href="https://github.com/microsoft/TypeScript/blob/master/src/lib/es5.d.ts#L1141">TypeScript</a>:</p>
<div class="highlight"><pre class="code typescript"><code><span class="nx">map</span><span class="o"><</span><span class="nx">U</span><span class="o">></span><span class="p">(</span><span class="nx">callbackfn</span><span class="p">:</span> <span class="p">(</span><span class="nx">value</span><span class="p">:</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">index</span><span class="p">:</span> <span class="kr">number</span><span class="p">,</span> <span class="nx">array</span><span class="p">:</span> <span class="k">readonly</span> <span class="nx">T</span><span class="p">[])</span> <span class="o">=></span> <span class="nx">U</span><span class="p">,</span> <span class="nx">thisArg</span><span class="p">?:</span> <span class="kr">any</span><span class="p">):</span> <span class="nx">U</span><span class="p">[];</span>
</code></pre></div>
<p>Incoming Array members are of type <code>T</code>, and the output Array contains members of type <code>U</code>. That is to say, we’re free to transform the members of this Array into a completely different data type. The crux of <code>map</code> is that each member of the outbound Array should correspond 1:1 with a member of the inbound Array.</p>
<p>In this example, we <code>map</code> an Array of Strings to an Array of DOM nodes. We can chain this to a <code>forEach</code> that handles adding nodes to the DOM. Three cheers for separation of concerns!</p>
<div class="highlight"><pre class="code javascript"><code><span class="kd">function</span> <span class="nx">createFancySpan</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">fancySpan</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">span</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">fancySpan</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="dl">"</span><span class="s2">fancy</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">fancySpan</span><span class="p">.</span><span class="nx">innerText</span> <span class="o">=</span> <span class="nx">text</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">fancySpan</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">[</span><span class="dl">"</span><span class="s2">Nita</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Kit</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Dairine</span><span class="dl">"</span><span class="p">]</span>
<span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">wizardName</span><span class="p">)</span> <span class="o">=></span> <span class="nx">createFancySpan</span><span class="p">(</span><span class="nx">wizardName</span><span class="p">))</span>
<span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">fancySpan</span><span class="p">)</span> <span class="o">=></span> <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">fancySpan</span><span class="p">));</span>
</code></pre></div>
<p><code>map</code> keeps our code free from extra Array declarations and manipulation. We get the values we need and pipe them right into the rest of our code.</p>
<h2 class='section-title' id=arrayfilter-take-an-array-give-me-back-some-of-it><a href='#arrayfilter-take-an-array-give-me-back-some-of-it' class='section-inner'>Array.filter: take an Array; give me back some of it</a></h2>
<p><code>Array.filter</code> intakes an Array and returns a new Array made out of elements from the original. <a href="https://github.com/microsoft/TypeScript/blob/master/src/lib/es5.d.ts#L1153">The TypeScript spec</a> for this method says:</p>
<div class="highlight"><pre class="code typescript"><code><span class="nx">filter</span><span class="p">(</span><span class="nx">callbackfn</span><span class="p">:</span> <span class="p">(</span><span class="nx">value</span><span class="p">:</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">index</span><span class="p">:</span> <span class="kr">number</span><span class="p">,</span> <span class="nx">array</span><span class="p">:</span> <span class="k">readonly</span> <span class="nx">T</span><span class="p">[])</span> <span class="o">=></span> <span class="nx">unknown</span><span class="p">,</span> <span class="nx">thisArg</span><span class="p">?:</span> <span class="kr">any</span><span class="p">):</span> <span class="nx">T</span><span class="p">[];</span>
</code></pre></div>
<p>Both the original and new Arrays contain elements of type <code>T</code>. This means that we should not be transforming Array elements. What we <em>are</em> doing here is building a new Array out of only elements that return <code>True</code> when passed into a provided function.</p>
<div class="highlight"><pre class="code javascript"><code><span class="kd">function</span> <span class="nx">isShortWord</span><span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="nx">string</span><span class="p">.</span><span class="nx">length</span> <span class="o"><=</span> <span class="mi">5</span><span class="p">;</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">onlyShortNames</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">Nita</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Kit</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Dairine</span><span class="dl">"</span><span class="p">].</span><span class="nx">filter</span><span class="p">((</span><span class="nx">wizardName</span><span class="p">)</span> <span class="o">=></span>
<span class="nx">isShortWord</span><span class="p">(</span><span class="nx">wizardName</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div>
<p><code>filter</code>, like <code>map</code>, can be chained, since it returns an Array:</p>
<div class="highlight"><pre class="code javascript"><code><span class="p">[</span><span class="dl">"</span><span class="s2">Nita</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Kit</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Dairine</span><span class="dl">"</span><span class="p">]</span>
<span class="p">.</span><span class="nx">filter</span><span class="p">((</span><span class="nx">wizardName</span><span class="p">)</span> <span class="o">=></span> <span class="nx">isShortWord</span><span class="p">(</span><span class="nx">wizardName</span><span class="p">))</span>
<span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">wizardName</span><span class="p">)</span> <span class="o">=></span> <span class="nx">createFancySpan</span><span class="p">(</span><span class="nx">wizardName</span><span class="p">))</span>
<span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">fancySpan</span><span class="p">)</span> <span class="o">=></span> <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">fancySpan</span><span class="p">));</span>
</code></pre></div>
<aside class="aside">
<h3 class="aside-title">Other cool Array methods</h3>
<p class="aside-body">
Array.some will tell you if the Array contains any members satisfying a condition. (“Does this Array contain any odd numbers?”) Array.every will tell you if the Array contains only members satisfying a condition. (“Are all of the members in this Array odd?”)
</p>
</aside>
<h2 class='section-title' id=arrayreduce-take-an-array-give-me-anything><a href='#arrayreduce-take-an-array-give-me-anything' class='section-inner'>Array.reduce: take an Array; give me anything</a></h2>
<p><code>Array.reduce</code> is the most open-ended way to iterate over an Array. This prototype method is designed to take an Array, do… whatever you want to it, and return that arbitrary result.</p>
<p>The <a href="https://github.com/microsoft/TypeScript/blob/master/src/lib/es5.d.ts#L1159">basic usage of this method</a> assumes that your return type is the same as the type of Array elements. In this type definition, the Array members and the return value are both of type <code>T</code>.</p>
<div class="highlight"><pre class="code typescript"><code><span class="nx">reduce</span><span class="p">(</span><span class="nx">callbackfn</span><span class="p">:</span> <span class="p">(</span><span class="nx">previousValue</span><span class="p">:</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">currentValue</span><span class="p">:</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">currentIndex</span><span class="p">:</span> <span class="kr">number</span><span class="p">,</span> <span class="nx">array</span><span class="p">:</span> <span class="k">readonly</span> <span class="nx">T</span><span class="p">[])</span> <span class="o">=></span> <span class="nx">T</span><span class="p">):</span> <span class="nx">T</span><span class="p">;</span>
</code></pre></div>
<p>For example, given an Array of Strings, you can use a reducer to find the longest String:</p>
<div class="highlight"><pre class="code javascript"><code><span class="kd">function</span> <span class="nx">returnLongerString</span><span class="p">(</span><span class="nx">str1</span><span class="p">,</span> <span class="nx">str2</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">str1</span><span class="p">.</span><span class="nx">length</span> <span class="o">>=</span> <span class="nx">str2</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">str1</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">str2</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">longestName</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">Nita</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Kit</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Dairine</span><span class="dl">"</span><span class="p">].</span><span class="nx">reduce</span><span class="p">(</span><span class="nx">returnLongerString</span><span class="p">);</span> <span class="c1">//String: "Dairine"</span>
</code></pre></div>
<p><code>Array.reduce</code> also allows you to return a different type of data by providing an initial value to the reducer function. <a href="https://github.com/microsoft/TypeScript/blob/master/src/lib/es5.d.ts#L1166">This type definition</a> looks a little different:</p>
<div class="highlight"><pre class="code typescript"><code><span class="nx">reduce</span><span class="o"><</span><span class="nx">U</span><span class="o">></span><span class="p">(</span><span class="nx">callbackfn</span><span class="p">:</span> <span class="p">(</span><span class="nx">previousValue</span><span class="p">:</span> <span class="nx">U</span><span class="p">,</span> <span class="nx">currentValue</span><span class="p">:</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">currentIndex</span><span class="p">:</span> <span class="kr">number</span><span class="p">,</span> <span class="nx">array</span><span class="p">:</span> <span class="k">readonly</span> <span class="nx">T</span><span class="p">[])</span> <span class="o">=></span> <span class="nx">U</span><span class="p">,</span> <span class="nx">initialValue</span><span class="p">:</span> <span class="nx">U</span><span class="p">):</span> <span class="nx">U</span><span class="p">;</span>
</code></pre></div>
<p>In this case, the Array members are of type <code>T</code>, but since the initial value provided is of type <code>U</code>, so is the return type.</p>
<p>This T → U transformation can occur if, for instance, we want to find the total length of Strings in an Array (String → Number):</p>
<div class="highlight"><pre class="code javascript"><code><span class="kd">function</span> <span class="nx">addStringLength</span><span class="p">(</span><span class="nx">currTotal</span><span class="p">,</span> <span class="nx">newString</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">currTotal</span> <span class="o">+</span> <span class="nx">newString</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">totalChars</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">Nita</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Kit</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Dairine</span><span class="dl">"</span><span class="p">].</span><span class="nx">reduce</span><span class="p">(</span>
<span class="p">(</span><span class="nx">acc</span><span class="p">,</span> <span class="nx">curr</span><span class="p">)</span> <span class="o">=></span> <span class="nx">addStringLength</span><span class="p">(</span><span class="nx">acc</span><span class="p">,</span> <span class="nx">curr</span><span class="p">),</span>
<span class="mi">0</span>
<span class="p">);</span> <span class="c1">//Number: 14</span>
</code></pre></div><h3 tabIndex=0>Reduce vs. other methods</h3>
<p><code>map</code> and <code>filter</code> are actually syntactic sugar over <code>reduce</code>, meaning you use <code>reduce</code> to implement anything you can implement using <code>map</code> or <code>filter</code>. For example, this is a reimplementation of the filter we saw above:</p>
<div class="highlight"><pre class="code javascript"><code><span class="kd">function</span> <span class="nx">isShortWordReducer</span><span class="p">(</span><span class="nx">shortWords</span><span class="p">,</span> <span class="nx">string</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span>
<span class="nx">string</span><span class="p">.</span><span class="nx">length</span> <span class="o"><=</span> <span class="mi">5</span>
<span class="p">)</span> <span class="p">{</span>
<span class="nx">shortWords</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">string</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">longWshortWordsords</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">onlyShortNamesReduced</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">Nita</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Kit</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Dairine</span><span class="dl">"</span><span class="p">].</span><span class="nx">reduce</span><span class="p">(</span>
<span class="p">(</span><span class="nx">acc</span><span class="p">,</span> <span class="nx">curr</span><span class="p">)</span> <span class="o">=></span> <span class="nx">isShortWordReducer</span><span class="p">(</span><span class="nx">acc</span><span class="p">,</span> <span class="nx">curr</span><span class="p">),</span>
<span class="p">[]</span>
<span class="p">);</span>
</code></pre></div>
<p>If you are replacing multiple chained <code>map</code>s and <code>filter</code>s with a single reducer, you may see performance gains over large data sets, since <a href="https://itnext.io/you-may-need-laziness-in-your-javascript-f03e8a2d4629">JavaScript Array iterators are not lazy</a>.</p>
<p>The vast majority of the time, however, I encourage you to stick with <code>map</code> and <code>filter</code> rather than replicating that behavior with <code>reduce</code>. Array iteration will generally not be your performance bottleneck. If you're working on something data-intensive for this to <em>become</em> your bottleneck, you hopefully are already using monitoring tools that can alert you to this issue.</p>
<p><code>map</code> and <code>filter</code> have a couple of advantages over <code>reduce</code>. Calculations in <code>map</code> or <code>filter</code> wil generally be more concise than the same code in a <code>reduce</code>. <code>map</code> and <code>filter</code> also keep your code scannable since your teammtes (or you, two months from now) can make assumptions about what data shape these functions return.</p>
<p>In other words, save <code>reduce</code> for when you <em>actually</em> want to reduce something.</p>
<h2 class='section-title' id=keep-learning><a href='#keep-learning' class='section-inner'>Keep learning!</a></h2>
<p><code>forEach</code>, <code>map</code>, <code>filter</code>, and <code>reduce</code> should be the first tools you reach for when working with Arrays. Playing to their intended uses will keep your code readable, predictable, and streamlined.</p>
<p>One way to become more confident with these methods, and with Array prototype methods in general, is to visit the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">MDN docs</a> to browse prototype methods and code samples.</p>
<p><a href="https://code.visualstudio.com/">Visual Studio Code</a> is a great code editor if you’re looking to actively expand your understanding of JavaScript. VSCode pops up documentation and TypeScript definitions as you work, giving you constant reminders of the intent behind the function or method you’re using. <em>I think this is fun.</em> 🤠</p>
<p>Happy coding, hang in there, and wash your hands!</p>
<p>PS - The names in this post are characters from the <em>Young Wizards</em> series by Diane Duane. These books were life-changing for me when I was younger and I absolutely encourage you to <a href="https://www.hmhbooks.com/shop/books/so-you-want-to-be-a-wizard/9780152162504">check them out for yourself</a>!</p>
Basic Keyboard Customization with QMKhttps://vgpena.github.io/qmk/2020-05-03T13:02:00-07:002021-05-04T13:36:14-07:00Violet PeñaThe world of custom keyboards can be overwhelming to a newbie. Here's how I set up my custom keyboard layout using QMK from the command line.<p>A few months ago, after a full year of waffling, I bought my first custom keyboard. During the setup process, I felt like most of the tutorials I was finding were geared towards people knowledgeable about keyboards and less familiar with programming in general. I'm exactly the opposite of this -- over 10 years' cumulative experience programming, but little knowledge of keyboards and their workings.</p>
<p>Because of this, I kept notes as I customized my keyboard layout. Here's what I did, and I hope it helps you get started with your own custom setup 🤓</p>
<p><figure role="img" class=" image-secondary">
<img src="/images/kbd/top.JPG" alt="A pink-and-white keyboard." title="My custom keyboard." width="3024px" height="4032px" />
<figcaption>
<p>My keyboard. What a beaut!</p>
</figcaption>
</figure></p>
<h2 class='section-title' id=why-a-custom-keyboard><a href='#why-a-custom-keyboard' class='section-inner'>Why a Custom Keyboard?</a></h2>
<p>I became interested in custom keyboards for aesthetic reasons. I was used to toggling between a chunky dark grey keyboard (when on a PC) or a slim silver one (for a Mac). Either way, keyboards were uniform and. Learning that there was another path -- of personal investment, care, and customization -- was intriguing to me.</p>
<p>Cost was my largest blocker to actually buying a keyboard. The first custom keyboards I was linked to ran about $400; the kit I actually bought totaled $340. This is a <em>lot</em> of money, but I planned to use the keyboard for work. $400 for a tool I would use 40+ hours per week, I figured, was actually a reasonable expense when all was said and done.</p>
<h2 class='section-title' id=the-kit><a href='#the-kit' class='section-inner'>The Kit</a></h2>
<p>On the advice of a coworker, I bought a <a href="https://kbdfans.com/products/fully-assembled-tofu65-mechanical-keyboards">Tofu65 assembled keyboard</a> from <a href="https://kbdfans.com/">KBDFans.com</a>.</p>
<aside class="aside">
<h3 class="aside-title">Take note</h3>
<p class="aside-body">
This keyboard is sometimes called a Tofu67 instead of a Tofu65.
</p>
</aside>
<p>I chose <a href="https://kbdfans.com/collections/cherry-switches/products/cherry-mx-silent-black">Cherry Silent Black</a> switches (to be considerate to officemates -- what innocent times those were). For keycaps, I found a <a href="https://kbdfans.com/products/bfcmmaxkey-pink-white-sa-profile-keycaps-set">pink-and-white Maxkey set</a> that would be a joy for me to use every day.</p>
<p>The keyboard took about two months to arrive; using it was as simple as plugging it into my computer's USB port. The shipment included a little wire tool for lifting keycaps off of the board, so physically rearranging keys was also trivial. The other side of this process -- configuring the keyboard firmware to send the correct signals to the computer -- would be more difficult.</p>
<p>A coworker advised me that getting set up to configure firmware would take a while, but would be worth the time. So I cleared my calendar one Saturday morning, poured myself a big cup of coffee, and got to work.</p>
<h2 class='section-title' id=creating-the-custom-layout><a href='#creating-the-custom-layout' class='section-inner'>Creating the Custom Layout</a></h2>
<p>Here's the process I followed to create and load a custom keyboard layout. This is what was useful to me, so some of these steps diverge from what you might find in other walkthroughs that assume more familiarity with keyboards in general.</p>
<aside class="aside">
<h3 class="aside-title">False start</h3>
<p class="aside-body">
I initially thought that customizing the keyboard layout would happen on the OS level. I spent some time poking around in the MacOS system preferences and even downloaded Ukelele before getting a vibe that I was headed in the wrong direction. Turns out that keyboard layouts are flashed onto the keyboard itself, not the computer. This means, among other things, that the layout is portable and can be used immediately on any computer that the keyboard is connected to. Which is really cool!
</p>
</aside>
<h3 tabIndex=0>Download and configure the QMK Toolbox</h3>
<p>My keyboard, like most others from KBDFans, is compatible with QMK firmware. Several of these next steps are paraphrases from the <a href="https://docs.qmk.fm/#/">QMK docs</a>.</p>
<p>Start by installing QMK with Homebrew:</p>
<div class="highlight"><pre class="code shell"><code>brew tap qmk/qmk
brew <span class="nb">install </span>qmk
</code></pre></div>
<p>This may take a while if Homebrew needs an update (which it always seems to??). Don't walk away for too long, though, since there are some interactive prompts to install dependencies of QMK.</p>
<p>Next, fork the <a href="https://github.com/qmk/qmk_toolbox">QMK Toolbox repo on Github</a> and run the QMK setup command using this remote URL:</p>
<div class="highlight"><pre class="code shell"><code>qmk setup <your_github_username>/qmk_toolbox
</code></pre></div>
<p>Finally, follow <a href="https://docs.qmk.fm/#/newbs_getting_started?id=_5-configure-your-build-environment-optional">QMK's customization instructions</a> to save yourself a lot of typing.</p>
<h3 tabIndex=0>Design the layout</h3>
<p>I did all of my layout editing in the online <a href="https://config.qmk.fm/#/kbdfans/kbd67/rev2/LAYOUT_65_ansi">QMK Configurator tool</a>. The drag-and-drop interface was simple to use, especially since I don't know much about the underlying processes. QMK has a good <a href="https://www.youtube.com/watch?v=-imgglzDMdY">video intro</a> to the configurator; I'll deviate from it in that I used QMK from the command line, not from a GUI.</p>
<h4 tabIndex=0>Select the keyboard</h4>
<p>Choose your keyboard type from the dropdown at the top of the configurator.</p>
<p>In my case, my keyboard (<code>kbdfans/kbd65</code>) isn’t actually in the list of available keyboards in the QMK Configurator, but it is supported under the name <code>kbdfans/kbd67</code>. This keyboard defaults to the <code>LAYOUT_65_ansi</code> layout which matched my keyboard perfectly.</p>
<aside class="aside">
<p class="aside-body">
Once I had the firmware installed, I was able to find a readme stating that kbd67 is just another name for kbd65. Confusing messaging, but everything worked as expected using the kbd67 option.
</p>
</aside>
<h4 tabIndex=0>Design the layout map</h4>
<p>This is the fun part! Drag and drop keys to where you actually want them. I won't get into using multiple layers, or any actual C programming 😅 It's very 1337 but not what I needed my first time around.</p>
<h4 tabIndex=0>Download the layout</h4>
<p>Since you already have the keyboard firmware installed, once you have your map made in the QMK Configurator, you can hit the <code>Download Keymap.json</code> button without compiling the layout. From now on you’ll be working completely in the command line, but keep this browser window open for follow-up tweaks to the layout.</p>
<h3 tabIndex=0>Flash the layout onto the keyboard</h3>
<aside class="aside">
<h3 class="aside-title">Important</h3>
<p class="aside-body">
The following process assumes you have a second keyboard connected; e.g., a built-in laptop keyboard. If you don't have a second keyboard, you will probably need to activate speech-to-text or an onscreen mouse-accessible keyboard before following the next steps.
</p>
</aside>
<p>Your keymap needs to be compiled in order to be flashed onto the keyboard. Locate the JSON file downloaded from the QMK configurator, and run:</p>
<div class="highlight"><pre class="code shell"><code>qmk compile <path/to/downloaded/layout>.json
</code></pre></div>
<p>If successful, QMK will output a <code>.hex</code> file into its root directory. For me, this was at <code>Users/<my_username>/qmk_firmware</code>.</p>
<p>Next, the keyboard needs to be put into DFU/Bootloader mode in order to be flashed. While in Bootloader mode, it will not send inputs to your computer like it normally does. If your keyboard underlight is on, the light will turn off when the board goes into Bootloader mode.</p>
<p>Keyboard vary in how they can be sent into Bootloader mode. QMK has <a href="https://docs.qmk.fm/#/newbs_flashing?id=put-your-keyboard-into-dfu-bootloader-mode">instructions on different ways to do this</a> — the first time I flashed my keyboard, the Spacebar+B strategy worked. Subsequent times, this didn’t work, but unplugging my keyboard and plugging it back in with the ESC key pressed did send it into Bootloader mode correctly.</p>
<aside class="aside">
<p class="aside-body">
I moved my ESC key the first time I flashed my keyboard, and I expected to hit the "new" ESC key to send it into Bootloader mode. Not so. The "original" ESC key, remapped to a different keycode, is still what needs to be pressed here.
</p>
</aside>
<p>With your keyboard in Bootloader mode, run <code>qmk flash</code> on the command line to send your layout onto the keyboard. Don't unplug the keyboard until you get a message that the flash has completed. Now your keyboard is using your custom layout! 🎉</p>
<p>You can flash your keyboard as many times as you want to. I flashed mine about ten times during that session as I honed what I actually wanted my keyboard to do.</p>
<h2 class='section-title' id=the-result><a href='#the-result' class='section-inner'>The result</a></h2>
<p>In the end, I have a keyboard that is completely tailored to what <em>I</em> want, and it feels glorious. In addition to a full keyboard, I have dedicated play/pause and volume up/down buttons. The volume buttons also let me skip tracks when paired with a modifier key 💅🏻 And, naturally, I have a couple of keys dedicated to toggling the keyboard underlight.</p>
<aside class="aside">
<p class="aside-body">
I had NO IDEA that my keyboard had an underlight until I took it out of bootloader mode for the first time. On top of that, it's a full-spectrum underlight! So of course my default setting is to cycle through the entire rainbow.
</p>
</aside>
<p><div class=" image-primary">
<img src="/images/kbd/win-2.JPG" alt="A pink-and-white keyboard." title="My custom keyboard." width="4032px" height="3024px" />
</div></p>
<p>All in all, the time and money I've invested in this keyboard has felt worth it -- because it <em>has</em> truly felt like an investment. I love having tools that feel good to use, that work well, that feel familiar to me. I've been using this keyboard for about a month now; it's a little puff of wind in my sails whenever I sit down to work, and I look forward to many years with it.</p>
<h2 class='section-title' id=thank-you><a href='#thank-you' class='section-inner'>Thank you</a></h2>
<p>First, thanks for reading this far, and I hope it's been helpful!</p>
<p>Thanks to <a href="http://egstad.com/">Jordan Egstad</a> for being an endless font of keyboard inspiration & knowledge. Also, thank you for letting me borrow your "starter keyboard" for 😅 <strong>months</strong> 😅 as I decided what I was actually going to buy.</p>
<p>Thanks also to <a href="https://angelariggs.github.io/">Angela Riggs</a> for additional keyboard intel, such as encouraging me to take my time setting up my dev environment.</p>
Do you want to build a slide deck?https://vgpena.github.io/do-you-want-to-build-a-slide-deck/2020-02-29T20:37:00-08:002021-05-04T13:36:14-07:00Violet PeñaGiving a presentation often means building a deck. Here's a comparison of my favorite deck-building tools, including times to use or avoid each of them.<p>Over the past several years, I’ve given a few conference talks and many less-formal workplace presentations. This means I’ve spent a lot of time writing and editing slide decks. Along the way, I’ve grown to love three deck-building tools: Dropbox Paper, Google Slides, and Keynote. They each have their own strengths and flourish in different settings.</p>
<p>Here’s a rundown of these presentation tools based on my preferences and experience.</p>
<h2 class='section-title' id=dropbox-paper><a href='#dropbox-paper' class='section-inner'>Dropbox Paper</a></h2>
<p><strong>The simple one.</strong> Technically, you don’t make decks in Paper, but it’s my go-to for for informal presentations.</p>
<p><figure role="img" class=" image-secondary">
<img src="/images/snowman.gif" alt="Ana from Disney's "Frozen" sings into a closed door. Subtitle reads: "Do you want to build a snowman?"" title="It doesn't have to be a snowman" width="281px" height="252px" />
<figcaption>
<p>It doesn't have to be a slide deck 🎵</p>
</figcaption>
</figure></p>
<p>If you hit the Present button on any Paper doc, you get a cleaned-up view of the doc with larger text, no toolbars, etc. The secret sauce here is that horizontal rules in the original doc create slide breaks in Presentation mode. This creates cleaner visuals and transforms a wall of text into something resembling a slide deck.</p>
<p>Paper lacks the layout and formatting options of other presentation apps. For informal presentations, this tradeoff is worth it because it frees you up to focus on the writing instead of the visuals. This is great news when you need to work quickly 😅 or when you simply don’t want to sink effort into type, colors, and spacing.</p>
<h3 tabIndex=0>Use Paper when…</h3>
<ul>
<li>The talk is fairly informal</li>
<li>You’re on a <em>super</em> tight deadline</li>
</ul>
<h3 tabIndex=0>Avoid Paper when..</h3>
<ul>
<li>You need a distinctive visual style</li>
<li>You need speaker notes</li>
</ul>
<h2 class='section-title' id=google-slides><a href='#google-slides' class='section-inner'>Google Slides</a></h2>
<p><strong>The collaborative one.</strong> Google Slides is my most-used presentation app, and the absolute winner for group work. You can grant different permissions levels; for example, allow anyone at your company to comment but restrict editing to specific individuals. Slides gives you robust drawing and layout features, but is lighter and easier to learn than Keynote.</p>
<p>Although Slides is web-based, it has an offline mode which is great for conference settings with unreliable internet. The caveat here is that offline presentations don’t play videos; the first frame shows as a poster image instead. In all situations, the Slides embedded video player feels unpolished as compared with Keynote.</p>
<h3 tabIndex=0>Use Slides when…</h3>
<ul>
<li>You’re working in a group</li>
</ul>
<h3 tabIndex=0>Avoid Slides when…</h3>
<ul>
<li>You want attractive video embedding</li>
</ul>
<h2 class='section-title' id=keynote><a href='#keynote' class='section-inner'>Keynote</a></h2>
<p><strong>The classy one.</strong> Keynote is for making an ultra-polished presentation with no compromises. Out of all these tools, Keynote gives you the most control over all aspects of your deck, and you get luxe features such as magic transitions 🤩 and beautiful video embedding. Keynote also includes helpful presenter tools, such as a Rehearsal Mode and a robust Presenter Display during the talk itself.</p>
<p>All of this comes with a couple of tradeoffs. Firstly, the learning curve for Keynote is steeper than that of Slides, and even if you’re good with Slides, Keynote won’t necessarily feel familiar. Additionally, group work in Keynote is challenging as compared to Slides.</p>
<h3 tabIndex=0>Use Keynote when…</h3>
<ul>
<li>You want the most beautiful deck possible</li>
<li>You want great video embedding</li>
</ul>
<h3 tabIndex=0>Avoid Keynote when…</h3>
<ul>
<li>Working in a group</li>
</ul>
<h2 class='section-title' id=in-conclusion><a href='#in-conclusion' class='section-inner'>In Conclusion</a></h2>
<p>Every presentation is different, and I haven’t found the One True Deck-Builder that I will use for every deck for the rest of my career. In the meantime, I rotate between Dropbox Paper, Google Slides, and Keynote depending on how quickly vs. collaboratively vs. polished I want to work.</p>
<p>I hope this comparison has been helpful. Sending you good presentation vibes!</p>
<hr>
<p>PS - Thank you to Ginger for asking me the original question about presentation tools 🙂</p>
<p>PPS - I haven’t used it professionally, so I can’t speak to it here, but I <em>love</em> Prezi. Maybe deserves an Honorable Mention?</p>
<p>PPPS - That's right, I got a February 29th publish date in there! Goooo leap years 🥳</p>
Using CSS Grid the right wayhttps://vgpena.github.io/using-css-grid-the-right-way/2019-02-17T13:58:00-08:002021-05-04T13:36:14-07:00Violet PeñaCSS Grid is fun to use but hard to learn. Here are three tips to help you understand and leverage the Grid spec.<p>CSS Grid is robust, flexible, and a refreshing paradigm shift from other CSS layout systems. While these are selling points for Grid, they also make it hard to learn.</p>
<p>“Learning” CSS Grid requires developing working knowledge of many new properties that don’t just describe <em>one</em> aspect of appearance or behavior, but feed into a completely new layout system. This system includes <a href="https://css-tricks.com/snippets/css/complete-guide-grid/">around 18</a> properties which use paradigms and syntax rarely (or never) seen anywhere else in the CSS spec.</p>
<p>This means that CSS Grid has a pretty high <a href="https://us.battle.net/forums/en/overwatch/topic/20759355930#post-2">skill floor</a> — a developer needs to learn and internalize lots of new information in order to be effective with it. Once you’re above that skill floor, Grid is an amazing ally in layout creation. Below that skill floor, Grid is an encumbrance. You wonder why you’re bothering to use it at all, since it seems to require lots of additional work for little reward.</p>
<p>In this post, I want to help you overcome that skill floor by showing you the most effective ways to leverage the Grid spec. While I’m not covering the spec in its entirety — for something like that, see <a href="https://css-tricks.com/snippets/css/complete-guide-grid/">this CSS Tricks post</a> — but what I cover here are, for me, the helpful aspects of this layout system.</p>
<h2 class='section-title' id=use-names-not-numbers><a href='#use-names-not-numbers' class='section-inner'>Use names, not numbers</a></h2>
<p>Grid columns and rows, at their most basic, are referred to by number. For example, this CSS sets up a grid with two columns and puts the page’s main content into the second column:</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.container</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="m">1</span><span class="n">fr</span> <span class="m">2</span><span class="n">fr</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.content</span> <span class="p">{</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="m">2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>This works, but it misses an amazing feature of Grid: you can give your rows and columns specific names. You should take advantage of this whenever possible.</p>
<p>Here’s the same CSS, adjusted to use names:</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.container</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="p">[</span><span class="n">sidebar</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span> <span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="m">2</span><span class="n">fr</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.content</span> <span class="p">{</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">content</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Even in lightweight cases like this, it's to your advantage to name grid areas.</p>
<h3 tabIndex=0>Benefits</h3>
<p>Adding names to your grid brings a couple of major benefits.</p>
<p><strong>Readability —</strong> Right off the bat, your code is easier to understand. Line 3 now <em>describes</em> everything going on inside of the Grid container. You’re not just listing out columns; you’re outlining the <em>intent</em> of each column.</p>
<p>Line 7 has also become more descriptive. Previously, we only knew that <code>.content</code> lived in the second column, which doesn’t mean much without more context — column 2 out of 3? 2 of 200? Assigning a column name, however, signals that this element has specifically been accounted for within the larger system. Naming also makes it easier to find the original column declaration, should we need to.</p>
<p><strong>Future-proofing —</strong> Adding names makes your CSS more flexible. Specifically, you can iterate on <code>.container</code> without having to edit <code>.content</code>.</p>
<p>Want to swap the visual order of the content and the sidebar? Easy.</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.container</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="m">2</span><span class="n">fr</span> <span class="p">[</span><span class="n">sidebar</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.content</span> <span class="p">{</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">content</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Want to add another column? No prob.</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.container</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="p">[</span><span class="n">related-posts</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span> <span class="p">[</span><span class="n">sidebar</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span> <span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="m">2</span><span class="n">fr</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.content</span> <span class="p">{</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">content</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Without using named columns, you would have to update the column number in line 7 to reflect the changes made in line 3. Named columns give <code>.content</code> consistent behavior that’s independent of the column count or order.</p>
<h2 class='section-title' id=use-codefrcode-as-your-flexible-unit><a href='#use-codefrcode-as-your-flexible-unit' class='section-inner'>Use <code>fr</code> as your flexible unit</a></h2>
<p>CSS Grid introduces the <code>fr</code> unit, which tells an area to occupy some fraction of the total available space. While <code>fr</code> might seem like a sidenote within the Grid spec, it's actually indispensible.</p>
<p>The <code>fr</code> unit is different from <code>%</code> or <code>vw</code> because while the latter units describe portions of a 100-unit whole, <code>fr</code>s are defined by the space not already used by something else. <code>fr</code>s split up this space relative to each other.</p>
<p>Here, the <code>content</code> column is twice as wide as the <code>sidebar</code> column.</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.container</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="p">[</span><span class="n">sidebar</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span> <span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="m">2</span><span class="n">fr</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.content</span> <span class="p">{</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">content</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Since there are no non-<code>fr</code> units and three <code>fr</code>s in total, 1fr = ~33% of the width of the grid.</p>
<h3 tabIndex=0>Benefits</h3>
<p>The <code>fr</code> unit offers a couple of things that other flexible units lack.</p>
<p><strong>Readability and clearer intent —</strong> Using <code>fr</code>s, unlike using percents, lets us stick with whole numbers that are sized relative to each other, not relative to a whole. This keeps the intended behavior clear. For example, line 3 is straightforward to translate into English: “The content is twice as wide as the sidebar”.</p>
<p><code>fr</code>s also let you divvy up space in ways that would be hard to calculate (and read) using percentages.</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.container</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="p">[</span><span class="n">sidebar</span><span class="p">]</span> <span class="m">3</span><span class="n">fr</span> <span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="m">4</span><span class="n">fr</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p><strong>Less math —</strong> The biggest benefit of the <code>fr</code> is that it takes the responsibility for doing exact arithmetic away from the developer and hands it off to the browser’s layout engine. For example, <a href="https://codepen.io/vvviolet/pen/VgVExq">here’s a CodePen</a> showing two ways to make the same layout using CSS Grid.</p>
<p>These lines are the crux of the demo:</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.percents</span><span class="o">,</span> <span class="nc">.frs</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-column-gap</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.percents</span> <span class="p">{</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="nb">repeat</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="n">calc</span><span class="p">((</span><span class="m">100%</span> <span class="n">-</span> <span class="m">40px</span><span class="p">)/</span><span class="m">3</span><span class="p">))</span>
<span class="p">}</span>
<span class="nc">.frs</span> <span class="p">{</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="nb">repeat</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="m">1</span><span class="n">fr</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>The code on line 7 is hard to write, hard to read, and brittle. Any change to <code>grid-column-gap</code> or to our column count will break the layout, unless we manually update the column width to match.</p>
<p>Line 11 can ignore the gap size and won’t require new math if we update the column count. It’s easy to read and future-proof.</p>
<h2 class='section-title' id=dont-use-a-grid-system><a href='#dont-use-a-grid-system' class='section-inner'>Don’t use a grid system</a></h2>
<p>This contradictory-sounding recommendation extends beyond the CSS Grid spec and bleeds into how web design works and how developers interface with designers and their work.</p>
<p>Layouts are often understood as elements aligned along a grid system.</p>
<p><div class=" image-primary">
<img src="/images/grid-1.png" alt="" title="A 14-column grid system." width="2147px" height="1249px" />
</div></p>
<p>Typically, development strives for exact parity with design. If designs are based on a 14-column grid, development will set up some kind of 14-column grid in code and write helper classes to make items span 1, 2, 3, 6, etc. columns. Most frontend frameworks, like <a href="https://getbootstrap.com/docs/4.3/layout/grid/">Bootstrap</a>, work this way.</p>
<p>In the above example, we have a 14-column grid, with these elements to place and size:</p>
<ol>
<li>The header, which starts at column 2 and spans 12 columns</li>
<li>The sidebar, which starts at column 2 and spans 4 columns</li>
<li>The main content, which starts at column 6 and spans 8 columns</li>
</ol>
<p>In CSS Grid, it’s easy to set up a system that mimics the design:</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.main</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-column-gap</span><span class="p">:</span> <span class="m">2rem</span><span class="p">;</span>
<span class="py">grid-row-gap</span><span class="p">:</span> <span class="m">1rem</span><span class="p">;</span>
<span class="py">grid-template-rows</span><span class="p">:</span> <span class="p">[</span><span class="n">header</span><span class="p">]</span> <span class="m">100px</span> <span class="p">[</span><span class="n">body</span><span class="p">]</span> <span class="nb">auto</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="nb">repeat</span><span class="p">(</span><span class="m">14</span><span class="p">,</span> <span class="m">1</span><span class="n">fr</span><span class="p">);</span>
<span class="p">}</span>
<span class="nc">.header</span> <span class="p">{</span>
<span class="nl">grid-row</span><span class="p">:</span> <span class="n">header</span><span class="p">;</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="m">2</span> <span class="p">/</span> <span class="n">span</span> <span class="m">12</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.sidebar</span> <span class="p">{</span>
<span class="nl">grid-row</span><span class="p">:</span> <span class="n">body</span><span class="p">;</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="m">2</span> <span class="p">/</span> <span class="n">span</span> <span class="m">4</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.content</span> <span class="p">{</span>
<span class="nl">grid-row</span><span class="p">:</span> <span class="n">body</span><span class="p">;</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="m">6</span> <span class="p">/</span> <span class="n">span</span> <span class="m">8</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>But is this actually a good plan? Our attempt at 1:1 reproduction has two drawbacks.</p>
<p>First, it foils our plan to name columns. Additionally, out of our 14 columns, we are only “using” columns 2, 5, 6, and 13. This <em>technically</em> works, but it suggests a bad signal-to-noise ratio.</p>
<p>Both of these problems are solved if we can take a couple of steps away from the original design:</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.main</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-column-gap</span><span class="p">:</span> <span class="m">2rem</span><span class="p">;</span>
<span class="py">grid-row-gap</span><span class="p">:</span> <span class="m">1rem</span><span class="p">;</span>
<span class="py">grid-template-rows</span><span class="p">:</span> <span class="p">[</span><span class="n">header</span><span class="p">]</span> <span class="m">100px</span> <span class="p">[</span><span class="n">body</span><span class="p">]</span> <span class="nb">auto</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="p">[</span><span class="n">left-gutter</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span> <span class="p">[</span><span class="n">sidebar</span><span class="p">]</span> <span class="m">4</span><span class="n">fr</span> <span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="m">8</span><span class="n">fr</span> <span class="p">[</span><span class="n">right-gutter</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.header</span> <span class="p">{</span>
<span class="nl">grid-row</span><span class="p">:</span> <span class="n">header</span><span class="p">;</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">sidebar</span> <span class="p">/</span> <span class="n">right-gutter</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.sidebar</span> <span class="p">{</span>
<span class="nl">grid-row</span><span class="p">:</span> <span class="n">body</span><span class="p">;</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">sidebar</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.content</span> <span class="p">{</span>
<span class="nl">grid-row</span><span class="p">:</span> <span class="n">body</span><span class="p">;</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">content</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Now instead of having fourteen columns, we only have four, but they still divide up the lateral space into fourteen parts. We have the exact same visual effect as in the first iteration, but our code is less noisy and directly reflects how it’s used.</p>
<p>We can continue this paradigm throughout the layout. Say that within the <code>.content</code> element, we have a need for auxiliary information (an author bio, a blurb, etc.) next to the main article.</p>
<p><div class=" image-primary">
<img src="/images/grid-2.png" alt="" title="A 14-column grid system with additional nested elements." width="2132x" height="1248px" />
</div></p>
<p>If we have adhered tightly to the 14-column grid, it appears that we need something like this:</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.content</span> <span class="p">{</span>
<span class="nl">grid-row</span><span class="p">:</span> <span class="n">body</span><span class="p">;</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="m">6</span> <span class="p">/</span> <span class="n">span</span> <span class="m">8</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.article</span> <span class="p">{</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="m">7</span> <span class="p">/</span> <span class="n">span</span> <span class="m">4</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.info</span> <span class="p">{</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="m">11</span> <span class="p">/</span> <span class="n">span</span> <span class="m">2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Which will be tricky, since CSS Grid has no concept of inheritance. <code>.info</code> doesn’t know anything about the grid set up on <code>.main</code>, its grandparent element.</p>
<p>If we have let go of the literal 14-column grid, however, we may notice that <code>.article</code> and <code>.info</code> don’t <em>need</em> to know anything about the top-level grid — they’re part of a new grid inside of <code>.content</code>.</p>
<div class="highlight"><pre class="code css"><code><span class="nc">.content</span> <span class="p">{</span>
<span class="nl">grid-row</span><span class="p">:</span> <span class="n">body</span><span class="p">;</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">content</span><span class="p">;</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="p">[</span><span class="n">left-gutter</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span> <span class="p">[</span><span class="n">article</span><span class="p">]</span> <span class="m">4</span><span class="n">fr</span> <span class="p">[</span><span class="n">info</span><span class="p">]</span> <span class="m">2</span><span class="n">fr</span> <span class="p">[</span><span class="n">right-gutter</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span><span class="p">;</span>
<span class="py">grid-column-gap</span><span class="p">:</span> <span class="m">2rem</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.article</span> <span class="p">{</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">article</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.info</span> <span class="p">{</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">info</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Using this setup, <code>.content</code> is simple and internally consistent, but also aligns perfectly with our outer columns set up on <code>.main</code>.</p>
<h3 tabIndex=0>Benefits</h3>
<p>In addition to what I’ve already outlined, looser adherence to the original design system sets us up as developers to leverage our expertise and our tools — the browser — more effectively. Pixels and columns are less salient than relationships and proportional space.</p>
<p>It’s not significant that <code>.article</code> starts at column 7 and <code>.info</code> at column 11. It <em>is</em> significant that <code>.article</code> is twice as wide as <code>.info</code>. Thinking about elements proportionally and questioning how they interact with each other helps us treat layouts as dynamic systems.</p>
<h3 tabIndex=0>Sidenote: Nesting Markup</h3>
<p>One thing you may have noticed about the code samples in this section is the usage of <code>left-gutter</code> and <code>right-gutter</code> columns. This CSS assumes the most flat HTML possible.</p>
<div class="highlight"><pre class="code html"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"main"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"header"</span><span class="nt">></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"sidebar"</span><span class="nt">></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"content"</span><span class="nt">></div></span>
<span class="nt"></div></span>
</code></pre></div><div class="highlight"><pre class="code css"><code><span class="nc">.main</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="p">[</span><span class="n">left-gutter</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span> <span class="p">[</span><span class="n">sidebar</span><span class="p">]</span> <span class="m">4</span><span class="n">fr</span> <span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="m">8</span><span class="n">fr</span> <span class="p">[</span><span class="n">right-gutter</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>If we are willing to put a wrapper div into the markup, we can write more direct CSS with fewer columns per element.</p>
<div class="highlight"><pre class="code html"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"main"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"wrapper"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"header"</span><span class="nt">></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"sidebar"</span><span class="nt">></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"content"</span><span class="nt">></div></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
</code></pre></div><div class="highlight"><pre class="code css"><code><span class="nc">.main</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="p">[</span><span class="n">left-gutter</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span> <span class="p">[</span><span class="n">wrapper</span><span class="p">]</span> <span class="m">12</span><span class="n">fr</span> <span class="p">[</span><span class="n">right-gutter</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.wrapper</span> <span class="p">{</span>
<span class="nl">grid-column</span><span class="p">:</span> <span class="n">wrapper</span><span class="p">;</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="py">grid-template-columns</span><span class="p">:</span> <span class="p">[</span><span class="n">sidebar</span><span class="p">]</span> <span class="m">1</span><span class="n">fr</span> <span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="m">2</span><span class="n">fr</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>The second approach feels inherently better because the math is simpler — you get to stop worrying as soon as possible about numbers that add to 14 and just think about a 1:2 ratio. This feels true to the spirit of CSS Grid.</p>
<p>What doesn’t feel true to CSS Grid, though, is adding the <code>.wrapper</code> div. Grid works hard to help us separate presentation from content — i.e., we don’t need to add extra elements to make the styling work or “behave nicely”. So, at least for today, I encourage you <em>not</em> to add or change markup for the sole purpose of cleaner CSS Grid styling.</p>
<h2 class='section-title' id=coda><a href='#coda' class='section-inner'>Coda</a></h2>
<p>Thanks for coming on this CSS Grid journey with me! I’ve been using and loving it over the past couple of months, and I hope this helps you understand and use it on your end 💐</p>
<p>To reiterate my points from the intro, CSS Grid is easy to use but difficult to learn. It’s a more intuitive paradigm than any other CSS layout technique, but it’s completely different from its predecessors.</p>
<p>All this to say: take Grid as slowly as you need to. Don’t try to understand it all just from reading the spec. Set up simple examples, pop open that web inspector (especially in Firefox!), and be kind to yourself.</p>
<p>It’ll be worth it.</p>
<h2 class='section-title' id=changelog><a href='#changelog' class='section-inner'>Changelog</a></h2>
<ul>
<li>3/1/2020: Fixed column typo (<a href="https://github.com/vgpena/vgpena.github.io/issues/5">#5</a>)</li>
</ul>