<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Cracked Chefs by Oluwaferanmi Adeniji]]></title><description><![CDATA[Battle-tested Coding patterns, Javascript wizardry, System Design, Product Engineering &amp; Management, and architectural secrets.]]></description><link>https://crackedchefs.devferanmi.xyz</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1753012104331/4bc137e4-cc0b-4fb5-bcca-a08e541d80da.jpeg</url><title>Cracked Chefs by Oluwaferanmi Adeniji</title><link>https://crackedchefs.devferanmi.xyz</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 24 Apr 2026 23:54:00 GMT</lastBuildDate><atom:link href="https://crackedchefs.devferanmi.xyz/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Ìrísí - A React Library for Building Product Videos in JSX]]></title><description><![CDATA[A few months ago, I needed to create a product demo video for something I was building. Nothing fancy, just a clean walkthrough showing the feature, how it works, what it looks like in action.
I did w]]></description><link>https://crackedchefs.devferanmi.xyz/r-s-a-react-library-for-building-product-videos-in-jsx</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/r-s-a-react-library-for-building-product-videos-in-jsx</guid><category><![CDATA[React]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Tue, 10 Mar 2026 08:42:21 GMT</pubDate><content:encoded><![CDATA[<p>A few months ago, I needed to create a product demo video for something I was building. Nothing fancy, just a clean walkthrough showing the feature, how it works, what it looks like in action.</p>
<p>I did what most engineers do. Opened a screen recorder, ran through the flow, hoped the demo gods were watching. They weren't. Three takes, and one accidental tab switch later, I had a funny recording and I was too tired to redo.</p>
<p>So I tried the other route, I sat with an LLM, described what I wanted scene by scene, asked it to help me piece together some animation code. It worked, kind of. But it was painful. The model kept hallucinating component APIs that didn't exist, the code it generated needed heavy editing, and the mental overhead of managing keyframes, timing offsets, and animation libraries manually was exhausting. I spent more time debugging the video than building the feature it was supposed to show.</p>
<p>That experience planted a question I couldn't let go of: <em>what if LLMs could generate product videos the same way they generate UI components?</em></p>
<p>The answer is <strong>Ìrísí</strong>.</p>
<hr />
<h2>The Name</h2>
<p>Ìrísí (ee-REE-see) is a Yoruba word. It means <em>appearance</em>, the way a thing looks, the form it takes, how it presents itself to the world.</p>
<p>I've been naming my developer tools after Yoruba words with real meaning. My AI SDK is called Ajala, after the legendary traveler who cycled the entire world. The name carries weight. Ìrísí felt right for this because that's exactly what the library is about: controlling how things appear, shaping the form of your product's story.</p>
<hr />
<h2>The Vision</h2>
<p>There's a version of the future I keep thinking about.</p>
<p>You finish building a feature. You write a short description of what it does. You hand it to an LLM. Two minutes later, you have a polished product video, animated, cinematic, the kind that makes your PM think you have a motion design team. You didn't touch a timeline. You didn't screen-record anything. The AI just... made it.</p>
<p>That's what Ìrísí is designed to enable.</p>
<p>The reason this is possible at all is because JSX is just text. It has a clear grammar, semantic component names, and readable props. When you write <code>&lt;Button variant="primary"&gt;Submit&lt;/Button&gt;</code>, a model doesn't need to guess what that does.</p>
<p>The problem with existing video tools is they weren't built with this in mind. They're built for humans operating GUIs — timeline panels, keyframe handles, layer stacks. That's a completely different paradigm from "write text that describes what you want."</p>
<p>Ìrísí is built on a different premise. What if a product video was just JSX?</p>
<pre><code class="language-jsx">&lt;Presentation theme="dark"&gt;
  &lt;Frame duration={5} transition="fade"&gt;
    &lt;BackgroundGradient colors={["#1e3a5f", "#0a0a0a"]} /&gt;
    &lt;Center&gt;
      &lt;Stack&gt;
        &lt;Eyebrow animate="fadeIn" delay={0.2}&gt;NEW FEATURE&lt;/Eyebrow&gt;
        &lt;Title animate="slideUp" delay={0.5} staggerBy="word"&gt;
          Instant Working Capital Loans
        &lt;/Title&gt;
        &lt;Subtitle animate="fadeIn" delay={1.2}&gt;
          Approved in under 60 seconds.
        &lt;/Subtitle&gt;
      &lt;/Stack&gt;
    &lt;/Center&gt;
  &lt;/Frame&gt;
&lt;/Presentation&gt;
</code></pre>
<p>Five seconds. Animated headline, staggered word reveal, gradient background, fade transition. An LLM can write that. It's just props.</p>
<hr />
<h2>The LLM-First Design Decision</h2>
<p>When I was speccing out Ìrísí, I made one decision that shapes everything: the API has to be something a model can generate reliably <em>without needing the docs open</em>.</p>
<p>That means three things:</p>
<p><strong>Component names read as plain English.</strong> <code>&lt;ScrambleText&gt;</code> scrambles text. <code>&lt;MaskReveal&gt;</code> reveals behind a mask. <code>&lt;BackgroundAurora&gt;</code> is an aurora background. No abbreviations, no cleverness.</p>
<p><strong>Prop values are named before they're numeric.</strong> <code>animate="slideUp"</code> not <code>animation={2}</code>. <code>easing="bounce"</code> not <code>easing={[0.68,-0.55,0.27,1.55]}</code>. The model should be able to infer what a prop does from its name alone.</p>
<p><strong>Zero required props where possible.</strong> A <code>&lt;Frame&gt;</code> with nothing on it still renders. A <code>&lt;Title&gt;</code> with just children looks good out of the box. The 80% case should be one line of JSX.</p>
<p>The result: when you hand Ìrísí's component descriptions to Claude and say "make me a product video for this feature", the code it writes should run. Not "pretty close, needs tweaks." Runs.</p>
<hr />
<h2>The Part That Makes It Real</h2>
<p>The component I'm most excited about is <code>&lt;UICursor&gt;</code>.</p>
<p>The hardest thing to fake in a product demo is interaction. You want to show a user clicking a button, filling a form, navigating a flow. Today your options are: screen-record the real thing and hope it cooperates, or spend an afternoon in a design tool animating every click manually.</p>
<p><code>&lt;UICursor&gt;</code> lets you script it:</p>
<pre><code class="language-jsx">&lt;UICursor
  moves={[
    { to: { x: 0.3, y: 0.4 }, duration: 0.8 },
    { to: { x: 0.6, y: 0.5 }, duration: 0.6, click: true },
    { type: "Feranmi Adeniji", duration: 1.5 },
    { to: { x: 0.7, y: 0.7 }, duration: 0.4, click: true }
  ]}
/&gt;
</code></pre>
<p>The cursor moves, clicks, types, choreographed, deterministic, zero screen recording. Pair it with <code>&lt;UIInput&gt;</code>, <code>&lt;UIButton&gt;</code>, <code>&lt;UIModal&gt;</code>, and you can build a complete product walkthrough for a feature that doesn't even exist yet.</p>
<p>An LLM can generate this. Describe the user flow in English, it writes the cursor script, the video renders.</p>
<hr />
<h2>How I'm Building It</h2>
<p>The spec is done, 170+ components across 17 categories, all documented with props. Text, layout, media, charts, UI mockups, backgrounds, transitions, annotations, audio, scroll controls, the works.</p>
<p>Implementation starts now. And I'm going to lean heavily on Claude Code for most of the actual coding.</p>
<p>There's a certain irony in using an LLM to build a library designed for LLMs to use. I'm fine with that.</p>
<hr />
<h2>Follow Along</h2>
<p>The repo is live at <a href="https://github.com/spiderocious/irisi">https://github.com/spiderocious/irisi</a>, star it to stay updated, open issues for features you want to see, or reach out if you want to contribute.</p>
<p>I'll be writing about the interesting engineering problems as they come up. The timeline engine is going to be non-trivial.</p>
<p>If you've ever finished a feature and wished the demo just built itself, that's what this is for.</p>
<p>Ìrísí. The way your product appears to the world.</p>
]]></content:encoded></item><item><title><![CDATA[How I Built "Wordshot" a Word Game That Scales to 10 Million Words (And the Architecture Decisions That Made It Possible)]]></title><description><![CDATA[Most word games have a few thousand words. I collected 10.2 million. What started as "let me scrape some names" turned into a three-week hardwork that forced every architectural decision I made afterward.
This is the story of building WordShot, a rea...]]></description><link>https://crackedchefs.devferanmi.xyz/how-i-built-wordshot-a-word-game-that-scales-to-10-million-words-and-the-architecture-decisions-that-made-it-possible</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/how-i-built-wordshot-a-word-game-that-scales-to-10-million-words-and-the-architecture-decisions-that-made-it-possible</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[Express]]></category><category><![CDATA[Game Development]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Wed, 31 Dec 2025 10:52:42 GMT</pubDate><content:encoded><![CDATA[<p>Most word games have a few thousand words. I collected 10.2 million. What started as "let me scrape some names" turned into a three-week hardwork that forced every architectural decision I made afterward.</p>
<p>This is the story of building WordShot, a real-time multiplayer word game where players race against time to answer categories using words that start with a randomly selected letter. Think Scattergories, but with 10.2 million words in the database, real-time WebSocket synchronization for 2-8 players, and architecture decisions that seemed obvious until they weren't..</p>
<p>It started simple enough. A word game needs words. Categories like Animals, Cities, Food, Names, the basics. I figured I'd grab some public domain word lists, maybe scrape Wikipedia for place names, and call it a day. A weekend project, tops.</p>
<p>Then I remembered: I'm Nigerian. This game would have Nigerian users. That means Yoruba names like "Ọmọkehinde" and "Adébáyọ̀" should be valid. Igbo names like "Chukwuemeka" and "Nneka" too. I couldn't just use American name databases.</p>
<p>So I started collecting.</p>
<h3 id="heading-the-bible-problem">The Bible Problem</h3>
<p>The game has a "Bible" category for biblical references. Simple, right? Just grab some names from the King James Bible and move on.</p>
<p>Except... how many biblical names are there actually?</p>
<p>First attempt: YouVersion API. Found about 800 common names (Abraham, Moses, David). Felt good about myself.</p>
<p>Second attempt: Seminary documents. Found open-source theological databases. YAML files with genealogies and cross-references. Another 1,200 names (Zerubbabel, Mahershalalhashbaz, yes these are real).</p>
<p>Third attempt: Bible JSON projects on GitHub. Multiple repos with structured Bible data. Different translations had different transliterations. Another 1,000 unique spellings.</p>
<p>I wrote a script that parsed all three sources. Recursively extracted names from nested structures. Deduplicated. Normalized Unicode (Hebrew names have diacritics). Final count: about 3,000 unique biblical names.</p>
<h3 id="heading-the-yoruba-names-challenge">The Yoruba Names Challenge</h3>
<p>This was harder. There's no "official Yoruba name database." It's an oral tradition, passed down through families. Different regions spell names differently. The romanization isn't standardized.</p>
<p>I needed AI.</p>
<p>I built an iterative script that prompted Claude, OpenAI, and Gemini in rounds. The approach: generate letter combinations (aa, ab, ad, ak...) and ask each AI provider for authentic Yoruba names starting with those letters.</p>
<p>Why this worked:</p>
<ul>
<li><p>Each AI provider has different training data</p>
</li>
<li><p>Rotating providers gave me diverse results</p>
</li>
<li><p>Letter combos forced systematic coverage</p>
</li>
<li><p>Incremental saves meant I didn't lose progress if something failed</p>
</li>
</ul>
<p>I let this run overnight. Next morning: about 12,500 unique Yoruba names.</p>
<p>But I wasn't done. I repeated the process for Igbo names, Hausa names, Swahili names. By the end, I had about 105,000 African names that no American word game would ever have.</p>
<h3 id="heading-the-dictionary-breakdown">The Dictionary Breakdown</h3>
<p>I found public domain dictionaries online. Massive 50MB text files with words and definitions. Hundreds of thousands of words. But they weren't categorized. I needed to know: is "aardvark" an animal? Is "abacus" a thing?</p>
<p>I wrote a parser that used definition keywords to categorize. Animal keywords: mammal, bird, reptile, fish, insect. Food keywords: edible, fruit, vegetable, dish. Place keywords: city, town, country, location.</p>
<p>This categorization wasn't perfect. "Apple" could be a food or a company. Context matters. But for a first pass, keyword matching got me about 40,000 categorized words.</p>
<h3 id="heading-the-maps-scraping-mission">The Maps Scraping Mission</h3>
<p>For the "Place" and "City" categories, I needed real locations. Not just "Paris" and "London", I wanted "Ogbomoso" and "Enugu" and "Zanzibar”, and even niche places like “Ejigbo”, “Iwo”, or “Ikoyi” etc.</p>
<p>I scraped Google Maps (Places API, 1000 requests/day free tier), Apple Maps (browser automation with Puppeteer), and Wikipedia ("List of cities in [country]" pages).</p>
<p>I ran this for every country on Earth. Took 2 days because rate limiting was brutal. Final count: about 115,000 place names.</p>
<h3 id="heading-the-pipeline">The Pipeline</h3>
<p>Now I had data from multiple sources:</p>
<ul>
<li><p>Bible: 3,000 names</p>
</li>
<li><p>African names: 8,000</p>
</li>
<li><p>Dictionary: 40,000 words</p>
</li>
<li><p>Maps: 15,000 places</p>
</li>
</ul>
<p>But the formats were all different. Some had uppercase, some lowercase. Some had Unicode, some ASCII. Some had duplicates across sources.</p>
<p>I needed a unified pipeline. The logic: normalize Unicode, lowercase everything, deduplicate by <code>word:category</code> key, validate (minimum length, no special chars), extract first letter, find aliases.</p>
<p>I ran this pipeline. Deduped everything. Validated each entry. Final database size: 10.2 million words across 13 categories.</p>
<h3 id="heading-the-alias-problem-still-ongoing">The Alias Problem (Still Ongoing)</h3>
<p>Even with 10.2 million words, there's a problem: spelling variations. "Grey" vs "Gray". "Judgement" vs "Judgment". "Theatre" vs "Theater". UK vs US vs EU spellings.</p>
<p>A player types "Grey" but the database has "Gray." They score zero. That's frustrating.</p>
<p>I built a background cron job that runs nightly. It evaluates words per night. For each word: ask AI providers for aliases, scrape dictionary sites for alternate spellings, use logic for UK/US/EU variations (our vs or, re vs er, ise vs ize).</p>
<p>This job processes words per time. The most common words get evaluated first. The long tail can wait.</p>
<h3 id="heading-the-feedback-loop">The Feedback Loop</h3>
<p>There's another spawn job that runs in the background. When a player submits an answer that's marked wrong (not in database), the system queues it for re-evaluation.</p>
<p>The process: ask AI if the word is valid for that category, web scraping for verification, combine signals. If valid, add to database and credit the user (future feature).</p>
<p>This means the database grows over time. Players teach the system. If 10 players submit "Oko" for "City" and it's actually a valid Nigerian city, the system learns. Next player who uses "Oko" gets points.</p>
<h3 id="heading-why-this-matters">Why This Matters</h3>
<p>The word collection wasn't just data entry. It forced every architectural decision I made afterward:</p>
<ol>
<li><p>10.2 million records made database indexes mandatory (queries were 150ms without them)</p>
</li>
<li><p>Progressive evaluation made background jobs non-blocking (can't freeze gameplay)</p>
</li>
<li><p>Spelling variations made the alias system complex (can't just check exact matches)</p>
</li>
<li><p>Multiple sources made the data pipeline critical (can't manually merge formats)</p>
</li>
<li><p>Continuous growth made the database design support writes during gameplay</p>
</li>
</ol>
<p>If I'd stopped at 100,000 words, I wouldn't have learned these lessons. The scale forced me to build better systems.</p>
<p>Three weeks of word collection. Ten million words. Every architecture decision afterward was shaped by this foundation.</p>
<h2 id="heading-feature-sliced-design-the-decision-i-got-right-from-day-one">Feature-Sliced Design (The Decision I Got Right From Day One)</h2>
<p>I've built systems that turned into spaghetti. I wasn't doing that again.</p>
<p>Before writing a single line of game logic, I knew three things:</p>
<ol>
<li><p>The game would have multiple modes (single-player, multiplayer, demo)</p>
</li>
<li><p>Features would grow independently</p>
</li>
<li><p>Folder-by-type (<code>/components</code>, <code>/hooks</code>, <code>/utils</code>) was a trap I'd fallen into before</p>
</li>
</ol>
<p>I chose Feature-Sliced Design from the start. Not because it was trendy, but because I'd seen what happens without it.</p>
<h3 id="heading-the-traditional-hell">The Traditional Hell</h3>
<p>On one of my old project, the structure looked like this: everything in <code>/components</code>, <code>/hooks</code>, <code>/utils</code>, <code>/types</code>. 47 components. 23 hooks. 31 utility files. 18 type files.</p>
<p>What happened:</p>
<ul>
<li><p>Want to understand multiplayer? Grep across 4 folders</p>
</li>
<li><p>Change one feature? Touch files in every folder</p>
</li>
<li><p>Onboard a new dev? "Good luck understanding how this all connects"</p>
</li>
<li><p>Remove a feature? Hope you found every related file</p>
</li>
</ul>
<p>It was chaos. Every feature touched every folder. No clear boundaries.</p>
<h3 id="heading-the-fsd-approach">The FSD Approach</h3>
<p>This time, I organized by feature. Each feature owns its complete stack: API calls, state management, UI components, types, routing.</p>
<p>The structure:</p>
<pre><code class="lang-plaintext">src/
├── features/
│   ├── game/           (single-player)
│   ├── multiplayer/    (multiplayer)
│   └── demo/           (walkthrough)
└── shared/             (cross-feature)
    ├── services/
    ├── hooks/
    └── ui/
</code></pre>
<p>What this gives me:</p>
<p><strong>Clear feature boundaries.</strong> Want to understand single-player? Everything is in <code>features/game/</code>. API calls, state management, UI components, types, routing, all in one place.</p>
<p><strong>Parallel development.</strong> I built the demo mode while multiplayer was still in progress. Zero conflicts. They don't share code except for <code>shared/</code>.</p>
<p><strong>Easy deletion.</strong> When I considered removing the demo feature, I looked at the <code>features/demo/</code> folder. That's it. No hunting across the codebase.</p>
<p><strong>Feature-level testing.</strong> Each feature can be tested in isolation. Mock the API layer, test the provider, verify the UI.</p>
<h3 id="heading-the-demo-mode-that-took-2-days">The Demo Mode That Took 2 Days</h3>
<p>The clearest proof that FSD worked: I built the demo mode in 2 days.</p>
<p>What is demo mode? Interactive walkthrough for first-time users. Shows how the game works step-by-step. No API calls, no real gameplay, just guided UI.</p>
<p>Why it was fast: Created <code>features/demo/</code> folder, copied UI components from <code>features/game/</code>, wrote a simple state machine for the walkthrough, hooked it into routing. Done.</p>
<p>No refactoring. No "how do I isolate this from the main game?" questions. FSD already had the answer: it's a separate feature.</p>
<p>If the codebase was folder-by-type, I'd still be untangling dependencies.</p>
<h3 id="heading-the-rule-i-follow">The Rule I Follow</h3>
<p>Not everything goes in <code>shared/</code>. There's a rule: if code is used by 2+ features, move it to <code>shared/</code>. Otherwise, keep it in the feature.</p>
<p>Examples moved to shared: Button component (used everywhere), sound service (used everywhere), cache service (used by game and multiplayer).</p>
<p>Examples that stayed in features: roulette screen (only single-player), WebSocket provider (only multiplayer), role encoding (multiplayer-specific).</p>
<p>This prevents premature abstraction. Code starts in a feature. If another feature needs it, then we move it to <code>shared/</code>.</p>
<h2 id="heading-the-minimal-state-philosophy">The Minimal State Philosophy</h2>
<p>React developers love state. I learned to hate it.</p>
<p>Not because state is bad. But because unnecessary state is a bug waiting to happen.</p>
<h3 id="heading-the-previous-project-where-state-killed-me">The Previous Project Where State Killed Me</h3>
<p>On my last project, we used Redux. Every feature dumped its state into the global store. Why? "Because we might need it elsewhere."</p>
<p>What happened: 37 action creators, 28 reducers, selectors everywhere. No one knew what was in the store at any given time. Debugging meant logging the entire state tree. Updates triggered re-renders across unrelated components.</p>
<p>The final straw: A dev updated <code>game.currentRound</code> and accidentally broke the notification badge because the badge subscribed to the entire <code>game</code> object, not just <code>game.roundsComplete</code>.</p>
<p>I swore off Redux after that project.</p>
<h3 id="heading-the-102m-words-problem">The 10.2M Words Problem</h3>
<p>With 10.2 million words in the database, I became paranoid about state.</p>
<p>Question: Should I cache the entire word database in Redux?</p>
<p>Math: 10.2M words × 100 bytes each = 1GB. JavaScript heap limit: 1.5GB. Answer: Hell no.</p>
<p>Question: Should I cache the current round's valid words in state?</p>
<p>Math: Player sees 3-5 categories per round. Each category has about 5,000 valid words. 5 categories × 5,000 words × 100 bytes = 2.5MB. Answer: Maybe, but probably overkill.</p>
<p>Question: Should I cache the player's answers in state?</p>
<p>Math: Player submits 3-5 answers per round. 10 rounds max = 50 answers total. 50 answers × 50 bytes = 2.5KB. Answer: Yes, this makes sense.</p>
<p>The scale forced me to be ruthless about what deserved to be in state.</p>
<h3 id="heading-my-decision-matrix">My Decision Matrix</h3>
<p>I made a decision matrix before writing any state management code:</p>
<p>For this project:</p>
<ul>
<li><p>2 features share state (Game and Multiplayer)</p>
</li>
<li><p>State transitions are simple (Player answers, Validation, Results)</p>
</li>
<li><p>No time-travel debugging needed</p>
</li>
<li><p>No middleware needed</p>
</li>
</ul>
<p>Verdict: Context API wins.</p>
<h3 id="heading-the-three-layer-state-architecture">The Three-Layer State Architecture</h3>
<p>Layer 1: Global State (Minimal). App-level state: error boundary state, sound preference. That's it.</p>
<p>Layer 2: Feature State (Context API). Each feature has its own provider. GameProvider for single-player. MultiplayerProvider for multiplayer.</p>
<p>Layer 3: Component State (Local UI). Everything else is component-local. Input values, modal visibility, selected tabs. This state doesn't need to be global. It's purely UI concern.</p>
<h3 id="heading-the-multiplayer-multi-provider-hierarchy">The Multiplayer Multi-Provider Hierarchy</h3>
<p>Multiplayer has two providers: WebSocketProvider (connection layer) and MultiplayerProvider (game state layer).</p>
<p>Why two providers?</p>
<p>WebSocketProvider handles low-level connection: socket instance, connection status, reconnection attempts, send message wrapper.</p>
<p>MultiplayerProvider handles game logic: room data, player list, game phase, actions (create room, join room, start game).</p>
<p>Why separate? WebSocket can reconnect without resetting game state. Game state can be manipulated independently of connection status. Testing: Mock WebSocket provider, test game logic in isolation.</p>
<h3 id="heading-what-i-keep-in-state-vs-what-i-dont">What I Keep in State vs What I Don't</h3>
<p>What's in state: Current game ID, current round number, player answers, multiplayer room data, WebSocket connection status.</p>
<p>What's NOT in state: Word database (way too big), validation results (fetched once from API), game history (stored in localStorage), sound effects (singleton service), UI animations (Framer Motion).</p>
<h3 id="heading-the-rule-derive-state-when-possible">The Rule: Derive State When Possible</h3>
<p>If data can be calculated from existing state, don't store it separately.</p>
<p>Bad: Store <code>currentRound</code>, <code>totalRounds</code>, and <code>isLastRound</code>. Now you have to keep <code>isLastRound</code> in sync.</p>
<p>Good: Store <code>currentRound</code> and <code>totalRounds</code>. Calculate <code>isLastRound = currentRound === totalRounds</code>.</p>
<p>One source of truth. No sync bugs.</p>
<h2 id="heading-the-serviceresult-pattern-why-i-stopped-using-exceptions">The ServiceResult Pattern (Why I Stopped Using Exceptions)</h2>
<p>Exceptions made sense until I had to debug them in production at 2 AM.</p>
<p>The problem isn't exceptions themselves. It's that exceptions make your code lie. A function signature says it returns <code>User</code>, but secretly it might throw <code>UserNotFoundError</code> or <code>DatabaseConnectionError</code> or <code>ValidationError</code>. You don't know until it happens.</p>
<h3 id="heading-the-production-bug">The Production Bug</h3>
<p>Backend code, Node.js + Express. User starts a game. Backend throws <code>LetterSelectionError</code> (couldn't find enough valid letters). Caught by the generic catch block. Returns 500 error. Frontend shows "Internal Server Error."</p>
<p>But it's not a server error. It's a validation error. The user selected incompatible categories. But the generic exception handling made everything a 500.</p>
<p>I had to dig through logs to find the real error. 2 AM. Production down.</p>
<h3 id="heading-the-problem-with-exceptions">The Problem With Exceptions</h3>
<p>Hidden control flow. Non-local reasoning. Lost type safety. Boilerplate everywhere.</p>
<p>To understand what a function can fail with, you have to read its entire implementation and every function it calls. TypeScript can't tell you what exceptions a function throws. The type system is blind to error paths.</p>
<h3 id="heading-the-serviceresult-pattern">The ServiceResult Pattern</h3>
<p>Every service method returns <code>ServiceResult&lt;T&gt;</code>. It's a discriminated union: either <code>{ success: true, data: T }</code> or <code>{ success: false, error: string }</code>.</p>
<p>Every caller must check <code>.success</code>. TypeScript enforces this. Try to access <code>.data</code> without checking? Compiler error.</p>
<p>Why this works at scale: With 10.2 million words, errors become common. Player types a word not in database. Player selects rare letter with not enough categories. Player submits too fast and hits rate limit. These aren't exceptional. They're normal operation.</p>
<p>With exceptions, you have to know every possible exception. Miss one, app crashes.</p>
<p>With ServiceResult, all error paths funnel through <code>!result.success</code>. One check. No surprises.</p>
<h3 id="heading-type-safety-across-50-websocket-events">Type Safety Across 50+ WebSocket Events</h3>
<p>This pattern extends to WebSocket. Room created response: either <code>{ success: true, data: Room }</code> or <code>{ success: false, message: string }</code>.</p>
<p>Benefits: Discriminated unions enforce success checks. TypeScript provides autocomplete for both paths. No silent failures.</p>
<h3 id="heading-the-pattern-that-looked-verbose-but-saved-me">The Pattern That Looked Verbose But Saved Me</h3>
<p>Yes, ServiceResult adds lines of code. Before was 1 line. After is 4 lines.</p>
<p>But here's what I gained:</p>
<p>Every error path is visible. No hidden throws. Compiler enforces error handling. Errors are data, not control flow. Consistent response format across all API endpoints.</p>
<p>Measured impact:</p>
<p>Before ServiceResult: 23 unhandled exceptions in production (first month). 7 of those were user-facing crashes. Average debug time: 45 minutes.</p>
<p>After ServiceResult: 0 unhandled exceptions. 0 user-facing crashes from error handling. Average debug time: 5 minutes.</p>
<h2 id="heading-database-design-the-denormalization-decision">Database Design: The Denormalization Decision</h2>
<p>Normalizing 10.2 million words seemed right. It was 98% slower.</p>
<p>This is the section where I learned that database theory and database reality are different things.</p>
<h3 id="heading-the-naive-approach">The Naive Approach</h3>
<p>Initial schema: just <code>word</code>, <code>category</code>, and <code>aliases</code>. No <code>startsWith</code> field. Calculate it on-the-fly with MongoDB's <code>$substr</code> operator.</p>
<p>Query to validate "Apple" in "Food" starting with "A": use <code>$expr</code> with <code>$substr</code> to check first character.</p>
<p>Performance: Full collection scan (COLLSCAN). 10.2 million documents examined. Query time: about 400ms.</p>
<p>Why so slow? MongoDB can't index computed fields. The <code>$substr</code> expression runs on every document. No way to optimize it.</p>
<h3 id="heading-the-denormalization-decision">The Denormalization Decision</h3>
<p>I added a <code>startsWith</code> field. Just one extra byte per document. Store the first letter explicitly.</p>
<p>Query becomes simpler: match on <code>word</code>, <code>category</code>, and <code>startsWith</code>.</p>
<p>Performance with compound index: Index scan (IXSCAN). About 89 documents examined (only words starting with 'a' in 'food'). Query time: less than 5ms.</p>
<p>Improvement: 98.75% faster.</p>
<h3 id="heading-the-trade-off-analysis">The Trade-Off Analysis</h3>
<p>Cost of denormalization: Extra field, 1 byte per document. 10.2M documents × 1 byte = 10MB. Disk space: Negligible.</p>
<p>Maintenance cost: One pre-save hook to keep <code>startsWith</code> in sync. 3 lines of code.</p>
<p>Benefit: 98% faster queries. No full collection scans. Scales to billions of words.</p>
<p>Verdict: Worth it.</p>
<h3 id="heading-compound-index-strategy">Compound Index Strategy</h3>
<p>I needed two indexes:</p>
<p>Index 1: <code>{ startsWith: 1, category: 1 }</code> for answer validation (most common query).</p>
<p>Index 2: <code>{ category: 1, startsWith: 1 }</code> for cache building (startup).</p>
<p>Why both orders? MongoDB can only use an index if the query matches the prefix of the index. Without both indexes, one query pattern would be slow.</p>
<p>Measured impact: Validation went from 400ms to 5ms. Cache build went from 800ms to 8ms.</p>
<h3 id="heading-embedded-vs-referenced-documents">Embedded vs Referenced Documents</h3>
<p>Another decision: How to store game sessions?</p>
<p>Option 1: Embedded. Everything in one document. Players, rounds, results, all nested.</p>
<p>Option 2: Referenced. Separate collections. Game session has player IDs pointing to Players collection, round IDs pointing to Rounds collection.</p>
<p>Decision matrix: Embedded wins on query complexity (1 query vs 3+), atomicity (single doc update vs multi-collection transaction), and game summary speed (10ms vs 100ms).</p>
<p>Why embedded won: Self-contained games (4-10 rounds, never more). Document size well below 16MB limit. Single query faster. Atomic updates prevent race conditions. Simpler code.</p>
<p>Document size analysis: Worst case 8 players, 10 rounds, 5 categories per round. About 63KB total. Well within 16MB limit.</p>
<h2 id="heading-the-background-jobs-that-never-stop">The Background Jobs That Never Stop</h2>
<p>The word collection ended. The word refinement never will.</p>
<h3 id="heading-the-alias-evaluator">The Alias Evaluator</h3>
<p>Even with 10.2 million words, the alias problem persists. "Grey" vs "Gray". "Judgement" vs "Judgment". UK vs US vs EU spellings.</p>
<p>I built a background cron job that runs nightly. It evaluates 1,000 words per night. For each word: check AI providers for aliases, web scraping for alternate spellings, logic for spelling variations (our/or, re/er, ise/ize).</p>
<p>The job processes 1,000 words per night. At that rate, it'll take 27 years to evaluate all 10.2 million words. But it's fine. The most common words get evaluated first. The long tail can wait.</p>
<h3 id="heading-the-feedback-loop-1">The Feedback Loop</h3>
<p>There's another spawn job. When a player submits an answer that's marked wrong (not in database), the system queues it for re-evaluation.</p>
<p>Process: Ask AI if the word is valid for that category. Web scraping for verification. Combine signals. If valid, add to database.</p>
<p>This means the database grows over time. Players teach the system. If 10 players submit "Oko" for "City" and it's actually a valid Nigerian city, the system learns it. Next player who uses "Oko" gets points.</p>
<h3 id="heading-the-continuous-improvement-pipeline">The Continuous Improvement Pipeline</h3>
<p>These background jobs aren't just cleanup. They're the system learning from real usage. Every failed answer is a signal. Every alias discovered is an improvement. The database isn't static. It evolves.</p>
<p>This is only possible because the architecture supports it. ServiceResult pattern makes errors data. Background jobs are non-blocking. Database design supports concurrent writes during gameplay.</p>
<h2 id="heading-the-patterns-that-scaled-and-the-ones-i-refactored">The Patterns That Scaled (And the Ones I Refactored)</h2>
<p>Not everything I built on day one survived contact with 10.2 million words.</p>
<h3 id="heading-what-held-up">What Held Up</h3>
<p>Feature-Sliced Design: Never had to refactor folder structure. Adding multiplayer didn't break single-player. Demo mode took 2 days.</p>
<p>ServiceResult Pattern: Zero unhandled exceptions in production. Every error path is visible and handled.</p>
<p>Minimal State Philosophy: Never hit memory limits. State management stayed simple even as features grew.</p>
<p>Pre-Computed Caches: Game starts in less than 10ms. Letter selection has 0% failure rate. Cache build takes 3 seconds on startup, saves hours of cumulative query time.</p>
<h3 id="heading-what-i-refactored">What I Refactored</h3>
<p>Initial letter selection: Had 2% failure rate. Users couldn't start games. Fixed with pre-validation during selection. Now 0% failures.</p>
<p>Validation flow: Was 150ms per query. Users waited too long. Added compound indexes and two-tier caching. Now less than 5ms.</p>
<p>Room cleanup: Memory leaked 400% daily. Abandoned rooms stayed in cache forever. Added periodic cleanup job and TTL. Now memory stays stable.</p>
<h3 id="heading-what-id-do-differently">What I'd Do Differently</h3>
<p>Start with Redis instead of in-memory cache. In-memory cache means single-server deployment. Can't scale horizontally. Redis would allow multi-server setup.</p>
<p>Build admin panel for word moderation earlier. Right now, adding/removing words requires database access. Admin panel would let non-technical team members curate the database.</p>
<p>Test on Nigerian mobile networks from day one. I built on fast Wi-Fi. Real users on MTN 3G had different experience. The three-layer reconnection strategy came from this pain.</p>
<h2 id="heading-the-numbers">The Numbers</h2>
<p>Let's be honest about what this architecture achieved.</p>
<p>Performance gains:</p>
<ul>
<li><p>Game start: 300ms to less than 10ms (97% faster)</p>
</li>
<li><p>Answer validation: 150ms to less than 5ms (97% faster)</p>
</li>
<li><p>API throughput: 5x increase (400% improvement)</p>
</li>
<li><p>Memory usage: 35% reduction</p>
</li>
<li><p>Game failures: 2% to 0% (100% elimination)</p>
</li>
</ul>
<p>Code quality:</p>
<ul>
<li><p>TypeScript coverage: 100% (zero JavaScript files)</p>
</li>
<li><p>Type safety: Zero <code>any</code> types in source code</p>
</li>
<li><p>Feature isolation: 3 independent feature folders</p>
</li>
<li><p>State layers: 3 distinct layers (global, feature, component)</p>
</li>
</ul>
<p>User experience:</p>
<ul>
<li><p>Reconnection success rate: 98% on mobile</p>
</li>
<li><p>Session recovery: 95% (5% edge cases like cleared storage)</p>
</li>
<li><p>Error rate: Less than 1% of game sessions encounter errors</p>
</li>
</ul>
<h2 id="heading-the-honest-conclusion">The Honest Conclusion</h2>
<p>10.2 million words taught me something: scale isn't just about performance. It's about architecture that doesn't collapse when your database grows 100x larger than you planned. It's about minimal state when your data is massive. It's about patterns that assume things will break, so they're built to handle it.</p>
<p>I didn't plan to collect 10.2 million words. But the architecture decisions I made, Feature-Sliced Design, minimal state, ServiceResult pattern, database denormalization, they're the reason the game still works when a player types "Ọmọkehinde" and the system finds it in 4ms, validates it against UK/US/EU spellings, checks aliases, and returns whether it's rare or common.</p>
<p>The word collection was a three-week obsession. The architecture is the reason it didn't become a three-month refactor.</p>
<p>That's the real lesson: Good architecture isn't about planning for scale. It's about making decisions that work at small scale and don't break at large scale. Feature-Sliced Design works with 3 features or 30. ServiceResult works with 10 errors or 10,000. Minimal state works with 100KB of data or 1GB.</p>
<p>The patterns that scale are the patterns that start simple and stay simple as complexity grows. Not because they're clever, but because they refuse to be clever. They just work.</p>
<hr />
<p><strong>Tech Stack:</strong></p>
<ul>
<li><p>Frontend: React 18, TypeScript 5.6, Vite 6, Tailwind CSS</p>
</li>
<li><p>Backend: Node.js 18, Express, TypeScript</p>
</li>
<li><p>Database: MongoDB with Mongoose</p>
</li>
<li><p>Real-Time: <a target="_blank" href="http://Socket.IO">Socket.IO</a></p>
</li>
<li><p>Performance: NodeCache, compound indexes, write-behind caching</p>
</li>
</ul>
<p><strong>Metrics:</strong></p>
<ul>
<li><p>10.2 million words across 13 categories</p>
</li>
<li><p>97% performance improvement (300ms to 10ms)</p>
</li>
<li><p>98% session recovery rate on mobile</p>
</li>
<li><p>0% game initialization failures</p>
</li>
<li><p>15,000 lines of code, 3 months part-time</p>
</li>
</ul>
<p>The game works. The architecture held up. The words keep growing. And I learned that sometimes the best architecture decision is the one that lets you obsess over word collection for three weeks without breaking everything else.</p>
]]></content:encoded></item><item><title><![CDATA[Maybe You Only Need Vanilla JavaScript: Challenging the Framework-First Mindset]]></title><description><![CDATA[Have you ever reached for create-react-app to build a simple counter? Or spun up Next.js for a page with three buttons? If you're nodding your head, you're not alone. Somewhere between 2015 and now, we collectively decided that frameworks aren't just...]]></description><link>https://crackedchefs.devferanmi.xyz/maybe-you-only-need-vanilla-javascript-challenging-the-framework-first-mindset</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/maybe-you-only-need-vanilla-javascript-challenging-the-framework-first-mindset</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Front-end Development]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Mon, 03 Nov 2025 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Have you ever reached for <code>create-react-app</code> to build a simple counter? Or spun up Next.js for a page with three buttons? If you're nodding your head, you're not alone. Somewhere between 2015 and now, we collectively decided that frameworks aren't just useful, they're mandatory.</p>
<p><strong>Note:</strong> <em>This article is based on my presentation at DevFest Ibadan 2025, hosted by Google Developer Group Ibadan on November 1, 2025, What started as a 45-minute talk about challenging our framework-first assumptions has been expanded here with additional examples, deeper technical explanations, and code you can actually run. If you were in the audience that day, thank you for the great questions. If you weren't, welcome to the conversation.</em></p>
<p>But what if I told you that for a significant portion of what we build, we're shipping 120KB of abstraction to solve problems we don't actually have?</p>
<p>Let me be clear upfront: <strong>This isn't an anti-framework rant.</strong> React, Vue, and Angular exist for excellent reasons, and we'll talk about those reasons honestly. But the pendulum has swung so far toward "framework-first" thinking that we've forgotten to ask a simple question: <em>Do I actually need this?</em></p>
<p>Today, we're challenging that default assumption. We'll compare vanilla JavaScript and React side-by-side, peek under the hood at what frameworks actually do, and most importantly, learn when each tool makes sense.</p>
<p>And if you're in Nigeria (or anywhere with expensive data and unreliable internet), this conversation isn't academic. Every kilobyte you ship costs your users money and patience.</p>
<p>Let's dig in.</p>
<hr />
<h2 id="heading-what-is-vanilla-javascript-anyway">What is "Vanilla" JavaScript Anyway?</h2>
<p>The first time I heard "vanilla JavaScript," I was genuinely confused. Is this a different language? A library I missed?</p>
<p>Think of vanilla ice cream. It's the base flavor, no toppings, no mix-ins, just pure ice cream. Other flavors are built on top of it:</p>
<ul>
<li><p>Chocolate = Vanilla + Cocoa</p>
</li>
<li><p>Strawberry = Vanilla + Strawberries</p>
</li>
<li><p>Mint Chip = Vanilla + Mint + Chocolate chips</p>
</li>
</ul>
<p><strong>Vanilla JavaScript = JavaScript without any additions.</strong> No React. No Vue. No frameworks, no libraries. Just the language as it exists in the browser.</p>
<p>A quick history note: JavaScript was created by Brendan Eich at Netscape in 1995, reportedly in just 10 days. It was originally called Mocha, then LiveScript, before becoming JavaScript. The problem it solved was simple but crucial: websites needed interactivity without full page reloads. Before JavaScript, every filter, every form submission, every tiny interaction required a server round-trip.</p>
<p>JavaScript has three parts:</p>
<ol>
<li><p><strong>The Language</strong>: Syntax, operators, data types, functions, objects, classes</p>
</li>
<li><p><strong>The Runtime APIs</strong>: Browser APIs (DOM, Fetch, localStorage) or Node.js APIs (fs, http, process)</p>
</li>
<li><p><strong>The Ecosystem</strong>: npm packages, build tools, developer tools, community</p>
</li>
</ol>
<p>When we talk about "Vanilla JavaScript," we're talking about using parts 1 and 2 without adding layers from part 3.</p>
<hr />
<h2 id="heading-the-golden-age-before-frameworks">The Golden Age Before Frameworks</h2>
<p>Before React arrived in 2013 (public release in 2015), and before Angular came even earlier, building with vanilla JavaScript had some genuinely beautiful qualities:</p>
<h3 id="heading-1-tiny-footprint">1. Tiny Footprint</h3>
<p>You didn't need to import anything. Write HTML, add a <code>&lt;script&gt;</code> tag, start coding. Zero bytes of dependencies.</p>
<h3 id="heading-2-zero-build-time">2. Zero Build Time</h3>
<p>No webpack. No Babel. No "waiting for the build to finish." You wrote code, hit refresh, and saw results instantly.</p>
<h3 id="heading-3-simple-deployment">3. Simple Deployment</h3>
<p>Remember those hosting platforms where you just upload a ZIP file? You'd create <code>index.html</code>, link your CSS and JS files, upload everything, and you were done. No build servers, no CI/CD pipelines, no deployment configurations.</p>
<h3 id="heading-4-no-frameworkvendor-lock-in">4. No Framework/Vendor Lock-In</h3>
<p>Your code was <em>yours</em>. If a new tool came along, you could adopt it gradually. You weren't married to React's release schedule or Vue's breaking changes.</p>
<h3 id="heading-5-lightweight-dev-environment">5. Lightweight Dev Environment</h3>
<p>These days, dev servers can take 10 minutes to reload on large React apps. You make a change, go get water, come back, and <em>maybe</em> it's finished recompiling. With vanilla JS? Instant feedback. Change file, refresh browser, done.</p>
<p>This sounds like paradise, right?</p>
<hr />
<h2 id="heading-why-frameworks-won-and-why-that-made-sense">Why Frameworks Won (And Why That Made Sense)</h2>
<p>Frameworks didn't take over because developers are sheep who follow trends. They took over because they solved <em>real, painful problems</em>:</p>
<h3 id="heading-1-cross-browser-nightmare">1. Cross-Browser Nightmare</h3>
<p>Different browsers implemented JavaScript features differently. Getting user location? Different APIs. CSS animations? Special code for Internet Explorer. Event handling? Safari did it differently than Chrome. You'd write one version for modern browsers, another for IE, and pray it worked on mobile.</p>
<p>Frameworks with bundlers like webpack and Babel would transpile your code to work everywhere. Write once, run anywhere.</p>
<h3 id="heading-2-manual-dom-hell">2. Manual DOM Hell</h3>
<p>Let's say you're building a counter. In vanilla JS, you had to:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">increment</span>(<span class="hljs-params"></span>) </span>{
    count++;  <span class="hljs-comment">// Data changed</span>
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'display'</span>).innerHTML = count;  <span class="hljs-comment">// Manually update UI</span>
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'badge'</span>).innerHTML = count;    <span class="hljs-comment">// Manually update UI again</span>
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'sidebar'</span>).innerHTML = count;  <span class="hljs-comment">// And again...</span>
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'btn'</span>).disabled = count &gt;= <span class="hljs-number">10</span>; <span class="hljs-comment">// Don't forget this one!</span>
    <span class="hljs-comment">// Easy to forget one. Bugs everywhere.</span>
}
</code></pre>
<p>Every single place that displays the count needs manual updating. Miss one? Your UI desyncs from your data. This is tedious and error-prone.</p>
<h3 id="heading-3-harder-reusability-more-complexity-for-reuse">3. Harder Reusability / More Complexity for Reuse</h3>
<p>Want to reuse a component? In vanilla JS, you'd have to manually structure functions, manage HTML templates, handle initialization. There was no standard component model.</p>
<h3 id="heading-4-state-chaos-global-variables-and-collisions">4. State Chaos - Global Variables and Collisions</h3>
<p>You'd import different script files, and if two scripts happened to use the same variable name, you were in trouble. No encapsulation meant collision risks everywhere.</p>
<p>React components are enclosed. Everything you define inside a component stays inside it.</p>
<h3 id="heading-5-untestable-code-tightly-coupled-harder-to-maintain">5. Untestable Code - Tightly Coupled, Harder to Maintain</h3>
<p>Look at this code:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'balance'</span>).textContent = patricia.getWalletBalance();
</code></pre>
<p>This is <em>tightly coupled</em> to both the HTML (via that specific ID) and the Patricia API. If Patricia shuts down tomorrow (like they did recently), you have to find every single line that references Patricia. If someone changes that <code>balance</code> ID in the HTML, this breaks silently.</p>
<p>Better practice? Write a facade:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getWalletBalance</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> patricia.getWalletBalance();  <span class="hljs-comment">// Can easily swap to Flutterwave</span>
}
</code></pre>
<p>But vanilla JS didn't enforce these patterns. Frameworks did.</p>
<hr />
<h2 id="heading-what-reactvueangular-actually-gave-us">What React/Vue/Angular Actually Gave Us</h2>
<p>Frameworks earned their dominance by providing five critical improvements:</p>
<h3 id="heading-1-component-reusability">1. Component Reusability</h3>
<p>Write a button component once, use it everywhere. Clear, modular, maintainable.</p>
<h3 id="heading-2-declarative-ui">2. Declarative UI</h3>
<p>Instead of saying "find this element, change its text, update this other element," you say "when count is 5, the UI looks like this." You describe <em>what</em> should be rendered, not <em>how</em> to update it.</p>
<h3 id="heading-3-reactive-data-binding">3. Reactive Data Binding</h3>
<p>Change the data, UI updates automatically. No manual syncing.</p>
<h3 id="heading-4-rich-ecosystems">4. Rich Ecosystems</h3>
<p>Thousands of libraries, established patterns, battle-tested solutions. Need routing? There's a library. Need state management? Multiple options.</p>
<h3 id="heading-5-team-alignment">5. Team Alignment</h3>
<p>Everyone knows React. Hiring is easier. Onboarding is faster. "Let's build this in React" is a no-brainer for team coordination.</p>
<p>These are <em>real</em> benefits. Frameworks won for good reasons.</p>
<hr />
<h2 id="heading-but-everything-has-a-cost">But Everything Has a Cost</h2>
<p>Here's the part we don't talk about enough. When you choose a framework, you're not just gaining features. You're accepting trade-offs. And it's not just you as a developer who pays, your users, your team, and your company all bear the costs.</p>
<h3 id="heading-the-trade-offs-we-accepted">The Trade-offs We Accepted:</h3>
<p><strong>1. Bundle Size Bloat</strong><br />That simple counter app? If you build it with React, you're shipping ~50-120KB of React library code just to count clicks. For users on slow networks or expensive data plans, that's pain.</p>
<p><strong>2. Build Complexity</strong><br />Most frameworks needs to be compiled, transpiled, bundled. Every change requires a build step, except you use the CDN versions (Content delivery network)</p>
<p><strong>3. Framework Lock-In</strong><br />If React is sunsetted tomorrow, you're in trouble. Companies literally pay framework maintainers to keep building because they know if development stops, their apps are stuck. Facebook gave React $1.5-2.5 million recently to ensure continued development.</p>
<p><strong>4. Abstraction Layers</strong><br />React hides how the DOM actually works. If you only know React, you don't know <code>getElementById</code> vs <code>querySelector</code> performance differences, or which DOM APIs are fast vs slow.</p>
<p><strong>5. Easier to "Mess Things Up"</strong><br />With React, you start importing libraries for everything. Form validation? Import a library. State management? Import Redux. Before you know it, you have 47 dependencies to do things that are built into the browser.</p>
<p>I once saw an engineer spend two days trying to pause background audio when users scrolled away in a TikTok-style app. He was managing Redux state, tracking which audios were playing, dispatching pause actions...</p>
<p>The vanilla solution? <code>document.querySelectorAll('audio').forEach(audio =&gt; audio.pause())</code>. Done.</p>
<p><strong>6. Long-Running Servers</strong><br />With Server-Side Rendering (SSR), Static Site Generation (SSG), and other modern framework features, you now need servers that actively process requests. This is different from just serving static HTML files. Your hosting costs go up.</p>
<p><strong>7. Hosting/Cloud Costs</strong><br />SSR, incremental regeneration, edge functions, all these cost money. Vercel, Netlify, and others make their money here.</p>
<p><strong>8. Time</strong><br />Every library you add increases load time. For users in poor network coverage areas, this isn't theoretical—it's the difference between your app loading or not.</p>
<p><strong>9. Trickle-Down Panic When Things Go Wrong</strong><br />Remember the npm supply chain attacks a few months ago? Libraries got hacked, scripts started reading <code>.env</code> files and uploading secrets to remote servers. If you're using vanilla HTML and CSS, you're not running <code>npm install</code> and you wouldn't have been affected.</p>
<p>Axios had a security vulnerability six months ago that could let attackers manipulate API requests. If you're on an old version and don't know, you're exposed.</p>
<p><strong>10. Cognitive Complexity for New Engineers</strong><br />You just learned JavaScript. Variables return strings, numbers, functions. Now someone shows you React and you see <code>return &lt;div&gt;Hello&lt;/div&gt;</code>. Wait, we're returning HTML? And why is it <code>className</code> instead of <code>class</code>? There's a learning curve just to understand the abstractions.</p>
<hr />
<h2 id="heading-feature-showdown-reactivity-amp-state">Feature Showdown: Reactivity &amp; State</h2>
<p>Let's get concrete. I'm going to show you the same app built two ways, and we'll compare them across eight dimensions.</p>
<h3 id="heading-the-challenge">The Challenge</h3>
<p>Build a car counter app. You're standing by a roadside counting BMWs and Mercedes-Benz cars that pass by. The app needs:</p>
<ul>
<li><p>A button for BMW (increments BMW count)</p>
</li>
<li><p>A button for Benz (increments Benz count)</p>
</li>
<li><p>Display total count (sum of both)</p>
</li>
<li><p>All displays update automatically</p>
</li>
</ul>
<p>Simple, right? Let's see both approaches.</p>
<hr />
<h3 id="heading-the-vanilla-js-approach">The Vanilla JS Approach</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> benzCount = <span class="hljs-number">0</span>;
<span class="hljs-keyword">let</span> totalCount = <span class="hljs-number">0</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">incrementBenzCount</span>(<span class="hljs-params"></span>) </span>{
    benzCount++;  <span class="hljs-comment">// Data changed...</span>
    totalCount++; <span class="hljs-comment">// Another data changed...</span>
    <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.benz-count'</span>).textContent = benzCount;  <span class="hljs-comment">// But we manually update UI</span>
    <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.total-count'</span>).textContent = totalCount;
    <span class="hljs-comment">// Imagine doing this everywhere...</span>
}
</code></pre>
<p><strong>What happens:</strong></p>
<ol>
<li><p>Increment the <code>benzCount</code> variable</p>
</li>
<li><p>Increment the <code>totalCount</code> variable</p>
</li>
<li><p>Find the <code>.benz-count</code> element in the DOM</p>
</li>
<li><p>Update its text content</p>
</li>
<li><p>Find the <code>.total-count</code> element in the DOM</p>
</li>
<li><p>Update its text content</p>
</li>
</ol>
<p>Four lines of code inside the function, two variables declared outside. And this is just for <em>one</em> button. The BMW button needs the same treatment.</p>
<p>You can wrap the <code>querySelector</code> calls in a helper function to reduce repetition:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateContent</span>(<span class="hljs-params">selector, value</span>) </span>{
    <span class="hljs-built_in">document</span>.querySelector(selector).textContent = value;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">incrementBenzCount</span>(<span class="hljs-params"></span>) </span>{
    benzCount++;
    totalCount++;
    updateContent(<span class="hljs-string">'.benz-count'</span>, benzCount);
    updateContent(<span class="hljs-string">'.total-count'</span>, totalCount);
}
</code></pre>
<p>Slightly cleaner, but still the same four lines of logic.</p>
<hr />
<h3 id="heading-the-react-approach">The React Approach</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [benzCount, setBenzCount] = useState(<span class="hljs-number">0</span>);
<span class="hljs-keyword">const</span> [bmwCount, setBmwCount] = useState(<span class="hljs-number">0</span>);
<span class="hljs-keyword">const</span> totalCount = benzCount + bmwCount;  <span class="hljs-comment">// Derive data automatically</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">incrementBenzCount</span>(<span class="hljs-params"></span>) </span>{
    setBenzCount(benzCount + <span class="hljs-number">1</span>);  <span class="hljs-comment">// Just update data</span>
}
</code></pre>
<p><strong>What happens:</strong></p>
<ol>
<li><p>Call <code>setBenzCount(benzCount + 1)</code></p>
</li>
<li><p>React handles everything else—UI updates automatically</p>
</li>
</ol>
<p>Notice something crucial: <code>totalCount</code> isn't a separate state. It's <strong>derived state</strong>, calculated from other state. This is a React best practice. Don't create redundant state; derive it.</p>
<hr />
<h3 id="heading-deep-dive-the-8-dimensions-of-comparison">Deep Dive: The 8 Dimensions of Comparison</h3>
<p>Let's analyze these two approaches across multiple dimensions.</p>
<h4 id="heading-1-declarative-vs-imperative"><strong>1. Declarative vs Imperative</strong></h4>
<p><strong>React (Declarative):</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> totalCount = benzCount + bmwCount;  <span class="hljs-comment">// Declare relationship once</span>
<span class="hljs-comment">// UI automatically updates when dependencies change. You describe WHAT, not HOW.</span>
</code></pre>
<p><strong>Vanilla (Imperative):</strong></p>
<pre><code class="lang-javascript">benzCount++;
updateContent(<span class="hljs-string">'.benz-count'</span>, benzCount);  <span class="hljs-comment">// Manual sync</span>
<span class="hljs-comment">// You explicitly tell the DOM what to do, every single time. Easy to forget steps.</span>
</code></pre>
<p>React lets you declare "total count equals the sum of these two values," and it handles keeping the UI in sync. Vanilla requires you to manually execute the sync steps each time.</p>
<h4 id="heading-2-cognitive-load"><strong>2. Cognitive Load</strong></h4>
<p><strong>React: Lower</strong><br />You think about state, not DOM manipulation. Mental model = "data flows down." Change the data, React handles the rest.</p>
<p><strong>Vanilla: Higher</strong><br />You must remember: (1) update variable, (2) find DOM node, (3) update it. Three-step process for every change. Easy to desync if you miss a step.</p>
<h4 id="heading-3-bug-probability"><strong>3. Bug Probability</strong></h4>
<p>In programming, more code = more potential bugs. If you write 10 lines, you can introduce up to 10 bugs (one per line). If you write 100 lines, up to 100 bugs.</p>
<p><strong>React:</strong><br />Fewer steps = fewer bugs. You change state, React handles rendering.</p>
<p><strong>Vanilla:</strong><br />More steps = more opportunities for errors. Forgot to update one display? Typo in a selector? Wrong element ID? Each is a potential bug.</p>
<h4 id="heading-4-memory-footprint"><strong>4. Memory Footprint</strong></h4>
<p><strong>React:</strong><br />~50-120KB (gzipped) for the React library<br />Virtual DOM (~3x actual DOM size in memory)<br />Heavy upfront cost</p>
<p><strong>Vanilla:</strong><br />~0KB overhead. Just your variables. The JavaScript engine is already in the browser—you don't import anything.</p>
<p><strong>The catch:</strong> For small apps (&lt;10KB), React's overhead is significant. For large apps (&gt;5MB), React's 120KB becomes negligible as a percentage of total size.</p>
<h4 id="heading-5-execution-speed-runtime"><strong>5. Execution Speed (Runtime)</strong></h4>
<p><strong>React:</strong><br />Slower per update. State change → diffing algorithm → batch updates → DOM patch = ~1-5ms per update cycle.</p>
<p><strong>Vanilla:</strong><br />Faster per update. Direct DOM manipulation = ~0.1ms per update.</p>
<p><strong>The catch:</strong> For 1-100 updates, the difference is negligible. For 10,000 updates/second (like a data visualization or game), vanilla wins.</p>
<h4 id="heading-6-what-happens-behind-the-hood"><strong>6. What Happens Behind The Hood</strong></h4>
<p><strong>React:</strong></p>
<ol>
<li><p>Triggers re-render</p>
</li>
<li><p>React diffs the Virtual DOM against the previous version</p>
</li>
<li><p>Batches changes together</p>
</li>
<li><p>Updates only the changed DOM nodes</p>
</li>
<li><p>Calls useEffect hooks</p>
</li>
</ol>
<p><strong>Vanilla JS:</strong></p>
<ol>
<li><p><code>querySelector</code> finds the node</p>
</li>
<li><p>Sets <code>textContent</code> directly</p>
</li>
<li><p>Done</p>
</li>
</ol>
<p>React does more work, but that work provides benefits: batching prevents multiple repaints, diffing ensures minimal DOM changes.</p>
<h4 id="heading-7-state-consistency"><strong>7. State Consistency</strong></h4>
<p><strong>React:</strong><br />Single source of truth. The state (<code>benzCount</code>) is the source of truth. UI always matches state (eventually). Impossible to desync.</p>
<p><strong>Vanilla:</strong><br />Dual sources of truth. Is the truth the <code>benzCount</code> variable? Or the DOM? Or both? If you update the variable but forget to update the DOM, they're out of sync.</p>
<h4 id="heading-8-memory-leaks"><strong>8. Memory Leaks</strong></h4>
<p><strong>React:</strong><br />Rare. Cleanup happens automatically when components unmount (unless you misuse <code>useEffect</code> by forgetting to return a cleanup function).</p>
<p><strong>Vanilla:</strong><br />Common. Forgot to remove an event listener? Memory leak. You declared a variable and attached an event listener:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> name = <span class="hljs-string">"feranmi"</span>;  <span class="hljs-comment">// Compilation assigns memory block "1101"</span>
<span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">'click'</span>, handler);  <span class="hljs-comment">// Assigns another memory block</span>
<span class="hljs-comment">// If you never remove this listener, the memory stays occupied forever</span>
</code></pre>
<p>When JavaScript compiles your code, it assigns memory addresses to variables. Let's say <code>name</code> gets memory address <code>1101</code>. That address is marked as "occupied" and stores the value <code>"feranmi"</code>.</p>
<p>If you never clean up (by removing event listeners or clearing variables), those memory blocks stay occupied even after you're done with them. The browser's garbage collector can't reclaim them because they're still referenced.</p>
<p>React manages this automatically. When a component unmounts, React cleans up event listeners and state. With vanilla JS, you're responsible for cleanup.</p>
<hr />
<h2 id="heading-but-waityou-can-do-reactivity-in-vanilla">But Wait—You CAN Do Reactivity in Vanilla</h2>
<p>Everything I just showed you about React's reactivity? You can build it yourself in vanilla JavaScript in about 10 lines of code.</p>
<p>Meet <strong>JavaScript Proxies</strong>.</p>
<h3 id="heading-building-your-own-usestate">Building Your Own useState</h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// 1. Create reactive state</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createReactiveState</span>(<span class="hljs-params">initialState, callback</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(initialState, {
        set(target, property, value) {
            target[property] = value;
            callback();  <span class="hljs-comment">// Notify on change</span>
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
    });
}

<span class="hljs-comment">// 2. Use it</span>
<span class="hljs-keyword">const</span> state = createReactiveState(
    { <span class="hljs-attr">count</span>: <span class="hljs-number">0</span> },
    <span class="hljs-function">() =&gt;</span> render()
);

<span class="hljs-comment">// 3. Render function (template literal)</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">render</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> { count } = state;
    <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'#app'</span>).innerHTML = <span class="hljs-string">`
        &lt;p&gt;Count: <span class="hljs-subst">${count}</span>&lt;/p&gt;
        &lt;p&gt;Double: <span class="hljs-subst">${count * <span class="hljs-number">2</span>}</span>&lt;/p&gt;
        &lt;p&gt;Status: <span class="hljs-subst">${count &gt; <span class="hljs-number">5</span> ? <span class="hljs-string">'High'</span> : <span class="hljs-string">'Low'</span>}</span>&lt;/p&gt;
        &lt;button onclick="state.count++"&gt;+&lt;/button&gt;
    `</span>;
}

<span class="hljs-comment">// Initial render</span>
render();
</code></pre>
<p><strong>What happens:</strong></p>
<ol>
<li><p><strong>State Proxy</strong>: Wraps your state object in a Proxy that intercepts changes</p>
</li>
<li><p><strong>Usage</strong>: When you do <code>state.count++</code>, the Proxy's <code>set</code> trap fires</p>
</li>
<li><p><strong>Trigger Rendering</strong>: The callback (<code>render()</code>) is called automatically</p>
</li>
</ol>
<p>You've just built React's <code>useState</code> in vanilla JavaScript.</p>
<h3 id="heading-important-caveat">Important Caveat</h3>
<p>This isn't production-ready. To truly replicate React, you'd need to add:</p>
<ul>
<li><p><strong>Batching updates</strong> (React doesn't re-render 10 times if you change 10 state values; it batches them)</p>
</li>
<li><p><strong>Diffing algorithm</strong> (React only updates changed DOM nodes, not the entire tree)</p>
</li>
<li><p><strong>Lifecycle hooks</strong> (equivalent to <code>useEffect</code>)</p>
</li>
<li><p><strong>Memory leak prevention</strong> (cleanup when components unmount)</p>
</li>
</ul>
<p>But the core concept? You just built it. React isn't magic, it's JavaScript using browser APIs cleverly.</p>
<hr />
<h2 id="heading-feature-showdown-components-amp-reusability">Feature Showdown: Components &amp; Reusability</h2>
<p>One of the biggest selling points for frameworks is component reusability. Let's see how both approaches handle this.</p>
<h3 id="heading-the-challenge-1">The Challenge</h3>
<p>Build a <code>&lt;ProductCard&gt;</code> component that displays:</p>
<ul>
<li><p>Product image</p>
</li>
<li><p>Product name</p>
</li>
<li><p>Product price</p>
</li>
<li><p>"Add to Cart" button</p>
</li>
</ul>
<hr />
<h3 id="heading-the-react-way">The React Way</h3>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductCard</span>(<span class="hljs-params">{ product, onAddToCart }</span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"product-card"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.name}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"price"</span>&gt;</span>${product.price}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> onAddToCart(product)}&gt;
                Add to Cart
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}

<span class="hljs-comment">// Usage</span>
&lt;ProductCard product={product} onAddToCart={handleAdd} /&gt;
</code></pre>
<p>Clean, familiar, composable. This only works in React.</p>
<hr />
<h3 id="heading-the-web-components-way">The Web Components Way</h3>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductCard</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">HTMLElement</span> </span>{
    connectedCallback() {
        <span class="hljs-keyword">const</span> product = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">this</span>.getAttribute(<span class="hljs-string">'product'</span>));

        <span class="hljs-built_in">this</span>.innerHTML = <span class="hljs-string">`
            &lt;div class="product-card"&gt;
                &lt;img src="<span class="hljs-subst">${product.image}</span>" alt="<span class="hljs-subst">${product.name}</span>" /&gt;
                &lt;h3&gt;<span class="hljs-subst">${product.name}</span>&lt;/h3&gt;
                &lt;p class="price"&gt;$<span class="hljs-subst">${product.price}</span>&lt;/p&gt;
                &lt;button class="add-to-cart"&gt;Add to Cart&lt;/button&gt;
            &lt;/div&gt;
        `</span>;

        <span class="hljs-built_in">this</span>.querySelector(<span class="hljs-string">'.add-to-cart'</span>).addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-built_in">this</span>.dispatchEvent(<span class="hljs-keyword">new</span> CustomEvent(<span class="hljs-string">'add-to-cart'</span>, {
                <span class="hljs-attr">detail</span>: product
            }));
        });
    }
}

<span class="hljs-comment">// Register the component</span>
customElements.define(<span class="hljs-string">'product-card'</span>, ProductCard);
</code></pre>
<p><strong>Usage:</strong></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">product-card</span> <span class="hljs-attr">product</span>=<span class="hljs-string">'{"name":"Phone","price":299,"image":"..."}'</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">product-card</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'product-card'</span>)
        .addEventListener(<span class="hljs-string">'add-to-cart'</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Added:'</span>, e.detail);
        });
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="heading-what-are-web-components">What Are Web Components?</h3>
<p><strong>Web Components</strong> are a set of web platform APIs that let you create new custom, reusable, and encapsulated HTML tags for use in web pages and web applications.</p>
<p>They're based on existing web standards and work across modern browsers, offering a way to extend HTML with new elements that have custom behavior and encapsulated styling.</p>
<p>Key features:</p>
<ul>
<li><p><strong>Custom HTML tags</strong> like <code>&lt;product-card&gt;</code></p>
</li>
<li><p><strong>Shadow DOM</strong> for style encapsulation (styles don't leak out, outside styles don't leak in)</p>
</li>
<li><p><strong>Works everywhere</strong>: React, Vue, Angular, or vanilla JS</p>
</li>
<li><p><strong>Zero dependencies</strong> (browser built-in)</p>
</li>
<li><p><strong>Perfect for design systems &amp; micro-frontends</strong></p>
</li>
</ul>
<h3 id="heading-the-advantage">The Advantage</h3>
<p><strong>React components only work in React.</strong></p>
<p><strong>Web Components work everywhere.</strong></p>
<p>Let's say you're building a design system for a company that has multiple teams using different frameworks. Team A uses React. Team B uses Vue. Team C uses Angular.</p>
<p>If you build components in React, you need to maintain three separate versions. Every time you update a button style, you update it in three places.</p>
<p>If you build with Web Components, you write it once. All teams import the same component. When React 19 comes out with breaking changes, your Web Components still work. When Vue 4 launches, your components still work.</p>
<p>You're not locked to any framework's release schedule.</p>
<hr />
<h2 id="heading-feature-showdown-client-side-routing">Feature Showdown: Client-Side Routing</h2>
<p>Frameworks like react-router, vue-router, and angular-router make routing seem like magic. But what are they actually doing?</p>
<h3 id="heading-how-framework-routers-work">How Framework Routers Work</h3>
<ol>
<li><p><strong>Listen for the</strong> <code>popstate</code> event (fires when URL changes via back/forward buttons)</p>
</li>
<li><p><strong>Check the routes list</strong> (map of paths to components)</p>
</li>
<li><p><strong>Render the correct component</strong> for the current path</p>
</li>
<li><p><strong>Cleanup and wait</strong> for the next route change</p>
</li>
</ol>
<p>That's it. The "magic" is just event listeners and conditional rendering.</p>
<h3 id="heading-how-to-implement-your-own-router">How to Implement Your Own Router</h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// 1. Define routes</span>
<span class="hljs-keyword">const</span> routes = {
    <span class="hljs-string">'/'</span>: renderProductsPage,
    <span class="hljs-string">'/cart'</span>: renderCartPage,
};

<span class="hljs-comment">// 2. Router handler</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">router</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> path = <span class="hljs-built_in">window</span>.location.pathname;
    <span class="hljs-keyword">const</span> render = routes[path] || render404;
    render();
}

<span class="hljs-comment">// 3. Navigate utility</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">navigate</span>(<span class="hljs-params">path</span>) </span>{
    history.pushState(<span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, path);
    router();
}

<span class="hljs-comment">// 4. Handle back/forward</span>
<span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'popstate'</span>, router);

<span class="hljs-comment">// 5. Intercept clicks</span>
<span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (e.target.matches(<span class="hljs-string">'a[href^="/"]'</span>)) {
        e.preventDefault();
        navigate(e.target.getAttribute(<span class="hljs-string">'href'</span>));
    }
});

<span class="hljs-comment">// Initial render</span>
router();
</code></pre>
<p><strong>What happens:</strong></p>
<ol>
<li><p><strong>Routes definition</strong>: Map paths to render functions</p>
</li>
<li><p><strong>Router handler</strong>: Looks at current URL, calls appropriate render function</p>
</li>
<li><p><strong>Navigate utility</strong>: Programmatically change routes via <code>history.pushState()</code></p>
</li>
<li><p><strong>popstate listener</strong>: Handles back/forward button clicks</p>
</li>
<li><p><strong>Click interceptor</strong>: Catches link clicks and uses <code>navigate()</code> instead of full page reload</p>
</li>
</ol>
<p>You've just built client-side routing in ~20 lines.</p>
<h3 id="heading-why-its-called-client-side">Why It's Called "Client-Side"</h3>
<p>Routing used to be a <em>server</em> thing. If you visited <code>/products</code>, the server returned a products page. If you visited <code>/cart</code>, the server returned a cart page. Every route change = full page reload.</p>
<p>Client-side routing moves this to the browser. The server sends all the JavaScript once. Then the JavaScript handles routing without talking to the server again.</p>
<p>That's why apps using react-router feel fast—no page reloads, just JavaScript swapping content.</p>
<hr />
<h2 id="heading-what-you-gain-by-going-vanilla">What You Gain By Going Vanilla</h2>
<p>When you deeply understand vanilla JavaScript, you gain five things:</p>
<h3 id="heading-1-deep-platform-understanding">1. Deep Platform Understanding</h3>
<p>You know <em>how</em> things actually work. You understand <code>getElementById</code> is faster than <code>querySelector</code>. You know which DOM APIs are O(n) vs O(1). You understand browser repaints and reflows.</p>
<p>This makes you a better developer <em>even when using frameworks</em> because you understand what's happening under the abstractions.</p>
<h3 id="heading-2-zero-framework-churn-framework-lock-in">2. Zero Framework Churn / Framework Lock-In</h3>
<p>No anxiety about React 19 breaking changes. No scrambling when a framework is deprecated. Your skills transfer across tools because you understand the foundation.</p>
<h3 id="heading-3-performance-by-default">3. Performance by Default</h3>
<p>The browser is already optimized for JavaScript and DOM manipulation. You get fast performance without needing to "optimize your bundle" or "code-split properly."</p>
<h3 id="heading-4-more-control">4. More Control</h3>
<p>You decide exactly what happens, when, and how. No framework making decisions for you.</p>
<h3 id="heading-5-future-proof-work-and-yourself">5. Future-Proof (Work AND Yourself)</h3>
<p>Your code will keep working. Browsers are backward-compatible. Code you write today in vanilla JS will work in browsers 10 years from now.</p>
<p>And <em>you</em> are future-proof. In an AI world where tools can generate boilerplate React code, your deep understanding of fundamentals, memory leaks, event loops, DOM performance, reactivity patterns, is what makes you valuable.</p>
<hr />
<h2 id="heading-the-point-because-we-need-to-say-it-clearly">The Point (Because We Need to Say It Clearly)</h2>
<p>If you take away three things from this article, let them be:</p>
<h3 id="heading-1-understand-the-whole-spectrum">1. Understand the Whole Spectrum</h3>
<p>Don't just learn React. Learn JavaScript deeply. Understand what React does under the hood. Know when frameworks add value and when they add bloat.</p>
<h3 id="heading-2-choose-based-on-project-needs">2. Choose Based on Project Needs</h3>
<p>Not every project needs React. A landing page with three buttons? Vanilla JS. A complex dashboard with real-time data and 50 interactive components? React makes sense.</p>
<h3 id="heading-3-dont-default-to-react-for-everything">3. Don't Default to React for Everything</h3>
<p>Break the reflex. When starting a new project, ask: "Do I actually need a framework for this?" Sometimes the answer is yes. But often, it's no.</p>
<hr />
<h2 id="heading-when-to-actually-use-vanilla-js">When to Actually Use Vanilla JS</h2>
<p>Here are five scenarios where vanilla JavaScript is the right choice:</p>
<h3 id="heading-1-smalllow-complexity-projects">1. Small/Low-Complexity Projects</h3>
<p>If your project is under 10-20 components or has minimal interactivity, vanilla JS will be faster to write, faster to load, and easier to maintain.</p>
<p><strong>Example:</strong> A personal portfolio site, a documentation page, a simple calculator.</p>
<h3 id="heading-2-performance-optimization-matters">2. Performance Optimization Matters</h3>
<p>If you're building for users on slow networks or expensive data plans (hello, Nigeria), every kilobyte matters. Vanilla JS has zero overhead.</p>
<p><strong>Example:</strong> A mobile app for emerging markets, an offline-first PWA.</p>
<h3 id="heading-3-learning-fundamentals">3. Learning Fundamentals</h3>
<p>If you're still grasping how JavaScript works, build projects in vanilla first. Understand closures, scope, async/await, DOM manipulation, event delegation. <em>Then</em> learn React.</p>
<p>You'll appreciate what frameworks do because you'll know what problems they solve.</p>
<h3 id="heading-4-you-need-more-control">4. You Need More Control</h3>
<p>Sometimes you need precise control over rendering timing, event handling, or memory management. Frameworks make decisions for you. Vanilla JS lets you decide.</p>
<p><strong>Example:</strong> A data visualization library, a game engine, performance-critical animations.</p>
<h3 id="heading-5-speed-for-light-projects">5. Speed for Light Projects</h3>
<p>For throwaway prototypes, internal tools, or quick demos, vanilla JS is faster. No <code>npm install</code>, no build step, no framework decisions. Just code.</p>
<hr />
<h2 id="heading-the-nigerian-context-why-this-really-matters">The Nigerian Context: Why This REALLY Matters</h2>
<p>Let me bring this home.</p>
<p>In Nigeria, where:</p>
<ul>
<li><p><strong>Data costs money</strong> (1GB can cost ₦500-1000, and many people are on prepaid)</p>
</li>
<li><p><strong>Internet can be slow</strong> (3G is common, 4G is unreliable, 5G is rare)</p>
</li>
<li><p><strong>Users are patient only so long</strong> (if your app doesn't load in 5 seconds, they'll switch to a competitor)</p>
</li>
</ul>
<p><strong>Every kilobyte matters.</strong></p>
<p>When you ship a React app that's 2MB after "optimization," you're asking Nigerian users to:</p>
<ol>
<li><p>Pay for that data</p>
</li>
<li><p>Wait for it to download over a slow connection</p>
</li>
<li><p>Hope their connection doesn't drop mid-download</p>
</li>
</ol>
<p>This isn't hypothetical. I've watched people close apps because "this one is not working" when really it's just... still loading.</p>
<p>A vanilla JS app that's 50KB loads fast, costs less data, and works on terrible connections.</p>
<p><strong>Choose wisely.</strong></p>
<p>Your technical choices have real-world consequences for real people. A smaller bundle isn't just a performance metric—it's respect for your users' constraints.</p>
<hr />
<h2 id="heading-final-thoughts-the-balanced-take">Final Thoughts: The Balanced Take</h2>
<p>Let's bring this full circle with five closing points:</p>
<h3 id="heading-1-frameworks-exist-for-good-reasons">1. Frameworks Exist for Good Reasons</h3>
<p>React, Vue, and Angular solved real problems: cross-browser compatibility, manual DOM updates, state management chaos, component reusability. They earned their dominance.</p>
<h3 id="heading-2-but-theyre-not-always-the-answer">2. But They're Not Always the Answer</h3>
<p>For small projects, simple interactions, or performance-critical apps, frameworks are often overkill. The overhead isn't worth it.</p>
<h3 id="heading-3-javascript-is-powerful-on-its-own">3. JavaScript is Powerful on Its Own</h3>
<p>With Proxies, Web Components, and modern DOM APIs, vanilla JavaScript can do <em>a lot</em>. You can build reactivity, routing, and components without frameworks.</p>
<h3 id="heading-4-small-bundles-happy-users-successful-businesses">4. Small Bundles = Happy Users = Successful Businesses</h3>
<p>Users on slow networks or expensive data plans will love you for keeping your app lightweight. Happy users stick around. Happy users tell friends. Happy users convert.</p>
<h3 id="heading-5-understanding-fundamentals-makes-you-a-better-developer">5. Understanding Fundamentals Makes You a Better Developer</h3>
<p>Whether you end up using React or vanilla JS, understanding <em>how things actually work</em> makes you more effective. You debug faster. You optimize better. You make smarter architectural decisions.</p>
<p>In an era where AI can generate boilerplate framework code, your deep understanding of fundamentals is what makes you irreplaceable.</p>
<hr />
<h2 id="heading-skilling-up-where-to-learn-more">Skilling Up: Where to Learn More</h2>
<p>Want to dive deeper into vanilla JavaScript? Here are the best resources:</p>
<p><strong>Books &amp; Websites:</strong></p>
<ul>
<li><p><strong>O'Reilly Books</strong>: "JavaScript: The Definitive Guide," "You Don't Know JS" series</p>
</li>
<li><p><strong>Web.dev</strong>: Google's web development resource with excellent JavaScript guides</p>
</li>
<li><p><strong>Mozilla Web Docs (MDN)</strong>: The definitive reference for JavaScript, DOM APIs, Web Components</p>
</li>
</ul>
<p><strong>Courses:</strong></p>
<ul>
<li><strong>Frontend Masters</strong>: Beginner to advanced JavaScript courses, including deep dives into Proxies, Shadow DOM, and Web APIs</li>
</ul>
<p><strong>Topics to Master:</strong></p>
<ul>
<li><p>JavaScript Proxies</p>
</li>
<li><p>Shadow DOM</p>
</li>
<li><p>Web Components</p>
</li>
<li><p>DOM APIs (and their performance characteristics)</p>
</li>
<li><p>Event delegation</p>
</li>
<li><p>Memory management and garbage collection</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion-the-real-framework-is-understanding">Conclusion: The Real Framework is Understanding</h2>
<p>I started learning to code by accident. I had an itel phone, installed a random app, and started writing HTML without even knowing it was code. I built a CBT app using link tags and thousands of <code>&lt;br&gt;</code> tags to "jump" between questions.</p>
<p>It was ridiculous. It was clever. It <em>worked</em>.</p>
<p>When I finally learned JavaScript, I didn't start with React. I used <code>alert()</code>, <code>confirm()</code>, and <code>querySelector</code>. Every line of code taught me something about <em>how the web works</em>.</p>
<p>That foundation, understanding the platform deeply, is what makes me effective today. Whether I'm writing React, Angular, or vanilla JavaScript, I know what's happening under the hood.</p>
<p>The best framework isn't React or Vue or Angular.</p>
<p><strong>The best framework is understanding.</strong></p>
<p>So before you type <code>npx create-react-app</code> for your next project, pause. Ask yourself: <em>Do I actually need this?</em></p>
<p>Sometimes the answer is yes. But often, more often than we admit, the answer is no.</p>
<p>And in those moments, vanilla JavaScript is enough.</p>
<p>**Choose wisely. Every kilobyte matters.**Resources from the Talk</p>
<p><strong>Slides:</strong> You can view the original presentation slides from DevFest Ibadan <a target="_blank" href="https://docs.google.com/presentation/d/1kEBwyRp0gRxhitfAjBVd5q5TiXqUu_fVQXAb-pydMxc/edit?slide=id.g2efc3e78840_3_10#slide=id.g2efc3e78840_3_10">here</a></p>
<hr />
]]></content:encoded></item><item><title><![CDATA[Building a Reusable AI SDK]]></title><description><![CDATA[Recently, I’ve found myself building AI enabled applications, like the AI content optimization platform “https://buffbyteai.xyz/” and a Anaemia detection using computer models https://nailtechapp.netlify.app/, some of my major problems is managing th...]]></description><link>https://crackedchefs.devferanmi.xyz/building-a-reusable-ai-sdk</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/building-a-reusable-ai-sdk</guid><category><![CDATA[AI]]></category><category><![CDATA[sdk]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Sun, 14 Sep 2025 20:40:00 GMT</pubDate><content:encoded><![CDATA[<p>Recently, I’ve found myself building AI enabled applications, like the AI content optimization platform “<a target="_blank" href="https://buffbyteai.xyz/">https://buffbyteai.xyz/</a>” and a Anaemia detection using computer models <a target="_blank" href="https://nailtechapp.netlify.app/">https://nailtechapp.netlify.app/</a>, some of my major problems is managing the api keys for my LLM providers, dynamic prompts, variable prefill, AI persona’s, retry/failover mechanisms, response structure validation (structure, type, defaults etc)</p>
<p>Imagine if it’s easy for me to use the same key accross different apps, while still being able to dynamically switch providers in a split second, and validate input and output from the LLMs used, this will make my development of AI-enabled applications super fast!.</p>
<p>The pain points are real:</p>
<ul>
<li><p>Repetitive setup across projects</p>
</li>
<li><p>Inconsistent error handling patterns</p>
</li>
<li><p>Manual JSON validation and parsing</p>
</li>
<li><p>API key management across environments</p>
</li>
<li><p>No standardized way to handle retries and failures</p>
</li>
<li><p>Provider-specific code that's hard to switch</p>
</li>
</ul>
<h2 id="heading-initial-thoughts">Initial Thoughts</h2>
<p>The solution seemed obvious: build a unified SDK that abstracts away provider differences while offering consistent developer experience. But the challenge was balancing simplicity with flexibility. Too simple, and it becomes limiting. Too complex, and it defeats the purpose of reducing boilerplate.</p>
<p>I wanted something that felt natural to use, a fluent API that could handle the 80% use case elegantly while still allowing customization for edge cases. The key insight was that most AI interactions follow the same pattern: authenticate, send prompt with variables, get structured response, handle errors.</p>
<h2 id="heading-the-solution-architecture">The Solution Architecture</h2>
<p>The SDK centers around two main methods:</p>
<p><strong>Initialize once, use everywhere:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> ai = sdk.initialize({
  <span class="hljs-attr">auth</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-string">"embedded"</span> | <span class="hljs-string">"fetch"</span>,
    <span class="hljs-attr">url</span>: <span class="hljs-string">"https://my-keys-api.com/keys"</span>,
    <span class="hljs-attr">keys</span>: { <span class="hljs-attr">claude</span>: <span class="hljs-string">"key1"</span>, <span class="hljs-attr">openai</span>: <span class="hljs-string">"key2"</span> }
  },
  <span class="hljs-attr">settings</span>: {
    <span class="hljs-attr">retryOnFail</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">maxRetry</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">cachable</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">trimPrompt</span>: <span class="hljs-literal">false</span>
  }
})
</code></pre>
<p><strong>Prompt with intelligence:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> ai.prompt(<span class="hljs-string">'Get weather in {{CITY}}'</span>, {
  <span class="hljs-attr">expectJson</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">jsonStructure</span>: { <span class="hljs-attr">temp</span>: <span class="hljs-string">"number"</span>, <span class="hljs-attr">condition</span>: <span class="hljs-string">"string"</span> },
  <span class="hljs-attr">validateJSON</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">errorOnInvalidJSON</span>: <span class="hljs-literal">true</span>
}, { <span class="hljs-attr">CITY</span>: <span class="hljs-string">"San Francisco"</span> })
</code></pre>
<p>The authentication system supports both embedded keys and remote fetching, solving the multi-environment deployment challenge. Variable interpolation with required validation prevents runtime errors. JSON structure validation ensures type safety with AI responses.</p>
<h2 id="heading-decision-matrix">Decision Matrix</h2>
<p>When designing the feature set, I evaluated each potential feature against three criteria:</p>
<p><strong>Impact</strong> (how much pain it solves),</p>
<p><strong>Complexity</strong> (implementation difficulty), and</p>
<p><strong>Usage Frequency</strong> (how often developers need it).  </p>
<p><strong>High Impact + Low Complexity + High Usage → V1</strong></p>
<ul>
<li><p>Variable interpolation and validation</p>
</li>
<li><p>Multi-provider authentication</p>
</li>
<li><p>JSON response handling and validation</p>
</li>
<li><p>Basic retry logic and caching</p>
</li>
</ul>
<p><strong>High Impact + High Complexity → V2</strong></p>
<ul>
<li><p>Streaming responses (complex WebSocket/SSE handling)</p>
</li>
<li><p>Usage tracking and cost estimation (requires pricing data maintenance)</p>
</li>
</ul>
<p><strong>Medium Impact + Medium Complexity → V2</strong></p>
<ul>
<li><p>Template management system</p>
</li>
<li><p>Advanced middleware and hooks</p>
</li>
</ul>
<p><strong>Low Impact or Very High Complexity → Future/Never</strong></p>
<ul>
<li><p>Complex prompt engineering features</p>
</li>
<li><p>Built-in fine-tuning capabilities</p>
</li>
</ul>
<p>This matrix helped avoid feature creep while ensuring V1 addresses the most painful developer problems.</p>
<h2 id="heading-version-1-core-foundation">Version 1: Core Foundation</h2>
<p>V1 focuses on the essential developer experience:</p>
<p><strong>Authentication &amp; Configuration</strong></p>
<ul>
<li><p>Multi-provider support (Claude, OpenAI, extensible to others)</p>
</li>
<li><p>Flexible auth: embedded keys or remote URL fetching</p>
</li>
<li><p>Global settings with per-request overrides</p>
</li>
</ul>
<p><strong>Smart Prompting</strong></p>
<ul>
<li><p><code>{{VARIABLE}}</code> interpolation with validation</p>
</li>
<li><p>Required variable checking (throws helpful errors)</p>
</li>
<li><p>Clean variable passing via options object</p>
</li>
</ul>
<p><strong>Response Handling</strong></p>
<ul>
<li><p>Automatic JSON parsing and validation</p>
</li>
<li><p>Type-safe structure checking against expected schema</p>
</li>
<li><p>Configurable error handling for invalid responses</p>
</li>
</ul>
<p><strong>Reliability</strong></p>
<ul>
<li><p>Retry logic for failed requests</p>
</li>
<li><p>Response caching to reduce API calls</p>
</li>
<li><p>Prompt trimming for token optimization</p>
</li>
</ul>
<p>This gives developers a production-ready foundation that eliminates most AI integration boilerplate while maintaining flexibility.</p>
<h2 id="heading-version-2-advanced-features">Version 2: Advanced Features</h2>
<p>Once V1 proves the core concept, V2 will add sophistication:</p>
<p><strong>Streaming Support</strong> Real-time response streaming for better user experience in chat applications and long-form content generation.</p>
<p><strong>Template Management</strong><br />Reusable prompt templates with versioning, making it easier to maintain and iterate on prompts across teams.</p>
<p><strong>Usage Analytics</strong> Token tracking, cost estimation, and usage limits to help manage AI budgets and optimize performance.</p>
<p><strong>Advanced Middleware</strong> Hooks for logging, analytics, custom validation, and request modification, enabling complex workflow integration.</p>
<h2 id="heading-why-this-approach-works">Why This Approach Works</h2>
<p>This SDK design succeeds because it follows proven software engineering principles:</p>
<p><strong>Progressive Enhancement</strong>: Start simple, add complexity gradually based on real usage patterns.</p>
<p><strong>Separation of Concerns</strong>: Authentication, prompting, and response handling are cleanly separated but work together seamlessly.</p>
<p><strong>Developer Experience First</strong>: The API feels natural and reduces cognitive load rather than adding abstraction complexity.</p>
<p><strong>Flexibility Without Bloat</strong>: Core functionality handles most use cases, while extension points allow customization without forcing complexity on simple users.</p>
<p>I have chosen the name “Ajala AI SDK”, Ajala stood out to me because of the legendary <strong>“Ajala, THE TRAVELER”</strong> who travelled the entire world on a bicycle, hoping to do that someday, but definitely not with a bicycle 😂😂😂 , <strong>Ajala AI SDK</strong> in the open, you can follow the development on <a target="_blank" href="https://github.com/spiderocious/ajala-ai-sdk">github</a>. Star the repo to stay updated, open issues for features you need, or reach out if you'd like to contribute code, documentation, or ideas.<br />Building developer tools is always better as a community effort!</p>
<p><strong>Bye.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Accessibility as the Bare Minimum: Frontend Engineer's Guide]]></title><description><![CDATA[Hey there, fellow Coding Chefs! 👋
You've shipped a beautiful product. The animations are smooth, the gradients are great, the Lighthouse performance score is a proud 94. Marketing is happy. Your PM i]]></description><link>https://crackedchefs.devferanmi.xyz/accessibility-as-the-bare-minimum-frontend-engineer-s-guide</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/accessibility-as-the-bare-minimum-frontend-engineer-s-guide</guid><category><![CDATA[a11y]]></category><category><![CDATA[Accessibility]]></category><category><![CDATA[frontend]]></category><category><![CDATA[Web Accessibility]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Contrast]]></category><category><![CDATA[performance]]></category><category><![CDATA[Developer Tools]]></category><category><![CDATA[#WCAG]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Wed, 23 Apr 2025 09:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5d5009ed2db7c7fb3cd7cf28/2e40e35e-5741-441a-a02b-17f8ff69e719.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey there, fellow Coding Chefs! 👋</p>
<p>You've shipped a beautiful product. The animations are smooth, the gradients are great, the Lighthouse performance score is a proud 94. Marketing is happy. Your PM is already talking about the launch tweet. You close your laptop feeling like a rockstar.</p>
<p>Then Monday morning, someone on your team pulls up the same site on a Tecno phone, outside, in the middle of a busy market. The sun is doing what a hot sun does. They squint. They tap. The button they need is there, technically, but the text on it is a soft grey on a slightly-softer grey, and between the dust, the glare, and the trader calling them back to the stall they were buying tomatoes from, they give up and close the tab.</p>
<p>Your app didn't crash. It didn't throw an error. It just quietly failed a real person.</p>
<p>As engineers who work on products that serve a wide variety of users, we're often blinded by our own context. We build on a 27-inch monitor in an conditioned environment. We test in Chrome DevTools. We assume the user is sitting still, with both hands free, looking at a 100% zoomed screen, on fibre internet, with perfect eyesight and no distractions.</p>
<p>But your user is somewhere else entirely.</p>
<p>They're in the crowded aisles of Tewure market in Ogbomoso, trying to pay a vendor before the queue behind them becomes an angry chorus. They're in the organised, air-conditioned comfort of a mall in Lekki, but they're holding a baby in one arm and a card in the other, trying to complete a checkout with one thumb. They're at a party in a Victoria Island club at 1AM, under strobing RGB lights, trying to split a bill with friends on the app you built. They're in a Danfo bus at 6PM, standing, hanging off a strap with one hand, squinting at the phone in the other.</p>
<p>And they all need your thing to work. Fast. In fewer clicks. With text they can actually read.</p>
<p>This is what accessibility really is. It's not a compliance checklist. It's not something you "add at the end." It's the floor you build everything else on top of. The minimum. The bare minimum.</p>
<p>Let's get cracking (or cooking),</p>
<hr />
<h2>Why This Matters (Beyond the Obvious)</h2>
<p>Most engineers I've met hear "accessibility" and their brain immediately jumps to one image: a blind user with a screen reader. And yes, that user exists, that user matters, and we'll get to them. But that mental model is what makes a11y feel like a niche concern, a nice-to-have, something for the 1%.</p>
<p>It isn't.</p>
<p>Here's the mental shift I want you to make: <strong>stop thinking about "disabled users." Start thinking about constraints.</strong></p>
<p>Constraints come in three flavours:</p>
<ul>
<li><p><strong>Permanent</strong> — a user who is blind, or has low vision, or motor impairment, or is colorblind.</p>
</li>
<li><p><strong>Temporary</strong> — a developer who just had LASIK and can't see the screen clearly for a week. A friend with a broken wrist who's typing one-handed.</p>
</li>
<li><p><strong>Situational</strong> — and this is the big one. Every single person is situationally constrained all the time.</p>
</li>
</ul>
<p>Bright sunlight is a visual impairment. A screaming toddler is a cognitive impairment. One-handed scrolling on a Danfo bus is a motor impairment. Trying to read a receipt under RGB strobe lights at Quilox is a visual impairment. A terrible 3G signal in a rural area is a bandwidth impairment that makes your fancy fonts not load, exposing whatever fallback stack you didn't think about.</p>
<p>Every pattern that helps the "permanent" user also helps the "situational" one. The blind user's screen reader announces your button text — and the sighted user in bright sunlight who can only read high-contrast text benefits from the exact same semantic markup that made the announcement possible.</p>
<p>Accessibility is universal design. When you build for the edges, you make the middle better for free.</p>
<p>I had to learn this the hard way.</p>
<p>I once shipped a modal on a project. It was stunning. Soft blurred backdrop, gentle 200ms fade-in, a close button in the corner that was just an × character in a light grey. I was proud of it. Design loved it. It passed every code review.</p>
<p>A month later, a user emailed support saying he couldn't close the modal. Couldn't click the X. Turned out he was on an Android phone, at work, in a warehouse with terrible fluorescent lighting, and he literally could not see the close button. The grey was too light. The touch target was too small. And because I'd built the modal with a <code>&lt;div&gt;</code> (more on that sin in a moment), the Esc key did nothing.</p>
<p>The fix took me 15 minutes. The damage, a user who walked away from a feature we spent three weeks building, was much longer.</p>
<p><strong>Accessibility isn't a feature you add. It's a floor you build on.</strong></p>
<hr />
<h2>Semantic HTML: The Foundation Everyone Skips</h2>
<p>If you learn nothing else from this article, learn this: <strong>use the right HTML tag.</strong></p>
<p>Most accessibility problems I've seen in the wild aren't solved with ARIA attributes, or screen reader testing, or expensive tooling. They're solved by replacing a <code>&lt;div&gt;</code> with a <code>&lt;button&gt;</code>.</p>
<p>Here's the original sin of modern frontend:</p>
<pre><code class="language-jsx">// Please don't do this
&lt;div className="btn" onClick={handleSubmit}&gt;
  Submit
&lt;/div&gt;
</code></pre>
<p>This looks like a button. It behaves like a button if you're a sighted user with a mouse. But:</p>
<ul>
<li><p>It's not focusable with the Tab key</p>
</li>
<li><p>It doesn't trigger on Enter or Space</p>
</li>
<li><p>A screen reader announces it as "Submit" (just text, not a button)</p>
</li>
<li><p>It doesn't get the browser's default button semantics</p>
</li>
<li><p>You now have to reimplement all of that by hand</p>
</li>
</ul>
<p>The fix:</p>
<pre><code class="language-jsx">&lt;button type="button" onClick={handleSubmit}&gt;
  Submit
&lt;/button&gt;
</code></pre>
<p>One tag change. You get keyboard focus, Enter and Space activation, screen reader announcement as "Submit, button," disabled-state handling, and form integration — all for free. Free. The browser was always going to give you this. You just refused to accept it.</p>
<p>Here's your cheat sheet of swaps:</p>
<ul>
<li><p>Use <code>&lt;button&gt;</code> for anything that performs an action. Not <code>&lt;div&gt;</code>. Not <code>&lt;span&gt;</code>. Not <code>&lt;a&gt;</code> without an <code>href</code>.</p>
</li>
<li><p>Use <code>&lt;a href="..."&gt;</code> for anything that navigates. Not <code>&lt;div onClick={navigate}&gt;</code>.</p>
</li>
<li><p>Use <code>&lt;input&gt;</code> and <code>&lt;label&gt;</code> for form fields. Always paired. Always.</p>
</li>
<li><p>Use <code>&lt;nav&gt;</code>, <code>&lt;main&gt;</code>, <code>&lt;header&gt;</code>, <code>&lt;footer&gt;</code>, <code>&lt;aside&gt;</code>, <code>&lt;article&gt;</code> to structure the page. Screen readers let users skip straight to these landmarks.</p>
</li>
<li><p>Use <code>&lt;h1&gt;</code> through <code>&lt;h6&gt;</code> in order. Don't pick <code>&lt;h3&gt;</code> because you like how it looks — style the <code>&lt;h1&gt;</code>.</p>
</li>
</ul>
<p>If you catch yourself typing <code>&lt;div role="button"&gt;</code>, stop, delete that, and type <code>&lt;button&gt;</code>. If you find yourself typing <code>&lt;div role="navigation"&gt;</code>, delete that, and type <code>&lt;nav&gt;</code>. The tag already exists. Use it.</p>
<hr />
<h2>Keyboard Navigation: The Test That Catches 60% of Your Issues</h2>
<p>Here's the cheapest, most humbling test you can run on your own website. Ready?</p>
<p><strong>Unplug your mouse. Put your trackpad hand behind your back. Try to use your app with only the keyboard.</strong></p>
<p>Tab, Shift+Tab, Enter, Space, Escape, arrow keys. That's it. That's your whole toolkit now.</p>
<p>If you can't get from the homepage to completing a purchase using only those keys, congratulations, you've just found out what your screen-reader users feel every day.</p>
<p>Here's what usually breaks:</p>
<ul>
<li><p><strong>Focus disappears.</strong> You Tab into a modal and suddenly have no idea where the focus ring is. Someone removed the default blue outline with <code>*:focus { outline: none }</code> because it "looked ugly" and forgot to add one back.</p>
</li>
<li><p><strong>Focus escapes modals.</strong> You open a dropdown or a dialog and Tab takes you to an element behind it. Focus should be trapped inside until the modal closes.</p>
</li>
<li><p><strong>Tab order is chaos.</strong> Your visually-linear form jumps from the first name field to the footer to the third step because someone used <code>position: absolute</code> and CSS grid to rearrange the DOM.</p>
</li>
<li><p><strong>Custom controls are dead.</strong> That slick custom dropdown you built with <code>&lt;div&gt;</code>s? Tab skips right over it. Or worse, lands on it and does nothing.</p>
</li>
</ul>
<p>The fixes, in order of effort:</p>
<p><strong>1. Never remove focus styles without replacing them.</strong></p>
<pre><code class="language-css">/* The war crime */
*:focus { outline: none; }

/* The minimum acceptable replacement */
*:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}
</code></pre>
<p>Use <code>:focus-visible</code> instead of <code>:focus</code> so the ring only shows up for keyboard users, not mouse clicks. Best of both worlds.</p>
<p><strong>2. Trap focus inside modals.</strong></p>
<p>When a modal opens, focus should move into it and stay there until it closes. Here's the minimum vanilla version:</p>
<pre><code class="language-javascript">function trapFocus(modalElement) {
  const focusable = modalElement.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const first = focusable[0];
  const last = focusable[focusable.length - 1];

  modalElement.addEventListener('keydown', (e) =&gt; {
    if (e.key !== 'Tab') return;
    if (e.shiftKey &amp;&amp; document.activeElement === first) {
      e.preventDefault();
      last.focus();
    } else if (!e.shiftKey &amp;&amp; document.activeElement === last) {
      e.preventDefault();
      first.focus();
    }
  });

  first?.focus();
}
</code></pre>
<p>In React, just use a library — <code>react-focus-lock</code> or the built-in focus management in Radix UI, React Aria, or Headless UI. Don't roll your own unless you're writing a component library.</p>
<p><strong>3. Add a skip link.</strong></p>
<p>At the top of your page, invisible until focused:</p>
<pre><code class="language-html">&lt;a href="#main" class="skip-link"&gt;Skip to main content&lt;/a&gt;
</code></pre>
<p>Your keyboard users will thank you. Tab once, Enter, and they skip past your 40-item navigation menu.</p>
<p><strong>4. Make sure everything interactive is reachable.</strong></p>
<p>If your Tab key doesn't land on a custom control, something is wrong. Either use a real <code>&lt;button&gt;</code> or <code>&lt;a&gt;</code>, or you're going to need <code>tabindex="0"</code> plus a pile of ARIA and keyboard handlers — and at that point, please, please just use the semantic HTML.</p>
<p>The keyboard test takes 5 minutes and catches the majority of real accessibility bugs. Do it before every major feature ships.</p>
<hr />
<h2>ARIA: Useful, Dangerous, and Mostly Unnecessary</h2>
<p>ARIA stands for Accessible Rich Internet Applications. It's a set of attributes you can add to HTML to give extra semantic information to assistive technology. Things like <code>role="dialog"</code>, <code>aria-label="Close"</code>, <code>aria-expanded="true"</code>.</p>
<p>Here's the thing nobody tells juniors:</p>
<p><strong>The first rule of ARIA is: don't use ARIA.</strong></p>
<p>Or, more precisely: no ARIA is better than bad ARIA. And most ARIA is bad ARIA.</p>
<p>The reason is that ARIA doesn't <em>do</em> anything by itself. It doesn't add behaviour. It just tells screen readers what to say. If you add <code>role="button"</code> to a <code>&lt;div&gt;</code>, you've told the screen reader it's a button — but you haven't made it focusable, haven't made it respond to Enter or Space, haven't made it look like a button. You've just lied to the screen reader. The user will now try to press the button, nothing will happen, and they'll leave.</p>
<p>That's worse than no ARIA at all.</p>
<p>So the workflow is:</p>
<ol>
<li><p>Use the right semantic HTML. Can you use <code>&lt;button&gt;</code>? Use <code>&lt;button&gt;</code>.</p>
</li>
<li><p>If semantic HTML can't express what you need, then add ARIA.</p>
</li>
<li><p>If you add ARIA, make sure you've also added the behaviour it implies.</p>
</li>
</ol>
<p>When do you actually need ARIA?</p>
<p><strong>Live regions</strong> for dynamic updates the user should hear:</p>
<pre><code class="language-html">&lt;div aria-live="polite" aria-atomic="true"&gt;
  Your cart has 3 items.
&lt;/div&gt;
</code></pre>
<p>When the text inside changes, a screen reader announces it without the user having to navigate there. Useful for toast notifications, form errors, live search results.</p>
<p><strong>Labels for icon-only buttons:</strong></p>
<pre><code class="language-html">&lt;button aria-label="Close modal"&gt;
  &lt;svg&gt;...&lt;/svg&gt;
&lt;/button&gt;
</code></pre>
<p>Without the <code>aria-label</code>, a screen reader says "button." With it, "Close modal, button." Night and day.</p>
<p><strong>Expanded/collapsed state for custom disclosure widgets:</strong></p>
<pre><code class="language-html">&lt;button aria-expanded="false" aria-controls="menu-items"&gt;
  Menu
&lt;/button&gt;
&lt;ul id="menu-items" hidden&gt;
  ...
&lt;/ul&gt;
</code></pre>
<p>Update <code>aria-expanded</code> in JavaScript when the menu opens. Screen readers will announce the state change.</p>
<p>Paired example, because this is where people go wrong the most:</p>
<pre><code class="language-jsx">// Bad ARIA — lying to the screen reader
&lt;div role="button" onClick={handleClick}&gt;
  Save
&lt;/div&gt;

// No ARIA, just correct HTML — the right answer
&lt;button onClick={handleClick}&gt;
  Save
&lt;/button&gt;
</code></pre>
<p>You didn't need ARIA. You needed the tag that already exists.</p>
<hr />
<h2>Colour, Contrast, and "I Can't Read This Under the Sun"</h2>
<p>Remember our friend in a busy market? This section is for them.</p>
<p>WCAG (the accessibility standard) specifies minimum contrast ratios between text and background:</p>
<ul>
<li><p><strong>4.5:1</strong> for normal body text</p>
</li>
<li><p><strong>3:1</strong> for large text (18pt regular or 14pt bold and up)</p>
</li>
<li><p><strong>3:1</strong> for non-text elements like icons and form borders</p>
</li>
</ul>
<p>That means if your body text is <code>#888</code> on a <code>#FFF</code> background (a contrast of about 3.5:1), it fails. Looks nice on your Macbook in a dark office. Unreadable on a Tecno Spark in Ogbomoso at noon.</p>
<p>The test is not "does it look readable to me right now." The test is "does it meet the ratio, objectively."</p>
<p>Quick ways to check:</p>
<ul>
<li><p><strong>Chrome DevTools</strong> — hover over any text in the Elements panel, click the colour swatch, it shows you the contrast ratio and tells you whether it passes AA or AAA.</p>
</li>
<li><p><strong>axe DevTools</strong> extension — free, audits your whole page, flags contrast failures with line numbers.</p>
</li>
<li><p><strong>Lighthouse</strong> — built into Chrome, runs a full accessibility audit.</p>
</li>
</ul>
<p>A few more rules that come up a lot:</p>
<p><strong>Don't rely on colour alone to convey information.</strong> The classic sin:</p>
<pre><code class="language-html">&lt;!-- Bad: only red tells the user this is an error --&gt;
&lt;p style="color: red"&gt;Your email is invalid&lt;/p&gt;

&lt;!-- Better: colour AND an icon AND clear text --&gt;
&lt;p class="error"&gt;
  &lt;svg class="error-icon"&gt;...&lt;/svg&gt;
  Your email address is missing an @ symbol
&lt;/p&gt;
</code></pre>
<p>A colorblind user sees two identical grey paragraphs otherwise. A user in bright sunlight sees two identical washed-out paragraphs. The icon and the text do the heavy lifting; the colour is a bonus.</p>
<p><strong>Design for the dim environments too.</strong> Your user at the club party with RGB lights bouncing off the screen needs high-contrast, chunky text. Your user at 2AM in bed needs the opposite. Support dark mode. Support system font sizes. Don't fix the font size to 12px because it "looks more refined" — let the browser scale.</p>
<p><strong>Test at 200% zoom.</strong> Open your app, Cmd + a bunch of times, see if your layout breaks. It probably will. A non-trivial number of users browse at 150-200% zoom by default, and they are often the users with the most disposable income (they're older). Breaking the layout at zoom means losing them.</p>
<hr />
<h2>Forms: Where Accessibility Goes to Die</h2>
<p>Forms are the single highest-value accessibility target in any app. Every checkout, signup, login, and onboarding funnel is a form. If forms are inaccessible, the business loses money directly.</p>
<p>Here's the non-negotiable checklist.</p>
<p><strong>1. Every input needs a real label.</strong></p>
<p>Not a placeholder. A label.</p>
<pre><code class="language-html">&lt;!-- Wrong: placeholder as label --&gt;
&lt;input type="email" placeholder="Email address" /&gt;

&lt;!-- Right --&gt;
&lt;label for="email"&gt;Email address&lt;/label&gt;
&lt;input id="email" type="email" /&gt;
</code></pre>
<p>Placeholders disappear the moment the user starts typing. If they get distracted (and remember, they're in a Danfo, holding a baby, at a club, with screaming toddlers), they now have no idea what the field is for. Real labels stay.</p>
<p><strong>2. Errors must be announced, not just shown.</strong></p>
<pre><code class="language-html">&lt;label for="email"&gt;Email address&lt;/label&gt;
&lt;input
  id="email"
  type="email"
  aria-invalid="true"
  aria-describedby="email-error"
/&gt;
&lt;p id="email-error" role="alert"&gt;
  Please enter a valid email address
&lt;/p&gt;
</code></pre>
<p>The <code>aria-describedby</code> links the error to the input, so when the user focuses the field, their screen reader reads both the label AND the error. The <code>role="alert"</code> makes the error announce itself the moment it appears.</p>
<p><strong>3. Required fields need words, not just asterisks.</strong></p>
<pre><code class="language-html">&lt;!-- Incomplete --&gt;
&lt;label for="name"&gt;Name *&lt;/label&gt;

&lt;!-- Complete --&gt;
&lt;label for="name"&gt;Name &lt;span class="required"&gt;(required)&lt;/span&gt;&lt;/label&gt;
&lt;input id="name" required aria-required="true" /&gt;
</code></pre>
<p>A red asterisk alone is useless if you're colorblind and your screen reader doesn't announce the styling.</p>
<p><strong>4. Touch targets need to be big enough.</strong></p>
<p>Minimum 44x44 CSS pixels for anything tappable. Your user is in a Danfo, the bus just hit a pothole, their thumb is wide, and the checkout button is an 18px-tall sliver. They miss. They tap the "Delete account" button next to it instead. You just lost a customer and maybe a lawsuit.</p>
<p>Give things room.</p>
<p><strong>5. Don't trap users in broken states.</strong></p>
<p>If a user tries to submit a form and there are errors, don't just highlight the fields in red and leave them to guess. Scroll to the first error. Focus it. Announce it. Make it trivial for them to fix and retry.</p>
<hr />
<h2>Images, Media, and the Alt Text Problem</h2>
<p>Alt text rules are simpler than most people think:</p>
<ul>
<li><p><strong>Informational images</strong> (product photos, charts, diagrams) — describe what they convey. "A red Toyota Corolla 2020 model, front three-quarter view."</p>
</li>
<li><p><strong>Decorative images</strong> (background textures, divider illustrations) — empty alt: <code>alt=""</code>. Not missing. Empty. An empty alt tells the screen reader "skip this." A missing alt tells it "read out the filename," which is how your users end up hearing "IMG underscore 2847 dot J P G."</p>
</li>
<li><p><strong>Functional images</strong> (an icon inside a link) — describe the action. An envelope icon inside a link to <code>/contact</code> gets <code>alt="Contact us"</code>, not <code>alt="Envelope"</code>.</p>
</li>
<li><p><strong>Images of text</strong> — just don't. Use real text. If you must (a logo), the alt text is the text in the image.</p>
</li>
</ul>
<p>The Nigerian angle here is real: on flaky 3G, your images often don't load at all. Good alt text isn't just for screen readers — it's what appears in the broken-image box, which is what half your users in bad-signal areas will actually see. It's the only content your site has in that moment. Make it count.</p>
<p>For video and audio:</p>
<ul>
<li><p><strong>Video</strong> needs captions (for deaf users, and for everyone watching in public without headphones).</p>
</li>
<li><p><strong>Audio</strong> needs transcripts (for deaf users, and for everyone who wants to skim instead of listen).</p>
</li>
<li><p><strong>Autoplay</strong> with sound is evil. A user opening your page in a quiet office, or at night beside a sleeping partner, or in a lecture hall, will never forgive you. <code>muted</code> or nothing.</p>
</li>
</ul>
<hr />
<h2>Testing: What You Actually Have to Do</h2>
<p>Here's the unglamorous truth: automated tools catch about 30% of accessibility issues. The other 70% needs a human.</p>
<p>But that 30% is cheap and you should absolutely start there.</p>
<p><strong>Automated tools:</strong></p>
<ul>
<li><p><strong>axe DevTools</strong> — free browser extension. Run it on any page, get a list of violations with line numbers and fixes. Use this religiously.</p>
</li>
<li><p><strong>Lighthouse</strong> — Chrome DevTools → Lighthouse tab → Accessibility category. Gives you a score and a punch list.</p>
</li>
<li><p><strong>Pa11y</strong> — CLI tool for CI integration. Add it to your pipeline and fail the build if new accessibility errors show up.</p>
</li>
<li><p><strong>ESLint plugins</strong> — <code>eslint-plugin-jsx-a11y</code> catches a lot of issues at the code level, before they ever ship.</p>
</li>
</ul>
<p><strong>Manual tests you should do before every major release:</strong></p>
<ol>
<li><p><strong>Keyboard only.</strong> The test from earlier. Tab through the entire user flow. Can you complete it?</p>
</li>
<li><p><strong>Screen reader.</strong> On Mac, VoiceOver is built in — press Cmd+F5. On Windows, download NVDA, it's free and excellent. On Android, TalkBack is in accessibility settings. Just spend 10 minutes navigating your own app with it. The first time you do this, it will change how you build forever.</p>
</li>
<li><p><strong>200% zoom.</strong> Cmd+ a bunch of times in the browser. Does the layout hold? Does text get clipped?</p>
</li>
<li><p><strong>Sunlight test.</strong> Take your laptop outside, in bright sun, and try to use the site. I'm not kidding. This is the single best test for contrast, and it doesn't require any special tooling.</p>
</li>
<li><p><strong>One-handed test.</strong> Pick up your phone, put your other hand behind your back, and try to complete a key flow. Can you reach the primary CTA with your thumb? Or is it in a corner you need two hands to hit?</p>
</li>
</ol>
<p>Doing these five tests once a sprint catches more real bugs than every automated tool combined.</p>
<hr />
<h2>What I'd Do Differently</h2>
<p>Looking back on the projects where I've shipped accessibility debt, there's a clear pattern: accessibility was always treated as a "phase 2" item, something we'd "get to after launch." And then, like all phase 2 items, it never happened, or it happened badly, or it happened two years later when someone on the team got annoyed enough to retrofit it.</p>
<p>Retrofitting accessibility is an order of magnitude more expensive than building it in.</p>
<p>If I were starting a new project today, I'd do three things differently:</p>
<p><strong>1. Treat semantic HTML as a non-negotiable from day one.</strong> Every <code>&lt;div onClick&gt;</code> in PR review gets rejected. Not discussed. Not "we'll refactor later." Rejected. It costs the engineer 15 seconds to change. It costs the company weeks to retrofit later.</p>
<p><strong>2. Add an accessibility checklist to the PR template.</strong></p>
<pre><code class="language-markdown">## Accessibility
- [ ] Keyboard-navigable end-to-end
- [ ] Focus states visible on all interactive elements
- [ ] Form inputs have real labels
- [ ] Colour contrast passes WCAG AA
- [ ] axe DevTools run, no new violations
- [ ] Tested at 200% zoom
</code></pre>
<p>Six checkboxes. Maybe five minutes per PR. It builds the muscle.</p>
<p><strong>3. Do one real screen reader test per feature.</strong> Not a full audit, just ten minutes with VoiceOver before calling something done. The number of bugs this catches, silently, before they ship, is ridiculous.</p>
<p>One project I was on shipped a "revamped" dashboard. We had beautiful charts, great animations, a lovely dark mode. Three weeks after launch, a user wrote in to say the whole dashboard was unusable on a screen reader every chart was an unlabelled canvas, every filter was a styled div, the whole thing announced as "blank, blank, blank." Fixing it took three sprints. Building it right the first time would have taken maybe three extra days of planning and one day of extra implementation.</p>
<p>That's the real cost of treating accessibility as phase 2. Not the ethics, not the compliance — the pure engineering waste.</p>
<hr />
<h2>The Honest Conclusion</h2>
<p>Your user isn't sitting at a 27-inch monitor in a quiet office.</p>
<p>They're in a market in Ogbomoso, trying to pay before the next customer shoves them aside. They're in a club in Lekki, under strobing lights, trying to split a bill. They're on a Danfo bus at rush hour, holding a strap, trying to check if their transfer cleared. They're in a mall in Ikeja with a toddler on their hip, tapping through a checkout with one thumb. They're at home at 2AM, half-awake, trying to order food without waking their partner.</p>
<p>Some of them are blind. Some of them are colorblind. Some of them are temporarily one-handed because they just came from the hospital. Some of them just forgot their glasses at the office. Some of them are fine, they're just tired.</p>
<p>Every single one of them is using your app under conditions you never tested for. And accessibility isn't some charitable concession you make for "other people." It's the minimum, the floor, the thing that has to be there before anything else you build on top of it can actually reach the people you built it for.</p>
<p>You don't need to memorise every ARIA attribute. You don't need to become an a11y expert. You just need to care enough to do the five-minute keyboard test, to use the button tag instead of a div, to pick a colour that passes contrast, to write a real label, to run axe once before you ship.</p>
<p>Most users you lock out won't email you. They'll just leave. Quietly. Permanently.</p>
<p><strong>Accessible websites aren't harder to build. They're just built differently from the start.</strong></p>
<p>Build for the market, the mall, the club, the Danfo, the couch at 2AM. Build for everyone, because that's who's actually using the thing.</p>
<p>Bye.</p>
]]></content:encoded></item><item><title><![CDATA[JavaScript Temporal Dead Zone and Variable Declarations]]></title><description><![CDATA[Part 3 of the JavaScript Deep Dive Series
In our previous article, we learned that JavaScript has a compilation phase where it scans through your code and sets up variable declarations. But not all variable declarations behave the same way during thi...]]></description><link>https://crackedchefs.devferanmi.xyz/javascript-temporal-dead-zone-and-variable-declarations</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/javascript-temporal-dead-zone-and-variable-declarations</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[js]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Web Design]]></category><category><![CDATA[web developers]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Thu, 06 Feb 2025 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p><em>Part 3 of the</em> <strong><em>JavaScript Deep Dive Series</em></strong></p>
<p>In our previous article, we learned that JavaScript has a compilation phase where it scans through your code and sets up variable declarations. But <strong>not</strong> all variable declarations behave the same way during this process.</p>
<p>Understanding the differences between <code>var</code>, <code>let</code>, and <code>const</code> - and the "Temporal Dead Zone" is important for writing predictable JavaScript and avoiding common bugs.</p>
<h2 id="heading-definitions">Definitions</h2>
<p>Before we proceed, let's explain a few terms you will come accross:</p>
<p><strong>Temporal Dead Zone (TDZ)</strong> - The period between when a variable is hoisted (during compilation) and when it's initialized with a value. During this time, accessing the variable throws a ReferenceError.</p>
<p><strong>Block Scope</strong> - A scope created by curly braces <code>{}</code>. Variables declared with <code>let</code> and <code>const</code> are confined to the block where they're declared.</p>
<p><strong>Function Scope</strong> - A scope created by functions. Variables declared with <code>var</code> are confined to the function where they're declared (or global if outside any function).</p>
<p><strong>Hoisting</strong> - The process during compilation where variable and function declarations are processed before code execution begins.</p>
<p><strong>Initialization</strong> - The moment a variable gets its first value assignment.</p>
<h2 id="heading-the-three-variable-declarations">The Three Variable Declarations</h2>
<p>JavaScript gives you three ways to declare variables, each with different scoping and hoisting behavior:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> teacher = <span class="hljs-string">"Kyle"</span>;     <span class="hljs-comment">// Function-scoped, undefined when hoisted</span>
<span class="hljs-keyword">let</span> student = <span class="hljs-string">"Frank"</span>;    <span class="hljs-comment">// Block-scoped, TDZ when hoisted  </span>
<span class="hljs-keyword">const</span> course = <span class="hljs-string">"JS"</span>;      <span class="hljs-comment">// Block-scoped, TDZ when hoisted, immutable</span>
</code></pre>
<h3 id="heading-var">VAR</h3>
<p><code>var</code> declarations are <strong>function-scoped</strong> and get initialized with <code>undefined</code> during the compilation phase:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(teacher);     <span class="hljs-comment">// undefined (not an error!)</span>
<span class="hljs-keyword">var</span> teacher = <span class="hljs-string">"Kyle"</span>;
<span class="hljs-built_in">console</span>.log(teacher);     <span class="hljs-comment">// "Kyle"</span>
</code></pre>
<p><strong>What happens:</strong></p>
<ol>
<li><p><strong>Compilation:</strong> <code>teacher</code> is declared in function scope, initialized with <code>undefined</code></p>
</li>
<li><p><strong>Execution:</strong> First <code>console.log</code> prints <code>undefined</code>, then assignment happens</p>
</li>
</ol>
<h3 id="heading-let-and-const-the-modern-approach">LET and CONST - The Modern Approach</h3>
<p><code>let</code> and <code>const</code> are <strong>block-scoped</strong> and exist in the Temporal Dead Zone until their declaration line:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(student);     <span class="hljs-comment">// ReferenceError!</span>
<span class="hljs-keyword">let</span> student = <span class="hljs-string">"Frank"</span>;
<span class="hljs-built_in">console</span>.log(student);     <span class="hljs-comment">// "Frank"</span>
</code></pre>
<p><strong>What happens:</strong></p>
<ol>
<li><p><strong>Compilation:</strong> <code>student</code> is declared in block scope but NOT initialized</p>
</li>
<li><p><strong>Execution:</strong> First <code>console.log</code> tries to access uninitialized variable → ReferenceError</p>
</li>
</ol>
<h2 id="heading-block-scope-in-action">Block Scope in Action</h2>
<p>Block scope means variables are confined to the nearest set of curly braces:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> globalVar = <span class="hljs-string">"I'm global"</span>;

<span class="hljs-keyword">if</span> (<span class="hljs-literal">true</span>) {
    <span class="hljs-keyword">var</span> functionScoped = <span class="hljs-string">"I escape the block"</span>;
    <span class="hljs-keyword">let</span> blockScoped = <span class="hljs-string">"I'm trapped in the block"</span>;
    <span class="hljs-keyword">const</span> alsoBlocked = <span class="hljs-string">"Me too"</span>;
}

<span class="hljs-built_in">console</span>.log(functionScoped);  <span class="hljs-comment">// "I escape the block"</span>
<span class="hljs-built_in">console</span>.log(blockScoped);     <span class="hljs-comment">// ReferenceError!</span>
<span class="hljs-built_in">console</span>.log(alsoBlocked);     <span class="hljs-comment">// ReferenceError!</span>
</code></pre>
<p><strong>The difference:</strong></p>
<ul>
<li><p><code>var</code> ignores block boundaries (function-scoped)</p>
</li>
<li><p><code>let</code> and <code>const</code> respect block boundaries (block-scoped)</p>
</li>
</ul>
<h2 id="heading-temporal-dead-zone-tdz">Temporal Dead Zone (TDZ)</h2>
<p>The TDZ is the time between variable hoisting and initialization:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Before declaration"</span>);

<span class="hljs-built_in">console</span>.log(a);  <span class="hljs-comment">// ReferenceError - TDZ violation</span>
<span class="hljs-built_in">console</span>.log(b);  <span class="hljs-comment">// undefined - no TDZ for var</span>

<span class="hljs-keyword">let</span> a = <span class="hljs-string">"Hello"</span>;
<span class="hljs-keyword">var</span> b = <span class="hljs-string">"World"</span>;

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"After declaration"</span>);
<span class="hljs-built_in">console</span>.log(a);  <span class="hljs-comment">// "Hello"  </span>
<span class="hljs-built_in">console</span>.log(b);  <span class="hljs-comment">// "World"</span>
</code></pre>
<p><strong>TDZ Timeline:</strong></p>
<ol>
<li><p><strong>Compilation:</strong> Both <code>a</code> and <code>b</code> are hoisted</p>
</li>
<li><p><strong>Execution starts:</strong> <code>a</code> is in TDZ, <code>b</code> is <code>undefined</code></p>
</li>
<li><p><strong>Line 3:</strong> Accessing <code>a</code> → ReferenceError (TDZ violation)</p>
</li>
<li><p><strong>Line 4:</strong> Accessing <code>b</code> → <code>undefined</code> (allowed)</p>
</li>
<li><p><strong>Line 6:</strong> <code>a</code> exits TDZ, gets value "Hello"</p>
</li>
<li><p><strong>Line 9:</strong> Both variables accessible normally</p>
</li>
</ol>
<h2 id="heading-practical-implications">Practical Implications</h2>
<h3 id="heading-loop-behavior">Loop Behavior</h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// var - function scoped, same variable</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">3</span>; i++) {
    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(i), <span class="hljs-number">100</span>);  <span class="hljs-comment">// 3, 3, 3</span>
}

<span class="hljs-comment">// let - block scoped, new variable each iteration  </span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">3</span>; i++) {
    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(i), <span class="hljs-number">100</span>);  <span class="hljs-comment">// 0, 1, 2</span>
}
</code></pre>
<h3 id="heading-const-immutability">Const Immutability</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> user = { <span class="hljs-attr">name</span>: <span class="hljs-string">"Kyle"</span> };
user.name = <span class="hljs-string">"Frank"</span>;        <span class="hljs-comment">// OK - modifying property</span>
<span class="hljs-built_in">console</span>.log(user.name);     <span class="hljs-comment">// "Frank"</span>

user = { <span class="hljs-attr">name</span>: <span class="hljs-string">"Suzy"</span> };    <span class="hljs-comment">// Error - reassigning const</span>
</code></pre>
<h3 id="heading-block-scope-benefits">Block Scope Benefits</h3>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processData</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (condition) {
        <span class="hljs-keyword">let</span> tempData = calculateSomething();
        <span class="hljs-keyword">let</span> result = process(tempData);
        <span class="hljs-keyword">return</span> result;
        <span class="hljs-comment">// tempData and result die here</span>
    }
    <span class="hljs-comment">// tempData and result not accessible here</span>
}
</code></pre>
<h2 id="heading-common-misconceptions">Common Misconceptions</h2>
<p><strong>"let and const aren't hoisted"</strong> False. They are hoisted but remain uninitialized in the TDZ.</p>
<p><strong>"const means immutable"</strong><br />Partially false. The binding is immutable, but object/array contents can change.</p>
<p><strong>"var is always bad"</strong> False. <code>var</code> has legitimate use cases, especially for function-scoped variables.</p>
<p><strong>"Block scope is just for loops"</strong> False. Any <code>{}</code> creates block scope for <code>let</code>/<code>const</code>.</p>
<h2 id="heading-when-to-use-which">When to Use Which</h2>
<p><strong>Use</strong> <code>const</code> by default - Prevents accidental reassignment</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> API_URL = <span class="hljs-string">"https://api.example.com"</span>;
<span class="hljs-keyword">const</span> users = [];  <span class="hljs-comment">// Can still push to array</span>
</code></pre>
<p><strong>Use</strong> <code>let</code> when you need reassignment - Clear signal of mutability</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> counter = <span class="hljs-number">0</span>;
<span class="hljs-keyword">let</span> currentUser = <span class="hljs-literal">null</span>;
</code></pre>
<p><strong>Use</strong> <code>var</code> sparingly - Only when you specifically need function scope</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processItems</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; items.length; i++) {
        <span class="hljs-comment">// var i is function-scoped, accessible after loop</span>
    }
    <span class="hljs-keyword">return</span> i;  <span class="hljs-comment">// Final value of i</span>
}
</code></pre>
<h2 id="heading-summary-choose-your-declaration-wisely">Summary: Choose Your Declaration Wisely</h2>
<p>Understanding variable declarations is fundamental to JavaScript mastery:</p>
<p><strong>Compilation vs Execution:</strong> All declarations are hoisted, but initialized differently <strong>TDZ Protection:</strong> <code>let</code>/<code>const</code> prevent access before initialization<br /><strong>Scope Boundaries:</strong> <code>var</code> ignores blocks, <code>let</code>/<code>const</code> respect them <strong>Best Practices:</strong> Prefer <code>const</code>, use <code>let</code> for reassignment, avoid <code>var</code> unless necessary</p>
<p>This knowledge sets the foundation for understanding:</p>
<ul>
<li><p>Why certain bugs occur during development</p>
</li>
<li><p>How closures capture variables correctly</p>
</li>
<li><p>Module patterns and encapsulation strategies</p>
</li>
<li><p>Modern JavaScript best practices</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[JavaScript Lexical Scope and Compilation]]></title><description><![CDATA[Part 2 of the JavaScript Deep Dive Series
Before JavaScript executes a single line of your code, something crucial happens behind the scenes. While most developers think JavaScript executes and runs code line by line(I know I mentioned this in the fi...]]></description><link>https://crackedchefs.devferanmi.xyz/javascript-lexical-scope-and-compilation</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/javascript-lexical-scope-and-compilation</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[javascript framework]]></category><category><![CDATA[js]]></category><category><![CDATA[React]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Wed, 22 Jan 2025 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p><em>Part 2 of the JavaScript Deep Dive Series</em></p>
<p>Before JavaScript executes a single line of your code, something crucial happens behind the scenes. While most developers think JavaScript executes and runs code line by line(I know I mentioned this in the first series), the reality is more sophisticated and understanding this process is the key to mastering scope, hoisting, and variable behavior. Javascript still executes code line by line, but before that it interprets/compiles the javascript code.<br />When you write a javascript code, the first thing that happens is what I refer to as “Parsing” also can be referred to as “Compilation” or interpretation.  </p>
<p>A relatable example is when you have a syntax error in your code on line 20, but immediately you recompile, you get an error, when infact your code hasn’t executed up to line 20, the reason why this error shows up immediately is because of the first step “Parsing/Compilation”, during this phase, Javascript engines runs through the code, define variables, verify syntaxes, etc.  </p>
<p>So, your code is first compiled, then executed, and that brings us to “The Two step process”.</p>
<h2 id="heading-javascripts-two-step-process">JavaScript's Two-Step Process</h2>
<p>Javascript follows a <strong>two-step process</strong>:</p>
<ol>
<li><p><strong>Compilation Phase</strong> - JavaScript scans through your entire code, setting up scope and preparing for execution</p>
</li>
<li><p><strong>Execution Phase</strong> - The actual running of your code, line by line</p>
</li>
</ol>
<h2 id="heading-this-compilation-step-is-where-all-the-magic-of-hoisting-scope-creation-and-variable-declarations-happens">This compilation step is where all the "magic" of <strong>hoisting</strong>, <strong>scope creation</strong>, and variable declarations happens.</h2>
<p><strong>Definitions</strong></p>
<p>Before we proceed into JavaScript's compilation process, let's explain a few terms you will come accross:</p>
<p><strong>Scope</strong> - The accessibility of variables and functions in different parts of your code. It determines where you can use a particular variable.</p>
<p><strong>Lexical Scope</strong> - Scope that is determined by where variables and functions are declared in your code (at write-time), not where they are called from (at runtime).</p>
<p><strong>Global Scope</strong> - The outermost scope in JavaScript. Variables declared here are accessible from anywhere in your program(more like in the window).</p>
<p><strong>Function Scope</strong> - A scope created inside a function. Variables declared here are only accessible within that function.</p>
<p><strong>Block Scope</strong> - A scope created by curly braces <code>{}</code> when used with <code>let</code> or <code>const</code>. Variables declared here are only accessible within that block.</p>
<p><strong>Source Reference</strong> - When a variable is being read or accessed (appears on the right-hand side of an assignment or in expressions like <code>console.log(variable)</code>).</p>
<p><strong>Target Reference</strong> - When a variable is being assigned a value (appears on the left-hand side of an assignment like <code>variable = "value"</code>).</p>
<p><strong>Compilation Phase</strong> - The first step where JavaScript scans through your code, sets up scope, and prepares variable declarations before any code executes.</p>
<p><strong>Execution Phase</strong> - The second step where JavaScript actually runs your code line by line.</p>
<p><strong>Scope Chain</strong> - The hierarchy of scopes that JavaScript searches through when looking up a variable, starting from the innermost scope and moving outward.</p>
<p><strong>Hoisting</strong> - The behavior where variable and function declarations are processed during the compilation phase, making them available throughout their scope even before their declaration line is reached during execution.</p>
<h3 id="heading-step-1-compilation-the-setup-phase">Step 1: Compilation - The Setup Phase</h3>
<p>During compilation, JavaScript's engine acts like an organizer, scanning through your code and asking two critical questions about every variable it encounters:</p>
<p><strong>"What scope does this belong to?"</strong><br /><strong>"Is this a source or target reference?"</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> teacher = <span class="hljs-string">"Kyle"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">otherClass</span>(<span class="hljs-params"></span>) </span>{
    teacher = <span class="hljs-string">"Suzy"</span>;
    topic = <span class="hljs-string">"React"</span>;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Welcome!"</span>);
}

otherClass();
</code></pre>
<p>Let's trace through the compilation phase:</p>
<p><strong>Line 1:</strong> <code>var teacher = "Kyle"</code></p>
<ul>
<li><p>Compiler finds <code>teacher</code> declaration</p>
</li>
<li><p>Creates <code>teacher</code> in <strong>global scope</strong></p>
</li>
<li><p>Notes: This will be a <strong>target reference</strong> (receiving a value)</p>
</li>
</ul>
<p><strong>Line 3:</strong> <code>function otherClass()</code></p>
<ul>
<li><p>Compiler creates <code>otherClass</code> function in <strong>global scope</strong></p>
</li>
<li><p>Creates <strong>new scope</strong> for inside the function</p>
</li>
</ul>
<p><strong>Line 4:</strong> <code>teacher = "Suzy"</code></p>
<ul>
<li><p>Compiler sees <code>teacher</code> reference</p>
</li>
<li><p>No declaration here, so it's a <strong>source reference</strong> (looking up existing variable)</p>
</li>
<li><p>Notes: Will look up scope chain during execution</p>
</li>
</ul>
<p><strong>Line 5:</strong> <code>topic = "React"</code></p>
<ul>
<li><p>Compiler sees <code>topic</code> reference</p>
</li>
<li><p>No declaration anywhere - this will create an <strong>implicit global</strong></p>
</li>
</ul>
<h2 id="heading-source-vs-target-references">Source vs Target References</h2>
<p>Understanding the difference between source and target references is crucial:</p>
<p><strong>Target Reference</strong> = <strong>Left-hand side</strong> of assignment (receiving a value)</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> student = <span class="hljs-string">"Frank"</span>;    <span class="hljs-comment">// student is TARGET</span>
teacher = <span class="hljs-string">"Kyle"</span>;         <span class="hljs-comment">// teacher is TARGET</span>
</code></pre>
<p><strong>Source Reference</strong> = <strong>Right-hand side</strong> of assignment (providing a value)</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(teacher);     <span class="hljs-comment">// teacher is SOURCE</span>
<span class="hljs-keyword">var</span> message = teacher;    <span class="hljs-comment">// teacher is SOURCE, message is TARGET</span>
</code></pre>
<h3 id="heading-why-this-matters">Why This Matters</h3>
<p>The engine handles source and target references completely differently:</p>
<p><strong>Target references:</strong> Must have a declared variable to assign to <strong>Source references:</strong> Must find an existing variable to read from</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Compilation phase creates these declarations</span>
<span class="hljs-keyword">var</span> teacher;              <span class="hljs-comment">// TARGET reference prepared</span>
<span class="hljs-keyword">var</span> student;              <span class="hljs-comment">// TARGET reference prepared</span>

<span class="hljs-comment">// Execution phase</span>
teacher = <span class="hljs-string">"Kyle"</span>;         <span class="hljs-comment">// TARGET - assigns to existing declaration</span>
<span class="hljs-built_in">console</span>.log(teacher);     <span class="hljs-comment">// SOURCE - looks up existing value</span>
topic = <span class="hljs-string">"React"</span>;          <span class="hljs-comment">// TARGET - no declaration found, creates global</span>
<span class="hljs-built_in">console</span>.log(subject);     <span class="hljs-comment">// SOURCE - no declaration found, ReferenceError!</span>
</code></pre>
<h2 id="heading-lexical-scope-where-you-write-matters">Lexical Scope - Where You Write Matters</h2>
<p><strong>Lexical scope</strong> means scope is determined by <strong>where you write your code</strong>, not where you call it. The physical placement of your variables and functions determines their scope relationships.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> teacher = <span class="hljs-string">"Kyle"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">otherClass</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> teacher = <span class="hljs-string">"Suzy"</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ask</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">console</span>.log(teacher);  <span class="hljs-comment">// Which teacher?</span>
    }

    ask();
}

otherClass(); <span class="hljs-comment">// "Suzy"</span>
</code></pre>
<p>The <code>ask()</code> function looks for <code>teacher</code> in this order:</p>
<ol>
<li><p><strong>Local scope</strong> (inside <code>ask</code>) - not found</p>
</li>
<li><p><strong>Enclosing scope</strong> (inside <code>otherClass</code>) - found "Suzy"!</p>
</li>
<li><p><strong>Global scope</strong> - never reaches here</p>
</li>
</ol>
<p>This lookup happens <strong>at compile time</strong> based on where you wrote the code, not where you called it.</p>
<h2 id="heading-scope-chain-resolution">Scope Chain Resolution</h2>
<p>JavaScript creates a <strong>scope chain</strong> during compilation - a linked list of scopes from innermost to outermost:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> <span class="hljs-built_in">global</span> = <span class="hljs-string">"I'm global"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">outer</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> outerVar = <span class="hljs-string">"I'm in outer"</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">inner</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">var</span> innerVar = <span class="hljs-string">"I'm in inner"</span>;
        <span class="hljs-built_in">console</span>.log(innerVar);  <span class="hljs-comment">// Found in inner scope</span>
        <span class="hljs-built_in">console</span>.log(outerVar);  <span class="hljs-comment">// Found in outer scope  </span>
        <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">global</span>);    <span class="hljs-comment">// Found in global scope</span>
        <span class="hljs-built_in">console</span>.log(missing);   <span class="hljs-comment">// ReferenceError!</span>
    }

    inner();
}

outer();
</code></pre>
<p><strong>Scope chain for</strong> <code>inner()</code> function: Inner Scope → Outer Scope → Global Scope</p>
<p>The engine walks up this chain until it finds the variable or reaches the end (ReferenceError).</p>
<h2 id="heading-the-compilation-process-in-action">The Compilation Process in Action</h2>
<p>Let's trace through a complete example:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(teacher);        <span class="hljs-comment">// What happens here?</span>

<span class="hljs-keyword">var</span> teacher = <span class="hljs-string">"Kyle"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ask</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(teacher);
}

ask();
</code></pre>
<p><strong>Compilation Phase:</strong></p>
<ol>
<li><p>Line 3: Create <code>teacher</code> declaration in global scope</p>
</li>
<li><p>Line 5: Create <code>ask</code> function in global scope</p>
</li>
<li><p>Line 6: Create new scope for <code>ask</code> function</p>
</li>
<li><p>All source references noted for execution phase</p>
</li>
</ol>
<p><strong>Execution Phase:</strong></p>
<ol>
<li><p>Line 1: <code>console.log(teacher)</code> - SOURCE reference to <code>teacher</code></p>
<ul>
<li><p><code>teacher</code> exists (from compilation) but value is <code>undefined</code></p>
</li>
<li><p>Output: <code>undefined</code></p>
</li>
</ul>
</li>
<li><p>Line 3: <code>teacher = "Kyle"</code> - TARGET reference</p>
<ul>
<li>Assigns "Kyle" to existing <code>teacher</code> declaration</li>
</ul>
</li>
<li><p>Line 8: <code>ask()</code> - Calls function</p>
</li>
<li><p>Line 6: <code>console.log(teacher)</code> - SOURCE reference</p>
<ul>
<li><p>Looks up <code>teacher</code> in scope chain, finds "Kyle"</p>
</li>
<li><p>Output: "Kyle"</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-common-scope-misconceptions">Common Scope Misconceptions</h2>
<p><strong>"Hoisting moves declarations to the top"</strong> False. Nothing physically moves. Compilation creates declarations before execution begins.</p>
<p><strong>"let and const aren't hoisted"</strong><br />False. They are hoisted but in a "temporal dead zone" until their line is reached.</p>
<p><strong>"Functions create scope"</strong> Partially true. Function declarations create scope, but so do blocks with <code>let</code>/<code>const</code>.</p>
<p><strong>"Scope is determined at runtime"</strong> False. Lexical scope is determined at compile time by where you write code.</p>
<h2 id="heading-practical-applications">Practical Applications</h2>
<p>Understanding compilation and lexical scope helps you:</p>
<p><strong>Debug Variable Access Issues</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">broken</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(name);  <span class="hljs-comment">// ReferenceError - not undefined!</span>
    <span class="hljs-keyword">let</span> name = <span class="hljs-string">"Frank"</span>;
}
</code></pre>
<p><strong>Predict Hoisting Behavior</strong></p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">typeof</span> teacher);  <span class="hljs-comment">// "undefined" (var hoisting)</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">typeof</span> student);  <span class="hljs-comment">// ReferenceError (let in TDZ)</span>

<span class="hljs-keyword">var</span> teacher = <span class="hljs-string">"Kyle"</span>;
<span class="hljs-keyword">let</span> student = <span class="hljs-string">"Frank"</span>;
</code></pre>
<p><strong>Understand Closure Creation</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeCounter</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> count = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> ++count;  <span class="hljs-comment">// Lexical scope preserves access to count</span>
    };
}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[JavaScript's Thread of Execution - How Code Really Runs]]></title><description><![CDATA[Part 1 of the JavaScript Deep Dive Series
Welcome to JavaScript Deep Dive - a comprehensive series where we'll journey through JavaScript's inner workings, one concept at a time. Over the next several articles, we'll explore everything from basic exe...]]></description><link>https://crackedchefs.devferanmi.xyz/javascripts-thread-of-execution-how-code-really-runs</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/javascripts-thread-of-execution-how-code-really-runs</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[javascript framework]]></category><category><![CDATA[Javascript library]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Tue, 07 Jan 2025 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p><em>Part 1 of the JavaScript Deep Dive Series</em></p>
<p><strong>Welcome to JavaScript Deep Dive</strong> - a comprehensive series where we'll journey through JavaScript's inner workings, one concept at a time. Over the next several articles, we'll explore everything from basic execution to advanced patterns like closures, promises, and object-oriented programming.</p>
<p><strong>What we'll cover in this series:</strong></p>
<ul>
<li><p><strong>Execution &amp; Memory</strong> - How JavaScript reads and stores your code</p>
</li>
<li><p><strong>Functions &amp; Execution Contexts</strong> - The foundation of JavaScript behavior</p>
</li>
<li><p><strong>Call Stack Fundamentals</strong> - Tracking function calls and nested execution</p>
</li>
<li><p><strong>Stack Overflow &amp; Limits</strong> - Understanding JavaScript's boundaries</p>
</li>
<li><p><strong>Closures &amp; Higher-Order Functions</strong> - The DRY principle in action</p>
</li>
<li><p><strong>Promises &amp; Async Patterns</strong> - Managing asynchronous operations</p>
</li>
<li><p><strong>Event Loop</strong> - How JavaScript handles non-blocking operations</p>
</li>
<li><p><strong>Object-Oriented Programming</strong> - The <code>new</code> keyword and beyond</p>
</li>
<li><p><strong>The</strong> <code>this</code> Keyword - Context and binding demystified</p>
</li>
<li><p><strong>Modern Classes</strong> - ES6+ OOP patterns</p>
</li>
</ul>
<h2 id="heading-javascripts-sequential-nature">JavaScript's Sequential Nature</h2>
<p>JavaScript operates on a simple principle: <strong>one thing happens at a time</strong>. Understanding this core concept is essential for writing predictable, debuggable code.</p>
<h3 id="heading-line-by-line-execution">Line-by-Line Execution</h3>
<p>JavaScript reads and executes code <strong>line by line, in order</strong>. When you write a program, JavaScript starts at the top and works its way down, executing each statement before moving to the next.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">"First"</span>);    <span class="hljs-comment">// Executes first</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Second"</span>);   <span class="hljs-comment">// Executes second  </span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Third"</span>);    <span class="hljs-comment">// Executes third</span>
<span class="hljs-comment">// Output: First, Second, Third</span>
</code></pre>
<p>This sequential execution means that the order you write code matters. Unlike human reading where you might skim or jump around, JavaScript is (and will be) methodical and predictable (in practice).</p>
<h3 id="heading-the-single-threaded-reality">The Single-Threaded Reality</h3>
<p>JavaScript is fundamentally <strong>single-threaded (read more about threading</strong> <a target="_blank" href="https://crackedchefs.devferanmi.xyz/introduction-to-cpu-threading-single-and-multi-threading?showSharer=true"><strong>here</strong></a><strong>),</strong> meaning it can only execute one command at a time. There's no parallel processing happening - each line must complete before the next begins.</p>
<p>This has profound implications:</p>
<ul>
<li><p><strong>Blocking operations</strong> stop everything else from running</p>
</li>
<li><p><strong>User interfaces</strong> can freeze if code takes too long</p>
</li>
<li><p><strong>Predictability</strong> is high - you know exactly what order things happen</p>
</li>
</ul>
<h2 id="heading-memory-storage-during-execution">Memory Storage During Execution</h2>
<p>As JavaScript executes code, it stores data in <strong>global memory</strong> (also called the variable environment). When you declare variables, JavaScript creates space for them and tracks their values.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> num = <span class="hljs-number">3</span>;        <span class="hljs-comment">// Creates 'num' in memory, stores 3</span>
<span class="hljs-keyword">const</span> string = <span class="hljs-string">"hello"</span>; <span class="hljs-comment">// Creates 'string' in memory, stores "hello"  </span>
<span class="hljs-keyword">let</span> result;           <span class="hljs-comment">// Creates 'result' in memory, initially undefined in value</span>
</code></pre>
<h3 id="heading-variable-hoisting">Variable Hoisting</h3>
<p>JavaScript actually scans through your code before executing it, setting up memory space for variables and functions. This is called <strong>hoisting</strong>.</p>
<p>javascript</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(myVar); <span class="hljs-comment">// undefined (not an error!)</span>
<span class="hljs-keyword">var</span> myVar = <span class="hljs-string">"Hello World"</span>;
<span class="hljs-built_in">console</span>.log(myVar); <span class="hljs-comment">// "Hello World"</span>
</code></pre>
<p>What actually happens:</p>
<ol>
<li><p>JavaScript creates <code>myVar</code> in memory during setup phase</p>
</li>
<li><p><code>myVar</code> initially gets the value <code>undefined</code></p>
</li>
<li><p>First <code>console.log</code> prints <code>undefined</code></p>
</li>
<li><p>Assignment happens: <code>myVar = "Hello World"</code></p>
</li>
<li><p>Second <code>console.log</code> prints "Hello World"</p>
</li>
</ol>
<h2 id="heading-tracing-execution-step-by-step">Tracing Execution Step by Step</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> num = <span class="hljs-number">3</span>;
<span class="hljs-keyword">const</span> string = <span class="hljs-string">"hello"</span>;
<span class="hljs-keyword">let</span> result;

<span class="hljs-comment">// Trace through execution step by step</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Step 1"</span>);
result = num + <span class="hljs-number">5</span>;
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Step 2"</span>);
<span class="hljs-built_in">console</span>.log(result);
</code></pre>
<p><strong>Execution order:</strong></p>
<ol>
<li><p><strong>Setup Phase</strong> (before any code runs):</p>
<ul>
<li><p>Create <code>num</code> in memory</p>
</li>
<li><p>Create <code>string</code> in memory</p>
</li>
<li><p>Create <code>result</code> in memory, value <code>undefined</code></p>
</li>
</ul>
</li>
<li><p><strong>Execution Phase</strong> (line by line):</p>
<ul>
<li><p>Line 1: Assign <code>3</code> to <code>num</code></p>
</li>
<li><p>Line 2: Assign <code>"hello"</code> to <code>string</code></p>
</li>
<li><p>Line 3: <code>result</code> stays <code>undefined</code> (no assignment yet)</p>
</li>
<li><p>Line 5: Execute <code>console.log("Step 1")</code> → outputs "Step 1"</p>
</li>
<li><p>Line 6: Calculate <code>num + 5</code> (3 + 5 = 8), assign to <code>result</code></p>
</li>
<li><p>Line 7: Execute <code>console.log("Step 2")</code> → outputs "Step 2"</p>
</li>
<li><p>Line 8: Execute <code>console.log(result)</code> → outputs <code>8</code></p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-common-pitfalls-and-misconceptions">Common Pitfalls and Misconceptions</h2>
<h3 id="heading-javascript-runs-multiple-things-at-once">"JavaScript runs multiple things at once"</h3>
<p><strong>False.</strong> JavaScript is strictly single-threaded for code execution. Even asynchronous operations follow specific rules we'll cover in later articles.</p>
<h3 id="heading-variables-exist-before-theyre-declared">"Variables exist before they're declared"</h3>
<p><strong>Partially true</strong> due to hoisting, but they're <code>undefined</code> until assignment. Understanding the difference between declaration and assignment is crucial.</p>
<h3 id="heading-execution-order-doesnt-matter">"Execution order doesn't matter"</h3>
<p><strong>False.</strong> Order is critical for correct runtime behavior. This becomes even more important with functions and scope.</p>
<h3 id="heading-memory-management-is-completely-automatic">"Memory management is completely automatic"</h3>
<p><strong>Mostly true</strong>, but understanding when and how JavaScript manages memory helps you write more efficient code and avoid memory leaks.</p>
<h2 id="heading-practical-applications-better-debugging">Practical Applications: Better Debugging</h2>
<p>Understanding execution flow transforms how you debug:</p>
<h3 id="heading-reading-error-messages">Reading Error Messages</h3>
<p>When you see an error like "Cannot read property 'x' of undefined", you can trace back through execution to find exactly when and why a variable became undefined.</p>
<h3 id="heading-predicting-program-behavior">Predicting Program Behavior</h3>
<p>Before running code, you can mentally trace through the execution steps and predict the output. This skill is invaluable for both development and interviews.</p>
<h3 id="heading-identifying-performance-issues">Identifying Performance Issues</h3>
<p>When you understand that JavaScript can only do one thing at a time, you start thinking about which operations might block the user interface and how to structure code for better performance.</p>
<h2 id="heading-summary-your-mental-execution-model">Summary: Your Mental Execution Model</h2>
<p>The key takeaway is developing a mental model of JavaScript as a <strong>methodical, step-by-step executor</strong>:</p>
<ol>
<li><p><strong>Setup Phase</strong>: JavaScript scans code and sets up memory space</p>
</li>
<li><p><strong>Execution Phase</strong>: Code runs line by line, in order</p>
</li>
<li><p><strong>Memory Management</strong>: Variables are stored and tracked throughout</p>
</li>
<li><p><strong>Single-threaded</strong>: Only one operation at a time</p>
</li>
</ol>
<p>This foundation is crucial for understanding more complex concepts like:</p>
<ul>
<li><p>How functions create their own execution contexts</p>
</li>
<li><p>Why closures work the way they do</p>
</li>
<li><p>How asynchronous operations fit into single-threaded execution</p>
</li>
<li><p>Object creation and the <code>this</code> keyword</p>
</li>
</ul>
<p><strong>Next up:</strong> We'll explore how functions create their own execution contexts and why understanding this concept is the key to mastering JavaScript scope, closures, and advanced patterns.</p>
]]></content:encoded></item><item><title><![CDATA[Introduction to CPU Threading: Single and Multi-threading]]></title><description><![CDATA[Have you ever wondered why some programs feel blazingly fast while others make you wait? Why your phone sometimes freezes when you're doing "simple" tasks? Or why some apps can handle multiple things at once while others force you to wait?
The answer...]]></description><link>https://crackedchefs.devferanmi.xyz/introduction-to-cpu-threading-single-and-multi-threading</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/introduction-to-cpu-threading-single-and-multi-threading</guid><category><![CDATA[cpu]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Tue, 31 Dec 2024 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Have you ever wondered why some programs feel blazingly fast while others make you wait? Why your phone sometimes freezes when you're doing "simple" tasks? Or why some apps can handle multiple things at once while others force you to wait?</p>
<p>The answer lies in something called <strong>threading</strong> - and it's one of the most important concepts in computing that affects every single app you use.</p>
<h2 id="heading-what-is-threading-really">What is Threading, Really?</h2>
<p>Think of threading as <strong>how programs/process organize work</strong>. Just like a restaurant needs to decide whether to have one waiter handle all tables or multiple waiters working simultaneously, programs need to decide how to handle multiple tasks.</p>
<p><strong>Threading</strong> is essentially the program's strategy for getting things done. It determines whether your app can (<strong>oversimplified</strong>):</p>
<ul>
<li><p>Download a file while you browse other tabs</p>
</li>
<li><p>Play music while you text</p>
</li>
<li><p>Process your photos while you take new ones</p>
</li>
<li><p>Or forces you to wait for one thing to finish before starting another</p>
</li>
</ul>
<h2 id="heading-why-your-cpu-cares-about-threading">Why Your CPU Cares About Threading</h2>
<p>Your computer's processor (CPU) is like having multiple workers available, but whether your programs actually <em>use</em> those workers depends on how they're designed.</p>
<p>Modern phones and computers have <strong>multiple cores</strong> - think of each core as a separate worker. Your iPhone might have 6 cores, your laptop might have 8, and high-end computers can have 16 or more. H<strong>aving multiple workers doesn't automatically mean your program uses them all</strong>.</p>
<p>It's like having a construction site with 8 workers, but if the foreman (your program) only knows how to give instructions to one worker at a time, the other 7 just stand around waiting.</p>
<p>This is why some apps feel snappy and responsive while others feel sluggish, even on the same device/server.</p>
<h2 id="heading-why-should-you-care">Why Should You Care?</h2>
<p>Understanding threading helps you:</p>
<ul>
<li><p><strong>Choose better apps</strong> - Multi-threaded apps generally feel more responsive</p>
</li>
<li><p><strong>Understand performance</strong> - Why some tasks are fast vs slow</p>
</li>
<li><p><strong>Make better decisions</strong> - When to close apps, when to wait, when to restart</p>
</li>
<li><p><strong>Appreciate good software</strong> - Recognize when developers have done threading well</p>
</li>
</ul>
<p>Plus, if you're learning to code or working with developers, understanding threading helps you communicate about performance and user experience more effectively.</p>
<p>Think of your CPU as a <strong>restaurant kitchen</strong>, and each <strong>core as a chef (read more about</strong> <a target="_blank" href="https://www.tomshardware.com/news/cpu-core-definition,37658.html">cores here</a><strong>)</strong>.</p>
<h3 id="heading-single-threaded-one-chef-one-order-at-a-time">Single-Threaded: One Chef, One Order at a Time</h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// JavaScript - Single-threaded</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Taking order 1"</span>);      <span class="hljs-comment">// Chef takes order</span>
processPayment();                   <span class="hljs-comment">// Chef processes payment  </span>
cookMeal();                        <span class="hljs-comment">// Chef cooks meal</span>
serveMeal();                       <span class="hljs-comment">// Chef serves meal</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Order 1 complete"</span>);   <span class="hljs-comment">// Only now can chef start order 2</span>
</code></pre>
<p><strong>What happens:</strong> One chef handles everything for one customer before moving to the next. If cooking takes 10 minutes, the entire restaurant waits.</p>
<p><strong>Pros:</strong> Simple, predictable, no coordination needed<br /><strong>Cons:</strong> Inefficient, blocking operations freeze everything</p>
<h3 id="heading-multi-threaded-multiple-chefs-parallel-work">Multi-Threaded: Multiple Chefs, Parallel Work</h3>
<pre><code class="lang-java"><span class="hljs-comment">// Java - Multi-threaded</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Restaurant</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleOrders</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// Each thread (chef) works independently</span>
        Thread chef1 = <span class="hljs-keyword">new</span> Thread(() -&gt; processOrder(<span class="hljs-string">"Table 1"</span>));
        Thread chef2 = <span class="hljs-keyword">new</span> Thread(() -&gt; processOrder(<span class="hljs-string">"Table 2"</span>));
        Thread chef3 = <span class="hljs-keyword">new</span> Thread(() -&gt; processOrder(<span class="hljs-string">"Table 3"</span>));

        chef1.start(); <span class="hljs-comment">// All chefs work simultaneously</span>
        chef2.start();
        chef3.start();
    }
}
</code></pre>
<p><strong>What happens:</strong> Multiple chefs work on different orders simultaneously. While one chef cooks, another takes orders, and a third serves meals.</p>
<p><strong>Pros:</strong> Efficient, non-blocking, better resource utilization<br /><strong>Cons:</strong> Complex coordination, potential conflicts (two chefs grabbing the same ingredient)</p>
<h2 id="heading-how-this-maps-to-your-cpu">How This Maps to Your CPU</h2>
<p>Your <strong>CPU</strong> has multiple <strong>cores</strong> (chefs), and each core can handle <strong>threads</strong> (tasks):</p>
<ul>
<li><p><strong>Single-core CPU:</strong> One chef, must do everything sequentially</p>
</li>
<li><p><strong>Dual-core CPU:</strong> Two chefs, can handle two tasks simultaneously</p>
</li>
<li><p><strong>Quad-core CPU:</strong> Four chefs, even more parallel processing</p>
</li>
<li><p><strong>Modern CPUs:</strong> 8, 16, or more cores with hyper-threading (each chef can juggle 2 tasks)</p>
</li>
</ul>
<h2 id="heading-real-world-examples">Real-World Examples</h2>
<h3 id="heading-single-threaded-languages">Single-Threaded Languages</h3>
<p><strong>JavaScript, Python (GIL), PHP</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Everything waits for this to finish</span>
<span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000</span>; i++) {
    <span class="hljs-comment">// Heavy computation blocks everything</span>
}
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Finally done!"</span>); <span class="hljs-comment">// UI frozen until here</span>
</code></pre>
<h3 id="heading-multi-threaded-languages">Multi-Threaded Languages</h3>
<p><strong>Java, C#, Go, Rust</strong></p>
<pre><code class="lang-java"><span class="hljs-comment">// Heavy work happens in background</span>
CompletableFuture.runAsync(() -&gt; {
    <span class="hljs-comment">// Heavy computation on separate thread</span>
    heavyCalculation();
});

<span class="hljs-comment">// UI stays responsive</span>
System.out.println(<span class="hljs-string">"UI still works!"</span>);
</code></pre>
<h2 id="heading-the-trade-offs">The Trade-offs</h2>
<h3 id="heading-when-single-threading-works-well">When Single-Threading Works Well</h3>
<ul>
<li><p><strong>Simple applications</strong> where tasks are quick</p>
</li>
<li><p><strong>I/O heavy applications</strong> (like web servers using asynchronous patterns)</p>
</li>
<li><p><strong>When avoiding complexity</strong> is more important than performance</p>
</li>
</ul>
<h3 id="heading-when-multi-threading-shines">When Multi-Threading Shines</h3>
<ul>
<li><p><strong>CPU-intensive tasks</strong> (image processing, calculations)</p>
</li>
<li><p><strong>Applications serving many users</strong> simultaneously</p>
</li>
<li><p><strong>When you can break work</strong> into independent pieces</p>
</li>
</ul>
<h2 id="heading-quick-comparison">Quick Comparison</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Aspect</td><td>Single-Threaded</td><td>Multi-Threaded</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Complexity</strong></td><td>Simple</td><td>Complex</td></tr>
<tr>
<td><strong>Performance</strong></td><td>Limited by one core</td><td>Can use all cores</td></tr>
<tr>
<td><strong>Debugging</strong></td><td>Predictable</td><td>Harder to debug</td></tr>
<tr>
<td><strong>Resource Usage</strong></td><td>Underutilizes CPU</td><td>Maximizes CPU usage</td></tr>
<tr>
<td><strong>Coordination</strong></td><td>Not needed</td><td>Critical</td></tr>
</tbody>
</table>
</div><p><strong>Bottom line is, Single-threading</strong> is like having one super-efficient chef who never makes mistakes but can only handle one thing at a time.</p>
<p><strong>Multi-threading</strong> is like having a full kitchen staff who can serve the whole restaurant simultaneously, but you need a head chef (programmer) who can coordinate them without chaos.</p>
<p>Choose based on your needs: simplicity and predictability vs. performance and resource utilization.</p>
]]></content:encoded></item><item><title><![CDATA[Writing Technical Implementation Documents: Complete Guide]]></title><description><![CDATA[Hey there, fellow Coding Chefs! 👋
Ever joined a project and spent three days just figuring out how the authentication system works? Or tried to add a simple feature only to discover it breaks two other components in mysterious ways? Or worse - found...]]></description><link>https://crackedchefs.devferanmi.xyz/writing-technical-implementation-documents-complete-guide</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/writing-technical-implementation-documents-complete-guide</guid><category><![CDATA[documentation]]></category><category><![CDATA[technical documentation]]></category><category><![CDATA[technical-deep-dive]]></category><category><![CDATA[Thinking]]></category><category><![CDATA[writing]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[backend]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Wed, 02 Oct 2024 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Hey there, fellow Coding Chefs! 👋</p>
<p>Ever joined a project and spent three days just figuring out how the authentication system works? Or tried to add a simple feature only to discover it breaks two other components in mysterious ways? Or worse - found yourself staring at your own code from six months ago, wondering what past-you was thinking?</p>
<p>The problem isn't your code. The problem is documentation.</p>
<p>Technical implementation documents are either non-existent, outdated, or written like academic papers that only make sense to the person who wrote them. But when done right, they're the difference between a smooth development process and weeks of confusion, debugging, and "why did we build it this way?" conversations.</p>
<p>Let's dive into writing technical implementation documents that actually help people build great software - including future you.</p>
<h2 id="heading-why-technical-docs-actually-matter-beyond-the-obvious">Why Technical Docs Actually Matter (Beyond the Obvious)</h2>
<p>Let's be real, most developers treat documentation like that gym membership they never use. "I'll definitely write docs... tomorrow... maybe next sprint... okay, fine, when the project is done."</p>
<p>But here's the thing: great technical implementation documents aren't just nice-to-have paperwork. They're the difference between a smooth development process and spending three weeks debugging why a feature that should have taken two days is mysteriously breaking everything else.</p>
<p>Think about it like this: when you're cooking, you don't just throw ingredients together and hope for the best (well, maybe you do, but your kitchen probably looks like a disaster zone). You plan the meal, understand how each ingredient interacts, and know what steps to take in what order.</p>
<p>Technical implementation documents are your recipe for building software that doesn't fall apart the moment someone else touches it.</p>
<h2 id="heading-the-anatomy-of-documents-that-actually-work">The Anatomy of Documents That Actually Work</h2>
<h3 id="heading-the-think-before-you-code-philosophy">The "Think Before You Code" Philosophy</h3>
<p>The best technical documents start before you write a single line of code. They're born from that crucial thinking phase where you're asking yourself the hard questions:</p>
<ul>
<li><p>What problem are we actually solving?</p>
</li>
<li><p>What are the different ways to solve this problem?</p>
</li>
<li><p>What could go wrong, and how do we handle it?</p>
</li>
<li><p>How does this fit into the bigger picture?</p>
</li>
</ul>
<p>I learned this the hard way when building a notification system that seemed simple on the surface. "Just send notifications when events happen," the requirements said. Easy, right?</p>
<p>Wrong.</p>
<p>Three weeks later, I was debugging race conditions, handling duplicate notifications, dealing with failed deliveries, and wondering why nobody mentioned that notifications needed to work across different time zones, support multiple languages, and gracefully handle users who'd disabled certain notification types.</p>
<p>A proper implementation document would have forced me to think through these scenarios upfront, instead of discovering them at 2 AM when the production system started melting down.</p>
<h3 id="heading-structure-that-makes-sense">Structure That Makes Sense</h3>
<p>Here's the thing about document structure - it should mirror how your brain actually processes information when approaching a new problem.</p>
<p><strong>Start with the "Why" (Context and Problem Statement)</strong></p>
<p>Don't jump straight into technical details. Start by explaining why this feature exists in the first place. What user problem does it solve? What business need does it address?</p>
<p>For example, instead of starting with "Implement user authentication using JWT tokens," start with "Users are frustrated with having to log in repeatedly across different parts of our application, leading to drop-offs and poor user experience."</p>
<p><strong>Then the "What" (Feature Overview)</strong></p>
<p>Now you can describe what you're building, but keep it high-level and user-focused. This section should be readable by non-technical stakeholders who need to understand the scope without getting lost in implementation details.</p>
<p><strong>The "How" (Implementation Strategy)</strong></p>
<p>This is where the technical meat lives, but don't just dump code everywhere. Explain your thinking process:</p>
<ul>
<li><p>Why did you choose this approach over alternatives?</p>
</li>
<li><p>What are the trade-offs you considered?</p>
</li>
<li><p>How does this integrate with existing systems?</p>
</li>
</ul>
<p><strong>The "What If" (Edge Cases and Error Handling)</strong></p>
<p>This is where most documents fail spectacularly. They focus on the happy path and completely ignore everything that can (and will) go wrong.</p>
<p>Real users don't follow your perfect user journey. They'll click buttons multiple times, have flaky internet connections, input weird data, and somehow find ways to break your system that you never imagined.</p>
<h3 id="heading-the-language-of-clarity">The Language of Clarity</h3>
<p>Technical writing doesn't mean you have to sound like a robot having a conversation with a database. Write like you're explaining the system to a smart colleague who's new to the project.</p>
<p>Instead of: "The authentication middleware intercepts incoming requests and validates JWT tokens against the configured secret key before allowing request propagation to downstream handlers."</p>
<p>Try: "When a user makes a request, our authentication system checks their login token to make sure they're allowed to access that feature. If the token is valid, the request continues normally. If not, we send them back to the login page."</p>
<p>Both say the same thing, but one actually helps people understand what's happening and why.</p>
<h2 id="heading-component-architecture-beyond-the-boxes-and-arrows">Component Architecture: Beyond the Boxes and Arrows</h2>
<h3 id="heading-the-lego-block-principle">The "Lego Block" Principle</h3>
<p>Good component architecture documentation doesn't just show what components exist - it explains how they fit together and why they're organized that way.</p>
<p>Think of your components like Lego blocks. Each block has a specific purpose, but the magic happens when you understand how they connect to build something bigger.</p>
<p>Instead of just listing components, explain the hierarchy and relationships:</p>
<pre><code class="lang-markdown">UserDashboard (main orchestrator)
├── ProfileSection (displays user info)
├── NotificationCenter (handles alerts)
│   ├── NotificationItem (individual alerts)
│   └── NotificationSettings (user preferences)
└── ActivityFeed (shows user actions)
<span class="hljs-code">    ├── ActivityItem (individual actions)
    └── ActivityFilter (sorting/filtering)</span>
</code></pre>
<p>But don't stop there. Explain why this structure makes sense:</p>
<p>"The UserDashboard acts as the main coordinator, fetching user data and passing it down to child components. Each section handles its own specific concerns - ProfileSection manages display logic, NotificationCenter handles alert workflows, and ActivityFeed deals with user action history. This separation means we can update notification logic without touching profile code, and vice versa."  </p>
<p>You can read more on seperating concerns and components architecture driven frontends <a target="_blank" href="https://crackedchefs.devferanmi.xyz/component-thinking-how-react-changed-my-entire-design-approach">here</a></p>
<h3 id="heading-state-management-strategy">State Management Strategy</h3>
<p>This is where things get interesting. State management is like organizing your kitchen - there are many ways to do it, but some approaches will drive you (and your teammates) absolutely crazy.</p>
<p>Document not just what state you're tracking, but where it lives and why:</p>
<p>"User authentication state lives in a global context because multiple components across the app need to know if someone is logged in. Notification preferences are stored locally in the NotificationCenter because only that component cares about them. Form data stays in individual form components unless it needs to persist across navigation, in which case it moves to session storage."</p>
<h3 id="heading-api-integration-patterns">API Integration Patterns</h3>
<p>API integration is where many projects turn into spaghetti code disasters. Your documentation should explain not just what endpoints you're calling, but how you're handling the inevitable chaos of network requests.</p>
<p>Instead of just listing API endpoints, explain the patterns:</p>
<p>"All API calls go through our apiClient utility, which handles authentication headers, retry logic, and error formatting automatically. For user-facing actions, we use optimistic updates - the UI changes immediately, then we sync with the server in the background. If the server request fails, we roll back the UI change and show an error message."</p>
<h2 id="heading-real-world-example-building-a-bank-statement-analyzer">Real-World Example: Building a Bank Statement Analyzer</h2>
<p>Let me walk you through how this looks in practice by documenting a bank statement analyzer app from scratch. By the end of this section, you'll have a complete technical implementation document you could actually hand to a development team.</p>
<p>Let's build this document together, step by step.</p>
<h3 id="heading-step-1-the-problem-context">Step 1: The Problem Context</h3>
<p>Every good technical document starts with understanding why the feature exists. Here's how we'd document our bank statement analyzer:</p>
<hr />
<p><strong>Bank Statement Analyzer - Problem Context</strong></p>
<p>"Many people struggle to understand their spending patterns and financial health. Traditional banking apps provide transaction lists but lack deeper insights into spending categories, trends, and financial behavior. Users want to upload their bank statements and receive comprehensive financial analysis without sharing sensitive data with third-party services permanently.</p>
<p>Current solutions either require expensive financial advisors, complex spreadsheet analysis, or sharing data with services that store information indefinitely. We need a solution that provides professional-level financial analysis while respecting user privacy through immediate data deletion after processing."</p>
<hr />
<p>See how we're not jumping into technical details yet? We're establishing the human problem first.</p>
<h3 id="heading-step-2-the-strategic-approach">Step 2: The Strategic Approach</h3>
<p>Now we explain what we're building and our high-level approach:</p>
<hr />
<p><strong>Solution Overview</strong></p>
<p>"We're building a client-side web application that allows users to upload CSV bank statements, processes them through AI analysis, and provides comprehensive financial insights. The key differentiator is our privacy-first approach - data is processed and immediately deleted, never stored permanently.</p>
<p>The application follows a linear workflow:</p>
<ol>
<li><p><strong>Upload Stage</strong>: Secure file upload with privacy consent</p>
</li>
<li><p><strong>Processing Stage</strong>: Real-time analysis progress with Claude AI</p>
</li>
<li><p><strong>Results Stage</strong>: Interactive financial analysis dashboard</p>
</li>
</ol>
<p>The architecture prioritizes user privacy, clear progress feedback, and comprehensive analysis presentation. Users can test the system with sample data before uploading personal information."</p>
<hr />
<h3 id="heading-step-3-component-architecture-amp-user-flow">Step 3: Component Architecture &amp; User Flow</h3>
<p>Here's where we break down the technical approach:</p>
<hr />
<p><strong>Application Architecture</strong></p>
<p>The application consists of four main stages, each handling specific user interactions and system processes:</p>
<pre><code class="lang-markdown">BankStatementAnalyzer (main application)
├── LandingPage (file upload interface)
│   ├── FileUploadDropzone (drag &amp; drop functionality)
│   ├── PrivacyConsentCheckbox (data processing agreement)
│   ├── CSVTemplateDownload (sample data provider)
│   └── FileValidation (CSV format verification)
├── ProcessingPage (analysis progress tracking)
│   ├── ProgressBar (visual progress indicator)
│   ├── ProcessingStatus (real-time status updates)
│   └── AnalysisPreview (partial results display)
├── ResultsPage (comprehensive financial analysis)
│   ├── SpendingCategorization (expense breakdown)
│   ├── TrendAnalysis (spending patterns over time)
│   ├── FinancialHealthScore (overall assessment)  
│   └── ActionableInsights (personalized recommendations)
└── ErrorBoundary (graceful error handling)
</code></pre>
<p><strong>Data Flow Architecture:</strong></p>
<pre><code class="lang-markdown">[User] → [File Upload] → [Client Validation] → [Claude API] → [Analysis] → [Results] → [Data Deletion]
</code></pre>
<p>The key architectural decision is processing everything client-side with API calls to Claude, ensuring no server-side data persistence.</p>
<hr />
<h3 id="heading-step-4-detailed-implementation-strategy">Step 4: Detailed Implementation Strategy</h3>
<p>Now we get into the technical meat:</p>
<hr />
<p><strong>Stage 1: Landing Page Implementation</strong></p>
<p>The landing page serves as the entry point and data collection interface. It must handle file validation, privacy consent, and provide testing capabilities.</p>
<p><strong>File Upload Strategy:</strong></p>
<ul>
<li><p>Support drag-and-drop and click-to-browse interfaces</p>
</li>
<li><p>Validate CSV format and file size (max 10MB) before upload</p>
</li>
<li><p>Provide real-time feedback on file validation status</p>
</li>
<li><p>Support multiple common CSV formats (comma, semicolon, tab-separated)</p>
</li>
</ul>
<p><strong>Privacy Consent Implementation:</strong></p>
<ul>
<li><p>Required checkbox: "I consent to my data being processed and deleted immediately after analysis"</p>
</li>
<li><p>Clear privacy policy explanation</p>
</li>
<li><p>Prevent upload until consent is given</p>
</li>
<li><p>Log consent status for audit purposes</p>
</li>
</ul>
<p><strong>CSV Template System:</strong></p>
<ul>
<li><p>Provide downloadable sample CSV with realistic (but fake) transaction data</p>
</li>
<li><p>Template includes: Date, Description, Amount, Category columns</p>
</li>
<li><p>Sample data demonstrates various transaction types and spending patterns</p>
</li>
<li><p>File naming: "sample_bank_statement.csv"</p>
</li>
</ul>
<p><strong>Edge Cases to Handle:</strong></p>
<ul>
<li><p>Invalid file formats (show specific error messages)</p>
</li>
<li><p>Files larger than size limit (progressive feedback)</p>
</li>
<li><p>Corrupted or empty CSV files</p>
</li>
<li><p>Users attempting upload without consent</p>
</li>
</ul>
<p><strong>Stage 2: Processing Page Implementation</strong></p>
<p>The processing page manages the analysis workflow and provides user feedback during potentially lengthy AI processing.</p>
<p><strong>Progress Tracking Strategy:</strong></p>
<ul>
<li><p>Break analysis into logical phases: "Parsing data", "Categorizing transactions", "Analyzing patterns", "Generating insights"</p>
</li>
<li><p>Show percentage complete for each phase</p>
</li>
<li><p>Estimated time remaining based on file size</p>
</li>
<li><p>Real-time status updates via WebSocket or polling</p>
</li>
</ul>
<p><strong>Claude API Integration:</strong></p>
<ul>
<li><p>Chunk large files into manageable segments for API processing</p>
</li>
<li><p>Implement retry logic with exponential backoff for failed requests</p>
</li>
<li><p>Handle rate limiting gracefully with user communication</p>
</li>
<li><p>Process data in stages: categorization → trend analysis → insights generation</p>
</li>
</ul>
<p><strong>User Experience Considerations:</strong></p>
<ul>
<li><p>Prevent page navigation/refresh during processing</p>
</li>
<li><p>Show preview insights as they become available</p>
</li>
<li><p>Provide cancel option with confirmation dialog</p>
</li>
<li><p>Handle browser tab switching (maintain processing state)</p>
</li>
</ul>
<p><strong>Stage 3: Results Page Implementation</strong></p>
<p>The results page presents comprehensive financial analysis in an digestible, interactive format.</p>
<p><strong>Analysis Categories:</strong></p>
<ul>
<li><p><strong>Spending Categorization</strong>: Food, Transportation, Entertainment, Bills, etc.</p>
</li>
<li><p><strong>Trend Analysis</strong>: Monthly spending patterns, seasonal variations</p>
</li>
<li><p><strong>Financial Health Metrics</strong>: Income-to-expense ratio, savings rate</p>
</li>
<li><p><strong>Behavioral Insights</strong>: Largest expenses, frequent merchants, unusual transactions</p>
</li>
</ul>
<p><strong>Data Visualization Strategy:</strong></p>
<ul>
<li><p>Interactive charts using Chart.js</p>
</li>
<li><p>Responsive design for mobile and desktop viewing</p>
</li>
<li><p>Export capabilities (PDF report, CSV summary)</p>
</li>
<li><p>Drill-down functionality for detailed transaction analysis</p>
</li>
</ul>
<p><strong>Security Implementation:</strong></p>
<ul>
<li><p>Automatic data deletion after results display (configurable timeout)</p>
</li>
<li><p>No local storage of sensitive transaction data</p>
</li>
<li><p>Clear indication when data has been purged</p>
</li>
<li><p>Option to download results before data deletion</p>
</li>
</ul>
<hr />
<h3 id="heading-step-5-error-handling-amp-edge-cases">Step 5: Error Handling &amp; Edge Cases</h3>
<p>This is where most documentation fails, but it's crucial for real-world applications:</p>
<hr />
<p><strong>Comprehensive Error Handling Strategy</strong></p>
<p><strong>File Upload Errors:</strong></p>
<ul>
<li><p>Invalid CSV format: "Please upload a valid CSV file with columns: Date, Description, Amount"</p>
</li>
<li><p>File size exceeded: "File size must be under 10MB. Consider splitting large statements."</p>
</li>
<li><p>Network failures: Retry mechanism with clear user communication</p>
</li>
<li><p>Unsupported file types: List supported formats and provide conversion guidance</p>
</li>
</ul>
<p><strong>Processing Errors:</strong></p>
<ul>
<li><p>Claude API failures: Fallback to basic categorization with user notification</p>
</li>
<li><p>Rate limiting: Queue system with estimated wait times</p>
</li>
<li><p>Network timeouts: Resume capability from last successful processing stage</p>
</li>
<li><p>Invalid data formats: Specific guidance on fixing common CSV issues</p>
</li>
</ul>
<p><strong>Privacy &amp; Security Errors:</strong></p>
<ul>
<li><p>Data deletion failures: Multiple deletion attempts with audit logging</p>
</li>
<li><p>Consent withdrawal: Immediate processing halt and data purge</p>
</li>
<li><p>Session timeout: Automatic data cleanup with user notification</p>
</li>
</ul>
<p><strong>Browser Compatibility Issues:</strong></p>
<ul>
<li><p>File API not supported: Graceful degradation with upload alternatives</p>
</li>
<li><p>JavaScript disabled: Server-side processing fallback (if implemented)</p>
</li>
<li><p>Mobile browser limitations: Responsive design with touch-friendly interfaces</p>
</li>
</ul>
<p><strong>Real-World Scenarios:</strong></p>
<ul>
<li><p>User uploads 2 years of transactions (large file handling)</p>
</li>
<li><p>Bank CSV has unusual formatting (flexible parser implementation)</p>
</li>
<li><p>User wants to analyze multiple accounts (batch processing capability)</p>
</li>
<li><p>Internet connection drops during processing (resume functionality)</p>
</li>
</ul>
<hr />
<h3 id="heading-step-6-technical-implementation-details">Step 6: Technical Implementation Details</h3>
<hr />
<p><strong>API Integration Specifications</strong></p>
<p><strong>Claude API Communication:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Pseudocode for Claude integration</span>
processTransactions(csvData) {
  <span class="hljs-comment">// Break data into chunks for processing</span>
  chunks = chunkTransactionData(csvData, <span class="hljs-number">1000</span>) <span class="hljs-comment">// 1000 transactions per chunk</span>

  results = []
  <span class="hljs-keyword">for</span> each chunk:
    analysis = <span class="hljs-keyword">await</span> claudeAPI.analyze({
      <span class="hljs-attr">data</span>: chunk,
      <span class="hljs-attr">analysisType</span>: [<span class="hljs-string">'categorization'</span>, <span class="hljs-string">'trends'</span>, <span class="hljs-string">'insights'</span>],
      <span class="hljs-attr">responseFormat</span>: <span class="hljs-string">'structured_json'</span>
    })
    results.push(analysis)
    updateProgressBar(chunk.index / chunks.length * <span class="hljs-number">100</span>)

  <span class="hljs-keyword">return</span> combineResults(results)
}
</code></pre>
<p><strong>Data Processing Pipeline:</strong></p>
<ol>
<li><p><strong>CSV Parsing</strong>: Convert uploaded file to structured data</p>
</li>
<li><p><strong>Data Cleaning</strong>: Remove duplicates, handle missing values</p>
</li>
<li><p><strong>Transaction Categorization</strong>: AI-powered expense categorization</p>
</li>
<li><p><strong>Trend Analysis</strong>: Time-series analysis of spending patterns</p>
</li>
<li><p><strong>Insight Generation</strong>: Personalized financial recommendations</p>
</li>
<li><p><strong>Result Formatting</strong>: Structure data for frontend visualization</p>
</li>
</ol>
<p><strong>Privacy Implementation:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Data lifecycle management</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DataManager</span> </span>{
  <span class="hljs-keyword">constructor</span>() {
    <span class="hljs-built_in">this</span>.processingData = <span class="hljs-literal">null</span>
    <span class="hljs-built_in">this</span>.autoDeleteTimer = <span class="hljs-literal">null</span>
  }

  processFile(file) {
    <span class="hljs-built_in">this</span>.processingData = file
    <span class="hljs-built_in">this</span>.startAutoDeleteTimer(<span class="hljs-number">30</span> * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>) <span class="hljs-comment">// 30 minutes</span>
    <span class="hljs-comment">// Process data...</span>
  }

  deleteData() {
    <span class="hljs-built_in">this</span>.processingData = <span class="hljs-literal">null</span>
    clearMemoryReferences()
    logDataDeletion()
  }
}
</code></pre>
<hr />
<h3 id="heading-step-7-testing-amp-validation-strategy">Step 7: Testing &amp; Validation Strategy</h3>
<hr />
<p><strong>Testing Strategy</strong></p>
<p><strong>Unit Testing Focus:</strong></p>
<ul>
<li><p>CSV parser handles various bank formats correctly</p>
</li>
<li><p>Transaction categorization accuracy (test with known transaction types)</p>
</li>
<li><p>Progress tracking updates correctly during processing</p>
</li>
<li><p>Data deletion mechanisms work reliably</p>
</li>
</ul>
<p><strong>Integration Testing:</strong></p>
<ul>
<li><p>End-to-end upload → processing → results workflow</p>
</li>
<li><p>Claude API integration under various load conditions</p>
</li>
<li><p>Error recovery scenarios (network failures, API timeouts)</p>
</li>
<li><p>Cross-browser compatibility testing</p>
</li>
</ul>
<p><strong>User Acceptance Testing:</strong></p>
<ul>
<li><p>Upload sample CSV and verify analysis accuracy</p>
</li>
<li><p>Test privacy consent workflow</p>
</li>
<li><p>Validate results make sense for different spending patterns</p>
</li>
<li><p>Mobile device usability testing</p>
</li>
</ul>
<p><strong>Performance Testing:</strong></p>
<ul>
<li><p>Large file processing (&gt;5MB CSV files)</p>
</li>
<li><p>Multiple concurrent users</p>
</li>
<li><p>API response time optimization</p>
</li>
<li><p>Memory usage during processing</p>
</li>
</ul>
<hr />
<h3 id="heading-your-complete-technical-implementation-document">Your Complete Technical Implementation Document</h3>
<p>Congratulations! You've just walked through creating a comprehensive technical implementation document. Let's see what we built:</p>
<p><strong>What We Covered:</strong>  </p>
<p>✅ <strong>Problem Context</strong> - Why the feature exists<br />✅ <strong>Solution Overview</strong> - High-level approach and key decisions<br />✅ <strong>Component Architecture</strong> - How pieces fit together<br />✅ <strong>Implementation Strategy</strong> - Detailed technical approach for each stage<br />✅ <strong>Error Handling</strong> - Real-world edge cases and recovery strategies<br />✅ <strong>API Integration</strong> - Specific technical implementation details<br />✅ <strong>Testing Strategy</strong> - How to validate the implementation works</p>
<p><strong>What Makes This Document Effective:</strong></p>
<ul>
<li><p><strong>Starts with user problems</strong>, not technical solutions</p>
</li>
<li><p><strong>Explains architectural decisions</strong> and why alternatives were rejected</p>
</li>
<li><p><strong>Covers edge cases</strong> that will definitely happen in production</p>
</li>
<li><p><strong>Provides specific implementation guidance</strong> without being too prescriptive</p>
</li>
<li><p><strong>Includes testing strategy</strong> so teams know how to validate their work</p>
</li>
<li><p><strong>Considers privacy and security</strong> as first-class concerns</p>
</li>
</ul>
<p>This document could be handed to a development team today, and they'd have everything needed to build a production-ready bank statement analyzer. They'd understand not just what to build, but why it's built that way and how to handle the tricky parts.</p>
<h2 id="heading-common-pitfalls-and-how-to-avoid-them">Common Pitfalls (And How to Avoid Them)</h2>
<h3 id="heading-the-code-dump-trap">The "Code Dump" Trap</h3>
<p>The biggest mistake in technical documentation is treating it like a code dump. Just pasting code blocks with minimal explanation doesn't help anyone understand the system.</p>
<p>Bad example:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleSubmit</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-keyword">if</span> (!data.partnerId) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
  submitSelection(data);
  updateState(<span class="hljs-string">'success'</span>);
  emitCallback({<span class="hljs-attr">selected</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">partner</span>: data});
}
</code></pre>
<p>Better example: "When users submit their partner selection, we first validate that they actually selected someone (users can be sneaky and try to submit empty forms). If validation passes, we send the selection to our API, update the widget to show success state, and notify the parent component about the selection so it can update its own interface accordingly."</p>
<h3 id="heading-the-everything-is-important-problem">The "Everything Is Important" Problem</h3>
<p>When everything is highlighted, nothing is highlighted. Not every implementation detail needs to be in your main documentation.</p>
<p>Focus on the decisions that matter:</p>
<ul>
<li><p>Why you chose this architecture over alternatives</p>
</li>
<li><p>How different components communicate</p>
</li>
<li><p>What happens when things go wrong</p>
</li>
<li><p>How the system will handle future changes</p>
</li>
</ul>
<p>Save the nitty-gritty implementation details for code comments and separate technical references.</p>
<h3 id="heading-the-its-obvious-assumption">The "It's Obvious" Assumption</h3>
<p>What's obvious to you after spending three weeks building something is definitely not obvious to the developer who's trying to understand it six months later (even if that developer is future you).</p>
<p>Document your assumptions and reasoning. If you decided to use a specific library, explain why. If you structured your state in a particular way, explain the thinking behind it.</p>
<h2 id="heading-testing-and-validation-strategies">Testing and Validation Strategies</h2>
<p>Great implementation documents don't just explain how to build something - they explain how to verify that it works correctly.</p>
<h3 id="heading-testing-philosophy">Testing Philosophy</h3>
<p>"Our testing strategy follows the principle of testing behavior, not implementation. We care that users can successfully select partners, not that our internal state management uses a specific pattern.</p>
<p>Component tests focus on user interactions: Can users search for partners? Does selection work correctly? Do error states display appropriate messages? Integration tests verify that the widget communicates correctly with parent components and handles API failures gracefully."</p>
<h3 id="heading-edge-case-validation">Edge Case Validation</h3>
<p>"We systematically test the scenarios that usually break in production:</p>
<ul>
<li><p>Network failures during search and submission</p>
</li>
<li><p>Rapid user interactions (clicking buttons multiple times)</p>
</li>
<li><p>Invalid or outdated data from the API</p>
</li>
<li><p>Keyboard navigation and screen reader accessibility</p>
</li>
<li><p>Mobile device interactions with touch interfaces"</p>
</li>
</ul>
<h2 id="heading-maintenance-and-evolution">Maintenance and Evolution</h2>
<p>The best technical documents acknowledge that software is a living thing that will change over time.</p>
<h3 id="heading-future-considerations">Future Considerations</h3>
<p>"This widget is designed to evolve. The current implementation handles single partner selection, but the architecture supports multiple selections with minimal changes. The search interface can be extended to support filters and sorting without affecting the core widget logic.</p>
<p>Key extension points:</p>
<ul>
<li><p>Additional search criteria can be added to the SearchInput component</p>
</li>
<li><p>New partner types can be supported by extending the PartnerCard component</p>
</li>
<li><p>Different selection workflows can be implemented as alternative modal components"</p>
</li>
</ul>
<h3 id="heading-migration-strategies">Migration Strategies</h3>
<p>"When rolling out this widget to replace existing partner selection implementations:</p>
<ol>
<li><p>Start with new features to validate the approach</p>
</li>
<li><p>Gradually migrate existing screens during their regular update cycles</p>
</li>
<li><p>Maintain backward compatibility with existing selection events</p>
</li>
<li><p>Provide clear migration guides for teams adopting the widget"</p>
</li>
</ol>
<h2 id="heading-team-collaboration-through-documentation">Team Collaboration Through Documentation</h2>
<h3 id="heading-bridging-the-communication-gap">Bridging the Communication Gap</h3>
<p>Technical implementation documents are often the bridge between different team members with different expertise levels. Your document might be read by:</p>
<ul>
<li><p>Frontend developers implementing the interface</p>
</li>
<li><p>Backend developers building supporting APIs</p>
</li>
<li><p>QA engineers creating test cases</p>
</li>
<li><p>Product managers understanding scope and limitations</p>
</li>
<li><p>Designers ensuring the implementation matches their vision</p>
</li>
</ul>
<p>Write with this diverse audience in mind. Use clear section headers so people can jump to what's relevant for them. Include diagrams and examples that help visual learners understand the concepts.</p>
<h3 id="heading-review-and-iteration">Review and Iteration</h3>
<p>The best documents are living documents that evolve with the project. Build review and update processes into your development workflow:</p>
<p>"This document will be updated as we learn from user feedback and encounter edge cases in production. Major architectural changes require document updates before implementation. All team members should feel empowered to suggest improvements to unclear sections."</p>
<h2 id="heading-tools-and-techniques">Tools and Techniques</h2>
<h3 id="heading-documentation-as-code">Documentation as Code</h3>
<p>Treat your technical documents like code. Use version control, peer reviews, and the same quality standards you apply to your implementation.</p>
<p>Keep documents close to the code they describe. If your widget lives in <code>/components/PartnerSelection/</code>, put the implementation document in <code>/docs/components/</code><a target="_blank" href="http://PartnerSelection.md"><code>PartnerSelection.md</code></a>. This makes it more likely that documents get updated when code changes.</p>
<h3 id="heading-diagrams-and-visual-aids">Diagrams and Visual Aids</h3>
<p>Sometimes a simple diagram communicates better than three paragraphs of text. Use tools like Mermaid, <a target="_blank" href="http://Draw.io">Draw.io</a>, or even hand-drawn sketches to illustrate:</p>
<ul>
<li><p>Component hierarchies</p>
</li>
<li><p>Data flow between components</p>
</li>
<li><p>User interaction workflows</p>
</li>
<li><p>State transitions</p>
</li>
<li><p>API communication patterns</p>
</li>
</ul>
<p>But don't go overboard. Diagrams should clarify, not complicate.</p>
<h3 id="heading-templates-and-consistency">Templates and Consistency</h3>
<p>Develop templates for common document types. Having a consistent structure makes it easier for team members to find information and reduces the cognitive load of starting new documents.</p>
<p>A basic implementation document template might include:</p>
<ul>
<li><p>Problem Context</p>
</li>
<li><p>Solution Overview</p>
</li>
<li><p>Architecture Decisions</p>
</li>
<li><p>Component Breakdown</p>
</li>
<li><p>API Integration</p>
</li>
<li><p>Error Handling</p>
</li>
<li><p>Testing Strategy</p>
</li>
<li><p>Future Considerations</p>
</li>
</ul>
<h2 id="heading-the-roi-of-good-documentation">The ROI of Good Documentation</h2>
<p>Let's talk about the elephant in the room - time. Writing good technical documentation takes time, and in a world of tight deadlines and feature requests, it often feels like a luxury.</p>
<p>But here's the math that changed my perspective:</p>
<p>A well-documented feature saves every future developer (including future you) about 2-4 hours of ramp-up time. If five people work on or reference that feature over its lifetime, you've saved 10-20 hours of collective time by spending 2-3 hours writing good documentation upfront.</p>
<p>More importantly, good documentation prevents the kinds of misunderstandings that lead to bugs, incorrect implementations, and frustrated team members. The cost of fixing these issues later is always higher than preventing them with clear communication upfront.</p>
<h2 id="heading-building-a-documentation-culture">Building a Documentation Culture</h2>
<h3 id="heading-making-it-part-of-the-process">Making It Part of the Process</h3>
<p>The best way to ensure documentation gets written is to make it a natural part of your development process, not an afterthought.</p>
<p>"Definition of Done" should include documentation updates. Code reviews should check that implementation matches documented design. Sprint planning should allocate time for documentation alongside development tasks.</p>
<h3 id="heading-leading-by-example">Leading by Example</h3>
<p>If you want your team to write better technical documents, start by writing better technical documents yourself. Share examples of documents that helped you understand complex systems. Celebrate when good documentation saves the team time or prevents bugs.</p>
<h3 id="heading-documentation-debugging">Documentation Debugging</h3>
<p>Treat unclear documentation like a bug. When someone asks questions that should be answered in your documentation, that's a sign the documentation needs improvement, not that the person asking is lazy.</p>
<h2 id="heading-wrapping-up-the-art-of-technical-storytelling">Wrapping Up: The Art of Technical Storytelling</h2>
<p>At its core, writing technical implementation documents is about storytelling. You're telling the story of how a system works, why it was built that way, and how someone else can successfully work with it.</p>
<p>The best technical documents don't just transfer information - they transfer understanding. They help readers build mental models of how systems work, so they can make good decisions when they need to modify or extend the code.</p>
<p>Remember: every system you build will eventually be maintained by someone else (including future you, who will have forgotten all the clever details). Write documentation that respects their time and intelligence. Explain not just what the code does, but why it does it that way.</p>
<p>Great technical documentation is a gift to your future self and your teammates. It's the difference between inheriting a well-organized kitchen with labeled ingredients and clear recipes, versus walking into a chaotic mess and hoping for the best.</p>
<p>Your code might work perfectly today, but your documentation determines whether it will still be maintainable and understandable six months from now.</p>
<p>A new day, another opportunity to build something well-documented and world-class! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Thought Driven Engineering: The Happy Path (EPISODE 1)]]></title><description><![CDATA[Hey there, Coding Chefs! 👨‍💻
Building solutions especially on the web can be strenous, time consuming, and sometimes frustrating especially when you have things like functional changes, design changes, flow changes etc. The intention of this articl...]]></description><link>https://crackedchefs.devferanmi.xyz/thought-driven-engineering-the-happy-path-episode-1</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/thought-driven-engineering-the-happy-path-episode-1</guid><category><![CDATA[System Architecture]]></category><category><![CDATA[System administration]]></category><category><![CDATA[architecture]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[engineering-management]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Wed, 10 Apr 2024 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Hey there, Coding Chefs! 👨‍💻</p>
<p>Building solutions especially on the web can be strenous, time consuming, and sometimes frustrating especially when you have things like functional changes, design changes, flow changes etc. The intention of this article is to work you through a path to ensure that your code on the frontend(software engineering) in particular is agile, modular, changeable, maintainable and less frustrating for you.</p>
<p>In order to do that you need to put thought to what you’re doing from Day-One, when engineering a product, no matter how small, planning <strong>cannot</strong> be an after-thought. You need to think about the feature, the different ways of doing the same thing, the caveats, pros, cons etc.</p>
<p>Without further ado, let’s get cracking (or cooking),</p>
<p>You know that feeling when you complete a task exactly the way you planned it?<br />When you write down "I'll build feature X using approach Y," then you actually execute it smoothly, and everything just... works?</p>
<p>There's something deeply satisfying about that experience. It's not just about getting the job done - it's about the confidence you build in your problem-solving abilities. It's proof that you didn't just stumble into a solution; you thought it through, planned it out, and executed it with intention.</p>
<p>But let's be honest - how often does that actually happen?</p>
<p>If you're like most developers (including past me), your typical workflow probably looks more like this: Get a task, open VS Code, start typing, hit a wall, Google frantically, try a different approach, hit another wall, refactor everything, and somehow arrive at a working solution three hours later, wondering how you even got there.</p>
<p>I used to live in that chaotic cycle. I thought I was being productive by jumping straight into code, but I was actually just creating more work for myself. Every "quick fix" became a debug marathon. Every "simple feature" turned into a refactoring nightmare.</p>
<p>Then I discovered something that changed everything: the power of thinking before coding.</p>
<p>Now, before you roll your eyes and think "obviously you should think first," hear me out. I'm not talking about the casual "hmm, let me think about this for 30 seconds" approach. I'm talking about a deliberate, structured way of approaching problems that consistently leads to what I call "the happy path" - where your implementation matches your plan, your code works the first time, and you feel genuinely confident in your solution.</p>
<h2 id="heading-the-satisfaction-of-intentional-development">The Satisfaction of Intentional Development</h2>
<p>Here's what I've learned: when you want to build something and you write down exactly how you'll do it, then successfully execute that plan, you don't just solve the immediate problem. You build something much more valuable - confidence in your ability to think through complex problems systematically.</p>
<p>It's the difference between feeling like you got lucky and knowing you're skilled.</p>
<p>When you approach a problem with "I'll build X using Y approach because Z," and then you actually execute that plan successfully, there's a level of satisfaction that random trial-and-error can never provide. You start to trust your own thinking process. You become confident in tackling bigger, more complex problems because you know you have a reliable way to break them down.</p>
<p>But this confidence doesn't come from just thinking harder. It comes from having a systematic approach that you can rely on, every single time.</p>
<h2 id="heading-the-problem-with-code-first-think-later">The Problem with "Code First, Think Later"</h2>
<p>Early in my career, I was the king of jumping straight into implementation. Got a task? Great, let me start coding immediately! I thought planning was just a waste of time that kept me from the "real work."</p>
<p>I remember building a chat platform called "Lauchat" for university students. I was so eager to start that I dove straight into writing HTML and CSS. No planning, no component thinking, just pure excitement and determination. The result? I ended up copying and pasting the same code everywhere, creating a bloated, unmaintainable mess that was impossible to update or extend.</p>
<p>But here's what really happened every time I skipped planning: I'd spend 30 minutes "saving time" by jumping to code, then waste 3 hours debugging issues that proper planning would have prevented. I was essentially building a house without blueprints and wondering why the roof kept falling down.</p>
<p>The turning point came when I realized that <strong>the code is not the hard part - the thinking is</strong>. Anyone can type JavaScript syntax, but not everyone can think through edge cases, state management, and system interactions before they become problems.</p>
<p>That's when I developed what I now call "Thought Driven Engineering" - a simple framework that consistently leads to that satisfying "happy path" experience.</p>
<h2 id="heading-the-framework-think-jot-decide-code">The Framework: Think, Jot, Decide, Code</h2>
<p>This isn't some complex methodology with fancy diagrams. It's a simple, sequential process that forces you to solve problems in your head before you solve them in code.</p>
<h3 id="heading-step-1-think-no-code-editor-allowed">Step 1: Think (No Code Editor Allowed)</h3>
<p>When you get a new task, your first instinct might be to open your editor and start typing. <strong>Don't.</strong></p>
<p>Instead, sit with the problem. Really sit with it. I like to eat <strong>pure bliss chocolates</strong>, step away from my computer, stare out, and just think.</p>
<p>Let me give you a real example. Let's say you're asked to build a countdown timer that counts down from a user-defined time, like 30 minutes.</p>
<p>Start by asking yourself the fundamental questions:</p>
<ul>
<li><p>What's the simplest way to implement this?</p>
</li>
<li><p>What's the most complex way I can imagine it being done?</p>
</li>
<li><p>How might this feature evolve in the future?</p>
</li>
</ul>
<p>But don't stop at the obvious stuff. Dig deeper:</p>
<ul>
<li><p>How will I manage the state of the countdown?</p>
</li>
<li><p>What happens if the user refreshes the page?</p>
</li>
<li><p>What if they close their laptop and open it again 20 minutes later?</p>
</li>
<li><p>Should the timer pause or keep running in the background?</p>
</li>
<li><p>How do I prevent two different tabs from interfering with each other?</p>
</li>
<li><p>Should I use the user's device time or server time?</p>
</li>
<li><p>What about timezone issues or daylight saving time?</p>
</li>
</ul>
<p>This is where most developers rush to code, but these questions are <strong>exactly</strong> what you need to think through first. Every "what if" scenario you consider now is a bug you won't have to fix later.</p>
<p><strong>Real-world thinking session:</strong> When I was building a traffic light timing app (yes, really!, more details below), I spent a good hour just thinking about the problem:</p>
<ul>
<li><p>How do traffic lights actually work?</p>
</li>
<li><p>Are the intervals consistent or do they vary?</p>
</li>
<li><p>What if the timing changes during different hours?</p>
</li>
<li><p>How do I account for the time it takes me to walk to my car?</p>
</li>
<li><p>What if I'm running late and need to adjust the calculation?</p>
</li>
</ul>
<p>That hour of thinking saved me days of rebuilding.</p>
<h3 id="heading-step-2-jot-brain-dump-everything">Step 2: Jot (Brain Dump Everything)</h3>
<p>Once you've thoroughly thought through the problem, start writing everything down. And I mean <strong>everything</strong>.</p>
<p>Don't worry about making it pretty or organized yet. Just get all your thoughts out of your head and onto paper (or a notes app).</p>
<p>For our countdown timer example, your notes might look like this:</p>
<pre><code class="lang-markdown">Countdown Timer - Brain Dump

Core functionality:
<span class="hljs-bullet">-</span> User inputs time (30 mins)
<span class="hljs-bullet">-</span> Timer counts down to zero
<span class="hljs-bullet">-</span> Show time remaining in MM:SS format
<span class="hljs-bullet">-</span> Alert/notification when time reaches zero

State management challenges:
<span class="hljs-bullet">-</span> Need to track: current time, target time, running/paused state
<span class="hljs-bullet">-</span> Should persist across page refreshes
<span class="hljs-bullet">-</span> Handle multiple tabs by segregrating cache keys (if using browser storage to persist)

Technical considerations:
<span class="hljs-bullet">-</span> setInterval vs requestAnimationFrame vs Date-based calculation?
<span class="hljs-bullet">-</span> Local storage for persistence
<span class="hljs-bullet">-</span> Web API for notifications
<span class="hljs-bullet">-</span> What if user changes system time?

Edge cases:
<span class="hljs-bullet">-</span> Invalid input (negative numbers, non-numbers)
<span class="hljs-bullet">-</span> Timer running when page isn't visible
<span class="hljs-bullet">-</span> Browser sleep/wake cycles
<span class="hljs-bullet">-</span> Multiple instances of the timer

Future features (might need):
<span class="hljs-bullet">-</span> Multiple timers
<span class="hljs-bullet">-</span> Preset times
<span class="hljs-bullet">-</span> Sound customization
<span class="hljs-bullet">-</span> Timer history
</code></pre>
<p>The key here is to capture <strong>everything</strong> you thought about in step 1. Don't filter or organize yet - just dump.</p>
<h3 id="heading-step-3-decide-choose-your-battle-plan">Step 3: Decide (Choose Your Battle Plan)</h3>
<p>Now comes the decision phase. Look at everything you've jotted down and start making concrete choices about how you'll implement the solution.</p>
<p>This is where you:</p>
<ul>
<li><p>Choose your technical approach</p>
</li>
<li><p>Decide which edge cases to handle now vs later</p>
</li>
<li><p>Plan your component structure</p>
</li>
<li><p>Identify external dependencies</p>
</li>
<li><p>Set your scope boundaries</p>
</li>
</ul>
<p>For our timer example:</p>
<pre><code class="lang-markdown">Implementation Decisions:

Technical approach:
✅ Use Date-based calculation (more accurate than setInterval)
✅ Store target time in localStorage
✅ Single timer for now (multiple timers = v2)
✅ Use browser's wakelock to keep the device active(and prevent sleep)

State structure:
<span class="hljs-bullet">-</span> targetTime: Date object
<span class="hljs-bullet">-</span> isRunning: boolean
<span class="hljs-bullet">-</span> timeRemaining: number (calculated)

Components needed:
<span class="hljs-bullet">-</span> TimeInput (for setting duration)
<span class="hljs-bullet">-</span> TimerDisplay (shows current countdown)
<span class="hljs-bullet">-</span> TimerControls (start/pause/reset)

Libraries needed:
<span class="hljs-bullet">-</span> None! Keep it vanilla for now

MVP scope:
✅ Basic countdown functionality
✅ Persistence across refreshes  
✅ Pause/resume capability
❌ Multiple timers (future)
❌ Preset times (future)
❌ Sound customization (future)

Edge cases to handle:
✅ Invalid input validation
✅ Browser tab visibility changes
❌ Multiple tab synchronization (complex, move to v2)
</code></pre>
<p>Notice how I'm making explicit decisions about what to include and what to defer. This prevents scope creep and keeps me focused.</p>
<h3 id="heading-step-4-code-finally">Step 4: Code (Finally!)</h3>
<p>Only now do you open your code editor. But here's the beautiful part - by this point, <strong>you've already solved the hard problems</strong>. The coding becomes almost mechanical because you know exactly what you're building and why.</p>
<p>Your implementation becomes clean and purposeful because you've thought through the architecture:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CountdownTimer</span> </span>{
  <span class="hljs-keyword">constructor</span>(containerId) {
    <span class="hljs-built_in">this</span>.container = <span class="hljs-built_in">document</span>.getElementById(containerId);
    <span class="hljs-built_in">this</span>.targetTime = <span class="hljs-literal">null</span>;
    <span class="hljs-built_in">this</span>.isRunning = <span class="hljs-literal">false</span>;
    <span class="hljs-built_in">this</span>.intervalId = <span class="hljs-literal">null</span>;

    <span class="hljs-built_in">this</span>.loadFromStorage();
    <span class="hljs-built_in">this</span>.render();
    <span class="hljs-built_in">this</span>.startUpdateLoop();
  }

  setDuration(minutes) {
    <span class="hljs-comment">// Input validation (planned in step 3)</span>
    <span class="hljs-keyword">if</span> (!minutes || minutes &lt;= <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Duration must be a positive number'</span>);
    }

    <span class="hljs-comment">// Date-based calculation (decided in step 3)</span>
    <span class="hljs-built_in">this</span>.targetTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-built_in">Date</span>.now() + minutes * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>);
    <span class="hljs-built_in">this</span>.saveToStorage();
  }

  <span class="hljs-comment">// Rest of implementation...</span>
}
</code></pre>
<p>Because you planned everything out, you're not making random decisions mid-implementation. You're not googling "how to handle timer edge cases" because you already thought through the edge cases. You're not refactoring your state structure because you already designed it.</p>
<h2 id="heading-real-world-example-my-traffic-light-app">Real-World Example: My Traffic Light App</h2>
<p>Let me share how this framework played out in a real project.<br />I was tired of always hitting(not the same as running red lights) red lights near my house, so I decided to build an app to time them perfectly such that I can get to all the lights while they’re green.</p>
<p><strong>Think Phase (1 hour):</strong> I sat outside with a notebook and actually observed the traffic lights. I timed them, looked for patterns, and thought about variables:</p>
<ul>
<li><p>Lights have different timing during rush hour vs off-peak</p>
</li>
<li><p>There's a pedestrian crossing that affects timing</p>
</li>
<li><p>I need to account for walking time to my car</p>
</li>
<li><p>Weather might affect how fast I walk</p>
</li>
</ul>
<p><strong>Jot Phase (30 minutes):</strong> I wrote down everything I observed:</p>
<ul>
<li><p>Red light: 2.5 minutes during rush hour, 2 minutes off-peak</p>
</li>
<li><p>Green light: 1.5 minutes consistent</p>
</li>
<li><p>My walking time: 45 seconds normal, 60 seconds if raining</p>
</li>
<li><p>Buffer time needed: 15 seconds for unexpected delays</p>
</li>
</ul>
<p><strong>Decide Phase (30 minutes):</strong> I chose a simple approach:</p>
<ul>
<li><p>Manual time input (not trying to be too smart)</p>
</li>
<li><p>Account for current time of day</p>
</li>
<li><p>Simple notification system</p>
</li>
<li><p>Mobile-first design (using it while getting ready)</p>
</li>
</ul>
<p><strong>Code Phase (2 hours):</strong> Because I'd planned everything, the coding was straightforward. No major surprises, no architectural changes, no "wait, I didn't think about this" moments.</p>
<p>The result? An app I still use daily that has saved me countless minutes of sitting at red lights.</p>
<h2 id="heading-why-this-framework-works">Why This Framework Works</h2>
<p><strong>1. It prevents tunnel vision:</strong> When you start coding immediately, you often get fixated on the first solution you implement, even if it's not the best one.</p>
<p><strong>2. It catches edge cases early:</strong> It's much easier to handle edge cases in the design phase than to try to fit them into existing code (obviously leading to more problem like breaking existing feature that’s currently working).</p>
<p><strong>3. It reduces decision fatigue:</strong> By making architectural decisions upfront, you don't waste mental energy on them during implementation.</p>
<p><strong>4. It creates better documentation:</strong> Your notes become natural documentation for future you (or your teammates).</p>
<p><strong>5. It makes debugging easier:</strong> When something goes wrong, you have a clear map of your thinking process to trace back through.</p>
<h2 id="heading-common-objections-and-my-responses">Common Objections (And My Responses)</h2>
<p><strong>"This feels like overthinking simple features"</strong></p>
<p>Trust me, I used to think the same thing. But here's what I learned: there are no "simple" features in production applications. Even a basic button has considerations around accessibility, error states, loading states, and user feedback.</p>
<p><strong>"Planning takes too long"</strong></p>
<p>In my experience, planning takes about 30 - 35%(up to 65%, on a system design of an entire app) of the total time you'll spend on a feature. But it saves you 50% of the debugging and refactoring time. The math works out strongly in favor of planning.</p>
<p><strong>"What if requirements change?"</strong></p>
<p>Good planning actually makes you more adaptable, not less. When you understand the problem deeply, you can respond to changes more intelligently. You know what's core to the solution and what's just implementation detail.</p>
<h2 id="heading-adapting-the-framework">Adapting the Framework</h2>
<p>This framework scales from small features to large projects:</p>
<p><strong>For small features (&lt; 1 day):</strong></p>
<ul>
<li><p>Think: 15-30 minutes</p>
</li>
<li><p>Jot: 10-15 minutes</p>
</li>
<li><p>Decide: 10-15 minutes</p>
</li>
<li><p>Code: The rest</p>
</li>
</ul>
<p><strong>For medium features (1-3 days):</strong></p>
<ul>
<li><p>Think: 1-2 hours</p>
</li>
<li><p>Jot: 30-60 minutes</p>
</li>
<li><p>Decide: 30-60 minutes</p>
</li>
<li><p>Code: The rest</p>
</li>
</ul>
<p><strong>For large projects (1+ weeks):</strong></p>
<ul>
<li><p>Think: Half a day to a full day</p>
</li>
<li><p>Jot: A few hours across multiple sessions</p>
</li>
<li><p>Decide: Half a day, possibly involving team discussions</p>
</li>
<li><p>Code: The rest, with periodic re-evaluation</p>
</li>
</ul>
<h2 id="heading-making-it-stick">Making It Stick</h2>
<p>The hardest part isn't learning this framework - it's building the discipline to use it when you're excited to start coding.</p>
<p>Here are some tricks that helped me:</p>
<p><strong>1. Close your code editor:</strong> Literally close VS Code when you get a new task. The temptation to "just peek at the existing code" will derail your thinking process.</p>
<p><strong>2. Use a timer:</strong> Set a timer for your thinking phase. Don't let yourself touch code until it goes off.</p>
<p><strong>3. Share your notes:</strong> Send your "Jot" phase notes to a teammate or rubber duck. Explaining your thinking helps solidify it.</p>
<p><strong>4. Celebrate good planning:</strong> When a feature goes smoothly because you planned well, take a moment to appreciate that. Positive reinforcement helps build the habit.</p>
<h2 id="heading-the-compound-effect">The Compound Effect</h2>
<p>Here's the thing that really sold me on this approach: the benefits compound over time.</p>
<p>When you consistently think through problems before coding, you start recognizing patterns. You get better at spotting potential issues. Your "Think" phase gets faster and more thorough simultaneously.</p>
<p>You also build a reputation as someone who writes solid, well-thought-out code. Your code reviews become faster because you've already considered the edge cases. Your estimates become more accurate because you understand the scope upfront.</p>
<h2 id="heading-when-to-break-the-rules">When to Break the Rules</h2>
<p>This framework isn't religious doctrine. There are times when you might skip or compress steps:</p>
<ul>
<li><p><strong>Prototyping/spikes:</strong> When you're exploring feasibility, feel free to code while thinking, don’t code without thinking regardless.</p>
</li>
<li><p><strong>Tiny bug fixes:</strong> For obvious one-line fixes, don't overthink it</p>
</li>
<li><p><strong>Well-understood patterns:</strong> If you've built the same type of feature 20 times, you can lean on experience. But don’t forget, you’re getting better too, so your solution should not be the same as the first time, which means your implementation should be better, which leads us back to thinking about the first solution, how has it panned out, did it stand the test of time? What can you improve. All of this is “still” thinking.</p>
</li>
</ul>
<p>But even in these cases, I find that a quick mental run-through of the framework helps.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>The "Think, Jot, Decide, Code" framework has fundamentally changed how I approach software development. It's transformed me from someone who writes code to someone who solves problems (and then expresses those solutions in code).</p>
<p>The next time you get a feature request, I challenge you to try this approach:</p>
<ol>
<li><p><strong>Think</strong> through the problem completely before touching your keyboard</p>
</li>
<li><p><strong>Jot</strong> down everything you've considered, no matter how small</p>
</li>
<li><p><strong>Decide</strong> on your approach, scope, and architecture</p>
</li>
<li><p><strong>Code</strong> with confidence and clarity</p>
</li>
</ol>
<p>You might feel like you're moving slower at first, but I promise you'll end up moving much faster in the long run. Your code will be cleaner, your bugs will be fewer, and your stress levels will be lower.</p>
<p>Remember: Great engineering isn't about how fast you can type code. It's about how well you can think through problems.</p>
<p>A new day, another opportunity to think before you code! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Web Security: The Frontend Engineer's Survival Guide]]></title><description><![CDATA[Hey there, fellow Coding Chefs! 👋
Picture this: You've just built the most beautiful web application. The CSS animations are smooth as butter, the JavaScript is pristine, and the user experience?.But then, one morning, you wake up to find that some ...]]></description><link>https://crackedchefs.devferanmi.xyz/web-security-the-frontend-engineers-survival-guide</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/web-security-the-frontend-engineers-survival-guide</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Security]]></category><category><![CDATA[Web Security]]></category><category><![CDATA[XSS]]></category><category><![CDATA[XSS Attacks]]></category><category><![CDATA[Front-end Security]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Wed, 11 Oct 2023 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Hey there, fellow Coding Chefs! 👋</p>
<p>Picture this: You've just built the most beautiful web application. The CSS animations are smooth as butter, the JavaScript is pristine, and the user experience?.<br />But then, one morning, you wake up to find that some hacker has turned your masterpiece into their personal playground. Not exactly the kind of user engagement you were hoping for, right?</p>
<p>Well, grab your favorite cup of coffee, and let's dive into the fascinating world of web security. By the end of this guide, you'll be equipped with enough knowledge to properly secure your web applications.</p>
<h2 id="heading-why-web-security-actually-matters">Why Web Security Actually Matters</h2>
<p>Web security isn't just some fancy buzzword - it's the difference between being a developer who builds cool stuff and being a developer who builds cool stuff that doesn't get hacked every other Tuesday.</p>
<p>Think about it: when users interact with your application, they're essentially saying, "Hey, I trust you with my data, my time, and sometimes my money." That's a huge responsibility.</p>
<h2 id="heading-the-battlefield">The Battlefield</h2>
<p>The frontend security landscape is filled with different threats listed below:</p>
<h3 id="heading-cross-site-scripting-xss-the-shape-shifter">Cross-Site Scripting (XSS): The Shape-Shifter</h3>
<p>XSS is like that friend who seems harmless but ends up eating all your pizza. It's one of the most common attacks out there, and it's pretty sneaky.</p>
<p>Imagine you're building a comment system for a blog. A user submits a comment, but instead of saying "Great article!", they submit something like <code>&lt;script&gt;alert('I am in your system!');&lt;/script&gt;</code>. If your application doesn't properly sanitize this input, boom! Every visitor sees that annoying alert popup.</p>
<p><strong>Three types you need to know:</strong></p>
<p><strong>Stored XSS</strong>: The malicious code gets permanently stored on your server. For example, imagine a social media platform e.g facebook where someone posts a status update containing JavaScript. Every friend who views that post would unknowingly execute the attacker's code.</p>
<p><strong>Reflected XSS</strong>: The malicious script comes through a URL parameter and immediately gets reflected back. Picture a search functionality where the search term gets displayed without proper sanitization. An attacker could craft a URL like <a target="_blank" href="http://yoursite.com/search?q=&lt;script&gt;stealCookies\(\)&lt;/script&gt;"><code>yoursite.com/search?q=&lt;script&gt;stealCookies()&lt;/script&gt;</code></a>.</p>
<p><strong>DOM-based XSS</strong>: This happens entirely in the browser by manipulating the client-side DOM without server involvement.</p>
<p><strong>Real-world impact:</strong> In 2020, eBay had an XSS vulnerability where attackers could inject malicious code into product listings, leading to stolen user cookies and credentials.</p>
<p><strong>How to do you ensure your web app is secured against XSS attacks:</strong></p>
<ul>
<li><p>Sanitize and validate every single input (Majority of frameworks already do this behind the scenes e.g NodeJs, Express, React, Angular etc)</p>
</li>
<li><p>Use Content Security Policy (CSP)</p>
</li>
<li><p>Escape output properly</p>
</li>
<li><p>Never use <code>innerHTML</code> with user-generated content/inputs</p>
</li>
</ul>
<h3 id="heading-clickjacking">Clickjacking</h3>
<p>Clickjacking tricks users into clicking hidden UI elements by overlaying malicious content over legitimate interfaces.</p>
<p>Here's how it works: An attacker creates a page promising you a free trip to Hawaii. But sneakily, they load your banking website in an invisible iframe positioned exactly over the "Claim Free Trip" button. When you click for your vacation, you're actually clicking "Transfer $1000" on your bank's website.</p>
<p><strong>Defense strategies:</strong></p>
<ul>
<li><p>Use X-Frame-Options header</p>
</li>
<li><p>Implement Content Security Policy with frame-ancestors</p>
</li>
<li><p>Set SameSite cookie attributes</p>
</li>
</ul>
<p><strong>Real example:</strong> Facebook got hit in 2015 where users were tricked into liking pages they never intended to interact with.</p>
<h3 id="heading-insecure-direct-object-reference-idor-like-a-guessing-game">Insecure Direct Object Reference (IDOR): Like a Guessing Game</h3>
<p>IDOR is like having a filing cabinet where folders are numbered 1, 2, 3, 4... and anyone who knows the pattern can access any file.</p>
<p>Picture an e-commerce platform where user profiles are accessed via URLs like <a target="_blank" href="http://yourstore.com/profile/123"><code>yourstore.com/profile/123</code></a>. If your application doesn't check whether the logged-in user should actually see profile 123, any user can just change the number and peek at other people's information.</p>
<p><strong>Defense:</strong></p>
<ul>
<li><p>Always verify user permissions (usually server-side/backend validations)</p>
</li>
<li><p>Use complex, non-guessable identifiers (UUIDs are your friend)</p>
</li>
<li><p>Never rely on "security through obscurity"</p>
</li>
</ul>
<h3 id="heading-cross-site-request-forgery-csrf-the-identity-thief">Cross-Site Request Forgery (CSRF): The Identity Thief</h3>
<p>CSRF tricks your browser into making requests you never intended to make. You're logged into your shopping website in one tab, and you click what looks like a funny meme in another tab. But that "meme" page contains hidden JavaScript that immediately transfers money from your account!</p>
<p><strong>Protection:</strong></p>
<ul>
<li><p>Use anti-CSRF tokens in forms</p>
</li>
<li><p>Set SameSite cookie attributes</p>
</li>
<li><p>Require re-authentication for sensitive actions</p>
</li>
</ul>
<p><strong>Historical note:</strong> YouTube got pwned by CSRF in 2008, allowing attackers to mess with user settings and video information.</p>
<h3 id="heading-man-in-the-middle-mitm-attacks-eavesdropping">Man-in-the-Middle (MITM) Attacks: Eavesdropping</h3>
<p>MITM attacks position themselves between you and the server, intercepting and potentially modifying everything that passes through. It's like someone secretly listening to your phone calls and occasionally chiming in.</p>
<p><strong>Protection:</strong></p>
<ul>
<li><p>Always use HTTPS (api calls, web pages must be HTTPS encrypted)</p>
</li>
<li><p>Implement HSTS headers</p>
</li>
<li><p>Secure WebSocket communications with TLS</p>
</li>
<li><p>Configure proper CORS settings</p>
</li>
</ul>
<p><strong>Real impact:</strong> Equifax's failure to properly secure connections during their 2018 breach allowed attackers to intercept sensitive personal information.</p>
<h3 id="heading-third-party-dependencies-the-trojan-horse">Third-Party Dependencies: The Trojan Horse</h3>
<p>Modern apps use tons of external libraries. Each dependency is a potential attack vector. If any library gets compromised, your application could be in trouble too.</p>
<p>An example:<br />You include a popular utility library. Everything's great for months. Then, the maintainer's npm account gets hacked, and a new version gets published with malicious code. If your build process auto-updates, congratulations - you just served malware to all your users!</p>
<p><strong>Risk mitigation:</strong></p>
<ul>
<li><p>Regularly audit dependencies with npm audit, Snyk, dependabot and other vulnerability scanning tools</p>
</li>
<li><p>Avoid abandoned, archived, or unmaintained libraries</p>
</li>
<li><p>Use Subresource Integrity (SRI) for external scripts (internal scripts)</p>
</li>
</ul>
<h2 id="heading-advanced-defense-mechanisms">Advanced Defense Mechanisms</h2>
<h3 id="heading-subresource-integrity-sri">Subresource Integrity (SRI)</h3>
<p>SRI ensures that external resources haven't been tampered with by verifying their cryptographic hash. It's like having a password for your JavaScript files!</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.example.com/library.js"</span> 
        <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"</span> 
        <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="heading-content-security-policy-csp-the-rulebook">Content Security Policy (CSP): The Rulebook</h3>
<p>CSP is like being the strict parent of your website. You set rules about what scripts can run and where resources can be loaded from.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"Content-Security-Policy"</span> 
      <span class="hljs-attr">content</span>=<span class="hljs-string">"default-src 'self'; 
               script-src 'self' https://trusted-cdn.com; 
               style-src 'self' 'unsafe-inline';"</span>&gt;</span>
</code></pre>
<p>This means: "Only load resources from my own domain, scripts only from my domain or <a target="_blank" href="http://trusted-cdn.com">trusted-cdn.com</a>, and styles from my domain or inline."</p>
<h3 id="heading-client-side-storage-security">Client-Side Storage Security</h3>
<p><strong>Golden rule:</strong> Never store sensitive data in localStorage or sessionStorage. These are like keeping your diary on the kitchen counter - anyone who gets into your house can read it.</p>
<p><strong>For authentication tokens:</strong> Use HttpOnly cookies that JavaScript can't access.</p>
<p><strong>For non-sensitive data:</strong> If you must store client-side, encrypt it first.</p>
<h2 id="heading-micro-frontend-security-challenges">Micro-Frontend Security Challenges</h2>
<p>As teams adopt micro-frontend architectures, new security challenges emerge:</p>
<p><strong>Dependency chaos:</strong> Multiple teams using different versions of libraries creates security inconsistencies.</p>
<p><strong>CORS complexity:</strong> Micro-frontends often communicate across domains, making CORS configuration critical.</p>
<p><strong>Solution:</strong> Standardize critical dependencies, configure strict CORS policies, and treat each micro-frontend as its own security zone.</p>
<h2 id="heading-zero-trust-architecture-trust-no-one">Zero Trust Architecture: Trust No One</h2>
<p>Zero Trust operates on the principle that threats can come from anywhere, so you should verify everything, all the time. It's like having checkpoints everywhere - want to access the kitchen? Show your ID. Want to use the bathroom? ID please.</p>
<p><strong>Core principles:</strong></p>
<ol>
<li><p><strong>Assume breach</strong> - Someone might already be in your system</p>
</li>
<li><p><strong>Verify explicitly</strong> - Check every request thoroughly</p>
</li>
<li><p><strong>Least privilege</strong> - Give minimal necessary permissions</p>
</li>
<li><p><strong>Continuous monitoring</strong> - Keep watching for suspicious activity</p>
</li>
</ol>
<h2 id="heading-staying-current-with-owasp">Staying Current with OWASP</h2>
<p>OWASP (Open Web Application Security Project) is like the Wikipedia of web security. Their "Top 10" is a regularly updated list of the most critical web application security risks.</p>
<p>The 2024 list includes classics like Broken Access Control, Injection attacks, and newer concerns like Software and Data Integrity Failures. Set aside time each month to browse OWASP resources - think of it as "security homework."</p>
<h2 id="heading-real-world-stories">Real-World Stories</h2>
<h3 id="heading-the-invisible-bank-transfer">The Invisible Bank Transfer</h3>
<p>A major bank had a secure transfer interface, but someone got creative. They created a viral gaming website: "Click the button as fast as you can!" The game page loaded the bank's transfer interface in an invisible iframe behind the game button. Every click to play the game actually authorized a small transfer to the attacker's account. The scary part? The bank's logs showed legitimate, authenticated requests.</p>
<h3 id="heading-the-social-media-butterfly-effect">The Social Media Butterfly Effect</h3>
<p>A social media platform allowed certain HTML attributes in comments for styling. A researcher discovered you could include: <code>&lt;img src="innocent.jpg" onload="stealAllTheThings()"&gt;</code>. The platform checked for script tags but missed this. Within hours, there were self-replicating posts and stolen authentication tokens.</p>
<h3 id="heading-the-dependency-disaster">The Dependency Disaster</h3>
<p>A startup used a tiny date formatting library maintained by one person as a hobby. The maintainer's npm account got compromised, and a new version included malicious code that only triggered 1% of the time. It took weeks to detect the data exfiltration.</p>
<h2 id="heading-building-your-security-mindset">Building Your Security Mindset</h2>
<p>Every time you write code, ask yourself: "How could someone abuse this?" It sounds paranoid, but it's actually a superpower.</p>
<p>For example, with a simple profile update form:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateProfile</span>(<span class="hljs-params">userData</span>) </span>{
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'profile-name'</span>).innerHTML = userData.name;
}
</code></pre>
<p>Ask: What if <a target="_blank" href="http://userData.name"><code>userData.name</code></a> contains <code>&lt;script&gt;alert('XSS!')&lt;/script&gt;</code>?</p>
<p>The security-conscious version:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateProfile</span>(<span class="hljs-params">userData</span>) </span>{
    <span class="hljs-keyword">const</span> safeName = DOMPurify.sanitize(userData.name);
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'profile-name'</span>).textContent = safeName;
}
</code></pre>
<h2 id="heading-performance-vs-security-finding-balance">Performance vs Security: Finding Balance</h2>
<p>Security and performance don't have to be enemies. Smart implementation minimizes overhead:</p>
<ul>
<li><p>Cache validation results for repeated inputs</p>
</li>
<li><p>Lazy load security libraries only when needed</p>
</li>
<li><p>Use efficient algorithms for security operations</p>
</li>
</ul>
<h2 id="heading-the-future-of-web-security">The Future of Web Security</h2>
<p>Keep an eye on:</p>
<ul>
<li><p><strong>WebAssembly security</strong> - New runtime, new considerations</p>
</li>
<li><p><strong>Privacy-first security</strong> - GDPR compliance and user privacy</p>
</li>
</ul>
<h2 id="heading-your-security-action-plan">Your Security Action Plan</h2>
<p>After reading this:</p>
<ol>
<li><p><strong>Audit your current projects</strong> - Look for potential security issues</p>
</li>
<li><p><strong>Implement one new security feature</strong> - Maybe add CSP headers</p>
</li>
<li><p><strong>Set up basic security testing</strong> - Add security checks to your test suite</p>
</li>
<li><p><strong>Follow OWASP</strong> - Check their resources regularly</p>
</li>
<li><p><strong>Join the community</strong> - Follow security researchers, join discussions</p>
</li>
</ol>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Building secure applications isn't just about protecting code - it's about protecting real people. Every form you secure properly means someone's personal information stays safe. Every XSS vulnerability you prevent means a user doesn't get their account compromised.</p>
<p>Security is a journey, not a destination. Start small, stay curious, and remember - every developer who takes security seriously makes the web a little bit safer for everyone.</p>
<p>Perfect security doesn't exist, but that doesn't mean we should give up. Every security measure you implement makes your application harder to attack, and often that's enough to make attackers move on to easier targets.</p>
<p><strong>Remember:</strong> You don't have to become a security expert overnight. Pick one concept from this guide, implement it in your next project, and gradually build your security knowledge. Your users (and your future self) will thank you.</p>
<p>A new day, another opportunity to build something secure and world-class! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Introduction to Web Rendering Strategies]]></title><description><![CDATA[Hey there, Coding Chefs!
Ever wondered why some websites load instantly while others take forever to show content? Or why Netflix feels so snappy while some e-commerce sites make you wait ages? The secret lies in rendering strategies - the different ...]]></description><link>https://crackedchefs.devferanmi.xyz/introduction-to-web-rendering-strategies</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/introduction-to-web-rendering-strategies</guid><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webdev]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Next.js 13.2]]></category><category><![CDATA[SSR and SSG]]></category><category><![CDATA[Server side rendering]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Tue, 05 Sep 2023 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Hey there, Coding Chefs!</p>
<p>Ever wondered why some websites load instantly while others take forever to show content? Or why Netflix feels so snappy while some e-commerce sites make you wait ages? The secret lies in <strong>rendering strategies</strong> - the different ways we can serve content to users.</p>
<p>Think of rendering strategies as different cooking methods.</p>
<p>You can serve a meal instantly (microwave), prepare it fresh when ordered (diners), or have it ready and waiting for order (like Chowdeck). Each approach has its place, and choosing the right one can make, mar or break your user experience.</p>
<p>Let's dive into the fascinating world of web rendering strategies and discover which one fits your next project!</p>
<h2 id="heading-1-static-site-generation-ssg-the-buffet-approach">1. Static Site Generation (SSG): The Buffet Approach</h2>
<p><strong>What it is:</strong> All your pages are pre-built at build time and served as static HTML files. It's like preparing all your meals in advance and keeping them ready to serve.</p>
<p><strong>How it works:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Next.js SSG example</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> fetchPosts();

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: { posts },
    <span class="hljs-attr">revalidate</span>: <span class="hljs-number">60</span> <span class="hljs-comment">// Regenerate every 60 seconds</span>
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Blog</span>(<span class="hljs-params">{ posts }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {posts.map(post =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{post.excerpt}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>Tech Stack:</strong> Next.js, Gatsby, Hugo, Jekyll, Nuxt.js (static mode), Astro</p>
<p><strong>Architecture:</strong></p>
<pre><code class="lang-markdown">Build Time:
[CMS/Data] → [Build Process] → [Static HTML/CSS/JS] → [CDN]

Request Time:
[User] → [CDN] → [Static Files] → [Instant Load]
</code></pre>
<p><strong>Perfect for:</strong></p>
<ul>
<li><p>Blogs and documentation sites</p>
</li>
<li><p>Marketing websites</p>
</li>
<li><p>Portfolios</p>
</li>
<li><p>Product landing pages</p>
</li>
<li><p>Company websites</p>
</li>
</ul>
<p><strong>Live Examples:</strong></p>
<ul>
<li><p><strong>Netflix's landing pages</strong> - Lightning fast marketing pages</p>
</li>
<li><p><strong>GitHub Pages</strong> - Documentation and project sites</p>
</li>
<li><p><strong>Vercel's website</strong> - Company marketing site</p>
</li>
<li><p><strong>Stripe's documentation</strong> - Developer docs</p>
</li>
</ul>
<p><strong>Pros:</strong>  </p>
<p>✅ Blazing fast loading times<br />✅ Great SEO out of the box<br />✅ Excellent caching capabilities<br />✅ Lower server costs<br />✅ High security (no server-side vulnerabilities)</p>
<p><strong>Cons:</strong><br />❌ Build times increase with content volume as we need to generate more contents at build time<br />❌ Not suitable for real-time data<br />❌ Requires rebuild for content updates (i.e you need to be trigger the build, so your pipeline has to be connected to your content delivery mechanism)<br />❌ Limited dynamic functionality</p>
<hr />
<h2 id="heading-2-incremental-static-regeneration-isr-the-smart-buffet">2. Incremental Static Regeneration (ISR): The Smart Buffet</h2>
<p><strong>What it is:</strong> Like SSG but with the ability to update specific pages after build time. Imagine a buffet that can refresh individual dishes without replacing the entire spread.</p>
<p><strong>How it works:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Next.js ISR example</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params">{ params }</span>) </span>{
  <span class="hljs-keyword">const</span> product = <span class="hljs-keyword">await</span> fetchProduct(params.id);

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: { product },
    <span class="hljs-attr">revalidate</span>: <span class="hljs-number">3600</span>, <span class="hljs-comment">// Revalidate every hour</span>
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticPaths</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> popularProducts = <span class="hljs-keyword">await</span> fetchPopularProducts();

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">paths</span>: popularProducts.map(<span class="hljs-function"><span class="hljs-params">p</span> =&gt;</span> ({ <span class="hljs-attr">params</span>: { <span class="hljs-attr">id</span>: p.id } })),
    <span class="hljs-attr">fallback</span>: <span class="hljs-string">'blocking'</span> <span class="hljs-comment">// Generate other pages on-demand</span>
  };
}
</code></pre>
<p><strong>Tech Stack:</strong> Next.js, Nuxt.js 3</p>
<p><strong>Architecture:</strong></p>
<pre><code class="lang-plaintext">Build Time:
[CMS] → [Build Popular Pages] → [CDN]

Request Time:
[User] → [CDN] → [Check TTL] → [Fresh? Serve : Regenerate] → [User]
</code></pre>
<p><strong>Perfect for:</strong></p>
<ul>
<li><p>E-commerce product pages</p>
</li>
<li><p>News websites</p>
</li>
<li><p>Social media platforms</p>
</li>
<li><p>Content-heavy sites with frequent updates</p>
</li>
<li><p>Large-scale blogs</p>
</li>
</ul>
<p><strong>Live Examples:</strong></p>
<ul>
<li><p><strong>Hulu</strong> - Video content pages</p>
</li>
<li><p><strong>TikTok's web version</strong> - User profile pages</p>
</li>
<li><p><strong>Reddit</strong> - Popular post pages</p>
</li>
<li><p><strong>Medium</strong> - Article pages</p>
</li>
</ul>
<p><strong>Pros:</strong><br />✅ Best of both worlds (speed + freshness)<br />✅ Scales to millions of pages<br />✅ Automatic cache invalidation<br />✅ Great for SEO<br />✅ Reduced build times</p>
<p><strong>Cons:</strong><br />❌ More complex than pure SSG<br />❌ First visitor after cache expiry waits longer<br />❌ Requires careful cache strategy planning<br />❌ Platform-specific (mainly Next.js)</p>
<hr />
<h2 id="heading-3-server-side-rendering-ssr-the-diner-kitchen">3. Server-Side Rendering (SSR): The Diner Kitchen</h2>
<p><strong>What it is:</strong> Pages are generated on the server for each request. Like cooking each meal fresh when a customer orders.</p>
<p><strong>How it works:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Next.js SSR example</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params">context</span>) </span>{
  <span class="hljs-keyword">const</span> { req, res, query } = context;
  <span class="hljs-keyword">const</span> userSession = <span class="hljs-keyword">await</span> getSession(req);
  <span class="hljs-keyword">const</span> personalizedData = <span class="hljs-keyword">await</span> fetchUserData(userSession.userId);

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: {
      <span class="hljs-attr">user</span>: userSession,
      <span class="hljs-attr">data</span>: personalizedData
    }
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params">{ user, data }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Welcome back, {user.name}!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">UserDashboard</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{data}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>Tech Stack:</strong> Next.js, Nuxt.js, SvelteKit, Remix, Express + React, PHP, Ruby on Rails</p>
<p><strong>Architecture:</strong></p>
<pre><code class="lang-plaintext">Request Time:
[User] → [Server] → [Database] → [Generate HTML] → [Send to User]
                ↓
          [Template Engine]
</code></pre>
<p><strong>Perfect for:</strong></p>
<ul>
<li><p>User dashboards</p>
</li>
<li><p>Admin panels</p>
</li>
<li><p>Personalized content</p>
</li>
<li><p>Real-time data applications</p>
</li>
<li><p>Authentication-heavy apps</p>
</li>
</ul>
<p><strong>Live Examples:</strong></p>
<ul>
<li><p><strong>Facebook</strong> - Personalized feeds</p>
</li>
<li><p><strong>Twitter/X</strong> - Timeline pages</p>
</li>
<li><p><strong>Gmail</strong> - Inbox views</p>
</li>
<li><p><strong>Slack</strong> - Workspace interfaces</p>
</li>
<li><p><strong>Shopify Admin</strong> - Merchant dashboards</p>
</li>
</ul>
<p><strong>Pros:</strong><br />✅ Real-time data<br />✅ Personalized content<br />✅ Great SEO<br />✅ Full access to server resources<br />✅ Secure (sensitive logic stays on server)</p>
<p><strong>Cons:</strong><br />❌ Slower than static approaches<br />❌ Higher server costs<br />❌ Server load increases with traffic<br />❌ Requires robust infrastructure<br />❌ Time to First Byte (TTFB) can be high</p>
<hr />
<h2 id="heading-4-client-side-rendering-csr-the-chowdeck-kitchen">4. Client-Side Rendering (CSR): The “Chowdeck” Kitchen</h2>
<p><strong>What it is:</strong> The server sends a minimal HTML shell, and JavaScript builds the page in the browser. Like giving customers ingredients and letting them cook. Essentially, the content/meal is waiting to be requested for.</p>
<p><strong>How it works:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// React CSR example</span>
<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [products, setProducts] = useState([]);
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">true</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchProducts</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/products'</span>);
      <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
      setProducts(data);
      setLoading(<span class="hljs-literal">false</span>);
    }

    fetchProducts();
  }, []);

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {products.map(product =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">ProductCard</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{product.id}</span> <span class="hljs-attr">product</span>=<span class="hljs-string">{product}</span> /&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>Tech Stack:</strong> React, Vue.js, Angular, Svelte (SPA mode), Vanilla JavaScript</p>
<p><strong>Architecture:</strong></p>
<pre><code class="lang-plaintext">Initial Load:
[User] → [Server] → [HTML Shell + JS Bundle] → [Browser] → [API Calls] → [Render]

Subsequent Navigation:
[User Click] → [Browser] → [API Call] → [Update DOM]
</code></pre>
<p><strong>Perfect for:</strong></p>
<ul>
<li><p>Interactive web applications</p>
</li>
<li><p>Dashboards with real-time updates</p>
</li>
<li><p>Games and multimedia apps</p>
</li>
<li><p>Apps requiring complex user interactions</p>
</li>
<li><p>Internal tools and admin panels</p>
</li>
</ul>
<p><strong>Live Examples:</strong></p>
<ul>
<li><p><strong>Figma</strong> - Design tool interface</p>
</li>
<li><p><strong>Discord</strong> - Chat application</p>
</li>
<li><p><strong>Spotify Web Player</strong> - Music streaming interface</p>
</li>
<li><p><strong>Notion</strong> - Note-taking app</p>
</li>
<li><p><strong>CodePen</strong> - Code editor</p>
</li>
</ul>
<p><strong>Pros:</strong><br />✅ Rich user interactions<br />✅ Fast navigation after initial load<br />✅ Reduced server load<br />✅ Great for app-like experiences<br />✅ Offline capabilities possible</p>
<p><strong>Cons:</strong><br />❌ Poor SEO by default (SEO engines see nothing on the page as they don’t typically run javascript)<br />❌ Slow initial page load<br />❌ Blank page while JavaScript loads<br />❌ Bundle size impacts performance<br />❌ Requires JavaScript enabled</p>
<hr />
<h2 id="heading-5-partial-hydration-the-selective-activation">5. Partial Hydration: The Selective Activation</h2>
<p><strong>What it is:</strong> Only specific parts of the page become interactive, leaving static content as-is. Like having some dishes ready to serve and some prepared fresh on demand.</p>
<p><strong>How it works:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Astro partial hydration example</span>
---
<span class="hljs-comment">// This runs on the server</span>
<span class="hljs-keyword">const</span> staticData = <span class="hljs-keyword">await</span> fetchStaticContent();
---

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Static content --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>{staticData.title}<span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Only this component becomes interactive --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">SearchBox</span> <span class="hljs-attr">client:load</span> /&gt;</span>

    <span class="hljs-comment">&lt;!-- Static again --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span>{staticData.footer}<span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></span>

<span class="hljs-comment">// SearchBox.jsx - Only this becomes interactive</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SearchBox</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [query, setQuery] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-comment">// Interactive logic here</span>
}
</code></pre>
<p><strong>Tech Stack:</strong> Astro, Fresh (Deno), Marko, Qwik</p>
<p><strong>Architecture:</strong></p>
<pre><code class="lang-plaintext">Server:
[Generate Static HTML] → [Mark Interactive Islands] → [Send to Browser]

Browser:
[Render Static] → [Hydrate Islands Only] → [Interactive Components]
</code></pre>
<p><strong>Perfect for:</strong></p>
<ul>
<li><p>Content-heavy sites with interactive widgets</p>
</li>
<li><p>Blogs with interactive components</p>
</li>
<li><p>Marketing sites with forms/search</p>
</li>
<li><p>Documentation with live examples</p>
</li>
<li><p>E-commerce with interactive features</p>
</li>
</ul>
<p><strong>Live Examples:</strong></p>
<ul>
<li><p><strong>Shopify's blog</strong> - Static content with interactive cart</p>
</li>
<li><p><strong>Astro's documentation</strong> - Static docs with interactive search</p>
</li>
<li><p><strong>The Guardian</strong> - Articles with interactive polls/widgets</p>
</li>
</ul>
<p><strong>Pros:</strong><br />✅ Best performance for content sites<br />✅ SEO-friendly<br />✅ Minimal JavaScript<br />✅ Progressive enhancement<br />✅ Fast Core Web Vitals</p>
<p><strong>Cons:</strong><br />❌ Limited framework support<br />❌ Complex state management between islands<br />❌ Learning curve for new concepts<br />❌ Less suitable for app-like experiences</p>
<hr />
<h2 id="heading-6-streaming-ssr-the-live-kitchen-show">6. Streaming SSR: The Live Kitchen Show</h2>
<p><strong>What it is:</strong> The server sends HTML in chunks as it's generated, showing content progressively. Like a live cooking show where you see each ingredient added.</p>
<p><strong>How it works:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// React 18 Streaming example</span>
<span class="hljs-keyword">import</span> { Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        {/* This renders immediately */}
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>My App<span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        {/* This streams in when ready */}
        <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">div</span>&gt;</span>Loading posts...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>}&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">AsyncPosts</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>

        {/* This also streams in independently */}
        <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">div</span>&gt;</span>Loading sidebar...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>}&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">AsyncSidebar</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AsyncPosts</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> fetchPosts(); <span class="hljs-comment">// This can take time</span>
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">PostList</span> <span class="hljs-attr">posts</span>=<span class="hljs-string">{posts}</span> /&gt;</span></span>;
}
</code></pre>
<p><strong>Tech Stack:</strong> Next.js 13+, Remix, SvelteKit, React 18+ with Streaming</p>
<p><strong>Architecture:</strong></p>
<pre><code class="lang-plaintext">Request:
[User] → [Server] → [Stream Header] → [Stream Component 1] → [Stream Component 2] → [Complete]
                      ↓                ↓                    ↓
                 [User sees]      [User sees]          [User sees]
</code></pre>
<p><strong>Perfect for:</strong></p>
<ul>
<li><p>News websites</p>
</li>
<li><p>Social media feeds</p>
</li>
<li><p>E-commerce with multiple data sources</p>
</li>
<li><p>Content platforms</p>
</li>
<li><p>Real-time applications</p>
</li>
</ul>
<p><strong>Live Examples:</strong></p>
<ul>
<li><p><strong>Instagram web</strong> - Stories and feed streaming</p>
</li>
<li><p><strong>Amazon</strong> - Product recommendations stream in</p>
</li>
<li><p><strong>YouTube</strong> - Comments load progressively</p>
</li>
<li><p><strong>LinkedIn</strong> - Feed content streams</p>
</li>
</ul>
<p><strong>Pros:</strong><br />✅ Perceived performance improvement<br />✅ Better Core Web Vitals<br />✅ SEO-friendly<br />✅ Progressive content loading<br />✅ Reduced Time to First Byte perception</p>
<p><strong>Cons:</strong><br />❌ Complex implementation<br />❌ Debugging challenges<br />❌ Requires modern frameworks<br />❌ Browser compatibility considerations</p>
<hr />
<h2 id="heading-7-edge-side-rendering-esr-the-distributed-kitchen">7. Edge-Side Rendering (ESR): The Distributed Kitchen</h2>
<p><strong>What it is:</strong> Rendering happens on edge servers close to users. Like having mini-kitchens in every neighborhood.</p>
<p><strong>How it works:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Vercel Edge Runtime example</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  <span class="hljs-attr">runtime</span>: <span class="hljs-string">'edge'</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">request</span>) </span>{
  <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">new</span> URL(request.url);
  <span class="hljs-keyword">const</span> country = request.geo?.country || <span class="hljs-string">'US'</span>;

  <span class="hljs-comment">// Generate content based on user location</span>
  <span class="hljs-keyword">const</span> localizedContent = <span class="hljs-keyword">await</span> generateContent(country);

  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(
    <span class="hljs-string">`&lt;html&gt;
      &lt;body&gt;
        &lt;h1&gt;Welcome from <span class="hljs-subst">${country}</span>!&lt;/h1&gt;
        <span class="hljs-subst">${localizedContent}</span>
      &lt;/body&gt;
    &lt;/html&gt;`</span>,
    {
      <span class="hljs-attr">headers</span>: { <span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span> },
    }
  );
}
</code></pre>
<p><strong>Tech Stack:</strong> Vercel Edge Functions, Cloudflare Workers, Deno Deploy, AWS Lambda@Edge</p>
<p><strong>Architecture:</strong></p>
<pre><code class="lang-plaintext">[User in Tokyo] → [Tokyo Edge Server] → [Generate HTML] → [User]
[User in London] → [London Edge Server] → [Generate HTML] → [User]
[User in NYC] → [NYC Edge Server] → [Generate HTML] → [User]
</code></pre>
<p><strong>Perfect for:</strong></p>
<ul>
<li><p>Global applications</p>
</li>
<li><p>Personalization based on location</p>
</li>
<li><p>A/B testing</p>
</li>
<li><p>Authentication middleware</p>
</li>
<li><p>Content localization</p>
</li>
</ul>
<p><strong>Live Examples:</strong></p>
<ul>
<li><p><strong>Shopify</strong> - Store localization</p>
</li>
<li><p><strong>Cloudflare's dashboard</strong> - Edge-rendered analytics</p>
</li>
<li><p><strong>Vercel's analytics</strong> - Real-time data processing</p>
</li>
</ul>
<p><strong>Pros:</strong><br />✅ Ultra-low latency<br />✅ Global scalability<br />✅ Reduced origin server load<br />✅ Geographic personalization<br />✅ Better performance worldwide</p>
<p><strong>Cons:</strong><br />❌ Limited runtime capabilities<br />❌ Cold start latency<br />❌ Vendor lock-in<br />❌ Debugging complexity<br />❌ Limited database access</p>
<hr />
<h2 id="heading-choosing-the-right-strategy-the-decision-matrix">Choosing the Right Strategy: The Decision Matrix</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Strategy</td><td>Initial Load</td><td>SEO</td><td>Real-time Data</td><td>Scalability</td><td>Complexity</td></tr>
</thead>
<tbody>
<tr>
<td><strong>SSG</strong></td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>❌</td><td>⭐⭐⭐⭐</td><td>⭐⭐</td></tr>
<tr>
<td><strong>ISR</strong></td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐</td></tr>
<tr>
<td><strong>SSR</strong></td><td>⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐</td><td>⭐⭐⭐</td></tr>
<tr>
<td><strong>CSR</strong></td><td>⭐⭐</td><td>⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td><td>⭐⭐</td></tr>
<tr>
<td><strong>Partial Hydration</strong></td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐</td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td></tr>
<tr>
<td><strong>Streaming</strong></td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td></tr>
<tr>
<td><strong>ESR</strong></td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td></tr>
</tbody>
</table>
</div><h2 id="heading-quick-decision-guide">Quick Decision Guide</h2>
<p><strong>Choose SSG when:</strong></p>
<ul>
<li><p>Content doesn't change frequently</p>
</li>
<li><p>SEO is crucial</p>
</li>
<li><p>You want maximum performance</p>
</li>
<li><p>Budget is limited</p>
</li>
</ul>
<p><strong>Choose ISR when:</strong></p>
<ul>
<li><p>You have thousands of pages</p>
</li>
<li><p>Content updates regularly but not real-time</p>
</li>
<li><p>You need both performance and freshness</p>
</li>
<li><p>You're using Next.js</p>
</li>
</ul>
<p><strong>Choose SSR when:</strong></p>
<ul>
<li><p>You need personalized content</p>
</li>
<li><p>Data changes frequently</p>
</li>
<li><p>SEO is important</p>
</li>
<li><p>You have server infrastructure</p>
</li>
</ul>
<p><strong>Choose CSR when:</strong></p>
<ul>
<li><p>Building an interactive app</p>
</li>
<li><p>SEO isn't a priority</p>
</li>
<li><p>You need rich user interactions</p>
</li>
<li><p>Real-time updates are crucial</p>
</li>
</ul>
<p><strong>Choose Partial Hydration when:</strong></p>
<ul>
<li><p>You have mostly static content</p>
</li>
<li><p>You need some interactivity</p>
</li>
<li><p>Performance is critical</p>
</li>
<li><p>You're okay with newer tech</p>
</li>
</ul>
<p><strong>Choose Streaming when:</strong></p>
<ul>
<li><p>You have multiple data sources</p>
</li>
<li><p>User experience is priority</p>
</li>
<li><p>You're using modern frameworks</p>
</li>
<li><p>Performance optimization is key</p>
</li>
</ul>
<p><strong>Choose ESR when:</strong></p>
<ul>
<li><p>You have global users</p>
</li>
<li><p>Latency is critical</p>
</li>
<li><p>You need geographic personalization</p>
</li>
<li><p>You have edge infrastructure</p>
</li>
</ul>
<h2 id="heading-hybrid-approaches-the-best-of-all-worlds">Hybrid Approaches: The Best of All Worlds</h2>
<p>Many modern applications combine multiple strategies:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Next.js App Router example combining strategies</span>
app/
├── page.js              <span class="hljs-comment">// SSG for homepage</span>
├── blog/
│   └── [slug]/
│       └── page.js      <span class="hljs-comment">// ISR for blog posts</span>
├── dashboard/
│   └── page.js          <span class="hljs-comment">// SSR for user dashboard</span>
└── app/
    └── page.js          <span class="hljs-comment">// CSR for interactive app</span>
</code></pre>
<h2 id="heading-performance-tips">Performance Tips</h2>
<ol>
<li><p><strong>Measure First:</strong> Use tools like Lighthouse, WebPageTest, and Core Web Vitals</p>
</li>
<li><p><strong>Progressive Enhancement:</strong> Start with SSG/SSR, add interactivity progressively</p>
</li>
<li><p><strong>Code Splitting:</strong> Only load JavaScript when needed</p>
</li>
<li><p><strong>Caching Strategy:</strong> Use CDNs, browser cache, and server-side caching effectively</p>
</li>
<li><p><strong>Monitor Real Users:</strong> Use RUM (Real User Monitoring) tools</p>
</li>
</ol>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Choosing the right rendering strategy is like choosing the right tool for the job. A hammer is great for nails but terrible for screws. Each rendering approach has its sweet spot:</p>
<ul>
<li><p><strong>Static sites</strong> → SSG/ISR</p>
</li>
<li><p><strong>Apps with real-time data</strong> → SSR/CSR</p>
</li>
<li><p><strong>Content + some interactivity</strong> → Partial Hydration</p>
</li>
<li><p><strong>Global performance</strong> → Edge rendering</p>
</li>
</ul>
<p>Remember: You don't have to pick just one! Modern applications often mix multiple strategies to get the best performance for each use case.</p>
<p>The key is understanding your users' needs, your content patterns, and your team's capabilities. Start simple, measure performance, and optimize based on real data.</p>
<p>Happy rendering, Coding Chefs! 🚀<br />A new day, another opportunity to build something secure and world-class! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Implementing Pixel Perfect Design as a Frontend Engineer]]></title><description><![CDATA[Hey there, Coding Chefs! 👨‍💻
Have you ever received a beautiful Figma design, felt confident about implementing it, then somehow ended up with something that looks... well, nothing like the original? The spacing is off, the colors don't quite match...]]></description><link>https://crackedchefs.devferanmi.xyz/implementing-pixel-perfect-design-as-a-frontend-engineer</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/implementing-pixel-perfect-design-as-a-frontend-engineer</guid><category><![CDATA[Frontend Development]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[figma]]></category><category><![CDATA[Figma to Code]]></category><category><![CDATA[#Figma #UXdesign #SoftwareDevelopment #DesignCollaboration #Prototyping #DesignHandoff #AssetManagement #UserTesting #EngineeringWorkflow #CollaborationTools]]></category><category><![CDATA[webdev]]></category><category><![CDATA[web]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Wed, 30 Jun 2021 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Hey there, Coding Chefs! 👨‍💻</p>
<p>Have you ever received a beautiful Figma design, felt confident about implementing it, then somehow ended up with something that looks... well, nothing like the original? The spacing is off, the colors don't quite match, the typography feels wrong, and you can't figure out why?</p>
<p>If you've been building websites or web applications, you've probably experienced this frustration. You stare at your implementation, then at the design, then back at your implementation, wondering how something that seemed so straightforward could go so wrong.</p>
<p>I know this pain intimately because I used to be absolutely terrible at translating designs into code. So bad, in fact, that I seriously considered switching from frontend to backend development just to avoid the constant design review sessions where designers would sit next to me, pointing out every tiny detail I'd missed.</p>
<p>But here's the thing - this isn't about being "bad at CSS" or lacking design skills. It's about a phenomenon I call "design implementation blindness" - and once you understand it, you can develop systems to overcome it completely.</p>
<p>The intention of this article is to walk you through how I went from dreading design implementation to consistently delivering pixel-perfect results, and share the visual testing methodology that changed everything for me.</p>
<p>Without further ado, let's get cooking,</p>
<h2 id="heading-my-design-implementation-nightmarefrustrations">My Design Implementation Nightmare/Frustrations</h2>
<p>Let me paint you a picture from my early career. I'd receive a beautiful Figma design - clean, modern, perfectly aligned. I'd spend hours implementing it, feeling pretty good about my progress. Then came the review session.</p>
<p>"The header padding should be 24px, not 20px."<br />"This button is 2px too wide."<br />"The line height on this text is creating too much space."<br />"The color is #3B82F6, not #4285F4."</p>
<p>And the worst part? I couldn't see these differences! To my eyes, my implementation looked exactly like the design. The designer would literally sit next to me, sometimes for hours, going through every element pixel by pixel.</p>
<p>It got so bad that I started avoiding frontend design implementations altogether. I remember thinking, "Maybe I'm just not cut out for this. Maybe I should focus on backend where things are more logical and less... visual."</p>
<p>But then I realized something important: this wasn't a skill problem. It was a systematic problem.</p>
<h2 id="heading-the-science-behind-design-implementation-blindness">The Science Behind Design Implementation Blindness</h2>
<p>Here's what I discovered: when you spend hours implementing a design, your brain starts building familiarity between what you're creating and what you're supposed to create. This familiarity creates a kind of cognitive blindness where your mind literally "fills in" the differences.</p>
<p>It's similar to how you might not notice typos in your own writing because your brain knows what you meant to write. When you're deep in implementation mode, your brain compensates for small discrepancies, making them invisible to you.</p>
<p>This happens because:</p>
<ol>
<li><p><strong>Pattern Recognition:</strong> Your brain recognizes the general structure and assumes the details are correct</p>
</li>
<li><p><strong>Attention Fatigue:</strong> After staring at the same elements for hours, you stop noticing small variations</p>
</li>
<li><p><strong>Context Switching:</strong> Moving between code and design repeatedly creates mental friction</p>
</li>
<li><p><strong>Confirmation Bias:</strong> You see what you expect to see, not what's actually there</p>
</li>
</ol>
<p>Understanding this helped me realize I needed a systematic approach to combat this blindness, not just "try harder" to be more detail-oriented.</p>
<h2 id="heading-my-visual-regression-testing-method">My Visual Regression Testing Method</h2>
<p>The breakthrough came when I developed a methodical approach that removes the guesswork and cognitive bias from design implementation. Here's the system that changed everything:</p>
<h3 id="heading-step-1-the-side-by-side-setup">Step 1: The Side-by-Side Setup</h3>
<p>Before writing any code, I set up my workspace for constant visual comparison:</p>
<pre><code class="lang-markdown">App/Monitor Setup:
<span class="hljs-code">        [Figma Design]                 [Browser] 
     Split-Screen - 50%                     50%</span>
</code></pre>
<p>The key is having the design and your implementation visible simultaneously at all times. No alt-tabbing, no mental comparisons - direct visual comparison.</p>
<h3 id="heading-step-2-component-by-component-implementation">Step 2: Component-by-Component Implementation</h3>
<p>Instead of building entire pages, I break everything down to the smallest possible components and implement them one by one:</p>
<p><strong>Wrong approach:</strong> Build entire homepage → Review everything at once → Get overwhelmed by feedback</p>
<p><strong>Right approach:</strong> Build button → Perfect it → Build input field → Perfect it → Build card → Perfect it → Compose them together</p>
<p>This approach has several benefits:</p>
<ul>
<li><p>Smaller scope means fewer variables to get wrong</p>
</li>
<li><p>Easier to spot discrepancies on isolated components</p>
</li>
<li><p>Problems don't compound across the entire page</p>
</li>
<li><p>You build attention to detail gradually</p>
</li>
</ul>
<p>I wrote an article entirely focused on components implementation <a target="_blank" href="https://crackedchefs.devferanmi.xyz/component-thinking-how-react-changed-my-entire-design-approach">here</a></p>
<h3 id="heading-step-3-the-pixel-inspection-ritual">Step 3: The Pixel Inspection Ritual</h3>
<p>For each component, I follow this inspection process:</p>
<ol>
<li><p><strong>Spacing Check:</strong> Use browser dev tools to verify margins, padding, and gaps</p>
</li>
<li><p><strong>Typography Check:</strong> Confirm font size, line height, letter spacing, and font weight</p>
</li>
<li><p><strong>Color Check:</strong> Use color picker tools to verify hex values match exactly</p>
</li>
<li><p><strong>Alignment Check:</strong> Ensure elements align with the design grid</p>
</li>
<li><p><strong>Responsive Check:</strong> Test behavior at different screen sizes</p>
</li>
</ol>
<h3 id="heading-step-4-the-100-match-verification">Step 4: The 100% Match Verification</h3>
<p>Before moving to the next component, I do a final verification:</p>
<ul>
<li><p>Screenshot my implementation</p>
</li>
<li><p>Place it side-by-side with the Figma design</p>
</li>
<li><p>Look for any visual differences</p>
</li>
<li><p>If I spot differences, fix them before proceeding</p>
</li>
</ul>
<p>Only when they're visually identical do I move forward.</p>
<h2 id="heading-practical-tools-and-techniques">Practical Tools and Techniques</h2>
<h3 id="heading-browser-developer-tools-setup">Browser Developer Tools Setup</h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// I use this CSS snippet during development to visualize spacing</span>
* {
  <span class="hljs-attr">outline</span>: <span class="hljs-number">1</span>px solid red;
}

<span class="hljs-comment">// Or for specific elements</span>
.debug {
  <span class="hljs-attr">outline</span>: <span class="hljs-number">1</span>px solid red;
  background: rgba(<span class="hljs-number">255</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
}
</code></pre>
<h3 id="heading-figma-to-css-translation">Figma to CSS Translation</h3>
<p>I extract exact values from Figma and create CSS custom properties:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-comment">/* Colors from Figma */</span>
  <span class="hljs-attribute">--primary-blue</span>: <span class="hljs-number">#3B82F6</span>;
  <span class="hljs-attribute">--text-gray</span>: <span class="hljs-number">#6B7280</span>;
  <span class="hljs-attribute">--background-white</span>: <span class="hljs-number">#FFFFFF</span>;

  <span class="hljs-comment">/* Spacing from Figma */</span>
  <span class="hljs-attribute">--spacing-xs</span>: <span class="hljs-number">4px</span>;
  <span class="hljs-attribute">--spacing-sm</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">--spacing-md</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">--spacing-lg</span>: <span class="hljs-number">24px</span>;

  <span class="hljs-comment">/* Typography from Figma */</span>
  <span class="hljs-attribute">--text-sm</span>: <span class="hljs-number">14px</span>;
  <span class="hljs-attribute">--text-base</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">--text-lg</span>: <span class="hljs-number">18px</span>;
  <span class="hljs-attribute">--line-height-tight</span>: <span class="hljs-number">1.25</span>;
  <span class="hljs-attribute">--line-height-normal</span>: <span class="hljs-number">1.5</span>;
}
</code></pre>
<h3 id="heading-the-screenshot-comparison-method">The Screenshot Comparison Method</h3>
<p>I take screenshots at different stages and create comparison grids:</p>
<pre><code class="lang-markdown">Original Design    |    My Implementation
<span class="hljs-code">    [Image]        |         [Image]
                   |
 After Feedback    |    Final Version  
    [Image]        |         [Image]</span>
</code></pre>
<p>This visual history helps me learn from mistakes and see improvement patterns.</p>
<h2 id="heading-dealing-with-design-ambiguity">Dealing with Design Ambiguity</h2>
<p>Sometimes designs aren't perfectly clear. Instead of guessing, I developed a system for handling ambiguity:</p>
<h3 id="heading-the-questions-framework">The Questions Framework</h3>
<p>Before implementing unclear elements, I ask:</p>
<ol>
<li><p><strong>Spacing:</strong> "What's the exact padding/margin here?"</p>
</li>
<li><p><strong>States:</strong> "How should this look on hover/focus/active?"</p>
</li>
<li><p><strong>Responsive:</strong> "How does this behave on mobile?"</p>
</li>
<li><p><strong>Edge cases:</strong> "What happens with long text or missing images?"</p>
</li>
</ol>
<h3 id="heading-documentation-during-implementation">Documentation During Implementation</h3>
<p>I document decisions and assumptions:</p>
<pre><code class="lang-markdown"><span class="hljs-section">## Implementation Notes</span>

<span class="hljs-section">### Header Component</span>
<span class="hljs-bullet">-</span> Used 24px padding (inferred from design grid)
<span class="hljs-bullet">-</span> Logo scales to 32px height on mobile (designer confirmed)
<span class="hljs-bullet">-</span> Navigation collapses at 768px breakpoint (standard practice)

<span class="hljs-section">### Button Component  </span>
<span class="hljs-bullet">-</span> Hover state darkens primary color by 10% (design system standard)
<span class="hljs-bullet">-</span> Focus outline uses brand blue (accessibility requirement)
</code></pre>
<h2 id="heading-the-transformation-results">The Transformation Results</h2>
<p>After implementing this system consistently, the changes were dramatic:</p>
<p><strong>Before:</strong></p>
<ul>
<li><p>Design reviews took 2-3 hours with multiple rounds of feedback</p>
</li>
<li><p>Constant back-and-forth with designers</p>
</li>
<li><p>High stress and low confidence</p>
</li>
<li><p>Considering switching to backend development</p>
</li>
</ul>
<p><strong>After:</strong></p>
<ul>
<li><p>First implementation usually 95%+ accurate</p>
</li>
<li><p>Design reviews became quick approval sessions</p>
</li>
<li><p>Designers started trusting my implementations</p>
</li>
<li><p>Confidence in frontend skills skyrocketed</p>
</li>
</ul>
<h2 id="heading-advanced-techniques">Advanced Techniques</h2>
<h3 id="heading-automated-visual-testing">Automated Visual Testing</h3>
<p>For larger projects, I started using tools for automated visual regression testing:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Example with Playwright for visual testing</span>
test(<span class="hljs-string">'header component matches design'</span>, <span class="hljs-keyword">async</span> ({ page }) =&gt; {
  <span class="hljs-keyword">await</span> page.goto(<span class="hljs-string">'/components/header'</span>);
  <span class="hljs-keyword">await</span> expect(page.locator(<span class="hljs-string">'.header'</span>)).toHaveScreenshot(<span class="hljs-string">'header-component.png'</span>);
});
</code></pre>
<h3 id="heading-design-system-integration">Design System Integration</h3>
<p>I created reusable components that enforce design consistency:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// Button component with design system constraints</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">{ 
  variant = <span class="hljs-string">'primary'</span>, 
  size = <span class="hljs-string">'md'</span>, 
  children, 
  ...props 
}</span>) </span>{
  <span class="hljs-keyword">const</span> baseClasses = <span class="hljs-string">'btn font-semibold rounded-lg transition-colors'</span>;
  <span class="hljs-keyword">const</span> variantClasses = {
    <span class="hljs-attr">primary</span>: <span class="hljs-string">'bg-blue-600 text-white hover:bg-blue-700'</span>,
    <span class="hljs-attr">secondary</span>: <span class="hljs-string">'bg-gray-200 text-gray-900 hover:bg-gray-300'</span>
  };
  <span class="hljs-keyword">const</span> sizeClasses = {
    <span class="hljs-attr">sm</span>: <span class="hljs-string">'px-3 py-1.5 text-sm'</span>,
    <span class="hljs-attr">md</span>: <span class="hljs-string">'px-4 py-2 text-base'</span>,
    <span class="hljs-attr">lg</span>: <span class="hljs-string">'px-6 py-3 text-lg'</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> 
      <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">baseClasses</span>} ${<span class="hljs-attr">variantClasses</span>[<span class="hljs-attr">variant</span>]} ${<span class="hljs-attr">sizeClasses</span>[<span class="hljs-attr">size</span>]}`}
      {<span class="hljs-attr">...props</span>}
    &gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  );
}
</code></pre>
<h3 id="heading-collaboration-improvements">Collaboration Improvements</h3>
<p>The systematic approach improved my collaboration with designers:</p>
<ol>
<li><p><strong>Shared vocabulary:</strong> We started using the same terms for spacing, colors, and typography</p>
</li>
<li><p><strong>Proactive communication:</strong> I'd share screenshots during implementation, not just at the end</p>
</li>
<li><p><strong>Design system evolution:</strong> My feedback helped improve the design system for developers</p>
</li>
</ol>
<h2 id="heading-common-pitfalls-and-how-to-avoid-them">Common Pitfalls and How to Avoid Them</h2>
<h3 id="heading-rushing-the-setup-phase">Rushing the Setup Phase</h3>
<p><strong>Mistake:</strong> Jumping straight into coding without proper planning and thinking.</p>
<p><strong>Solution:</strong> Always set up side-by-side comparison before writing any code. Follow my think first approach to <a target="_blank" href="https://crackedchefs.devferanmi.xyz/thought-driven-engineering-the-happy-path-episode-1">coding</a></p>
<h3 id="heading-implementing-too-much-at-once">Implementing Too Much at Once</h3>
<p><strong>Mistake:</strong> Building entire sections before checking accuracy<br /><strong>Solution:</strong> Work component by component, perfecting each piece</p>
<h3 id="heading-ignoring-edge-cases">Ignoring Edge Cases</h3>
<p><strong>Mistake:</strong> Only implementing the "happy path" shown in designs<br /><strong>Solution:</strong> Always ask about hover states, loading states, and responsive behavior</p>
<h3 id="heading-inconsistent-measurement">Inconsistent Measurement</h3>
<p><strong>Mistake:</strong> Eyeballing spacing and sizes instead of measuring<br /><strong>Solution:</strong> Always use dev tools to verify exact measurements</p>
<h2 id="heading-building-your-own-system">Building Your Own System</h2>
<p>Here's how to start implementing this approach:</p>
<h3 id="heading-1-setup-and-awareness">1: Setup and Awareness</h3>
<ul>
<li><p>Configure your workspace for side-by-side comparison</p>
</li>
<li><p>Start noticing when you make assumptions about designs</p>
</li>
<li><p>Take screenshots of your implementations vs designs</p>
</li>
</ul>
<h3 id="heading-2-component-by-component-practice">2: Component-by-Component Practice</h3>
<ul>
<li><p>Choose a simple design to implement</p>
</li>
<li><p>Break it into the smallest possible components</p>
</li>
<li><p>Perfect each component before moving to the next</p>
</li>
</ul>
<h3 id="heading-3-measurement-and-documentation">3: Measurement and Documentation</h3>
<ul>
<li><p>Start extracting exact values from designs</p>
</li>
<li><p>Document your implementation decisions</p>
</li>
<li><p>Create a simple design system for your components</p>
</li>
</ul>
<h3 id="heading-4-review-and-refine">4: Review and Refine</h3>
<ul>
<li><p>Review your progress and accuracy improvements</p>
</li>
<li><p>Identify patterns in the mistakes you make</p>
</li>
<li><p>Refine your process based on what you learned</p>
</li>
</ul>
<h2 id="heading-the-mindset-shift">The Mindset Shift</h2>
<p>The biggest change wasn't technical - it was mental. I went from viewing design implementation as a creative guessing game to treating it as a systematic, measurable process.</p>
<p><strong>Old mindset:</strong> "This looks about right"<br /><strong>New mindset:</strong> "This measures exactly right"</p>
<p><strong>Old mindset:</strong> "Close enough is good enough"<br /><strong>New mindset:</strong> "Pixel perfect is the standard"</p>
<p><strong>Old mindset:</strong> "I'll fix it in review"<br /><strong>New mindset:</strong> "I'll get it right the first time"</p>
<p>This shift transformed not just my design implementation skills, but my entire approach to frontend development.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>What started as my biggest weakness in frontend development became one of my greatest strengths. The systematic approach to visual accuracy didn't just improve my design implementation - it made me a more methodical, detail-oriented developer overall.</p>
<p>The key insights that changed everything:</p>
<ul>
<li><p><strong>Design implementation blindness</strong> is a real cognitive phenomenon, not a skill deficiency</p>
</li>
<li><p><strong>Systematic comparison</strong> removes guesswork and bias from the process</p>
</li>
<li><p><strong>Component-by-component implementation</strong> prevents problems from compounding</p>
</li>
<li><p><strong>Exact measurement</strong> beats visual estimation every time</p>
</li>
<li><p><strong>Documentation and process</strong> turn accuracy into a repeatable skill</p>
</li>
</ul>
<p>If you're struggling with design implementation, remember: this isn't about natural talent or having a "good eye." It's about having a good system.</p>
<p>The next time you receive a design to implement:</p>
<ul>
<li><p>Set up proper side-by-side comparison</p>
</li>
<li><p>Break it down into the smallest components</p>
</li>
<li><p>Measure everything, assume nothing</p>
</li>
<li><p>Perfect each piece before combining them</p>
</li>
</ul>
<p>You might feel like you're moving slower at first, being so methodical about every detail. But trust me - the long-term benefits in accuracy, confidence, and designer relationships are absolutely worth it.</p>
<p>A new day, another opportunity to build pixel perfect interfaces! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Beginner's guide to Javascript LocalStorage]]></title><description><![CDATA[The web is now dominated with more frontend web applications than ever, alas increasing the yearn to keep data on the browser for future purposes.

You might be building the next-generation e-commerce platform and want to keep cart data on the browse...]]></description><link>https://crackedchefs.devferanmi.xyz/beginners-guide-to-javascript-localstorage</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/beginners-guide-to-javascript-localstorage</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[CSS]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Fri, 21 Aug 2020 14:27:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1598020044252/wbMzA5d6_.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>The web is now dominated with more frontend web applications than ever, alas increasing the yearn to keep data on the browser for future purposes.</p>
</blockquote>
<p>You might be building the next-generation e-commerce platform and want to keep cart data on the browser or even building a simple todo list app.
No doubt, Javascript's localStorage API is a very easy way to make that possible on the browser. We'll be using the localStorage API to save and retrieve details of cities across the world.
This tutorial is targeted towards developers with basic knowledge of javascript, If you haven't started  Javascript before, I recommend you should read my previous article.</p>
<p>To get started, I recommend you have a browser, a code editor to punch in some codes, and of course a cup of coffee to roll along.</p>
<p><strong>Let's dive in</strong></p>
<p>Javascript LocalStorage is an application programming interface that allows access to saving and retrieving data on the client's computer. At its very basic level, it is an object and can be accessed across all sub-domains of an application.</p>
<p>What I mean is If you save an item to localStorage on website.com, You can still access it on developers.website.com but never from another domain.</p>
<p>So now you understand what Localstorage really is, Let's get to code.</p>
<p>Assuming we have a list of cities to be 'Cairo, Japan, Ogbomoso, Lagos, New York City',
We can save this to the localStorage as a string and also receive it.</p>
<p>To save this to localStorage we can use </p>
<p>localStorage.setItem(key,item) or localstorage.itemname = item;</p>
<p>Let's break it down:</p>
<p><strong>key</strong> is the unique name you have chosen to save an item, so In our case, we are saving cities, So our key would be cities. 
It is important to note that, the key is also the name you'll use to retrieve back your saved data.
Furthermore, If a key already exists in the localStorage, the new name will overwrite the previous data. So Imagine we already stored cities, our new cities will displace/delete the previous one and replace it.</p>
<p><strong>Saving Data into localStorage : </strong></p>
<pre><code> <span class="hljs-keyword">var</span> cities = <span class="hljs-string">'Cairo,Japan,Ogbomoso,Lagos,New York'</span>; <span class="hljs-comment">//variable containing cities</span>
<span class="hljs-comment">//to save cities ,we'll use localstorage.setItem</span>
localStorage.setItem(<span class="hljs-string">'cities'</span>,cities); <span class="hljs-comment">//or localStorage.cities = cities;</span>
<span class="hljs-comment">//the first parameter is the unique name we are using to save it and the second paremeter  is the data we're saving</span>
</code></pre><p><strong>Retrieving Data from LocalStorage </strong>
To retrieve data from localStorage we'll use the localStorage.get(key) or localStorage.itemname;
In this case, we'll be retrieving our list of cities(key).</p>
<pre><code><span class="hljs-keyword">var</span> cities = localStorage.getItem(<span class="hljs-string">'cities'</span>); <span class="hljs-comment">//or localStorage.cities;</span>
<span class="hljs-comment">//  'Cairo,Japan,Ogbomoso,Lagos,New York'</span>
</code></pre><p>We talked about saving and retrieving, what of deleting? 
Oh yeah, It's essential to have a delete option too.
We can remove an item/data from localStorage by referencing the key by using 
localStorage.removeItem(key).
In our case, we might want to remove 'cities' from the database.</p>
<pre><code> <span class="hljs-built_in">local</span>Storage.removeItem(key);
</code></pre><p>And that's all about localStorage.If you have any questions or contributions feel free to drop them in the comments section.</p>
<pre><code>A <span class="hljs-keyword">new</span> day another opportunity to be world-<span class="hljs-class"><span class="hljs-keyword">class</span>.</span>
</code></pre>]]></content:encoded></item><item><title><![CDATA[Component Thinking: How React Changed My Entire Design Approach]]></title><description><![CDATA[Hey there, Coding Chefs! 👨‍💻
Ever built a website where you had to copy the same header HTML to 15 different pages? Then later, when you needed to add just one link to that header, you had to hunt down and update all 15 files? Yeah, that's the nigh...]]></description><link>https://crackedchefs.devferanmi.xyz/component-thinking-how-react-changed-my-entire-design-approach</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/component-thinking-how-react-changed-my-entire-design-approach</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[architecture]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Thu, 14 May 2020 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Hey there, Coding Chefs! 👨‍💻</p>
<p>Ever built a website where you had to copy the same header HTML to 15 different pages? Then later, when you needed to add just one link to that header, you had to hunt down and update all 15 files? Yeah, that's the nightmare I'm talking about.</p>
<p>If you're a developer who's been building websites or web apps, you've probably experienced this pain. You start with good intentions building clean, working pages. But as your project grows, you realize you're duplicating the same pieces of code everywhere. Navigation bars, user cards, buttons, forms - the same HTML and CSS scattered across multiple files.</p>
<p>What starts as a quick copy-paste solution slowly becomes a maintenance nightmare. Want to change a button style? Hope you remember all the places you used it. Need to add a new navigation item? Get ready for some serious find-and-replace action.</p>
<p>There's a better way to think about building user interfaces - something called "component thinking." And for me, learning this concept through React didn't just change how I wrote code; it completely rewired how I approach design and development.</p>
<p>The intention of this article is to walk you through this transformation - how I went from copying and pasting code everywhere to building reusable, maintainable component systems. Whether you're using React, Vue, Angular, or even vanilla JavaScript, this mindset shift will change how you build interfaces forever.</p>
<p>Without further ado, let's get cooking,</p>
<h2 id="heading-the-copy-paste-nightmare">The Copy-Paste Nightmare</h2>
<p>Picture this: You're excited about a new project. You dive straight into coding, building beautiful pages with HTML and CSS. Everything looks great, users are happy, and you feel like a rockstar developer.</p>
<p>Then comes the inevitable request: "Can you update the header design across all pages?"</p>
<p>Suddenly, you realize you've copied the same header code to 15 different files. What should be a 5-minute change becomes a 2-hour hunt-and-replace mission, and you're terrified you'll miss one and break the entire design consistency.</p>
<p>This was my reality when I built "Lauchat" - a chat platform for university students during the holidays. I was so eager to build something real that I jumped straight into implementation without thinking about reusability or maintainability.</p>
<p>Here's what my approach looked like:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- page1.html --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"logo"</span>&gt;</span>Lauchat<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/home"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/messages"</span>&gt;</span>Messages<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/profile"</span>&gt;</span>Profile<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"user-info"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Welcome, John<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"avatar.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"User Avatar"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-comment">&lt;!-- page2.html --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"logo"</span>&gt;</span>Lauchat<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/home"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/messages"</span>&gt;</span>Messages<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/profile"</span>&gt;</span>Profile<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"user-info"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Welcome, John<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"avatar.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"User Avatar"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-comment">&lt;!-- ...and 13 more files with the exact same code --&gt;</span>
</code></pre>
<p>Every page had the same header, the same navigation, the same user cards, the same everything. When I needed to add a notification icon to the header, I had to update 15 different files. When I wanted to change the styling, I had to hunt down every instance.</p>
<p>The codebase became bloated, heavy, and incredibly slow to maintain. Adding new features felt like walking through a minefield - one wrong move and something else would break.</p>
<h2 id="heading-the-react-revelation">The React Revelation</h2>
<p>Then I discovered React, and everything changed.</p>
<p>At first, I didn't understand the hype. "Why do I need this complex framework when I can just write HTML and CSS?" I thought. But when I learned about components, something clicked in my brain that fundamentally altered how I think about building interfaces.</p>
<p>React introduced me to a simple but powerful concept: <strong>reusable, self-contained pieces of UI</strong>.</p>
<p>Here's how that same header would look as a React component:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// Header.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Header</span>(<span class="hljs-params">{ username, avatar }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"logo"</span>&gt;</span>Lauchat<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Navigation</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">UserInfo</span> <span class="hljs-attr">username</span>=<span class="hljs-string">{username}</span> <span class="hljs-attr">avatar</span>=<span class="hljs-string">{avatar}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Navigation.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Navigation</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/home"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/messages"</span>&gt;</span>Messages<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/profile"</span>&gt;</span>Profile<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// UserInfo.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserInfo</span>(<span class="hljs-params">{ username, avatar }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user-info"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Welcome, {username}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{avatar}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"User Avatar"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Usage in any page</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomePage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> <span class="hljs-attr">username</span>=<span class="hljs-string">"John"</span> <span class="hljs-attr">avatar</span>=<span class="hljs-string">"avatar.jpg"</span> /&gt;</span>
      {/* Page content */}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Suddenly, that 15-file update nightmare became a single change in one component file. Need to add a notification icon? Update the Header component once, and it appears everywhere. Want to change the navigation? Modify the Navigation component, and every page updates automatically.</p>
<h2 id="heading-the-mental-shift-from-pages-to-components">The Mental Shift: From Pages to Components</h2>
<p>Learning React didn't just teach me a new syntax - it completely rewired how I think about user interfaces.</p>
<p><strong>Before React (Page Thinking):</strong></p>
<ul>
<li><p>I designed entire pages as monolithic blocks</p>
</li>
<li><p>Repeated elements were copy-pasted</p>
</li>
<li><p>Changes required hunting through multiple files</p>
</li>
<li><p>Inconsistencies crept in over time</p>
</li>
</ul>
<p><strong>After React (Component Thinking):</strong></p>
<ul>
<li><p>I break designs into small, reusable pieces</p>
</li>
<li><p>Each piece has a single responsibility</p>
</li>
<li><p>Changes happen in one place and propagate everywhere</p>
</li>
<li><p>Consistency is enforced by the architecture</p>
</li>
</ul>
<p>This shift changed everything about my design process. Now, when I look at a Figma design, I don't see pages - I see components.</p>
<p>Looking at a typical landing page, I might identify:</p>
<ul>
<li><p>Header component</p>
</li>
<li><p>Hero section component</p>
</li>
<li><p>Feature card component (reused 3 times)</p>
</li>
<li><p>Testimonial component (reused 5 times)</p>
</li>
<li><p>Footer component</p>
</li>
</ul>
<p>Each component becomes a building block that I can use, reuse, and combine to create complex interfaces.</p>
<h2 id="heading-my-component-design-framework">My Component Design Framework</h2>
<p>Over time, I developed a simple framework for deciding what should be a component:</p>
<h3 id="heading-1-the-reusability-test">1. The Reusability Test</h3>
<p><strong>Question:</strong> Will this UI pattern appear in more than one place?</p>
<p>If yes, it's probably a component. Even if you're not sure, erring on the side of componentization usually pays off.</p>
<h3 id="heading-2-the-responsibility-test">2. The Responsibility Test</h3>
<p><strong>Question:</strong> Does this piece of UI have a single, clear purpose?</p>
<p>A button that submits a form? Component. A card that displays user information? Component. A section that does five different things? Probably needs to be broken down.</p>
<h3 id="heading-3-the-independence-test">3. The Independence Test</h3>
<p><strong>Question:</strong> Can this piece of UI function on its own with just props?</p>
<p>Good components are like pure functions - given the same inputs, they produce the same output. They don't depend on global state or external side effects to function.</p>
<h3 id="heading-4-the-naming-test">4. The Naming Test</h3>
<p><strong>Question:</strong> Can I give this a clear, descriptive name?</p>
<p>If you can't name it clearly, it probably doesn't have a clear purpose. "UserProfileCard" is good. "LeftSidebarThingWithStuff" is not.</p>
<h2 id="heading-real-impact-on-development">Real Impact on Development</h2>
<p>The transformation wasn't just theoretical - it had immediate, practical benefits:</p>
<p><strong>Development Speed:</strong> Instead of building the same UI elements repeatedly, I could focus on building new components and composing existing ones.</p>
<p><strong>Maintenance:</strong> Bug fixes and design updates became single-file changes instead of project-wide hunts.</p>
<p><strong>Consistency:</strong> When everything uses the same Button component, all buttons behave consistently across the application.</p>
<p><strong>Testing:</strong> I could test components in isolation, making it easier to catch and fix issues.</p>
<p><strong>Collaboration:</strong> Other developers could use my components without understanding their implementation details.</p>
<h2 id="heading-a-practical-example">A Practical Example</h2>
<p>Let me show you how this plays out with a common pattern - user cards.</p>
<p><strong>Old Approach (Copy-Paste Hell):</strong></p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- In messages.html --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"user-card"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"user1.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"User 1"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"user-info"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>John Doe<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"status"</span>&gt;</span>Online<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"message-btn"</span>&gt;</span>Send Message<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-comment">&lt;!-- In contacts.html --&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"user-card"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"user2.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"User 2"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"user-info"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Jane Smith<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"status"</span>&gt;</span>Away<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"message-btn"</span>&gt;</span>Send Message<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-comment">&lt;!-- ...copied 20 more times across different files --&gt;</span>
</code></pre>
<p><strong>Component Approach:</strong></p>
<pre><code class="lang-jsx"><span class="hljs-comment">// UserCard.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserCard</span>(<span class="hljs-params">{ user, onMessageClick }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{user.avatar}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{user.name}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user-info"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">status</span> ${<span class="hljs-attr">user.status.toLowerCase</span>()}`}&gt;</span>
          {user.status}
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> 
          <span class="hljs-attr">className</span>=<span class="hljs-string">"message-btn"</span> 
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> onMessageClick(user.id)}
        &gt;
          Send Message
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Usage anywhere</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ContactsList</span>(<span class="hljs-params">{ contacts }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"contacts"</span>&gt;</span>
      {contacts.map(user =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">UserCard</span> 
          <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>
          <span class="hljs-attr">user</span>=<span class="hljs-string">{user}</span>
          <span class="hljs-attr">onMessageClick</span>=<span class="hljs-string">{handleMessageClick}</span>
        /&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>With this approach:</p>
<ul>
<li><p>Need to add a "call" button? One change in UserCard.jsx</p>
</li>
<li><p>Want to show different status colors? Update the CSS class logic once</p>
</li>
<li><p>Need to track analytics on message button clicks? Add it to the onClick handler once</p>
</li>
</ul>
<h2 id="heading-the-ripple-effect">The Ripple Effect</h2>
<p>Component thinking didn't just improve my React code - it changed how I approach all frontend development.</p>
<p>Even when I work with other frameworks or vanilla JavaScript, I think in terms of:</p>
<ul>
<li><p>Reusable modules</p>
</li>
<li><p>Single responsibility</p>
</li>
<li><p>Clear interfaces</p>
</li>
<li><p>Composition over duplication</p>
</li>
</ul>
<p>This mindset has made me a better developer across all technologies, not just React.</p>
<h2 id="heading-types-of-components-understanding-your-building-blocks">Types of Components: Understanding Your Building Blocks</h2>
<p>Not all components are created equal. Over time, I've learned to categorize components based on their purpose and behavior. This helps with organization, naming, and knowing where to put your logic.</p>
<h3 id="heading-ui-components-the-visual-layer">UI Components (The Visual Layer)</h3>
<p>These are your pure visual elements - they receive props and render UI without any complex logic.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// Button.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">{ variant = <span class="hljs-string">'primary'</span>, size = <span class="hljs-string">'md'</span>, children, onClick }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> 
      <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">btn</span> <span class="hljs-attr">btn-</span>${<span class="hljs-attr">variant</span>} <span class="hljs-attr">btn-</span>${<span class="hljs-attr">size</span>}`}
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClick}</span>
    &gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Input.jsx  </span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Input</span>(<span class="hljs-params">{ label, type = <span class="hljs-string">'text'</span>, placeholder, value, onChange }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"input-group"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>{label}<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
        <span class="hljs-attr">type</span>=<span class="hljs-string">{type}</span>
        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">{placeholder}</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">{value}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{onChange}</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>When to use:</strong> For basic visual elements that don't manage their own state.</p>
<h3 id="heading-layout-components-the-structure">Layout Components (The Structure)</h3>
<p>These components handle positioning, spacing, and overall page structure.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// Container.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Container</span>(<span class="hljs-params">{ children, maxWidth = <span class="hljs-string">'1200px'</span> }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">maxWidth</span> }}&gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Grid.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Grid</span>(<span class="hljs-params">{ columns = <span class="hljs-number">3</span>, gap = <span class="hljs-string">'1rem'</span>, children }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> 
      <span class="hljs-attr">className</span>=<span class="hljs-string">"grid"</span>
      <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> 
        <span class="hljs-attr">display:</span> '<span class="hljs-attr">grid</span>', 
        <span class="hljs-attr">gridTemplateColumns:</span> `<span class="hljs-attr">repeat</span>(${<span class="hljs-attr">columns</span>}, <span class="hljs-attr">1fr</span>)`, 
        <span class="hljs-attr">gap</span> 
      }}
    &gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>When to use:</strong> For consistent spacing, layouts, and responsive design patterns.</p>
<h3 id="heading-stateful-components-the-smart-ones">Stateful Components (The Smart Ones)</h3>
<p>These components manage their own internal state and handle user interactions.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// SearchBox.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SearchBox</span>(<span class="hljs-params">{ onSearch }</span>) </span>{
  <span class="hljs-keyword">const</span> [query, setQuery] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    setIsLoading(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">await</span> onSearch(query);
    setIsLoading(<span class="hljs-literal">false</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Input</span> 
        <span class="hljs-attr">value</span>=<span class="hljs-string">{query}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setQuery(e.target.value)}
        placeholder="Search..."
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">disabled</span>=<span class="hljs-string">{isLoading}</span>&gt;</span>
        {isLoading ? 'Searching...' : 'Search'}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>When to use:</strong> When you need to manage form inputs, toggles, or any interactive behavior.</p>
<h3 id="heading-widget-components-the-feature-blocks">Widget Components (The Feature Blocks)</h3>
<p>These are self-contained features that combine multiple components and handle their own data fetching.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// UserProfileWidget.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfileWidget</span>(<span class="hljs-params">{ userId }</span>) </span>{
  <span class="hljs-keyword">const</span> [user, setUser] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">true</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetchUser(userId).then(<span class="hljs-function"><span class="hljs-params">userData</span> =&gt;</span> {
      setUser(userData);
      setIsLoading(<span class="hljs-literal">false</span>);
    });
  }, [userId]);

  <span class="hljs-keyword">if</span> (isLoading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">LoadingSpinner</span> /&gt;</span></span>;
  <span class="hljs-keyword">if</span> (!user) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ErrorMessage</span> <span class="hljs-attr">message</span>=<span class="hljs-string">"User not found"</span> /&gt;</span></span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Card</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Avatar</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{user.avatar}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{user.name}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">UserInfo</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{user.name}</span> <span class="hljs-attr">email</span>=<span class="hljs-string">{user.email}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">UserActions</span> <span class="hljs-attr">userId</span>=<span class="hljs-string">{userId}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Card</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>When to use:</strong> For complete features that can be dropped into any page independently.</p>
<h3 id="heading-pure-components-the-predictable-ones">Pure Components (The Predictable Ones)</h3>
<p>These components always render the same output for the same inputs - no side effects, no state changes.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// ProductCard.jsx (Pure component)</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductCard</span>(<span class="hljs-params">{ product }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"product-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.name}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"price"</span>&gt;</span>${product.price}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"description"</span>&gt;</span>{product.description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>When to use:</strong> For components that are purely presentational and don't need to manage state or side effects.</p>
<h2 id="heading-code-organization-strategies">Code Organization Strategies</h2>
<p>How you organize your components can make or break your development experience. Here's the structure I use:</p>
<h3 id="heading-folder-structure-by-type">Folder Structure by Type</h3>
<pre><code class="lang-markdown">src/
├── components/
│   ├── ui/              # Basic UI components
│   │   ├── Button/
│   │   ├── Input/
│   │   └── Card/
│   ├── layout/          # Layout components
│   │   ├── Container/
│   │   ├── Grid/
│   │   └── Header/
│   ├── widgets/         # Feature widgets
│   │   ├── UserProfile/
│   │   ├── SearchBox/
│   │   └── ProductList/
│   └── pages/           # Page-level components
│       ├── HomePage/
│       └── ProfilePage/
</code></pre>
<h3 id="heading-individual-component-structure">Individual Component Structure</h3>
<p>Each component gets its own folder with everything it needs:</p>
<pre><code class="lang-markdown">Button/
├── index.js           # Main component file
├── Button.test.js     # Tests
├── Button.stories.js  # Storybook stories (if using)
├── Button.module.css  # Component-specific styles
└── README.md          # Component documentation
</code></pre>
<h3 id="heading-the-barrel-export-pattern">The Barrel Export Pattern</h3>
<p>Use index.js files to create clean imports:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// components/ui/index.js</span>
<span class="hljs-keyword">export</span> { <span class="hljs-keyword">default</span> <span class="hljs-keyword">as</span> Button } <span class="hljs-keyword">from</span> <span class="hljs-string">'./Button'</span>;
<span class="hljs-keyword">export</span> { <span class="hljs-keyword">default</span> <span class="hljs-keyword">as</span> Input } <span class="hljs-keyword">from</span> <span class="hljs-string">'./Input'</span>;
<span class="hljs-keyword">export</span> { <span class="hljs-keyword">default</span> <span class="hljs-keyword">as</span> Card } <span class="hljs-keyword">from</span> <span class="hljs-string">'./Card'</span>;

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">import</span> { Button, Input, Card } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/ui'</span>;
</code></pre>
<h2 id="heading-naming-strategies">Naming Strategies</h2>
<p>Good naming makes your codebase self-documenting. Here are my rules:</p>
<h3 id="heading-component-names">Component Names</h3>
<ul>
<li><p><strong>PascalCase</strong> for component names: <code>UserProfileCard</code>, not <code>userProfileCard</code></p>
</li>
<li><p><strong>Descriptive and specific</strong>: <code>SubmitButton</code> instead of <code>Button2</code></p>
</li>
<li><p><strong>Avoid technical jargon</strong>: <code>ProductCard</code> instead of <code>ProductCardComponent</code></p>
</li>
</ul>
<h3 id="heading-props-naming">Props Naming</h3>
<ul>
<li><p><strong>camelCase</strong> for prop names: <code>onClick</code>, <code>isLoading</code>, <code>maxWidth</code></p>
</li>
<li><p><strong>Boolean props</strong> start with <code>is</code>, <code>has</code>, <code>can</code>, or <code>should</code>: <code>isVisible</code>, <code>hasError</code>, <code>canEdit</code></p>
</li>
<li><p><strong>Event handlers</strong> start with <code>on</code>: <code>onClick</code>, <code>onSubmit</code>, <code>onUserSelect</code></p>
</li>
</ul>
<h3 id="heading-file-naming">File Naming</h3>
<ul>
<li><p><strong>Component files</strong> match component names: <code>UserProfileCard.jsx</code></p>
</li>
<li><p><strong>Utility files</strong> use kebab-case: <code>api-client.js</code>, <code>date-utils.js</code></p>
</li>
<li><p><strong>Constants</strong> in UPPER_SNAKE_CASE: <code>API_ENDPOINTS.js</code></p>
</li>
</ul>
<h3 id="heading-css-class-naming">CSS Class Naming</h3>
<p>I use BEM (Block Element Modifier) methodology:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Block */</span>
<span class="hljs-selector-class">.user-card</span> { }

<span class="hljs-comment">/* Element */</span>
<span class="hljs-selector-class">.user-card__avatar</span> { }
<span class="hljs-selector-class">.user-card__name</span> { }
<span class="hljs-selector-class">.user-card__actions</span> { }

<span class="hljs-comment">/* Modifier */</span>
<span class="hljs-selector-class">.user-card--featured</span> { }
<span class="hljs-selector-class">.user-card--compact</span> { }
</code></pre>
<h3 id="heading-practical-naming-examples">Practical Naming Examples</h3>
<pre><code class="lang-jsx"><span class="hljs-comment">// Good component naming</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfileCard</span>(<span class="hljs-params">{ user, isEditable, onEdit, onDelete }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
        <span class="hljs-attr">className</span>=<span class="hljs-string">"user-card__avatar"</span> 
        <span class="hljs-attr">src</span>=<span class="hljs-string">{user.avatar}</span> 
        <span class="hljs-attr">alt</span>=<span class="hljs-string">{user.name}</span> 
      /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user-card__info"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user-card__name"</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user-card__email"</span>&gt;</span>{user.email}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      {isEditable &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user-card__actions"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onEdit}</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"secondary"</span>&gt;</span>
            Edit
          <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onDelete}</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"danger"</span>&gt;</span>
            Delete
          <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Usage with clear prop names</span>
&lt;UserProfileCard
  user={currentUser}
  isEditable={userCanEdit}
  onEdit={handleUserEdit}
  onDelete={handleUserDelete}
/&gt;
</code></pre>
<h2 id="heading-the-component-hierarchy">The Component Hierarchy</h2>
<p>Understanding how components relate to each other helps with both organization and reusability:</p>
<pre><code class="lang-markdown">Page Component
├── Layout Components (Header, Sidebar, Footer)
├── Widget Components (UserProfile, ProductList)
│   └── UI Components (Card, Button, Avatar)
└── UI Components (directly used on page)
</code></pre>
<p><strong>Flow of data and events:</strong></p>
<ul>
<li><p><strong>Props flow down</strong>: Parent components pass data to children</p>
</li>
<li><p><strong>Events bubble up</strong>: Child components notify parents of interactions</p>
</li>
<li><p><strong>State lives high</strong>: Shared state lives in the nearest common parent</p>
</li>
</ul>
<p>This hierarchy helps you decide where to put logic and how to structure your component tree for maximum reusability.</p>
<h2 id="heading-getting-started-with-component-thinking">Getting Started with Component Thinking</h2>
<p>If you're still in the copy-paste phase, here's how to start thinking in components:</p>
<ol>
<li><p><strong>Look for Patterns:</strong> Next time you're building a UI, notice when you copy code. Each copy is a potential component.</p>
</li>
<li><p><strong>Start Small:</strong> Don't try to componentize everything at once. Start with obvious reusable pieces like buttons, cards, or form inputs.</p>
</li>
<li><p><strong>Practice Decomposition:</strong> Take an existing page and try to break it down into components. Draw boxes around reusable pieces.</p>
</li>
<li><p><strong>Think in Composition:</strong> Instead of building monolithic pages, practice combining smaller components to create larger ones.</p>
</li>
<li><p><strong>Organize Early:</strong> Set up a proper folder structure from the beginning. It's easier to maintain organization than to refactor later.</p>
</li>
</ol>
<h2 id="heading-common-pitfalls-to-avoid">Common Pitfalls to Avoid</h2>
<p>As you start thinking in components, watch out for these mistakes:</p>
<p><strong>Over-componentizing:</strong> Not everything needs to be a component. A single <code>&lt;div&gt;</code> with text probably doesn't need its own component file.</p>
<p><strong>Under-componentizing:</strong> If you're copying code more than twice, it should probably be a component.</p>
<p><strong>Poor prop design:</strong> Avoid passing too many props or unclear prop names. If your component needs 10+ props, consider breaking it down.</p>
<p><strong>Mixing concerns:</strong> Don't put data fetching logic in UI components. Keep your concerns separated.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Learning component thinking through React was one of those "aha!" moments that fundamentally changed my career. It transformed me from someone who builds websites to someone who builds systems of reusable components.</p>
<p>This mindset shift goes beyond just React - whether you're using Vue, Angular, Svelte, or even vanilla JavaScript, thinking in terms of reusable, well-organized components will make you a better developer.</p>
<p>The key concepts to remember:</p>
<ul>
<li><p><strong>Different component types</strong> serve different purposes (UI, layout, stateful, widgets, pure)</p>
</li>
<li><p><strong>Proper organization</strong> makes your codebase maintainable and scalable</p>
</li>
<li><p><strong>Good naming</strong> makes your code self-documenting</p>
</li>
<li><p><strong>Component hierarchy</strong> helps you structure data flow and reusability</p>
</li>
</ul>
<p>The next time you're building a UI, ask yourself:</p>
<ul>
<li><p>What patterns am I repeating?</p>
</li>
<li><p>How can I break this into smaller, reusable pieces?</p>
</li>
<li><p>What type of component am I building?</p>
</li>
<li><p>How should I organize and name this?</p>
</li>
</ul>
<p>You might feel like you're moving slower at first, setting up proper organization and thinking through component design. But trust me, the long-term benefits in maintainability, consistency, and development speed are absolutely worth it.</p>
<p>A new day, another opportunity to think in components! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[What the heck is Fetch Request </>]]></title><description><![CDATA[fetch(url)
Hi, If you stumble upon this article you might have been wondering 
what Fetch is in Javascript.
Yoo gear up you're about to get everything you know.. ::)
So let's get to business, There are asynchronous ways of fetching
 and sending reque...]]></description><link>https://crackedchefs.devferanmi.xyz/what-the-heck-is-fetch-request-lessgreater</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/what-the-heck-is-fetch-request-lessgreater</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Sun, 24 Nov 2019 10:46:49 GMT</pubDate><content:encoded><![CDATA[<pre><code>fetch(url)
</code></pre><p>Hi, If you stumble upon this article you might have been wondering 
what Fetch is in Javascript.
Yoo gear up you&#39;re about to get everything you know.. ::)</p>
<p>So let&#39;s get to business, There are asynchronous ways of fetching
 and sending requests to the server,
There are numerous ways of doing that of which fetch is included.
 Fetch is an advanced form for the old but not outdated way (XMLHttpRequest).</p>
<p>Parameters/Properties : </p>
<ul>
<li><p>URL:  fetch takes the URL of the request</p>
</li>
<li><p>BODY: You can specify the data to send to the server in the body property</p>
</li>
<li><p>Request Method: Fetch can take all the request methods such as the get, post,  put, delete.</p>
</li>
</ul>
<p><strong>CODELAB</strong>
<em>Worthy of note that fetch gives us a promise of which we should attach a .then method ,
If you have not heard of promises I suggest you read about it</em></p>
<p>Above is the first statement you ought to write to declare a fetch request. 
While the URL takes the URL of your database.
During this CodeLab we&#39;d be fetching quote from quotes.rest
 using this url (https://quotes.rest/qod.json?category=inspire), Notice this is a get request.</p>
<pre><code>fetch(<span class="hljs-string">"https://quotes.rest/qod.json?category=inspire"</span>)
.<span class="hljs-keyword">then</span>(response=&gt;response.text())
.<span class="hljs-keyword">then</span>(<span class="hljs-function"><span class="hljs-params">(data)</span>=&gt;</span>{
  <span class="hljs-built_in">console</span>.log(data);
});
</code></pre><p><em>CODE EXPLAINED</em></p>
<p>fetch(&quot;https://quotes.rest/qod.json?category=inspire&quot;) like I
 said returns a promise and we attach a .then method to fetch
 the request in text format with (response.text()) we can use response.json().
Then we attach a promise to the response with (.then(data)) which we then console.
You can try out the code and play with it.</p>
<p><em>Using Post Request</em></p>
<p>We assume an anonymous server-side URL which accepts a post request (username)</p>
<pre><code>fetch(url,{
method: <span class="hljs-string">'POST'</span>,
body: <span class="hljs-built_in">JSON</span>.stringify({<span class="hljs-string">"username"</span>:<span class="hljs-string">"username"</span>});
})
.then(<span class="hljs-function"><span class="hljs-params">response</span>=&gt;</span>response.text())
.then(<span class="hljs-function">(<span class="hljs-params">data</span>)=&gt;</span>{
<span class="hljs-built_in">console</span>.log(data):
});
</code></pre><p>Yoo, Guess what ? you already now fetch request so you can 
now use fetch request for all your async request.
Ohh, You have a question, Do not hesitate to drop your questions... :)</p>
<pre><code>A <span class="hljs-keyword">new</span> day, Another oppurtunity to be a World <span class="hljs-class"><span class="hljs-keyword">Class</span> <span class="hljs-title">Software</span> <span class="hljs-title">developer</span></span>
</code></pre>]]></content:encoded></item><item><title><![CDATA[Filling Online Forms Like a Guru]]></title><description><![CDATA[When It comes to filling forms on the internet, especially when filling forms for international competitions, debates, mentorship, etc The form is worth filling carefully. I would be enumerating on how to fill the forms like an expert.

Copy Links, D...]]></description><link>https://crackedchefs.devferanmi.xyz/filling-online-forms-like-a-guru</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/filling-online-forms-like-a-guru</guid><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Mon, 02 Sep 2019 18:14:29 GMT</pubDate><content:encoded><![CDATA[<p><strong>W</strong>hen It comes to filling forms on the internet, especially when filling forms for international competitions, debates, mentorship, etc The form is worth filling carefully. I would be enumerating on how to fill the forms like an expert.</p>
<ul>
<li><strong>Copy Links, Don&#39;t cram them.</strong>
While the majority of people tend to read links to a form on their heads, It is not appropriate to cram links on your head because you might forget totally, or forget some part of the link rendering it totally inaccessible. Instead, copy the links to your clipboards for easy access.</li>
</ul>
<p><em>Maybe you don&#39;t have internet data to access the form as at the time you copied it,
The best thing you could do is to open your browser preferably google chrome,
Open a new tab,
Paste the link.
It&#39;ll have saved the link till the next time you have data. Once you have data what you have to do is to open the browser and you&#39;ll be able to locate the link in the tab.</em></p>
<ul>
<li><strong>Use Efficient Browsers</strong>
As a developer, I&#39;m imploring you to use Google Chrome, not Google Go, Mozilla, Firefox or Opera when filling forms.
You can use these browsers for other things but not when filling forms. Reason being that</li>
</ul>
<p>1.<em> Some forms require Gmail Sign in especially Google Forms,You need to be signed in to fill or access the form.
An experience I  had is with a timed google form the form was to be filled in few seconds and unluckily for me, I opened it in another browser that wasn&#39;t google chrome, So I had issues filling the form because I wasn&#39;t logged In.</em></p>
<p>2.<em> Form States: What do we mean by form states, There are forms that you close them halfway because you need to check something, Chrome has the ability to keep whatever you have filled till the next time to come back.</em></p>
<ul>
<li><em>*Don&#39;t Fill Forms Early</em>
Don&#39;t fill online forms immediately they are out because while a form might be released to the public the form may still be going on testing, You filling it at that time might lead to you losing the data you filled.
And also an early form submission can lead to your form being overlooked because you submit too early, Most people believe that too-knows submit faster.</li>
</ul>
<ul>
<li><strong>Read forms through before filling It</strong>
Take your time to read the questions through before answering them, Find out how the questions are related to each other and start from there. After filling your form go through It one more time before submitting.</li>
</ul>
<ul>
<li><strong>Adhere to all Instructions</strong>
Always make sure you adhere to all instructions when filling a form, Don&#39;t upload a picture when the form is asking for your CV/Resume, Don&#39;t enter numbers when an email is required.</li>
</ul>
<ul>
<li><p><strong>Enter Valid Informations</strong>
Always make sure you write valid information like Email, Phone Numbers, Location and residential addresses.
For example, I created a form sometime ago that asks for the user&#39;s location but surprisingly we already tracked your location using your IP address, So filling a wrong location in the form might lead to automatic disqualification.</p>
</li>
<li><p><strong>Always Take Note of any message that pops up after submission</strong>
There are now automated form processors that can access your forms and accept or reject it immediately always make sure you look back on the return message.
There are forms that gives you more information about the form you just filled, messages like 
<em>we&#39;ll get back to you on a so-so-so date</em>
<em>Check your mail for responses</em>
<em>Get a verification code or mail</em>
These messages are important in getting it right.</p>
</li>
</ul>
<ul>
<li><strong>Check your mail everyday </strong>
Check your mail at least every 13 hours for updates on the form you filled.</li>
</ul>
<p>I am sure after reading all these you&#39;d be able to fill your next online forms smartly,Do something nice share this article with your friends</p>
]]></content:encoded></item><item><title><![CDATA[Why should you visit Nigeria]]></title><description><![CDATA[The Booming Music Scene
The music and entertainment scene in Nigeria is arguably one of the most exciting things about the country. The list of artists—past and present—who continue to boost the country’s global image with their Afrobeat, Highlife, a...]]></description><link>https://crackedchefs.devferanmi.xyz/why-should-you-visit-nigeria</link><guid isPermaLink="true">https://crackedchefs.devferanmi.xyz/why-should-you-visit-nigeria</guid><dc:creator><![CDATA[Oluwaferanmi Adeniji]]></dc:creator><pubDate>Thu, 22 Aug 2019 10:54:56 GMT</pubDate><content:encoded><![CDATA[<p><strong>The Booming Music Scene</strong>
The music and entertainment scene in Nigeria is arguably one of the most exciting things about the country. The list of artists—past and present—who continue to boost the country’s global image with their Afrobeat, Highlife, and Afropop tunes is endless. If you’re lucky, you’ll catch some of them at the clubs. Otherwise, you’ll catch yourself churning out dance moves to them you didn’t know you otherwise had. Either way, you’ll get lucky.</p>
<p><strong>Nigerians Go “All in” With Parties</strong>
If you haven’t heard this before—Nigerians party big! Practically every celebration is a mini-festival, regardless of the occasion or the time of day. As for the big ones, such as weddings, well, they’re huge. A tourist attraction almost.</p>
<p>Also, these parties are not restricted to the weekends, and most of them pretty much have an unspoken “everyone is welcome” policy. Nightlife in Nigeria is another realm of its own. No matter your tastes, there’s something for you.</p>
<p><strong>All You Can Eat… and Then Some More</strong>
Nigeria has some of the healthiest foods and food combinations on the planet! In addition to this, you can find a variety of dishes to delight your taste buds, starting locally at the buka&#39;s (local eateries), and spanning a continental and intercontinental reach at some of the nicest hotels and restaurants you’ll ever visit. However, watch out for pepper if you can’t handle it.
 <a target='_blank' rel='noopener noreferrer'  href="https://timbu.com/nigeria">Timbu.com/Nigeria</a> </p>
]]></content:encoded></item></channel></rss>