<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Evan Sutherland</title>
    <description>The latest articles on Forem by Evan Sutherland (@stackoverfloweth).</description>
    <link>https://forem.com/stackoverfloweth</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F281275%2F8198b34f-5d65-44a0-94f4-ddd7235199d4.png</url>
      <title>Forem: Evan Sutherland</title>
      <link>https://forem.com/stackoverfloweth</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/stackoverfloweth"/>
    <language>en</language>
    <item>
      <title>Unsolicited Wisdom: My Take on Clean Code in the Frontend</title>
      <dc:creator>Evan Sutherland</dc:creator>
      <pubDate>Mon, 01 Jul 2024 16:38:00 +0000</pubDate>
      <link>https://forem.com/stackoverfloweth/unsolicited-wisdom-my-take-on-clean-code-in-the-frontend-22bb</link>
      <guid>https://forem.com/stackoverfloweth/unsolicited-wisdom-my-take-on-clean-code-in-the-frontend-22bb</guid>
      <description>&lt;h2&gt;
  
  
  Always avoid
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cryptic names.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;This applies to variables, functions, classes, types, filenames, everything! This means no single letter variables, no abbreviations, nothing cute. It’s better to have names that are long but clear than names that are short and confusing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing unit tests to prove nothing.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Unit tests are most effective when they’re asserting something that’s not obvious. Think of a unit test as a comment on steroids, comments explain something that doesn’t make sense, unit tests explain the code AND assert that it doesn’t get changed. Furthermore, if it turns out we can simplify or we change that code, the test MUST be changed whereas comments are content to just float around misleading people.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Most ternaries, especially nested ones.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;This one is pretty straight forward, ternaries work best for simple assignments. &lt;code&gt;const url = isAbsolute(path) ? "https://" + path : path&lt;/code&gt;. When you’re doing more than simple assignment, ternaries just make your code harder to read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Magic strings, magic numbers, magic in general.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;This is another of many rules with the same goal, simple to understand code. When we come across functionality that is driven by very specific strings/numbers, it’s hard to know the significance. Did the developer choose &lt;code&gt;42&lt;/code&gt; because that’s the answer to all of our problems? Or is &lt;code&gt;43&lt;/code&gt; okay too? Does &lt;code&gt;getProduct(20)&lt;/code&gt; mean we’re going to get product by id &lt;code&gt;20&lt;/code&gt;? or maybe getting 20 products back in an array? Magic might feel nifty, time-saving, or cleaver as an author but I promise everyone else who has to work with it will be worse off.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try to avoid
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Abusing utilities.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Dumping logic into a “util” in the pursuit of “DRY” code. For a service to be classified as a “utility” it should be applicable to ANY project not just Polly. So if you’re about to add a new utility it should be something that would be useful to poptarts.com, puginarug.com, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clever solutions.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Try to choose simple solutions over fancy ones. This tends to create more maintainable code bases, especially with junior devs on the team. Often times more senior devs get bored and over engineer solutions that add unnecessary complexity. Sometimes we trick ourselves into thinking that complexity is justified because of something like performance, but it’s almost never the case. Don’t trade easily understood for a few milliseconds of faster page load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comments in code.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Comments should be thought of as a necessary evil. They are a tool that serves a purpose, but wielding that tool should be done with great tact. Robert Martin mentions this in Clean Code perfectly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Usually they are crutches or excuses for poor code or justifications for insufficient decisions, amounting to little more than the programming talking to himself."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Code should be readable and understandable without comments. If you feel like you need to add a comment to explain yourself, be sure you can’t accomplish the same ends with better naming.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// products that cost $4
const products = await getProducts(4)

// if products is loaded and not errored
if(products.results &amp;amp;&amp;amp; !products.loading &amp;amp;&amp;amp; !products.errored) {
  // update products to include category
  return mapProducts(products.results)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const desiredPriceRange = 4
const productsInPriceRange = await getProductsByPrice(desiredPriceRange)

const productsAreLoadedAndNotErrored = products.results &amp;amp;&amp;amp; !products.loading &amp;amp;&amp;amp; !products.errored
if(productsAreLoadedAndNotErrored) {
  return setCategoryOnProducts(products.results)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even with readable code, sometimes we’re tempted to use comments to tell future devs why certain logic was used. Maybe this is business logic, or a lesson hard learned, but the solution should probably be a unit test, not a comment. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using javascript to solve css problems.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is primarily about separation of concern, but also is almost always better for performance. CSS Is really good at CSS things. Just because you could solve it in JS doesn’t mean you should!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nesting.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Aka pyramid of doom. Every time you nest something, you’re asking the reader to jump into a rabbit hole. We as a reader must retain the context of what’s happening above while continuing through this nested context. If you need an if statement in your function, make sure whats nested inside is ridiculously simple or have it call another function that we can dig into when we’re done with this function. &lt;/p&gt;

&lt;p&gt;Using an else also usually just creates more unnecessary nesting. It’s preferable to return early.&lt;/p&gt;

&lt;p&gt;This applies to both conditions in TS as well as DOM nodes. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enums in Typescript&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enums do not provide the same level of type safety as other TypeScript constructs like union types. They allow implicit type coercion, which can lead to subtle bugs. It’s safer and a better developer experience to just turn your enum into a string union. type Color = 'red' | 'blue' | 'green' &lt;/p&gt;

&lt;h2&gt;
  
  
  Potential code smell
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Using ts-expect-error, eslint-ignore.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In general, if you have to circumvent the tools that are in place to ensure code quality and consistency that’s almost certainly a bad idea. There are times when these things are actually acceptable (eslint-ignore more so than ts-expect-error). However, the presence of these is definitely a code smell and reason to dig deeper as a code reviewer.&lt;/p&gt;

&lt;p&gt;If you ever do intend to submit one of these into production code, it’s helpful to include your reasoning in the comment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding new dependency.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Adding dependencies to a project can seem like a quick solution to many problems, but it’s important to consider the long-term impacts. Dependencies come with overhead, keeping them up-to-date, learning their syntax, and working within their dev cycle to get bugs resolved. Using external dependencies often limits our ability to provide consistent developer experience and opens up our app to security vulnerabilities and overall bloat.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Type casting.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When comparing Typescript to Javascript it’s often said "TypeScript makes easy things hard and hard things any". Typescript is hard, it requires us to define our logic twice. Often times developers who are new to Typescript will only focus on the runtime logic, neglecting the mirrored logic for types. The lazy solution to this is to just cast your type from whatever Typescript says it is to what you wanted it to be. Sometimes it’s necessary, but Typescript is often trying to tell you something useful. Be sure to heed this advice from time to time and not use casting indiscriminately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Committing dead or commented out code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We use git, if you need to preserve a previous iteration of what you’re working on, commit it and it will continue to be available to you until you squash and merge. It’s too easy to forget to remove your commented out code. &lt;/p&gt;

&lt;p&gt;If you come across dead or commented out code you should&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complicated, flakey tests.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;If your test is hard to write, the underlying code is probably too complicated and responsible for too much. Tests should be just as readable and maintainable as our production code. Which is quite a daunting task, but one that we should take seriously. Tests that are too complex to understand provide little value.&lt;/p&gt;

&lt;p&gt;Often times complex tests are also flakey tests. When any number of tests are flakey, it jeopardizes the faith developers will have in the entire test suite. &lt;/p&gt;

&lt;p&gt;It’s better to have more tests that are concise and simple than it is to have fewer tests that are large and hard to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try to encourage
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Breaking things out.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Breaking out functions, services, components to keep things small and concise. Every function/service/component should have a SINGLE purpose, if you’re adding a block of logic that’s doing something else, it should be pulled out into a separate dependency. Also whenever you’re inside a loop (for-loop, or v-for), the contents should probably be a separate function/component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encapsulate complexity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A common example of this is conditions. Rather than putting a condition in an if statement and expecting the reader to understand what we’re checking, move it into an easily understood const. For example, &lt;code&gt;if(user.age &amp;gt; 16 &amp;amp;&amp;amp; user.ownsCar &amp;amp;&amp;amp; user.hasLicense) { ... }&lt;/code&gt;  is much more easily understood as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const userCanDrive = user.age &amp;gt; 16 &amp;amp;&amp;amp; user.ownsCar &amp;amp;&amp;amp; use.hasLicense

if(userCanDrive){ ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Avoid extra noise.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Skip semi-colons, avoid excess DOM nodes, don’t be repetitive in variable names, use self-closing vue components. The less boilerplate, the faster we can all get to the meaningful parts. Be sure that the noise you’re removing is actually noise, and not helpful context. Don’t take this rule to mean you should be playing code golf.&lt;/p&gt;

&lt;h2&gt;
  
  
  Always encourage
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Consistency!&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;It’s always better to be consistent than accurate. Even if you have a more “correct” syntax, if the “less correct” syntax is use all over you should use the “less correct” syntax. Take your great idea to the team and open a separate PR to update all of the places to use your new “correct” syntax.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Boy scout’s rule.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Leave the code cleaner than you found it. Even if it wasn’t you’re fault that there’s a mess in a file, it’s all of our responsibilities to get the codebase as clean as possible.&lt;/p&gt;

&lt;p&gt;If you open a file and it’s a hot mess, don’t feel like you have to fix EVERYTHING. The goals says “cleaner” not “perfect”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic HTML.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;This is a skill that’s deeply underrated. Take some time to learn some of the nuance of semantic HTML, this makes a bigger difference than you might think. Like so many things, Chrome tends to hide a lot of our mistakes. &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>cleancode</category>
      <category>frontend</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The case against comments</title>
      <dc:creator>Evan Sutherland</dc:creator>
      <pubDate>Fri, 28 Jun 2024 00:54:54 +0000</pubDate>
      <link>https://forem.com/stackoverfloweth/the-case-against-comments-4kne</link>
      <guid>https://forem.com/stackoverfloweth/the-case-against-comments-4kne</guid>
      <description>&lt;p&gt;Most developers starting out assume comments are like sprinkles. They're something everyone likes and the more you use it, the prettier your donut. One of my favorite authors Robert C. Martin, author of "Clean Code", has this to say about comments.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Usually they are crutches or excuses for poor code or justifications for insufficient decisions, amounting to little more than the programer talking to himself."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Given this context, it's not surprising that junior devs write so many comments, since their code tends to be pretty rough around the edges. Even veteran developers who can truly write beautiful code sometimes think they need to reach for comments.&lt;/p&gt;

&lt;p&gt;I'd like to make a case against this impulse.&lt;/p&gt;




&lt;h2&gt;
  
  
  How comments are used
&lt;/h2&gt;

&lt;h3&gt;
  
  
  To explain what is already obvious
&lt;/h3&gt;

&lt;p&gt;There are plenty of times I've seen developers write perfectly simple code only to litter it with comments that explain what was already obvious.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkUserPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;permission&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Permission&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// if user is not authenticated, throw error&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserNotAuthenticatedError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// get current user role&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentUserRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUserRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// check if current user role includes permission&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;currentUserRole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;permission&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  To hold on to dead code
&lt;/h3&gt;

&lt;p&gt;Many devs can't help but comment out code they're afraid to delete.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// const hasPermission = await checkUserPermission(permissions.posts.edit)&lt;/span&gt;

&lt;span class="c1"&gt;// if(!hasPermission){&lt;/span&gt;
&lt;span class="c1"&gt;//   router.reject('insufficient access')&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  To explain strange business logic
&lt;/h3&gt;

&lt;p&gt;Even the most eloquent engineer might struggle to explain particularly complex or misleading business logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateLoyaltyMemberDiscount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoyaltyMember&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// loyalty members discount is 1% per month before merger, max 5%&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;monthsInInterval&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2010&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  To document code
&lt;/h3&gt;

&lt;p&gt;Especially in situations like projects that use vanilla JS, tools like JSDoc can provide some seriously useful context that happens to be provided in the form of comments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Calculates the loyalty discount for a customer based on their membership duration.
 * 
 * - Loyalty members receive a 1% discount for each month they were members before the merger.
 * - The maximum discount is capped at 5%.
 * 
 * @param {Customer} customer - The customer object.
 * @param {boolean} customer.isLoyaltyMember - Indicates if the customer is a loyalty member.
 * @param {Date} customer.startDate - The start date of the customer's loyalty membership.
 * @returns {number} The calculated loyalty discount.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateLoyaltyMemberDiscount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why comments are evil
&lt;/h2&gt;

&lt;p&gt;Most comments are added in an effort to improve readability, but what's evil about comments is they inevitably do the exact opposite. Even the best, most clearly written comment will eventually become evil, serving the demise of the code it was sworn to protect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comments can move
&lt;/h3&gt;

&lt;p&gt;Just like in real estate, comments are all about location. As blocks of code get moved, lines added, lines removed, the location of a comment might get moved away from the block it was referring to. &lt;/p&gt;

&lt;h3&gt;
  
  
  Comments can be outdated
&lt;/h3&gt;

&lt;p&gt;Codebases are constantly changing. Functions get renamed, conditions get added, APIs get deprecated, bugs are removed, bugs are added. How much do you trust other engineers, or yourself in 6 months, to make sure to refactor comments alongside the code that the comments refer to? &lt;/p&gt;

&lt;h3&gt;
  
  
  Comments can be misleading
&lt;/h3&gt;

&lt;p&gt;Now imagine that a refactor happens and nobody catches the outdated comment in code review. That comment is now not only wrong, it's misleading. Future engineers will spend more time trying to figure out how the code ever worked than they would if there was no comment at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to stop using comments
&lt;/h2&gt;

&lt;p&gt;Fortunately, the problem of explaining our poor code has better solutions than adding comments. Most of the time code is capable of explaining itself, it just takes a little practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give your variables, parameters, functions clear names
&lt;/h3&gt;

&lt;p&gt;Avoid single letter variables, acronyms, or shortening in general. There is no good reason in modern development to not be verbose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Break things out
&lt;/h3&gt;

&lt;p&gt;Some developers seem to think that you should only break out a function, component, file, if you think it's in pursuit of DRY code. Or in other words, only if it's likely to be reused. That's more of a convenient side-effect of the primary goal, keeping blocks of code small and concise!&lt;/p&gt;

&lt;h3&gt;
  
  
  Encapsulate primitives and conditions with clear names
&lt;/h3&gt;

&lt;p&gt;Whenever you see a primitive, a ternary, an if statement, or any other condition, see if breaking out a variable would make the intent clearer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 42 is the offset of the header&lt;/span&gt;
&lt;span class="nf"&gt;scrollTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// if animal is a dog&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sound&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sound&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headerOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;span class="nf"&gt;scrollTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;headerOffset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;animalIsDog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sound&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sound&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animalIsDog&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use unit tests
&lt;/h3&gt;

&lt;p&gt;Even with all of the tips above, some bits of business logic are too weird to explain easily in code. Complexity like this is a great candidate for a unit test. The title of your unit test can literally be the comment you were going to write, but a good test lets you assert the behavior doesn't change without mucking up the production code itself. &lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Let's look an example of some seriously ugly code and clean it up using the suggestions above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Usr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;perm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// validates user has API access and active session&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt;&lt;span class="nx"&gt;Usr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="c1"&gt;// user must have API access&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;perm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="c1"&gt;// check session is active&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/usr/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/valid`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;valid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;valid&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valid&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;valid&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USER_PERMISSIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;API&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ADMIN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserPermission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;USER_PERMISSIONS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;USER_PERMISSIONS&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserPermission&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validateUserHasActiveApiSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userNotSignedUpForApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;checkUserHasApiAccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userNotSignedUpForApi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;checkSessionStillActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkUserHasApiAccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;USER_PERMISSIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkSessionStillActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;UserSessionApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkUserSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;valid&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserSessionApi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;checkUserSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/usr/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/valid`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionValidityStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sessionValidityStatus&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This rewrite might be longer, but each block is tiny and significantly easier to understand and as a result maintain. Best of all, as the code evolves there are no comments that will get moved out of place, outdated, or misleading. &lt;/p&gt;

&lt;p&gt;Comments in code is a tool, you should use all the tools at your disposal to make the cleanest code base possible. However, it's important to understand that all tools have their downsides. So, next time you think your code needs a comment, see if you can fix it without a comment.&lt;/p&gt;

</description>
      <category>beginners</category>
    </item>
    <item>
      <title>Is mitt dead? 🥊</title>
      <dc:creator>Evan Sutherland</dc:creator>
      <pubDate>Wed, 19 Jun 2024 02:36:31 +0000</pubDate>
      <link>https://forem.com/stackoverfloweth/is-mitt-dead-3lb0</link>
      <guid>https://forem.com/stackoverfloweth/is-mitt-dead-3lb0</guid>
      <description>&lt;p&gt;Mitt was first released 7 years ago. Today, it has open issues going back to 2021, issues waiting to be triaged, open PRs completely ignored, and no commits since mid 2023. Are the issues not worth doing? Is the library just avoiding exceeding it's 200 byte "microscopic" constraint? Maybe the author is busy with new projects and is waiting on new contributors? It's hard to say, but it makes me wonder if it's just dead.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a meaningful aim for a project like this?
&lt;/h2&gt;

&lt;p&gt;Mitt is clearly still successful. It's easily one of the most popular Typescript event emitter libraries coming up on ~7M  downloads on npm. Having an audience makes it easy to assume it's good as is, but would it be even more popular if it were more actively maintained? Or would feature bloat kill it entirely? Does keeping that 200 byte zip size actually matter?&lt;/p&gt;

&lt;p&gt;Here's the past 5 years of downloads according to npm.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdt381heddfqixb2pwui.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdt381heddfqixb2pwui.png" alt="Growth on npm" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Despite a flat-lined commit history.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F630pdpzby4bcdea18oza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F630pdpzby4bcdea18oza.png" alt="Decline of commits" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When does it make sense to stop?
&lt;/h2&gt;

&lt;p&gt;Is it normal for projects to just stop? With the pace of change, especially as it relates to Typescript, if you're not changing it must mean you're dying. Is an event emitter just so simple that it can actually be "done"?&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking it personally
&lt;/h2&gt;

&lt;p&gt;In our case we needed a &lt;code&gt;once&lt;/code&gt; function. It's clear that mitt is &lt;strong&gt;not&lt;/strong&gt; interested in adding this feature any time soon. The implication was that this is a problem for users to solve, though we couldn't get the types to pass. So we built our own&lt;/p&gt;

&lt;h2&gt;
  
  
  Kitbag Events
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://events.kitbag.dev/"&gt;https://events.kitbag.dev/&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type safe events and payload&lt;/li&gt;
&lt;li&gt;Api includes &lt;code&gt;on&lt;/code&gt;, &lt;code&gt;off&lt;/code&gt;, &lt;code&gt;once&lt;/code&gt;, &lt;code&gt;emit&lt;/code&gt;, and &lt;code&gt;clear&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Support global Handlers&lt;/li&gt;
&lt;li&gt;Supports broadcast channel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxuban9zqqxmwno4vygfx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxuban9zqqxmwno4vygfx.png" alt="Kitbag Logo" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kitbag Events is a fresh take on an old concept. Like Mitt it's tiny with zero dependencies, though not trying to be "microscopic". My bet is that developers would prefer a modern library that's actively maintained, even it it comes with some extra bytes. Come check it out, drop a star ⭐️, and let us know if this was a good bet.&lt;/p&gt;

&lt;p&gt;Happy engineering!&lt;/p&gt;

</description>
      <category>typescript</category>
    </item>
    <item>
      <title>Introducing a new router for Vue</title>
      <dc:creator>Evan Sutherland</dc:creator>
      <pubDate>Fri, 24 May 2024 03:18:10 +0000</pubDate>
      <link>https://forem.com/stackoverfloweth/introducing-a-new-router-for-vue-3c22</link>
      <guid>https://forem.com/stackoverfloweth/introducing-a-new-router-for-vue-3c22</guid>
      <description>&lt;h2&gt;
  
  
  Brief history of my journey with vue-router
&lt;/h2&gt;

&lt;p&gt;Virtually every developer using Vue.js is currently using or has only ever used vue-router. Many of those developers, myself included, are mostly happy with it. The biggest complaint I hear is the lack of strongly typed routes, which is usually solved with a bit of Typescript wrapping your routes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// router/routes.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RouteLocationRaw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RouteRecordRaw&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RouteFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;RouteLocationRaw&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;club&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;clubId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clubs.view&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;clubId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile.view&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RouteFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;routes&lt;/code&gt; becomes your source of truth, so navigation should always use a route from &lt;code&gt;routes&lt;/code&gt; to send proper names to vue-router.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;routes.club('club-123')&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;go&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;club&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/router-link&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The syntax of defining routes is a bit cumbersome but honestly works fairly well. However, because I’m a serial starter-of-new-projects and love a challenge, I teamed up with &lt;a href="https://github.com/pleek91"&gt;Pleek91&lt;/a&gt; to see if we could build our own.&lt;/p&gt;




&lt;h1&gt;
  
  
  Introducing Kitbag Router
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://router.kitbag.dev"&gt;https://router.kitbag.dev&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It’s intentionally different
&lt;/h2&gt;

&lt;p&gt;We made the decision to start the project from scratch; solving problems from first principles rather than taking the path of so many others and try to build on top of the relatively old vue-router project. This means Kitbag Router is NOT a drop in replacement for projects using vue-router. Therefore, this freedom also means we can have a relentless pursuit of the best possible developer experience possible, not weighed down by having to have feature parity with vue-router.&lt;/p&gt;

&lt;h2&gt;
  
  
  First and foremost, it’s type safe!
&lt;/h2&gt;

&lt;p&gt;Kitbag Router uses a createRoutes utility that returns routes with the name, path, query, all preserved in the Route type. This means the routes you provide to createRouter will maintain type safety when accessing the current route or performing navigation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vwxfiyh97t9bpo9c6qj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vwxfiyh97t9bpo9c6qj.gif" alt="Image description" width="1744" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type safety in routing means auto complete when assigning to on &lt;code&gt;&amp;lt;router-link&amp;gt;&lt;/code&gt;, easy discovery of available routes when defining a &lt;code&gt;beforeRouteEnter&lt;/code&gt; hook, and ensuring that Typescript will error if the expected params for a route change without updating the &lt;code&gt;router.push()&lt;/code&gt; call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Params are way more powerful
&lt;/h2&gt;

&lt;p&gt;Not only does Kitbag Router know what params are expected for a given route, it can also support param types beyond &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Kitbag Router ships with built in support for params of typeString, &lt;code&gt;Number&lt;/code&gt;, &lt;code&gt;Boolean&lt;/code&gt;, &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;RegExp&lt;/code&gt;, &lt;code&gt;JSON&lt;/code&gt;, as well as any custom param type you define. Not only is this type useful when navigating, but it also means a route that expects a &lt;code&gt;number&lt;/code&gt; for an “id” param won’t be considered a match if the value provided in the URL doesn’t satisfy the number constraint. Furthermore, your Vue component that gets rendered for the route doesn’t have to worry about whether the param will be present or not or having to convert it from string to the type we know it’s supposed to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support for the query
&lt;/h2&gt;

&lt;p&gt;Params aren’t relegated to only the path. Kitbag Router allows you to configure your expected params in the query the same way you’re used to defining params in other parts of the URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling rejections
&lt;/h2&gt;

&lt;p&gt;Inevitably when defining your routes, you’ll want to add a “catch all” or “not found” route. While Kitbag Router fully supports defining plain ol’ Regex in your path/query, it also ships with even better support for handling &lt;code&gt;NotFound&lt;/code&gt;. We call this a “rejection”, which is customizable and can be extended to any custom rejection you need, like perhaps &lt;code&gt;NotAuthorized&lt;/code&gt;. When a rejection is triggered, usually from within one of your hooks, Kitbag Router will automatically render the rejection component you assigned for the given rejection type.&lt;/p&gt;

&lt;h2&gt;
  
  
  And more…
&lt;/h2&gt;

&lt;p&gt;These are the key features we think really make Kitbag Router compelling but there is so much more. Kitbag router is built for Vue3 and support async components, route hooks, editable params from useRoute, components for RouterLink and RouterView, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it ready?
&lt;/h2&gt;

&lt;p&gt;Kitbag Router is still super green and currently maintained by a team of 2. It has not yet had a stable release (on 0.2.0 as of the time I’m writing this), so things are still likely to change. That being said, I hope you’ll give it a try, maybe &lt;a href="https://github.com/kitbagjs/router"&gt;give it a star&lt;/a&gt;. We’re excited to hear from the community on what features we should focus on next.&lt;/p&gt;

&lt;p&gt;Happy engineering!&lt;/p&gt;

</description>
      <category>vue</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
