<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>sirajchokshi.com</title>
        <link>https://sirajchokshi.com</link>
        <description>Programming, design, etc posts</description>
        <lastBuildDate>Mon, 29 Jan 2024 08:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>sirajchokshi.com</title>
            <url>https://sirajchokshi.com/favicon.svg</url>
            <link>https://sirajchokshi.com</link>
        </image>
        <copyright>All rights reserved 2026, Siraj Chokshi</copyright>
        <item>
            <title><![CDATA[Refactors and Overfitting]]></title>
            <link>https://sirajchokshi.com/blog/overfitting</link>
            <guid>https://sirajchokshi.com/blog/overfitting</guid>
            <pubDate>Mon, 29 Jan 2024 08:00:00 GMT</pubDate>
            <description><![CDATA[Why you should consider delaying that next refactor. Overfitting versus incurring technical debt.]]></description>
            <content:encoded><![CDATA[<p>When clearing out cobwebs in an old part of a project (especially one I didn't write), it's easy to get carried away. I often catch myself thinking, "I wish I had time to rewrite this whole thing."</p>
<p>Engineers hate tech debt. At every CTO, VP, or director Q&#x26;A I've attended, an IC asks about how much time will be dedicated to paying it down in the next quarter or year. The answer is always unsatisfactory.</p>
<p>The unspoken reason tech debt payments are so hard to get sign-off on is clear[^1]: they provide little quantifiable value to the business. From the top-down, <a href="https://www.paulgraham.com/icad.html" rel="noreferrer" target="_blank">playing it safe is preferred</a>.</p>
<p>[^1]: When you're at a large firm it always feels good to hear an exec admit the writing is on the wall. Candor is common where I work right now, but there is always something that is not being said.</p>
<ol>
<li>An initial solution is developed</li>
<li>Feature creep from building $n + 1$ takes place</li>
<li>A refactor takes place to abstract or generalize the solution</li>
<li>Repeat steps 2-3 for the life of the project</li>
</ol>
<p>This cycle is inherent in creating any system. What matters is how long the cycle lasts. Keeping this cycle too short or too long is expensive:</p>
<ul>
<li>Too long --> technical debt</li>
<li>Too short --> overfitting</li>
</ul>
<p>I find that the technical debt problem is well understood and the overfitting problem, exacerbated by avoidable refactors, is not.</p>
<h2>Overfitting</h2>
<p>You can think of refactors like database or <a href="https://docs.djangoproject.com/en/5.0/topics/migrations/" rel="noreferrer" target="_blank">Django migrations</a>. Refactors are a way to keep the codebase in sync with business problems. The longer you wait to do them, the more of a headache they become, but a large, superfluous migration can be dangerously expensive.</p>
<p>A refactor is a functionally equivalent solution that incorporates '$n+1$' features into a new solution that treats all features as first-class citizens, where $n$ is all features added before the last refactor or architecture plan.</p>
<p>This leads to a new set of problems. Each time new features are added to the solution, the scope must be broadened. The more you try to generalize, the more you overfit[^2]. The more you overfit, the more you have to refactor.</p>
<p>It follows that unnecessary refactors lead to unnecessary overfitting. It's important to avoid refactoring as the new guy or overzealous engineer.</p>
<p>[^2]: I'm borrowing the term 'overfitting' from the problem in machine learning. It occurs when a model is trained to fit a specific set of data too closely. As a result, the model will perform well on the training data, but poorly on new data in the field.</p>
<h2>Basic Real-World Example</h2>
<p>Traffic systems are a hard problem. This example is oversimplified.
Say we had a traffic control system that handled a single intersection. We might
start with a simple solution involving a single traffic light. Soon we will realize
that we need to handle multiple lanes of traffic. We might refactor to a solution
that handles multiple lights. In the revised solution, the number of lanes and their
attributes are codified.</p>
<p>Over time, our model of the problem becomes more complex. We need to handle multiple intersections, pedestrians, and transit lanes. We might refactor into a solution that handles all of these things. Construction costs money and time, so we want to minimize rebuilding and weak optimizations.</p>
<p>This example is fairly contrived, but its principles fit any system with flow and constraints.</p>
<h2>Back to Software</h2>
<p>In software, product needs are much more fluid than roads and infrastructure; this cycle occurs a lot faster[^3]. Any ground-up refactor will accomplish incorporating new features in a way that feels elegant to the solution, but it's a local maximum with consequences.</p>
<p>[^3]: It's not difficult to iterate faster than public works in most industries. It seems like every exciting BART or Caltrain plan is always years out of reach.</p>
<p><img src="/images/posts/overfitting/abstraction.png" alt="Software Abstraction"></p>
<p>Taking this idea to its limits, the only way to avoid refactors is to have perfect foresight. Often, this is realized as a domain-specific language (DSL) that is expressive enough to handle all the features that will be added in the future[^4]. In implementation, a system robust enough to handle any programmable business need would approximate a programming language. Getting just the right amount of abstraction is always difficult and requires great judgment.</p>
<p>[^4]: DSLs are great, but not a silver bullet. The reason migrations exist in the first place is an acknowledgement that a problem is too complex to be solved in one go.</p>
<p>Refactors are reflective only of current and known needs. Modeling real world problems is hard, but complete rewrites lead to premature optimization and overfitting to the current problem set. There is a tendency to refine a working solution to the point of diminishing returns.</p>
<p>By refactoring too early, you are creating too rigid a solution. The framework that solves the current feature set will inevitably be too narrow for the next one.</p>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[How To Use Side Projects]]></title>
            <link>https://sirajchokshi.com/blog/side-projects</link>
            <guid>https://sirajchokshi.com/blog/side-projects</guid>
            <pubDate>Fri, 26 Jan 2024 08:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>I have found that there are two distinct motivations for side projects:</p>
<ol>
<li>To build a solution to a problem</li>
<li>To use a new technology</li>
</ol>
<p>I have also found that these two goals are often at odds with each other. When I want to learn a new technology, I am trying to learn a new way of thinking about problems. It's difficult to implement basic product needs when you're figuring out how to handle sorting a list in a new language.</p>
<p>Trying new things is important. There was a time 10 years ago when everybody's JavaScript looked different. Now we have many great ways to write JavaScript. Whether you prefer functional patterns or dependency injection and OOP, the tooling around those conventions borrows from other languages.</p>
<p>Neither of these motivations is misplaced. But it's difficult to keep track of both how the system maps to the business problem and how the technology maps to the system. Tackling more problems that are novel to you increases the surface area of the problem, while your capacity to solve it remains the same.</p>
<p>Most people are most effective at learning one thing at a time. It follows that the reason a lot of programmers don't finish side projects is because they're trying to learn too much at once. It's easy to get greedy and try to kill two birds with one stone. Similar to how <a href="https://devblogs.microsoft.com/oldnewthing/20081121-00/?p=20123" rel="noreferrer" target="_blank">there is always a higher priority</a>, there is always something new to learn.</p>
<p>I approach side projects more effectively by applying as many constraints as possible and being intentional about one goal. Like all good work, focus is required.</p>
<p>When learning a new technology, I'll default to an app I've built before. Some examples include a Socket-based chat app, a simple CMS, or a cloud-backed Todo app[^1]. The product problem is narrow. These apps have a low ceiling[^2] but also a low floor, making them great for learning.</p>
<p>[^1]: Building systems that have some user-facing and data-fetching components are great since they force you to use practical async code.
[^2]: I don't mean to say that these apps cannot be executed well. <a href="https://honk.me/" rel="noreferrer" target="_blank">Honk</a> proved otherwise.</p>
<p>If I am trying to build a product or write software to solve a problem, then design and product are where my energy goes.</p>
<p>You want to use a stack as boring as possible--a stack with no big 'if's. If you're most comfortable with NoSQL than SQL, then use it. It should be intuitive for you to prototype, teardown, rebuild, and deploy. Minimize twists and turns.</p>
<p>No advice is grossly generalizable. I've met people who love to struggle through problems and hold a lot of context at once. This probably isn't true for most people. There's a reason companies use boring stacks. But if you know yourself better than I do (which is likely), then you should do whatever gets you to output great things. Being honest with yourself goes a long way.</p>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[Embedding Figma Prototypes]]></title>
            <link>https://sirajchokshi.com/blog/figma-embed</link>
            <guid>https://sirajchokshi.com/blog/figma-embed</guid>
            <pubDate>Sun, 14 Jan 2024 08:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>I'm a huge fan of <a href="https://www.figma.com/prototyping/" rel="noreferrer" target="_blank">Figma prototypes</a>. They have proven to be a great way to share interactions (rather than static designs) with peers and clients. Developers and clients often have trouble inferring interaction and animation from static designs since they don't have declarative knowledge of UI design patterns[^1]. Figma prototypes are a great way to bridge that gap with minimal effort.</p>
<p>[^1]: There is also a productivity boost, even without this context loss. I am usually developing my own designs, but even with <a href="https://www.framer.com/motion/" rel="noreferrer" target="_blank">Framer Motion</a>, I just find it easier to iterate on flows and interactions with prototyping animations in Figma.</p>
<p></p>
<p>Figma's <a href="https://help.figma.com/hc/en-us/articles/360039818874-Smart-animate-layers-between-frames" rel="noreferrer" target="_blank">"smart animate"</a> mode is particularly useful for prototyping animations. It essentially generates a tween[^2] between two artboards based on the position and size of the layers in each frame. Sometimes results are surprisingly good. While it tends to perform pretty poorly on complex animations, it's great for simple interactions that do add polish to a design.</p>
<p>[^2]: A tween is a type of animation that interpolates between two states. For example, a tween between two artboards might move a layer from one position to another. <a href="https://en.wikipedia.org/wiki/Inbetweening" rel="noreferrer" target="_blank">Read more on Wikipedia</a>.</p>
<h2>Embedding Figma Prototypes</h2>
<p>Figma prototypes can be shared via a link, but it's also possible to embed them in a webpage. It's awesome for quick demos within a website or blog post without writing a lot of one-off code. MDX makes it even easier to embed Figma prototypes in a blog post.</p>
<p>There's no great off-the-shelf solution for styling the embed, but Figma provides a couple options to hide their baked-in UI and iframe-ing in the prototype itself.</p>
<p>This is how an embed from Figma looks by default:</p>
<pre><code class="language-html">&#x3C;iframe
  style="border: none;"
  width="800"
  height="450"
  src="https://www.figma.com/embed?embed_host=share&#x26;url=https://www.figma.com/proto/..."
>&#x3C;/iframe>
</code></pre>
<p>Already, there are a few annoying things about this embed:</p>
<ul>
<li>The iframe is not responsive</li>
<li>The Figma embed UI is too busy over the prototype</li>
</ul>
<h3>Prop API</h3>
<p>If we're embedding a lot of prototypes, it's nice to have a reusable component that handles these issues. I wanted this component to:</p>
<ol>
<li>Be responsive to the container width</li>
<li>Bring my own UI for metadata and controls</li>
<li>Link to the original Figma file</li>
</ol>
<p>Given the constraints, here's the API I came up with:</p>
<pre><code class="language-ts">type FigmaEmbedProps = {
  url: string;
  aspectRatio: number;
};
</code></pre>
<p>I'll admit that having to provide an aspect ratio is pretty awkward, but it's the only way to make the embed responsive. The content is not only cross-origin but rendered on a canvas inside of Figma's app code, so aspect ratio inference is not possible.</p>
<p>Given the aspect ratio, we can calculate the height of the embed based on the width of the container.</p>
<p>As for getting a link to the Figma file, we can parse the <code>url</code> parameter to extract the file id and construct a link to the editor page.</p>
<pre><code class="language-tsx">function FigmaEmbed({ url, aspectRatio }: FigmaEmbedProps) {
  if (!url.includes("hideUI")) {
    // if the url is unopionated about hiding
    // the Figma UI, then hide it
    url += "%26hide-ui%3D1";
  }

  return (
    &#x3C;div
      style={{
        position: "relative",
        height: "auto",
        aspectRatio,
      }}
    >
      &#x3C;iframe
        style={{
          width: "100%",
          height: "100%",
          border: "none",
        }}
        // forward provided embed url
        src={url}
        loading="lazy"
      />
    &#x3C;/div>
  );
}
</code></pre>
<pre><code class="language-tsx">import { FigmaLogo } from "icon-library"; // not a real package

/**
 * Extract the file id from a Figma prototype url
 */
function extractFileURL(url: string) {
  const regex = /proto%2F(.*?)%2F/;

  const match = url.match(regex);
  const id = match?.[1];

  return id;
}

function FigmaEmbed({ url, aspectRatio }: FigmaEmbedProps) {
  const fileId = extractFileURL(url);

  if (!url.includes("hideUI")) {
    // if the url doesn't is unopionated about
    // hiding the Figma UI, then hide it
    url += "%26hide-ui%3D1";
  }

  return (
    &#x3C;div className="figma-embed">
      {fileId &#x26;&#x26; (
        &#x3C;a href={file} target="_blank">
          &#x3C;FigmaLogo />
          Open in Figma
        &#x3C;/a>
      )}
      &#x3C;iframe src={url} loading="lazy" />
    &#x3C;/div>
  );
}
</code></pre>
<h3>Designing Overlays</h3>
<p>I wanted to create a floating link to the Figma file and have it positioned over the prototype itself. This link needs to always be readable, and we don't know what the background of the embed's artboard will be until runtime.</p>
<p>There are a few solutions to this problem, but I decided to use CSS <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode" rel="noreferrer" target="_blank">mix-blend-mode</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-blend-mode" rel="noreferrer" target="_blank">background-blend-mode</a> to maintain contrast. Most of the time the link will be over a pure color, so <code>difference</code> and <code>darken</code> work well to provide basic readability and a background for a hover state.</p>
<pre><code class="language-scss">.figma-embed {
  position: relative;

  /* ... */

  a {
    position: absolute;
    top: 16px;
    left: 16px;
    z-index: 1;

    mix-blend-mode: difference;
    background-blend-mode: darken;

    color: white;
    background: transparent;

    &#x26;:hover {
      background: #121313;
    }
  }
}
</code></pre>
<h3>Putting it all together</h3>
<p>Here's the final React component made to fit with the rest of this site:</p>
<p>&#x3C;Figma
url="https://www.figma.com/embed?embed_host=share&#x26;url=https%3A%2F%2Fwww.figma.com%2Fproto%2FwbMsekj41OFW9sCkpPRd58%2FEmbedded-Figma-Prototypes%3Ftype%3Ddesign%26node-id%3D97-574%26t%3DKQ20KtCCGbjzNyzL-1%26scaling%3Dmin-zoom%26page-id%3D95%253A549%26mode%3Ddesign"
aspectRatio={4 / 3}
/></p>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[Intent as a Primitive]]></title>
            <link>https://sirajchokshi.com/blog/component-intent</link>
            <guid>https://sirajchokshi.com/blog/component-intent</guid>
            <pubDate>Fri, 12 Jan 2024 08:00:00 GMT</pubDate>
            <description><![CDATA[The significance of intent as a design primitive in software and a more versatile approach for UI library components.]]></description>
            <content:encoded><![CDATA[<p>Intent is an underrated primitive in software design. I'm not talking about user intent, but rather the intent of the creator of the interface.</p>
<pre><code class="language-ts">export type Intent =
  | "default"
  | "muted" // e.g. a grey button
  | "success"
  | "danger"
  | "warning";
</code></pre>
<p>The concept of intent is ingrained in nearly every design system. For example, in MUI, a button has a <code>color</code> prop (in MUI, color tokens are defined by their intent). These parts of the system work together like this: <code>&#x3C;Button color="danger">Delete&#x3C;/Button></code>.</p>
<p>UI libaries like <a href="https://blueprintjs.com/docs/#core/components/alert" rel="noreferrer" target="_blank">Blueprint</a> and <a href="https://evergreen.segment.com/components/alert" rel="noreferrer" target="_blank">Evergreen</a> use the name intent for this prop.</p>
<p>I prefer calling this prop <code>intent</code> instead of <code>color</code> because it is more to the point. An intent prop can be used for more than just buttons; it can be applied to notifications, banners, results, and various other components.</p>
<p>The MUI method of using colors named for their intent is a bit cumbersome, but allows for an escape hatch for when specific colors are needed. The use of intent as a prop works great in tandem with utility props like those that <code>styled-system</code> introduced.</p>
<p>It is a great abstraction since its implementation lies at the component layer. This provides enough flexibility to create a design language that is consistent while also being narrowable for product needs.</p>
<p>This might sound like a nitpick—what's in a name[^1]? But I think it's important to have an accurate name for such a keystone concept. While software design communicates with users, a design system communicates with one's peer implementing <code>@company/ui</code> in their product. Intent seems like the best way to create a unified API across the entire system for this purpose.</p>
<p>[^1]: From a code perspective, I was so satisfied when I came across the name 'intent' when studying Segment's <a href="https://evergreen.segment.com/" rel="noreferrer" target="_blank">Evergreen</a> design system. I had been bouncing between <code>color</code> and <code>type</code>, both of which caused collisions with other props.</p>
<pre><code class="language-tsx">&#x3C;Notification.Tray>
  &#x3C;Notification.Item intent="success">
    Your changes have been saved
  &#x3C;/Notification.Item>
  &#x3C;Notification.Item intent="warning">
    Your session will expire in 2 minutes
  &#x3C;/Notification.Item>
  &#x3C;Notification.Item>
    Consider saving your changes with &#x26;#8984; + S
  &#x3C;/Notification.Item>
&#x3C;/Notification.Tray>
</code></pre>
<p></p>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[Last updated dates with Contentlayer]]></title>
            <link>https://sirajchokshi.com/blog/contentlayer-last-updated</link>
            <guid>https://sirajchokshi.com/blog/contentlayer-last-updated</guid>
            <pubDate>Mon, 11 Dec 2023 08:00:00 GMT</pubDate>
            <description><![CDATA[How to add last updated dates to your Contentlayer documents.]]></description>
            <content:encoded><![CDATA[<p>When building documentation and blog sites in fields where recency is important (like technology), it's useful to display the last updated date of a post. While not supported at the framework level, last edited labels are easy to implement with Contentlayer's <a href="https://contentlayer.dev/docs/reference/source-files/define-document-type-eb9db60e#computedfields" rel="noreferrer" target="_blank">computed fields</a>.</p>
<h2>Getting the last updated date</h2>
<p>Contentlayer document types give us reference to the raw source file, which we can use to get the last modified date using Node functions.</p>
<pre><code class="language-ts">import fs from "node:fs";
import path from "node:path";

import { DocumentGen } from "contentlayer/core";

/**
 * Check when a contentlayer document's source
 * file was last updated
 */
export function getLastEditedDate(doc: DocumentGen): Date {
  const filepath = path.join("posts/", doc._raw.sourceFilePath);
  const stats = fs.statSync(filepath);
  return stats.mtime;
}
</code></pre>
<h2>Defining a computed field</h2>
<p>This helper can be used to define a <code>lastEdited</code> field on the <code>Post</code> document type which will resolve at build time.</p>
<pre><code class="language-ts">import { getLastEditedDate } from "../utils";
import { defineDocumentType } from "contentlayer/source-files";

export const Post = defineDocumentType(() => ({
  name: "Post",
  contentType: "mdx",
  filePathPattern: `**/*.mdx`,
  fields: {
    title: { type: "string", required: true },
    date: { type: "date", required: true },
  },
  computedFields: {
    lastEdited: {
      type: "date",
      resolve: getLastEditedDate,
    },
  },
}));
</code></pre>
<h2>Using the <code>lastEdited</code> field</h2>
<p>After generating types again the <code>lastEdited</code> field is available on the <code>Post</code> type and can be rendered on posts. The field is a <code>Date</code> object, so it can be formatted using a library like <a href="https://date-fns.org/" rel="noreferrer" target="_blank">date-fns</a>.</p>
<pre><code class="language-tsx">import { Post, allPosts } from "contentlayer/generated";
import { useMDXComponent } from "next-contentlayer/hooks";
import { format } from "date-fns";

export default function Post({ post }: { post: Post }) {
  const MDXContent = useMDXComponent(post.body.code);

  return (
    &#x3C;article>
      &#x3C;h1>{post.title}&#x3C;/h1>
      &#x3C;MDXContent />
      &#x3C;footer>
        Last updated
        &#x3C;time dateTime={post.lastEdited}>
          {format(post.lastEdited, "LLLL d, yyyy")}
        &#x3C;/time>)
      &#x3C;/footer>
    &#x3C;/article>
  );
}
</code></pre>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[CSS Variable Scoping]]></title>
            <link>https://sirajchokshi.com/blog/css-var-scoping</link>
            <guid>https://sirajchokshi.com/blog/css-var-scoping</guid>
            <pubDate>Sun, 10 Dec 2023 08:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>CSS variables are often underutilized in favor of CSS-in-JS solutions. I work in a lot of styled-component and Emotion projects and I find myself reaching for CSS variables more and more.</p>
<p>CSS variables:</p>
<ol>
<li>Are scoped the an element and it's children</li>
<li>Work with the <code>calc()</code> function</li>
<li>Can be changed at runtime</li>
</ol>
<h2>Theming</h2>
<pre><code class="language-tsx">import styled from "@emotion/styled";
import { variant } from "styled-system";
import * as Menu from "@radix-ui/react-menu";

const MenuItem = styled(Menu.Item)`
  background: var(--background);
  color: var(--color);

  ${({ theme }) =>
    variant({
      prop: "intent",
      variants: {
        "default:hover": {
          "--color": theme.colors.grey900,
          "--background": `${theme.colors.grey400}`,
        },
        "danger:hover": {
          "--color": theme.colors.red800,
          "--background": theme.colors.red100,
        },
      },
    })}
`;

export function Menu() {
  return (
    &#x3C;Menu.Root>
      &#x3C;Menu.Content>
        &#x3C;MenuItem>View Details&#x3C;/MenuItem>
        &#x3C;MenuItem>Add Record&#x3C;/MenuItem>
        &#x3C;Menu.Separator />
        &#x3C;MenuItem intent="danger">Delete&#x3C;/MenuItem>
      &#x3C;/Menu.Content>
    &#x3C;/Menu.Root>
  );
}
</code></pre>
<p>In the above example, we are using the <code>variant</code> function from <code>styled-system</code> to create a button component that can be themed. Note how we map theme colors, named for their color, to CSS variables named for their user-facing intent.</p>
<h2>Responsive Design</h2>
<p>For scalable designs (e.g. graphics made with code) we can use calculations with CSS variables to properly scale children up and down without having to manually calculate the values.</p>
<pre><code class="language-scss">.card {
  &#x26;__wrapper {
    --card-padding: 1rem;

    padding: var(--card-padding);

    @media (min-width: 1200px) {
      --card-padding: 1.625rem;
    }

    @media (min-width: 720px) {
      --card-padding: 1.25rem;
    }
  }

  &#x26;__main {
    position: absolute;
    top: var(--card-padding);
    left: var(--card-padding);
    width: calc(100% - (var(--card-padding) * 2));
    height: calc(100% - (var(--card-padding) * 2));
  }
}
</code></pre>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[Linked mentions with Contentlayer]]></title>
            <link>https://sirajchokshi.com/blog/contentlayer-linked-mentions</link>
            <guid>https://sirajchokshi.com/blog/contentlayer-linked-mentions</guid>
            <pubDate>Fri, 08 Dec 2023 08:00:00 GMT</pubDate>
            <description><![CDATA[Implementing a wiki-like backlink system with Contentlayer, NextJS, and MDX.]]></description>
            <content:encoded><![CDATA[<p>My ideal personal site is something in between a journal and wiki. A killer feature of wikis is bi-directional links. These are also known as metioned links or backlinks. If you're reading a page, you can see all the pages that link to it; a great way to discover related content.</p>
<p><a href="https://contentlayer.dev" rel="noreferrer" target="_blank">Contentlayer</a> is a library that acts as like an ORM for markdown content. It has become popular in the <a href="https://nextjs.org" rel="noreferrer" target="_blank">Next.js</a> ecosystem as a way to manage content for static sites. It's easy to build on top of since all content is available through a strongly-typed, generated module.</p>
<p>The <code>allDocuments</code> array can be iterated over to find all the documents that link to a given page. Here's a function that returns an array of backlinks for a given slug:</p>
<pre><code class="language-ts">import { allDocuments } from "contentlayer/generated";

function getLinkedMentions(slug: string) {
  return (
    allDocuments
      // filter out documents that don't contain a link
      // to the provided document
      .filter((doc) => doc.body.raw.includes("[[" + slug))
      // map to title and slug for rendering
      .map((doc) => ({
        title: doc.title,
        url: doc.url,
      }))
  );
}
</code></pre>
<h3>Usage</h3>
<p>Then, in your page component, you can call this function and render the results. The example below is in Next.js, but the approach can be used broadly.</p>
<pre><code class="language-tsx">import { getLinkedMentions } from "@/lib/linked-mentions";

export default function Page({ slug }) {
  const mentions = getLinkedMentions(slug);
  return (
    &#x3C;div>

      &#x3C;!-- page content -->

      &#x3C;h3>Mentions&#x3C;/h3>
      &#x3C;ul>
        {mentions.map((link) => (
          &#x3C;li>
            &#x3C;a href={link.url}>{link.title}&#x3C;/a>
          &#x3C;/li>
        ))}
      &#x3C;/ul>
    &#x3C;/div>
  );
}
</code></pre>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[React Compound Component Guidelines]]></title>
            <link>https://sirajchokshi.com/blog/compound-components</link>
            <guid>https://sirajchokshi.com/blog/compound-components</guid>
            <pubDate>Sat, 25 Nov 2023 08:00:00 GMT</pubDate>
            <description><![CDATA[Guidelines for effective compound component (Radix UI-like) APIs in React.]]></description>
            <content:encoded><![CDATA[<p>Compound components are a pattern that allow your component to be composed of multiple sub-components put together outside of the component itself. This pattern is useful for components that have multiple parts that need to be controlled by the parent component.</p>
<p>The pattern became popular thanks to <a href="https://reach.tech/" rel="noreferrer" target="_blank">Reach UI</a> and, more recently, <a href="https://www.radix-ui.com/primitives/docs/overview/introduction" rel="noreferrer" target="_blank">Radix Primitives</a>. These libraries utilize this pattern to offer ready-to-use accessibility and behavior. However, they delegate styling and composition to the user.</p>
<pre><code class="language-tsx">import * as Tabs from "@radix-ui/react-tabs";

export default () => (
  &#x3C;Tabs.Root>
    &#x3C;Tabs.List>
      &#x3C;Tabs.Trigger value="1">1&#x3C;/Tabs.Trigger>
      &#x3C;Tabs.Trigger value="2">2&#x3C;/Tabs.Trigger>
    &#x3C;/Tabs.List>
    &#x3C;Tabs.Content value="1">Tab 1 contents&#x3C;/Tabs.Content>
    &#x3C;Tabs.Content value="2">Tab 2 contents&#x3C;/Tabs.Content>
  &#x3C;/Tabs.Root>
);
</code></pre>
<p>Users can define their own markup using this API. The parent component, controlled by the library developer, can still manage state and behavior.</p>
<p>If you want to read more about compound components, I recommend <a href="https://kentcdodds.com/blog/compound-components-with-react-hooks" rel="noreferrer" target="_blank">this article</a> by Kent C. Dodds.</p>
<p>This remainder of this post contains some guidelines I've come up with for creating compound components after both consuming and implementing them.</p>
<h2>Designing defensive slots</h2>
<p>In the compound pattern, slots are represented as children of sub-components as opposed to props. React understands children as an array of <code>ReactNode</code> regardless of the use case, so it's important to design your slots defensively.</p>
<h3>Ensure there is only one child</h3>
<p>If there should only be one child, use <code>React.Children.only</code> to ensure that there is only one child. This will throw an error if there is more than one child.</p>
<p>This is useful for slots that should only have one child. Common examples are icon wrappers like <code>&#x3C;Button.Append></code>, <code>&#x3C;Input.Prepend></code>, or <code>&#x3C;Input.Icon></code>.</p>
<pre><code class="language-tsx">const iconWrapperCSS = css`
  width: 2em;
  height: 2em;
  display: flex;
  align-items: center;
  justify-content: center;

  svg {
    width: 1.5em;
    height: 1.5em;
  }
`;

const IconWrapper = ({ children }) => {
  const { toggleMenu } = useMenuContext();

  // assert that there is only one child
  const child = React.Children.only(children);

  return (
    &#x3C;div css={iconWrapperCSS}>
      {React.cloneElement(child, {
        onClick: () => toggleMenu(),
      })}
    &#x3C;/div>
  );
};
</code></pre>
<h3>Apply Props to Children</h3>
<h4>React.cloneElement</h4>
<p>If you need to add props to children, use <code>React.cloneElement</code> to add props to children. This is useful for slots that need to pass props, such as listeners, to a child.</p>
<p>Radix establishes the convention of using the <code>asChild</code> prop to indicate that the child should be cloned. Without this prop, the children are rendered into the default element (e.g., a button for a trigger).</p>
<pre><code class="language-tsx">const AccordionTrigger = ({ children, asChild }) => {
  const [isOpen, toggleOpen] = useReducer((open) => !open, false);

  if (asChild) {
    // assert that there is only one child
    const child = React.Children.only(children);

    // clone the child with listener and state
    return React.cloneElement(child, {
      onClick: toggleOpen,
      "aria-expanded": isOpen,
    });
  }

  return &#x3C;button onClick={toggleOpen}>{children}&#x3C;/button>;
};
</code></pre>
<h4>React.Children.map</h4>
<p>Use <code>React.Children.map</code> with <code>React.cloneElement</code> when iterating over children.
This allows you to add props to the children.</p>
<pre><code class="language-tsx">const Tabs = ({ children }) => {
  const [activeTab, setActiveTab] = useState(0);

  return (
    &#x3C;div>
      {React.Children.map(children, (child, index) => {
        if (React.isValidElement(child)) {
          return React.cloneElement(child, {
            "data-active": index === activeTab,
            onClick: () => setActiveTab(index),
          });
        }
      })}
    &#x3C;/div>
  );
};
</code></pre>
<h2>API Design</h2>
<h3>Export Structure</h3>
<p>Compound components allow users to import from a single namespace for convenience. Sometimes, users may want to import a single component separately.
They can do this to optimize for tree-shaking or to avoid naming collisions. For this reason, it's important to export both un-prefixed and prefixed components.</p>
<pre><code class="language-tsx">import { Root } from "./components/root";
import { Item } from "./components/item";
import { Trigger } from "./components/trigger";
import { Content } from "./components/content";

export {
  // un-prefixed exports for namespacing
  Root,
  Item,
  Trigger,
  Content,

  // exports for prefixed, non-namespaced imports
  MenuRoot,
  MenuItem,
  MenuTrigger,
  MenuContent,
};
</code></pre>
<h3>Styling States</h3>
<p>Compound components are often used for components that have multiple states. For example, a menu can be open or closed. A tab can be active or inactive. A switch can be on or off.</p>
<p>When providing a component that has multiple states, it's important to provide a way to style each state. Accessible components should use ARIA attributes to indicate state, but these do not provide enough coverage and can be unintuitive as selectors.</p>
<p>For example, a menu can be open or closed. The <code>aria-expanded</code> attribute is used to indicate this state. While workable, a declarative set of <code>data-*</code> attributes allows for a more user-focused API.</p>
<pre><code class="language-tsx">const Tabs = ({ children }) => {
  const [activeTab, setActiveTab] = useState(0);

  return (
    &#x3C;div>
      {React.Children.map(children, (child, index) => {
        if (React.isValidElement(child)) {
          return React.cloneElement(child, {
            // add data-active attribute to indicate state
            "data-active": index === activeTab,
            onClick: () => setActiveTab(index),
          });
        }
      })}
    &#x3C;/div>
  );
};
</code></pre>
<p>Then the <code>active</code> tab case can be styled like so:</p>
<pre><code class="language-css">[data-active="true"] {
  background: var(--color-primary);
  color: var(--color-white);
}
</code></pre>
<h3>Controlled Components</h3>
<p>Complex or multi-step interfaces, like forms, demand inversion of control. In other words, the parent component should control the state of the child. A rich API should allow for controlled components as an opt-in.</p>
<p>This can be done by accepting a prop to use as state and defaulting to internal state when the prop is not defined. Additionally, a callback for updates (e.g., selecting a tab) should be provided by the user.</p>
<pre><code class="language-tsx">type TabControlledProps = {
  current: number;
  setCurrent: (index: number) => void;
};

type TabsProps = Partial&#x3C;TabControlledProps> &#x26; PropsWithChildren;

const Tabs = (props: TabProps) => {
  const [currentTab, setCurrentTab] = useState(0);
  const { current: controlledCurrent } = props;

  // if the current prop is defined, use it as the state
  const activeTab = controlledCurrent ?? currentTab;
  // if the current prop is defined, use the provided callback to update it
  const setActiveTab = controlledCurrent ? props.setCurrent : setCurrentTab;

  return (
    &#x3C;div>
      {React.Children.map(props.children, (child, index) => {
        if (React.isValidElement(child)) {
          return React.cloneElement(child, {
            // use calculated state
            "data-active": index === activeTab,
            onClick: () => setActiveTab(index),
          });
        }
      })}
    &#x3C;/div>
  );
};
</code></pre>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[Colophon]]></title>
            <link>https://sirajchokshi.com/blog/colophon</link>
            <guid>https://sirajchokshi.com/blog/colophon</guid>
            <pubDate>Thu, 23 Nov 2023 08:00:00 GMT</pubDate>
            <description><![CDATA[How this site was built and why it is closed source.]]></description>
            <content:encoded><![CDATA[<p>I treat this site as a journal for ideas and sometimes a playground for new technologies. I've chosen to keep it closed source. Unfinished ideas, experiments, and other things that I don't want to share publicly are all stored here.</p>
<p>This site is more personal expression than a software product. Personal websites of mine have been forked and copied before, which is fine. However, I no longer want others using my site as a template. Josh W Comeau has <a href="https://www.joshwcomeau.com/blog/why-my-blog-is-closed-source/" rel="noreferrer" target="_blank">a great write-up</a> on this topic. I'd be reiterating a lot of what he said if I continued here.</p>
<p>Below is some general information on how this site was built. If you have any questions about the implementation, feel free to contact me on <a href="https://twitter.com/sirajchokshi" rel="noreferrer" target="_blank">Twitter</a>.</p>
<p>| Using         |                                                                                                      |
| ------------- | ---------------------------------------------------------------------------------------------------- |
| <strong>Rendering</strong> | <a href="https://nextjs.org/" rel="noreferrer" target="_blank">Next.js</a>, <a href="https://contentlayer.io/" rel="noreferrer" target="_blank">Content Layer</a>, <a href="https://mdxjs.com/" rel="noreferrer" target="_blank">MDX</a> |
| <strong>Styling</strong>   | <a href="https://emotion.sh/" rel="noreferrer" target="_blank">Emotion</a>, <a href="https://sass-lang.com/" rel="noreferrer" target="_blank">SCSS</a>, <a href="https://xstyled.dev/" rel="noreferrer" target="_blank">XStyled</a>      |
| <strong>Type</strong>      | <a href="https://rsms.me/inter/" rel="noreferrer" target="_blank">Inter</a>, <a href="https://www.jetbrains.com/lp/mono/" rel="noreferrer" target="_blank">JetBrains Mono</a>                |
| <strong>Hosting</strong>   | <a href="https://vercel.com/" rel="noreferrer" target="_blank">Vercel</a>                                                                        |</p>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[Sharing is a feature]]></title>
            <link>https://sirajchokshi.com/blog/sharability</link>
            <guid>https://sirajchokshi.com/blog/sharability</guid>
            <pubDate>Tue, 02 May 2023 07:00:00 GMT</pubDate>
            <description><![CDATA[Why it is important to make it easy to share content from your application.]]></description>
            <content:encoded><![CDATA[<h2>Apps don't own communication</h2>
<p>Communication needs to be reliable. Users will always default to established platforms for sharing anything critical. Another chatbox, notification bell, or comment thread is not always appreciated. It is easy for new applications to become <a href="https://devblogs.microsoft.com/oldnewthing/20081121-00/?p=20123" rel="noreferrer" target="_blank">"another thing"</a> to check.</p>
<p>Everything important happens on Slack, Teams, meeting notes, email, or whatever the team's preferred ritual is. If you need to be a part of that, you need to make it easy to share content from your application.</p>
<h2>Sharing is a feature</h2>
<p>If you are building a product that houses content, said content should be easy to share.</p>
<h3>Printability</h3>
<p>Say you are building office applications. Users often default to printing a page as a PDF to share content over email when they are unsure of the recipient's ability to open the file; a common pattern for sharing content cross-platforms.</p>
<p>It might be tempting to build a bespoke print or PDF export feature, but there is undoubtedly a more efficient use of your time. There is nothing wrong with using the browser's built-in print dialog: it is well-established and reliable.</p>
<p>Not all pages, especially, single-page applications with complex layouts are suitable to print out of the gate. In this case we can use the CSS <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/Printing" rel="noreferrer" target="_blank"><code>@media print</code></a> rule to create a print-friendly version of the page.</p>
<pre><code class="language-css">@media print {
  .document {
    /* remove dark-mode styles */
    color: black !important;
    background: none !important;
  }

  .toolbar,
  .cursor,
  .suggestion {
    /* hide elements that don't make sense to print */
    display: none;
  }
}
</code></pre>
<p>Some interfaces (like Google Sheets) completely override the browser print dialog in favor of a more feature-rich version. This is a great way to add polish to your product, but it can also be a much larger undertaking than ensuring the page is print-friendly out of the box.</p>
<p>In Google's case it makes sense to provide a custom UI since spreadsheets are complex and do not have an intuitive print layout. For getting off the ground with most applications this would be overkill.</p>
<h3>Open Graph</h3>
<p>Most people who work on websites or sell anything digital (i.e. SEO farmers) should be familiar with open graph (OG) tags. If you don't: they are data a website can provide to social media platforms to customize the images and preview text on a card.</p>
<p>{/* <img src="/images/sharing/nextjs-docs-og.png" alt="Example of OG tags in Slack using the NextJS Documentation"> */}</p>
<p>Open graph data is used to generate a preview card when a link is shared in Slack. It's important for teammates to know what they're clicking at a glance.</p>
<h2>APIs &#x26; Resources</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API" rel="noreferrer" target="_blank">Clipboard API</a> - A browser API for reading and writing to the clipboard.</li>
<li><a href="https://ogp.me/" rel="noreferrer" target="_blank">Open Graph Protocol</a> - A standard for sharing content on social media.</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share" rel="noreferrer" target="_blank">Web Share API</a> - A browser API for sharing content to native apps.</li>
</ul>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[Sidenotes for Markdown]]></title>
            <link>https://sirajchokshi.com/blog/sidenotes-for-markdown</link>
            <guid>https://sirajchokshi.com/blog/sidenotes-for-markdown</guid>
            <pubDate>Mon, 28 Mar 2022 07:00:00 GMT</pubDate>
            <description><![CDATA[Adding sidenote rendering and syntax to Markdown files.]]></description>
            <content:encoded><![CDATA[<p>I recently wanted to add sidenotes (also called margin notes) to my blog. This site is built with ~~Gatsby.js~~ <em>Next.js</em>, and the content is written in Markdown. If you've searched for a solution to this problem before, you have likely run into <a href="https://www.gwern.net/Sidenotes" rel="noreferrer" target="_blank">Gwern's post</a>. They cover known sidenote implementations comprehensively, so we don't need to do our own homework. We do, however, need to figure out a way to make this accessible in Markdown.</p>
<p>The solution I was looking for entailed:</p>
<ol>
<li>No JavaScript after build-time</li>
<li>Simple syntax for using sidenotes</li>
<li>The resulting markup is somewhat semantic</li>
</ol>
<h2>Quick Demo</h2>
<p>On desktop, this text fills the right margin, and on mobile, it simply collapses into a box below the relevant paragraph.Like this! ~~formatting~~ <em>works</em> <strong>here</strong> too.</p>
<h2>Remark Plugin (Not Recommended)</h2>
<p>I originally wrote this blog using <a href="https://remark.js.org" rel="noreferrer" target="_blank">Remark</a>. The common, hacky way to build custom components using Remark is to create a codeblock with the language set to a specifier for your component instead of a real programming language.</p>
<p>Take, for example, if we wanted to add a newsletter button to our page:</p>
<pre><code class="language-md"># My title

This is a button:

```newsletter-button
Subscribe to my newsletter!
```
</code></pre>
<p>We would then write a Remark plugin that checks all code blocks in the syntax tree where <code>lang</code> is <code>newsletter-button</code> and then swaps the code block's node out for a custom HTML node. The code block node is commonly overloaded for custom components since it allows for arbitrary content.</p>
<p>This is pretty much exactly what I did when building sidenotes with Remark. If you just want to see the Gatsby plugin itself, all of it can be found <a href="https://gist.github.com/SirajChokshi/0c8b380ac8c048049206b943ebc27a2f" rel="noreferrer" target="_blank">here</a>. I no longer recommend this approach. Keep reading for a more idiomatic method of implementing sidenotes.</p>
<h2>With MDX</h2>
<p><a href="https://mdxjs.com/" rel="noreferrer" target="_blank">MDX</a> is a markup format that allows you to use JSX within markdown. It blends rich-text and dynamic presentation methods. As a result, we only use forceful syntax when necessary. If you are used to writing React like I am, this leads to a very comfortable writing experience.</p>
<p>Below is an example of a React component (<code>Sidenote</code>) being used in an MDX file.</p>
<pre><code class="language-mdx">&#x3C;Sidenote content={"An interesting tidbit about foo!"}>
  Something about foo.
&#x3C;/Sidenote>
</code></pre>
<p>If you need it, the Sidenote component is implemented as follows:</p>
<pre><code class="language-tsx">const Sidenote: FC&#x3C;SidenoteProps> = ({ children, content }) => (
  &#x3C;div className="sidenote-wrapper">
    {children}
    &#x3C;aside>{content}&#x3C;/aside>
  &#x3C;/div>
);
</code></pre>
<h2>Limitations</h2>
<p>While this approach is simple, it is also naive. It requires some manual restraint, as overlaying is not dealt with in any way. In other words, if there are many sidenotes in the page gutter, then they will stack on top of one another. My writing style does not lean on sidenotes too hard, so this works out.</p>
<p>A way around this is to provide some API for specifying the offset of the sidenote. Below is a vanilla CSS solution that uses CSS variables to offset the sidenote. Alternatively, you could use a prop in the MDX component to specify the offset using styled-system, Tailwind, or whatever you prefer.</p>
<pre><code class="language-mdx">&#x3C;Sidenote content={"An interesting tidbit about foo!"} offset={3}>
  Something about foo.
&#x3C;/Sidenote>
</code></pre>
<pre><code class="language-css">/* Map attributes to CSS variables */

[data-offset="1"] {
  --offset: 1;
}

[data-offset="2"] {
  --offset: 2;
}

[data-offset="3"] {
  --offset: 3;
}

...

/* Use CSS variables to offset the sidenote */
.sidenote-wrapper {
  margin-top: calc(var(--offset) * 1.5rem);
}
</code></pre>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[Assessing Skill]]></title>
            <link>https://sirajchokshi.com/blog/assessing-skill</link>
            <guid>https://sirajchokshi.com/blog/assessing-skill</guid>
            <pubDate>Tue, 05 Jan 2021 08:00:00 GMT</pubDate>
            <description><![CDATA[Anecdotes from interviewing undergraduates.]]></description>
            <content:encoded><![CDATA[<p>Interviewing is far from perfect. Any employers' goal is to tighten the correlation between interview success and job performance. I call this discrepancy the 'interview gap': the set of all work functions where an interview is a poor predictor.</p>
<p>Gaining alignment in any kind of interview is difficult. As of now, most of my experience comes from recruiting for undergraduate clubs for student designers, developers, and 'product managers' [^1]. I doubt these roles are as competitive as they are at Stripe, but in smaller pools, you get to assess candidates in ways that are not possible at scale.</p>
<p>[^1]: We call them 'product managers', but they are really just project and people managers. I think conflating the two roles is probably a mistake, but it works when you want a no latency between scoping, delegation, and delivery.</p>
<p>This post is a collection of thoughts on problems with the technical interviewing and application processes I ran at <a href="https://uiuc.hack4impact.org" rel="noreferrer" target="_blank">Hack4Impact</a> and <a href="https://illinoislabs.org" rel="noreferrer" target="_blank">Illinois Labs</a>.</p>
<h2>Problems With Hiring</h2>
<h3>Long term vs Short term Problems</h3>
<p>Interviews can only test how individuals solve problems in the short term, but are accepted as a predictor of long term problem solving ability in lieu of experience. The closest approximation possible is taking a problem directly the job and facilitating a candidate's approach. Here, <strong>the gap still persists as a time limit alongside unfamiliarity which can hurt candidates, yet has little affect on job performance.</strong> Inversely, some candidates may be great at debugging code academically, but fail to design a new system.</p>
<h3>Experience Bias</h3>
<p>Generally, a poorer interview is passable alongside demonstrated experience. An issue we face by having a candidate pool of undergraduates is a lack of experience. Candidate years typically skew right, with a larger amount of underclassmen applying. A lack of experience in our applicants can make some excelling individuals shine, but will generally shift more weight to an interview. <strong>Experience bias puts leverage on the interview gap.</strong></p>
<h3>Project Assessment</h3>
<p>Projects are an incredibly difficult way to assess an applicant's technical skills. There is no value in rewarding applicants for having cool project ideas. Ideas are cheap, implementation is not. Following this line of thinking, we should probably read their code. Here we run into our next problem: there is no timely, or meaningful way to assess implementation without understanding the product decisions made. This rabbit hole is not worth exploring. I recommend using projects as a surface level heuristic for capacity to learn. <strong>Instead of trying to figure out how "good" a project is, see what types of technologies this candidate is picking up, how fast they are doing it, and if they can briefly explain their choices.</strong></p>
<h2>What to do</h2>
<p>Given these limitations, what actually works?</p>
<p>Some signals I've found are: great personal websites, having strong opinions, and just being enthusiastic about the work in conversation [^2]. What you are really trying to figure out is, respectively: attention to detail, deep engagement with work, and ability to contribute to a team.</p>
<p>[^2]: It's hard to think about interviewing without considering the meta. There are certainly people who are just good at "interviewing", but not fun to work with. After a while of either interviewing or talking to the candidate it's pretty obvious who is who.</p>
<p>Interviews should feel more like technical conversations than interrogations. The best signal comes from learning how someone thinks through a problem they have already solved.</p>
<p>I've been interviewed this way at startups: a conversation about something I've built and work through the decisions made. Even if the interviewee hasn't built a software product (or any product!), they should show they have gone deep. Having tried to fake it, I've found this interview is pretty hard to brute force as it lets one <strong>probe decision-making, not just outcomes.</strong></p>
<p>I think it's hard to recognize great talent (besides referrals) without a good amount of experience with the role or profile. Having taste essential. The interview gap will always exist, but supplementing with other signals is a good way to fill it.</p>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[Drop the 'I' and When to Use Prefixes]]></title>
            <link>https://sirajchokshi.com/blog/drop-the-i</link>
            <guid>https://sirajchokshi.com/blog/drop-the-i</guid>
            <pubDate>Sun, 25 Oct 2020 07:00:00 GMT</pubDate>
            <description><![CDATA[Clearer naming conventions for a strongly typed web.]]></description>
            <content:encoded><![CDATA[<p>Wider adoption of TypeScript has led to a web that is more type-safe than ever. Many stacks are still written solely in JavaScript, but a multitude of developers are transitioning over. During this transition, developers are bringing practices from other paradigms along with them. TypeScript is on the newer end of languages, and there are a variety of standardized practices in circulation. This post is a refresher on semantics and consistent, readable code. While the ideas presented are not new, new structurally typed frontends re-contextualize them.</p>
<h2>Dropping the 'I'</h2>
<p>The title practice and inspiration for this write-up concern the 'I'-prefixed naming conventions some employ when writing TypeScript and other strongly typed languages. The vast majority of Interface usage I have come across is operational as a type. After all, vanilla JavaScript deals with objects as dictionaries rather than classes, so this practice carried over with TypeScript's interfaces.</p>
<p>Consequent to the semantic use of interfaces, naming one with an 'I' (e.g., <code>interface IFoo { ... }</code>) as opposed to without it (e.g., <code>interface Foo { ... }</code>) is not only redundant as the type is strongly specified, but harmful to readability and debugging. Consider the following:</p>
<pre><code class="language-typescript">interface IVehicle {
  name: string;
}

interface ICar extends IVehicle {
  make: string;
  year: number;
}
</code></pre>
<p>Nothing about these definitions alone is wrong, but let's step through an example of their use.</p>
<pre><code class="language-typescript">// initialize a car
const myCar: ICar = { name: "My Car", make: "Honda", year: 2000 };

// initialize an array of vehicles with `myCar`
const myVehicles: IVehicle[] = [myCar];

myVehicles; // [{ "name": "My Car", "make": "Honda", "year": 1998 }]
</code></pre>
<p>In the above example, the 'I'-prefix stands out, more so than with the original definitions. This presents a consistency issue, which turns out to be one of the more fundamental issues with using this convention in TypeScript. If this representation of a car needs to be <code>ICar</code>, should <code>myCar</code> not be instantiated as <code>myICar</code>? I say the answer to this question is strong 'no', but recognize there is a bigger issue at play.</p>
<p>It is likely that somewhere along the line of creating many <code>ICar</code> and <code>IVehicle</code> references, the author drops the prefix, as in the example above. When scanning through the prior example, nothing pops out as distinctly incorrect or even poor practice. If most programmers would be fine scanning through this snippet and leaving <code>myCar</code> named as-is, then the issue lies within the naming of the interface itself. Its real purpose is as a validated key-value store (à la <code>struct</code> in C).</p>
<p>By dropping the 'I', code is more consistent and readable at the sacrifice that your type is implemented as an interface, but this caveat is not all that important for most TypeScript developers.</p>
<p>Broadly, a simple way to think about how prefixes in naming should work is to think about how a piece of code is used rather than how it is implemented. No user cares whether the web app they do their taxes with is written in Java, or Ruby, or even Haskell, only that it works and is performant enough. By the same token, it probably does not keep an engineer up at night not knowing if the List interface they interact with is implemented as a linked-list or resizable array.</p>
<h2>When Using Prefixes</h2>
<p>Drawing directly from the previous example, there is a reason that most languages implement a list interface as <code>List&#x3C;T></code> as opposed to <code>IList&#x3C;T></code> because if they perform the same semantic purpose, the underlying implementation is not all that important. C# is notable exception. The Microsoft .NET style guide popularized type prefixes. By-the-book workflows led to overuse of the 'hungarian' convention A good time to use prefixes, however, is in the opposite case: a semantic disagreement between two definitions with similar contents.</p>
<p>Take, for example, loading in data from a spreadsheet whose rows need to be displayed in a web table. The head of my original data could look like the following:</p>
<p>| product_id | price |
| ---------- | ----- |
| 1097B      | 40.25 |
| 1024D      | 35.00 |
| 1112A      | 28.00 |
| 1024D      | 35.00 |
| ...        | ...   |</p>
<p>To match this table schema, I have defined an interface below and used it to display.</p>
<pre><code class="language-typescript">interface Row {
  product_id: string;
  price: number;
}
</code></pre>
<p>This type definition is perfect for displaying the data directly from the spreadsheet, but what if we want to combine all duplicate entries and store quantity as a column? We define another interface to keep quantity associated with a product. The bigger question is what to call this new interface.</p>
<p>This is where prefix naming can be incredibly helpful: in situations where the computer cannot distinguish the meaning between two pieces of data. Let's shelve the table-row example for the time being. The snippet below centers user scores around an average as part of a rating system.</p>
<pre><code class="language-cpp">#include &#x3C;iostream>

...

double averageScore = 3.36;
double uncenteredUserScore = 4.00;

double centeredUserScore = uncenteredUserScore - averageScore;

cout &#x3C;&#x3C; centeredUserScore &#x3C;&#x3C; endl; // 0.64
</code></pre>
<p>To the compiler, this sequence of operations is assignment and subtraction, so our prefixes make no difference. Each value is a floating point, so prepending 'D' as a prefix (e.g. <code>DScore</code>) is distracting. Instead, prefixes are here to provide context to values, which, when later referenced, can make their misuse clear to any reader.</p>
<p>A statistical analogy is a great one. Statisticians work with calculus and linear algebra, but they are really in the business of forming conclusions from datasets through contextualization. In the same way, it is the programmer's job to provide the context a computer cannot understand. This is why semantic prefixes are so powerful for both debugging and readability.</p>
<p>Returning to the web table exercise from earlier, we can now use prefixes to create two versions of our type. The former type could be renamed to <code>rawRow</code>, and a new one, containing any new fields necessary, could have the name <code>processedRow</code>. Having many named variables also assists in leaning into functional programming for easier debugging.</p>
<pre><code class="language-typescript">interface rawRow {
  product_id: string;
  price: number;
}

interface processedRow extends rawRow {
  quantity: number;
}

const processedRows: processedRow[] = rawDataFromSpreadsheet
  // Add new field for all data types
  .map((elem) => ({ ...elem, quantity: 1 }))
  // Process duplicates into single entries with increased quantity
  .reduce(function (accumulator: processedRow[], cur: processedRow) {
    let found = accumulator.find(function (elem: processedRow) {
      return elem.product_id === cur.product_id;
    });
    if (found) {
      found.quantity += cur.quantity;
    } else {
      accumulator.push(cur);
    }
    return accumulator;
  }, []);
</code></pre>
<p>Now, as long as we reference the correctly prefixed value when accessing this data, we should be able to put together a table similar to the following:</p>
<p>| product_id | price     | quantity |
| ---------- | --------- | -------- |
| 1097B      | 40.25     | 1        |
| <strong>1024D</strong>  | <strong>35.00</strong> | <strong>2</strong>    |
| 1112A      | 28.00     | 1        |
| ...        | ...       | ...      |</p>
<h2>In Practice</h2>
<p>While I am of the belief that I made a strong case for not using type prefixes, there is nothing more valuable in code readability than consistency. The team I work on uses 'I'-prefixes for interfaces within our TypeScript frontends. When developing, it's important to use conventions from your style guide. An abstract "best practice" is not valuable until it is consistent. With many projects, sticking with what engineers find comfortable will help teams move fast. In some cases that calls for keeping the 'I'.</p>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
        <item>
            <title><![CDATA[Why and How to Write Functional JavaScript with ES6]]></title>
            <link>https://sirajchokshi.com/blog/functional-javascript</link>
            <guid>https://sirajchokshi.com/blog/functional-javascript</guid>
            <pubDate>Wed, 27 May 2020 07:00:00 GMT</pubDate>
            <description><![CDATA[ES6 allows for integration of functional programming in existing JavaScript programs.]]></description>
            <content:encoded><![CDATA[<p>With functional programming's increasing popularity many developers are giving it a shot. While you
might often mutate state (e.g. using an ES1 Array method like <code>.push</code> or <code>.pop</code>) or loop through data there are advantages to
breaking this norm. Frontend frameworks like React and Angular are incorporating more functional ideas into their developer
experiences.</p>
<h2>What is Functional Programming?</h2>
<p>An often used and concise description of functional programming is "a paradigm involving functions as first-class citizens,
or in short first-class functions". To break this down a bit further for the uninitiated,
a function is first-class when it is able to be used as if it was a variable. This includes being returned, passed as an argument or reassigned.</p>
<p>For example:</p>
<pre><code class="language-javascript">// where `a` and `b` are numbers
const add = function (a, b) {
  return a + b;
};

const calc = (operation, a, b) => {
  return operation(a, b);
};

// Pass `add`, `1`, and `2` as arguments to the `calc` function
calc(add, 1, 2); // = 3
</code></pre>
<p>In this case <code>add</code> is declared as a traditional function and assigned to a variable, and it can be invoked directly with <code>add(a,b)</code>.
<code>add</code> can also be passed as a variable (as in <code>calc()</code>). While this scenario is just overcomplicated arithmetic there are actual advantages
to the functional paradigm. Note we avoid defining variables with 'var' or 'let' and instead opt for 'const' which is cannot be reassigned, I'll talk more about this shortly.</p>
<h2>Advantages of Functional Programming</h2>
<p>Functional programming is nothing new. Being modeled after lambda calculus and mathematical functions, functional programming languages like LISP and Haskell have been around for over 60 and 30 years respectively. While you may not see these names crop up often they still have they <a href="https://engineering.fb.com/security/fighting-spam-with-haskell/" rel="noreferrer" target="_blank">still have their uses</a> and for good reason. Some companies are even using Haskell for a lot of their infra. Check out <a href="https://mercury.com" rel="noreferrer" target="_blank">mercury.com</a> and <a href="https://hasura.io" rel="noreferrer" target="_blank">hasura.io</a>Functional programming poses advantages that, in practice, are unique to the paradigm.</p>
<h3>No Side Effects &#x26; Debugging</h3>
<p>Functional programming opts for programming without side effects. Much like a mathematical function, functions take input(s) and return one or more outputs.
When writing code with functions with no side effects, also known as pure functions, a program will often become much easier to debug. Data and state are
received and returned throughout a series of breakpoints (i.e. pure functions) which allows a programmer to pinpoint errors with ease.</p>
<h3>Code Readability</h3>
<p>One caveat of writing pure functions and reducing state changes is allocating memory. Luckily JavaScript garbage collection is far from expensive, making it
a great playground for exploring the benefits of functional programming. One of these benefits is readability. Functional programming allows for abstract
concepts to be condensed and obscured for clean, very readable code. A great example of this are JavaScript ES5's Array methods like <code>map()</code> and <code>filter()</code>.</p>
<p>Since React 16.8, the framework has supported, and has made it clear they intend to move to, using functions from components
and functional hooks for state management. Both of these implementations replacing their class or object-based predecessors.
The React team made this change to provide a simpler and more readable development experience for frontend engineers. Further,
understanding functional programming can prove useful when writing clean code in React.</p>
<h2>Why JavaScript and ES6?</h2>
<p>While all these ideas may sound great something that may have come across your mind is 'why JavaScript'? The language is extremely popular
due to its dominance on the web, not because it is very readable or logical. These conditions allow for many inexperienced and experienced
programmers alike to write JavaScript in completely different ways. By moving towards a functional paradigm streamlining repositories becomes
a lot easier. Clearly, this would be true of any style guide or paradigm, but there are other, more compelling reason, to write functionally
in ES6.</p>
<h3>JavaScript Supports a Variable Number of Arguments</h3>
<p>JavaScript is somewhat unique in the way it handles arguments in functions. It essentially allows for a variable amount of predefined, or undefined, arguments
to be passed to a function and will not throw an error unless the compiler flags a variable a required (e.g. it is returned or directly manipulated). This allows functions
to be written with either truthy values or JavaScript's implicit iterable <code>arguments</code> array as seen in the following example.</p>
<pre><code class="language-javascript">/*
 *  returns the sum for any length of numerical arguments
 */
function sum() {
  let sum = 0;
  for (const arg of arguments) sum += arg;
  // iterate through JavaScript's implicitly created `arguments` array
  return sum;
}

sum(); // = 0
sum(1, 2, 3, 4); // = 10
</code></pre>
<h3>Writing Recursively</h3>
<p>Most newcomers to the functional paradigm question the efficiency of recursion and that uncertainty is well-founded. In most popular (read: object-oriented)
programming languages like Python, C/C++, or Java, recursion can definitely bloat the call stack. This, however, is resolved with <a href="https://en.wikipedia.org/wiki/Tail_call" rel="noreferrer" target="_blank">tail call optimization</a>,
which enables recursive functions calls without adding a new stack frame to the call stack which will help avoid a <code>RangeError</code>.
Also called tail call elimination, this technique has been added to the JavaScript specifications with EMCAScript 2015 (ES6) and is available in Node.JS.
This type of optimization is present in strictly functional languages like Haskell. Unfortunately most browser engines <a href="https://kangax.github.io/compat-table/es6/" rel="noreferrer" target="_blank">(with the odd exception of Safari)</a>
have not implemented this part of ES6. While this is concerning for functional JavaScript right now,
it is also a clear sign of the direction the language is taking in shifting its focus paradigm.</p>
<h2>Why Not to Use Functional Programming</h2>
<p>As any computer scientist should know, throwing new, exciting, or complex technology at one's issues is not the most productive way to go about solving a problem.
While functional programming can be a valuable item in a developer's toolbox, the most valuable tool, as corny as it sounds, is judgement.
Knowing more paradigms can also allow one to both find styles they like to write in themselves and jump into another developer's codebase with ease.</p>]]></content:encoded>
            <author>blog@sirajchokshi.com (Siraj Chokshi)</author>
        </item>
    </channel>
</rss>