<?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[Fortune's Blog]]></title><description><![CDATA[Fortune's Blog]]></description><link>https://blog.fortunealebiosu.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 27 Apr 2026 02:42:15 GMT</lastBuildDate><atom:link href="https://blog.fortunealebiosu.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[I Built an AI Agent That Figures Out Your Content Niche — So You Don't Have To]]></title><description><![CDATA[Simple question, right? Except it's not. Not really.
Ask ten different creators that question and you'll get ten wildly different answers. A developer who live-codes on Twitch is nothing like a lifest]]></description><link>https://blog.fortunealebiosu.dev/hitt-ai-agent</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/hitt-ai-agent</guid><category><![CDATA[langgraph]]></category><category><![CDATA[ai-agent]]></category><category><![CDATA[AI]]></category><category><![CDATA[fullstackdeveloper]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Mon, 06 Apr 2026 01:56:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/635e716e79c5fd3f72f4078b/d609fa1e-0533-4f5c-b25a-9450a477d242.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Simple question, right? Except it's not. Not really.</p>
<p>Ask ten different creators that question and you'll get ten wildly different answers. A developer who live-codes on Twitch is nothing like a lifestyle creator on Instagram. A B2B thought leader on LinkedIn has completely different needs than a YouTube educator breaking down finance for Gen Z.</p>
<p>That's exactly the problem I ran into building my AI operator for content creators. I needed a way to <em>actually understand</em> each user before we could help them. A basic onboarding form wasn't going to cut it.</p>
<p>So I built an AI agent that holds a real conversation with users, asks the right follow-up questions, and produces a detailed niche profile — all during onboarding. Here's how it works, and more importantly, <strong>why I built it this way</strong>.</p>
<h2>The Problem With Standard Onboarding</h2>
<p>Most onboarding flows ask you to fill out a form. Pick your niche from a dropdown. Choose your goals. Click next.</p>
<p>The problem? Content creation doesn't fit in a dropdown.</p>
<p>The difference between "tech content" and "beginner-friendly Python tutorials for career switchers" is enormous. One is useless to an AI system trying to help you. The other tells you <em>everything</em>.</p>
<p>I needed onboarding to be a conversation — not a form. And I needed that conversation to be persistent, resumable, and capable of reasoning across multiple turns.</p>
<p>That's when I turned to LangGraph.</p>
<h2>What Even Is LangGraph?</h2>
<p>At a high level, LangGraph is a library for building <strong>stateful, multi-step AI workflows</strong> as a graph.</p>
<p>Think of it like a state machine for AI agents. You define nodes (things the agent can <em>do</em>) and edges (the rules for moving between them). What makes it powerful is that it handles state persistence natively — meaning your agent can pause, wait for external input (like a user answering a question), and pick back up exactly where it left off.</p>
<p>Here's the mental model: <strong>LangGraph is like a choose-your-own-adventure book where the AI decides which page to turn to — and can bookmark its place.</strong></p>
<h2>How I Structured the Agent</h2>
<img src="https://cdn.hashnode.com/uploads/covers/635e716e79c5fd3f72f4078b/6c9d2e99-ec22-478f-94e8-b7c05894bcca.svg" alt="" style="display:block;margin:0 auto" />

<p>The agent has two nodes:</p>
<p><code>analyze</code> — This is where the heavy lifting happens. It builds a prompt from the user's initial niche description (and any follow-up answers they've provided), calls the LLM with structured output via Zod schemas, and returns one of two things:</p>
<ol>
<li><p>A set of follow-up questions (when it needs more info)</p>
</li>
<li><p>A completed <code>finalNicheDescription</code> (when it has enough to work with)</p>
</li>
</ol>
<p><code>awaitUser</code> — This calls LangGraph's <code>interrupt()</code> function, which pauses execution and saves all of the agent state to Postgres, indicating that we have gotten to a "checkpoint". The agent literally stops running and waits. When the user submits their answers, the frontend resumes the graph by sending back the answers with a <code>Command({ resume: answers })</code>.</p>
<p>The routing logic is simple: after <code>analyze</code>, if the agent is done (or has looped 3 times), go to <code>END</code>. Otherwise, go to <code>awaitUser</code> and loop back to <code>analyze</code> once answers come in.</p>
<pre><code class="language-typescript">// Simplified edge logic
const shouldContinue = (state: NicheAgentState) =&gt; {
  if (state.isComplete || state.iterationCount &gt;= 3) return "END";
  return "awaitUser";
};
</code></pre>
<p>That 3-iteration cap is important. More on that in a second.</p>
<h2>The Part Most Tutorials Skip: Checkpointing Across HTTP Requests</h2>
<p>Here's where things get interesting.</p>
<p>Each time the user submits answers, they're making a <strong>new HTTP request</strong>. The agent has no memory between requests — unless you explicitly persist it somewhere. This is where LangGraph's Postgres checkpointer comes in.</p>
<p>Every time the graph hits an <code>interrupt()</code>, it saves the <em>entire agent state</em> to Postgres. When the next request comes in with the same <code>threadId</code>, the graph loads that checkpoint and resumes as if nothing happened.</p>
<pre><code class="language-typescript">// Route handler: start vs resume
if (action === "start") {
  input = { initialNiche: niche };
} else {
  input = new Command({ resume: answers });
}

await graph.stream(input, {
  configurable: { thread_id: threadId }
});
</code></pre>
<p>The <code>threadId</code> is what ties everything together. It gets sent to the client on the first <code>questions</code> SSE event, and the client sends it back with every subsequent request. Lose the <code>threadId</code>, and the graph can't find its checkpoint — the conversation is gone.</p>
<p>This is also why the agent survives server restarts. The state lives in Postgres, not in memory.</p>
<h2>Where People Go Wrong: Over-Questioning</h2>
<p>Here's a mistake I almost made.</p>
<p>My first instinct was to let the agent ask as many questions as it needed until it was fully confident. Makes sense in theory. In practice, it's a disaster.</p>
<p>Users don't want to answer six rounds of questions during onboarding. They'll drop off. They'll give lazy answers. They'll start saying "I don't know" just to get through it.</p>
<p>The 3-iteration cap forces the agent to be decisive. By the third loop, it has to commit to a <code>finalNicheDescription</code> regardless of how confident it feels. This actually made the output <em>better</em>, not worse — it stopped the agent from nitpicking and made it prioritise the signal it already had.</p>
<p><strong>Constraints make AI systems more useful, not less.</strong></p>
<h2>The Structured Output Problem</h2>
<p>One thing I got wrong early on: trusting the LLM to return consistent JSON.</p>
<p>Even with a well-crafted prompt, raw LLM output is unpredictable. The agent might return valid JSON one call and a slightly different shape the next. That breaks your downstream code.</p>
<p>The fix was using <code>withStructuredOutput(analysisSchema)</code> — where <code>analysisSchema</code> is a Zod schema that the LLM <em>must</em> conform to. If it doesn't, the call fails and you get a proper error instead of silently broken data.</p>
<pre><code class="language-typescript">const model = getModel(AI_MODELS.GROK_REASONING)
  .withStructuredOutput(analysisSchema);
</code></pre>
<p>The output schema captures everything the agent might return: <code>reasoningSteps</code>, <code>isComplete</code>, <code>questions[]</code>, and <code>finalDescription</code> (which itself has a detailed shape: <code>niche</code>, <code>subNiche</code>, <code>contentPillars</code>, <code>targetAudience</code>, <code>tone</code>, and whether the creator covers current affairs).</p>
<p>That last field — <code>doesCurrentAffairs</code> — sounds minor but it genuinely changes how the AI operator writes content. Small structured fields like that pay off downstream.</p>
<h2>Streaming the Reasoning to the UI</h2>
<p>Users get nervous when nothing happens. A spinner for 10 seconds feels broken.</p>
<p>Since the agent does real multi-step reasoning before deciding what to ask, I wanted to stream those reasoning steps to the UI in real-time via Server-Sent Events (SSE). Each step shows up as the agent "thinks through" the creator's niche.</p>
<p>The route handler inspects each LangGraph update as it streams and emits typed SSE events:</p>
<ul>
<li><p><code>reasoning_step</code> — intermediate thinking, shown progressively</p>
</li>
<li><p><code>questions</code> — the follow-up questions for the user (includes <code>threadId</code>)</p>
</li>
<li><p><code>final_result</code> — the completed niche profile</p>
</li>
</ul>
<p>On the client side, the component reads the SSE stream manually, buffers partial chunks, and updates state as events arrive. It's a bit fiddly, but the UX payoff is worth it — users can see the agent <em>working</em>, which builds trust.</p>
<h2>What Does the Final Output Look Like?</h2>
<p>After at most 3 loops, the agent returns a <code>DetailedNiche</code> that looks something like this:</p>
<pre><code class="language-json">{
  "niche": "Software development",
  "subNiche": "Backend engineering for self-taught developers",
  "contentPillars": ["System design", "API architecture", "Career growth"],
  "targetAudience": "Self-taught developers transitioning to mid-level roles",
  "tone": "Practical, no-fluff, peer-to-peer",
  "doesCurrentAffairs": "sometimes"
}
</code></pre>
<p>This gets persisted to Supabase via an upsert on <code>user_id</code>, and every subsequent AI feature in the platform uses it as context. The onboarding agent essentially writes the creative brief that the rest of the system follows.</p>
<hr />
<h2>When Should You Build Something Like This?</h2>
<p>If your product serves a wide spectrum of users and the <em>type</em> of user fundamentally changes what your product should do — you probably need personalised onboarding.</p>
<p>A generic onboarding form gets you a generic product experience. An agent that asks the right questions gets you a product that feels like it was built specifically for that user.</p>
<p>The LangGraph + Postgres checkpointing pattern is the right call when:</p>
<ul>
<li><p>Your onboarding requires <strong>multiple turns</strong> (back-and-forth, not just a form submit)</p>
</li>
<li><p>You need the conversation to <strong>survive page refreshes and server restarts</strong></p>
</li>
<li><p>The output needs to be <strong>structured and validated</strong> (not just a free-text summary)</p>
</li>
</ul>
<p>If your onboarding is a single form with five fields, you don't need any of this. But if you're building a product where "who is this user, exactly?" is a hard question — this pattern is worth every line of complexity.</p>
]]></content:encoded></item><item><title><![CDATA[Building a Production-Ready Notification System That Actually Scales]]></title><description><![CDATA[So you've built an app that sends notifications to users. Congrats! But now your users are growing, your push notification volume is skyrocketing, and suddenly things are breaking down. Push requests are timing out. Messages are getting lost. Your da...]]></description><link>https://blog.fortunealebiosu.dev/building-notifications</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/building-notifications</guid><category><![CDATA[System Design]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Python]]></category><category><![CDATA[backend]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Sun, 18 Jan 2026 21:45:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/IgQo1_gUzBY/upload/e15d0ac63d6fee0bfb06a592773b5009.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So you've built an app that sends notifications to users. Congrats! But now your users are growing, your push notification volume is skyrocketing, and suddenly things are breaking down. Push requests are timing out. Messages are getting lost. Your database is screaming for help.</p>
<p>If this sounds familiar, you're not alone. Building a notifications system that can handle production traffic is way harder than it looks. In this post, I'm going to walk you through exactly how I built a notification service that can handle real-world load while staying reliable.</p>
<p>Let me start by showing you what we're dealing with here.</p>
<h2 id="heading-the-challenge">The Challenge</h2>
<p>You might be thinking: "How hard can sending notifications be?" Well, buckle up. Here's what you actually need to handle:</p>
<p>You need to send thousands of notifications simultaneously without overwhelming the Push Notifications API. You need to retry failed messages intelligently so they eventually deliver. You need to track what fails and why. You need to monitor everything so you catch issues before your users do.</p>
<p>And you need to do all of this while keeping your database load reasonable. That last one is super important because your primary database is probably doing a lot of other work too.</p>
<p>So yeah. It's not just a "send notification and hope it gets delivered."</p>
<h2 id="heading-the-architecture">The Architecture</h2>
<p>Here's the system I built. It has several key pieces working together:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768769316720/e68c6eb5-5a70-4701-acb5-5709e5439592.png" alt class="image--center mx-auto" /></p>
<p><strong>FastAPI Application</strong>: Webhooks and triggers hit this. It enqueues notifications but doesn't wait for them to actually send.</p>
<p><strong>NotificationEnqueueService</strong>: Figures out who needs to receive the notification based on sharing settings, grabs their push tokens, and gets everything ready.</p>
<p><strong>CacheService</strong>: A two-tier cache using Redis for speed and Supabase as a fallback. This is crucial for performance.</p>
<p><strong>NotificationService</strong>: The workhorse. It processes messages from the queue, handles retries, talks to Expo, and moves failures to a dead letter queue.</p>
<p><strong>Supabase Queue (pgmq)</strong>: Message queue that persists notifications until they're sent. The setup had 2 queues, an initial queue for persisting notifications and a dead-letter queue for persisting failed notifications.</p>
<p><strong>NotificationScheduler</strong>: Runs every 15 minutes to process pending notifications in batches.</p>
<p><strong>Expo Push Notification API</strong>: Actually delivers the notifications to user devices.</p>
<p>The key insight here is that sending notifications is async. Your API returns immediately. Then the scheduler processes them in the background. This keeps your endpoints fast and prevents your database from getting hammered.</p>
<h2 id="heading-where-performance-matters">Where Performance Matters</h2>
<p>Let's talk about the parts of this system that actually affect how well it scales.</p>
<h3 id="heading-caching-strategy">Caching Strategy</h3>
<p>Notification settings and push tokens get requested a lot. If you hit the database for every single user every single time you need their settings, your database is toast.</p>
<p>So I implemented a lazy-loading cache using Redis:</p>
<ol>
<li><p>Check Redis first (super fast)</p>
</li>
<li><p>On cache miss, fetch from Supabase (slower but still reasonable)</p>
</li>
<li><p>Cache the result for an hour</p>
</li>
<li><p>If Redis is down, just use Supabase directly</p>
</li>
</ol>
<p>The key thing is: never fail if Redis is unavailable. Your notifications are too important. Always have a fallback.</p>
<p>This approach reduced database queries by about 80 percent for frequently accessed data. That's a massive difference when you're handling high volume.</p>
<h3 id="heading-batch-operations">Batch Operations</h3>
<p>Fetching notification settings one user at a time would be incredibly slow. Instead, I use Redis MGET to fetch multiple items in one call. Then any items that aren't cached get fetched from Supabase in a single batch query.</p>
<p>So instead of 1000 database calls, you might make 5 or 10. The difference is night and day.</p>
<h3 id="heading-concurrency-control">Concurrency Control</h3>
<p>The Expo API has rate limits. If you hammer it with too many concurrent requests, it will reject you. But you also don't want to send notifications one at a time because that's painfully slow.</p>
<p>So I use <code>asyncio.Semaphore</code> in Pyhon to limit concurrent sends. By default it's set to 20 concurrent requests, and can easily be scaled up or down based on your Expo rate limits. This keeps the Expo API happy while still moving through the queue quickly.</p>
<p>When you hit a rate limit, the system backs off exponentially. First retry after 2 seconds, then 4, then 8, and so on. This gives the API time to breathe without losing messages.</p>
<h2 id="heading-handling-failures-gracefully">Handling Failures Gracefully</h2>
<p>Here's the thing about production systems: things fail. Your job is to make sure failures don't cascade and destroy everything.</p>
<h3 id="heading-dead-letter-queue">Dead Letter Queue</h3>
<p>If a notification fails to send after retries, it moves to a dead letter queue for manual review. But I don't keep failures around forever. After 3 failures, the message is logged and discarded.</p>
<p>Why log it and not just ignore it? Because you need visibility into what's breaking. I use PostHog to capture these errors with full context. Then you can actually investigate and fix issues instead of wondering why notifications are missing.</p>
<h3 id="heading-exponential-backoff">Exponential Backoff</h3>
<p>When a message fails, you don't want to immediately retry. And you definitely don't want to retry at the same time as everything else that failed. Exponential backoff with some randomness spreads out retry attempts so you don't create a thundering herd that brings the whole system down.</p>
<h2 id="heading-the-real-world-problems-i-ran-into">The Real World Problems I Ran Into</h2>
<p>Building this thing in production meant running into some annoying edge cases.</p>
<h3 id="heading-environment-variable-shenanigans">Environment Variable Shenanigans</h3>
<p>I had my <code>REDISDB</code> environment variable set to a string instead of a number. This caused a ValueError when the code tried to convert it to an integer. Dumb mistake, but it happens. The fix was simple: create a helper function that safely parses integer environment variables and gracefully falls back to defaults.</p>
<p>This made me realize something important. Your configuration parsing needs to be bulletproof. If it crashes, your entire service is down before it even starts.</p>
<h3 id="heading-breaking-changes-in-dependencies">Breaking Changes in Dependencies</h3>
<p>The Expo SDK updated to version 2.2.0 and changed exception names from <code>PushResponseError</code> to <code>PushServerError</code>. Plus the constructor signature changed. This broke all my error handling.</p>
<p>The lesson here is tedious but important: vendor dependencies carefully. Test your error handling paths. Keep an eye on changelog updates, especially for critical dependencies.</p>
<h3 id="heading-redis-availability">Redis Availability</h3>
<p>Redis going down shouldn't cause the whole system to fail. But I had to explicitly handle this in the cache layer. If Redis doesn't respond, don't crash. Just use Supabase. Yes, it's slower. But slow is better than broken.</p>
<h2 id="heading-testing-all-this-complexity">Testing All This Complexity</h2>
<p>With this many moving parts, you absolutely need comprehensive tests. I wrote 50 tests covering unit, integration, and scheduler scenarios.</p>
<p>The tricky part was mocking all the dependencies correctly. Supabase, Redis, and Expo all needed to be mocked in a way that actually tests the logic. I used pytest fixtures for each service and monkeypatching for dependency injection.</p>
<p>One thing I learned: test the happy path, but spend even more time on error cases. The happy path usually works. It's the errors that bite you in production.</p>
<h2 id="heading-performance-gains-that-actually-matter">Performance Gains That Actually Matter</h2>
<p>Let's get concrete about what this architecture actually does for you:</p>
<p><strong>Caching</strong>: 80 percent reduction in database queries for notification settings and push tokens.</p>
<p><strong>Batch Operations</strong>: Instead of 1000 individual database calls, you make maybe 10. That's a massive difference.</p>
<p><strong>Concurrency Control</strong>: You can process notifications at high volume without overwhelming the Expo API.</p>
<p><strong>Queue Processing</strong>: Handles 100 messages per scheduler run. You can increase this if needed.</p>
<p><strong>Lazy Loading</strong>: Only caches data when it's actually used, so memory usage stays reasonable.</p>
<p>Put these together and you've got a system that can actually scale.</p>
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<p>If you're building a notifications system, here's what matters:</p>
<ol>
<li><p>Always have fallbacks. Redis is great, but Supabase fallback is what keeps you alive when things break.</p>
</li>
<li><p>Test thoroughly. 50 tests might sound like a lot, but for critical infrastructure it's the minimum.</p>
</li>
<li><p>Handle errors gracefully. Never let a single failure break the whole system. Log it, track it, but keep moving.</p>
</li>
<li><p>Monitor everything. PostHog integration gives you visibility into what's actually happening. You can't fix what you can't see.</p>
</li>
<li><p>Design for scale from the start. Concurrency control and batch processing aren't optional if you plan to grow.</p>
</li>
</ol>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Building a notification system that handles real production load is hard. You need reliability, performance, and observability all at the same time. But when you get it right, you've got something that scales, fails gracefully, and gives you the visibility to fix issues before they become disasters.</p>
<p>The system I built here uses Python, FastAPI, Supabase, Redis, Expo Server SDK, PostHog, and the APScheduler in Fast API. All of these are solid production-ready tools. The real trick is putting them together in a way that doesn't fall over when things get busy.</p>
<p>If you're tackling this problem, I hope this gives you some ideas for how to approach it. Notifications might seem simple on the surface, but getting them right in production is where the real engineering happens.</p>
]]></content:encoded></item><item><title><![CDATA[WTF are Sitemaps??]]></title><description><![CDATA[As an engineer, you're probably already familiar with "Search Engine Optimization" or SEO for short. If you're not familiar with SEO, it is the practice of enhancing your website to rank higher in search engine results so that your website receives m...]]></description><link>https://blog.fortunealebiosu.dev/wtf-are-sitemaps</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/wtf-are-sitemaps</guid><category><![CDATA[software development]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Wed, 04 Sep 2024 01:44:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/VQJXJ4IaU_o/upload/f5f78866967ca8cc3887e5171aa57d0d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As an engineer, you're probably already familiar with "Search Engine Optimization" or SEO for short. If you're not familiar with SEO, it is the practice of enhancing your website to rank higher in search engine results so that your website receives more traffic. Frontend Engineers are mostly tasked with this responsibility as search engines index content from the UI they implement.<br />Typically the amateur move to improve SEO is just spamming a bunch of <code>&lt;meta/&gt;</code> tags in the <code>&lt;head/&gt;</code> section of the HTML document, and praying to God that it works.<br />But another great way to boost your site's SEO is to include a sitemap in your web project.</p>
<p>A sitemap is a file that gives search engines information about what pages, media content, or files are important on your website. Sitemaps are very effective on large-scale websites and better help search engines discover URLs for your website.</p>
<p>Sitemaps are usually in XML format (XML is a markup language with a similar structure to HTML), but sitemaps can also be written in plaintext or RSS (RSS has a similar structure to XML).</p>
<h2 id="heading-what-does-a-sitemap-look-like">What Does a Sitemap Look Like?</h2>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">urlset</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.sitemaps.org/schemas/sitemap/0.9"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">url</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">loc</span>&gt;</span>https://www.example.com/<span class="hljs-tag">&lt;/<span class="hljs-name">loc</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">lastmod</span>&gt;</span>2023-09-01<span class="hljs-tag">&lt;/<span class="hljs-name">lastmod</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">changefreq</span>&gt;</span>daily<span class="hljs-tag">&lt;/<span class="hljs-name">changefreq</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">priority</span>&gt;</span>1.0<span class="hljs-tag">&lt;/<span class="hljs-name">priority</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">url</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">url</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">loc</span>&gt;</span>https://www.example.com/about<span class="hljs-tag">&lt;/<span class="hljs-name">loc</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">lastmod</span>&gt;</span>2023-08-25<span class="hljs-tag">&lt;/<span class="hljs-name">lastmod</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">changefreq</span>&gt;</span>monthly<span class="hljs-tag">&lt;/<span class="hljs-name">changefreq</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">priority</span>&gt;</span>0.8<span class="hljs-tag">&lt;/<span class="hljs-name">priority</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">url</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- More URLs can be added here --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">urlset</span>&gt;</span>
</code></pre>
<h3 id="heading-explanation-of-the-elements">Explanation of the Elements</h3>
<ul>
<li><p><code>&lt;urlset&gt;</code>: The root element that encapsulates all the URLs in the sitemap. It uses a standard XML namespace.</p>
</li>
<li><p><code>&lt;url&gt;</code>: This element represents a single URL in the sitemap.</p>
</li>
<li><p><code>&lt;loc&gt;</code>: The location of the URL (i.e., the full URL of the page).</p>
</li>
<li><p><code>&lt;lastmod&gt;</code>: The date when the URL was last modified. This helps search engines understand how recently the content has been updated.</p>
</li>
<li><p><code>&lt;changefreq&gt;</code>: Indicates how often the content at the URL is expected to change (e.g., "daily," "weekly," "monthly").</p>
</li>
<li><p><code>&lt;priority&gt;</code>: A value between 0.0 and 1.0 that indicates the priority of the URL relative to other pages on the site.</p>
</li>
</ul>
<h2 id="heading-creating-your-own-sitemaps">Creating your own Sitemaps</h2>
<p>Now that you know what a sitemap looks like, you are free to create your own sitemaps manually, but there are many sitemap generator tools online like <a target="_blank" href="https://xml-sitemaps.com">xml-sitemaps.com</a> to help you generate your sitemap. If you're using WordPress, plugins like Yoast SEO can help you generate your sitemaps. If you build your web applications with a framework like Next.js, you can write your sitemaps using Typescript which is later converted to an XML-based sitemap at <em>build time</em>.</p>
<h2 id="heading-submitting-your-sitemaps">Submitting your Sitemaps</h2>
<p>According to Google Search Central, <em>"a sitemap is merely a hint: it doesn't guarantee that Google will download the sitemap or use the sitemap for crawling URLs on the site."</em>. In order to make your sitemap available to Google, you can either:</p>
<ol>
<li><p>Submit the sitemap on the Google Search console</p>
</li>
<li><p>Use the Google Search Console API</p>
</li>
</ol>
<p>Make sure to keep your sitemaps updated regularly and do not overload your sitemaps in order to maintain their efficiency.</p>
<p>If you want to know more about sitemaps, you can checkout Google Search Central at <a target="_blank" href="https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview">https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview</a></p>
<p>If you came this far, thanks a lot for reading, and if you'd like to discover more tips like this or you want to connect with me, connect with me on <a target="_blank" href="https://linkedin.com/in/fortunealebiosu">LinkedIn</a>!</p>
]]></content:encoded></item><item><title><![CDATA[A Beginner's Guide to Terraform]]></title><description><![CDATA[Okay, backstory! It all started when I was working on my current side project DocGuard, which involves cloud storage was my obvious go-to AWS S3 at the time, especially because I already had an AWS account and wanted to try out another AWS service ot...]]></description><link>https://blog.fortunealebiosu.dev/terraform-for-beginners</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/terraform-for-beginners</guid><category><![CDATA[Terraform]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Fri, 10 May 2024 18:00:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/LATYeZyw88c/upload/e1c91c0acda427bc51adbc5bdf0300c9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Okay, backstory! It all started when I was working on my current side project <a target="_blank" href="https://docguard.fortunethedev.co">DocGuard</a>, which involves cloud storage was my obvious go-to AWS S3 at the time, especially because I already had an AWS account and wanted to try out another AWS service other than RDS (which btw had incurred costs I didn't know about). Desperate to try S3, I tried it and I loved it as it was working so well with my application until disaster struck.</p>
<p>AWS had suspended my account over the unpaid charges from the RDS instance that was still running(which was so funny because I swore I turned those off), and just like that my beloved cloud storage was gone. But then I remembered that Google Cloud had a similar service with their storage buckets.</p>
<p>So I thought to myself this was a good time to learn Terraform as I had heard so many good things about it. So if you've never heard about Terraform, it is an infrastructure-as-code tool that enables you to spin up infrastructure and set up resources in the cloud (clear of AWS CloudFormation btw, an argument for another day).</p>
<p>Using Terraform I was able to quickly set up my environment on Google Cloud Platform and provision a new storage bucket in my project right from my code editor. The wonderful thing about Terraform is that it is cloud-agnostic as it is not for a specific cloud vendor and can be used with multiple cloud vendors or providers like AWS, Google Cloud Platform, or Microsoft Azure just to name a few.</p>
<p>To get started with Terraform:</p>
<ol>
<li><p>Install the Terraform binary for your device, depending on your OS. You can get the latest version of Terraform from <a target="_blank" href="https://developer.hashicorp.com/terraform/install">https://developer.hashicorp.com/terraform/install</a></p>
</li>
<li><p>Add Terraform to PATH.</p>
<p> Instructions for Windows: <a target="_blank" href="https://stackoverflow.com/a/55949463">https://stackoverflow.com/a/55949463</a></p>
<p> Instructions for MacOS and Linux: <a target="_blank" href="https://stackoverflow.com/a/50445479">https://stackoverflow.com/a/50445479</a></p>
</li>
<li><p>Make sure you have the AWS CLI or Google Cloud CLI installed and you have authenticated into the respective CLI</p>
</li>
<li><p>Create the Terraform configuration at the root of your project in a file called <code>main.tf</code></p>
<pre><code class="lang-plaintext"> terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
       version = "~&gt; 4.16"
     }

     google = {
       source = "hashicorp/google"
       version = "4.51.0"
     }
   }
 }

 provider "google" {
   project = "sylvan-repeater-407810"
   region  = "us-east4"
   zone    = "us-east4-c"
   credentials = file("./docguard-service-key.json")
 }

 resource "google_storage_bucket" "docguard-bucket" {
   name = "docguard-bucket-v1"
   location = "us-east4"
 }
</code></pre>
<p> The above block of code is called the Terraform configuration.</p>
<p> The <code>terraform {}</code> section will contain all the settings including the required providers you need in your project.</p>
<p> The <code>provider {}</code> section shows the details for the provider(s) you want to use, for example in this configuration, I used the <code>google</code> provider and it contained the project id, region, availability zone, and my credentials file.</p>
<p> The <code>resource {}</code> section contains the resource or service you're trying to set up on a particular provider. For example, in this configuration, I was using the "google_storage_bucket" service on the "google" provider, and I called the storage bucket "docguard-bucket-v1".</p>
<p> You may be wondering what the difference is between <code>required_providers</code> and <code>provider</code> . <code>required_providers</code> will and must contain all the Cloud Providers you will be using in your project so that they can be installed by Terraform, while <code>provider</code> shows the configuration for each of the providers you specified in <code>required_providers</code>.</p>
<p> Another important thing to note in this is that, <code>provider</code> shows what cloud vendor you're using in your configuration. You can have more than one <code>provider</code> block. While <code>resource</code> shows what resources you want to set up for each provider.</p>
</li>
<li><p>Now that your Terraform configuration is done, we have to start up Terraform using <code>terraform init</code> . This lets Terraform download the providers and everything needed to build your infrastructure.</p>
</li>
<li><p>Next, you can validate if the changes in your configuration (<code>main.tf</code>) are valid using the <code>terraform validate</code> . If the changes in your configuration are valid, the CLI will return a success message.</p>
</li>
<li><p>Finally, you can apply your changes and push your provisioned infrastructure to your cloud provider using the <code>terraform apply</code> command.</p>
</li>
</ol>
<p>And that's it. Basic cloud computing all from your code editor with minimal effort. If you liked this article, give it a like or comment, and feel free to connect with me on <a target="_blank" href="https://linkedin.com/in/fortunealebiosu">LinkedIn</a> or <a target="_blank" href="https://twitter.com/alebiosu_thedev">Twitter</a>.</p>
<p>Thanks for reading, and I'll see you in the next one!</p>
]]></content:encoded></item><item><title><![CDATA[Making Caching Efficient]]></title><description><![CDATA[As I explained in the previous article in this series, caching is very useful when your data doesn't change very quickly. But how can you make your caching efficient?
Caching Design Patterns
You have a cache yes, but how do you get data into it? Cach...]]></description><link>https://blog.fortunealebiosu.dev/making-caching-efficient</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/making-caching-efficient</guid><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[System Design]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Tue, 26 Mar 2024 21:28:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/FHl79chXS6s/upload/7fc6d011d3095c68ca72ede091dc23e8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As I explained in the previous article in this series, caching is very useful when your data doesn't change very quickly. But how can you make your caching efficient?</p>
<h2 id="heading-caching-design-patterns">Caching Design Patterns</h2>
<p>You have a cache yes, but how do you get data into it? Caching Design Patterns are different rules you use to populate your cache (get data into your cache). Each design pattern has its advantages and disadvantages, therefore you should use a certain pattern depending on what your app/system requires. Let's Dive In!</p>
<ol>
<li><p>Cache Aside/Lazy Loading: In this design pattern, the app checks the cache first, if there is a cache hit, it returns the result to the app, but if there is a cache miss, the app then checks the primary database, retrieves the result, then updates the cache, before returning the result to the app.</p>
<p> This is pretty simple to implement, plus only requested data will be kept in the cache, and should the cache fail, it won't be fatal. It just results in increased latency till the cache is populated again.</p>
<p> But there are some downsides: any cache miss results in 3 extra trips, one to the primary database, the trip back to the cache, and the trip back to the app. Data can also get stale, and it is the responsibility of the developer to invalidate this data (more on this later)</p>
</li>
<li><p>Write Through: In this design pattern, the cache is updated immediately after writes are made to the database. This reduces the number of trips needed to get data into the cache (2 trips as opposed to 3 in lazy-loading) and data in the cache is never stale.</p>
<p> But the downside of this is that: cache churn is a huge possibility (lots of data in the cache that will never be read), and the cache may never be filled with certain data till a write of it has been made to the database.</p>
</li>
</ol>
<h2 id="heading-cache-eviction">Cache Eviction</h2>
<p>A cache size is designed to be small, so that search is fast and efficient. But due to its small size, the cache is bound to get full. It is our responsibility as developers to decide how the data in the cache gets removed, whether the cache is full or not. This is called cache eviction. There are 3 main ways of implementing cache eviction, which are:</p>
<ol>
<li><p>Explicit Deletion: This means explicitly removing a certain piece of data from the cache. This can be used whether the cache is full or not.</p>
</li>
<li><p>Removing the LRU data: LRU stands for least recently used. This means removing the data that was retrieved the earliest from the cache. This eviction strategy is used when the cache is full. This can be easily implemented by tracking when a certain piece of data was last retrieved.</p>
</li>
<li><p>Using a TTL: TTL means Time-To-Live. Essentially this means every piece of data in the cache will only live in the cache for a certain amount of time, like 60 minutes. Once that time elapses, the data is removed from the cache. Adding TTLs to your cached data can be very useful for combatting cache churn in the write-through design pattern. This is used to prevent the cache from keeping stale data and can be used if the cache is full or not.</p>
</li>
</ol>
<p>Lastly, if your cache evictions happen too frequently, you might want to consider scaling up or scaling out your cache. Scaling up means increasing the cache size while scaling out means adding more cache nodes to your system.</p>
<p>If you enjoyed this, don't forget to leave a like or a comment, and you can connect with me on <a target="_blank" href="https://linkedin.com/in/fortunealebiosu">LinkedIn</a> or <a target="_blank" href="https://twitter.com/alebiosu_thedev">Twitter</a>. Thanks for reading and I'll see you in the next one!</p>
]]></content:encoded></item><item><title><![CDATA[What exactly is Caching?]]></title><description><![CDATA[What is Caching?
Let's say you had a bad with a lot of items in it, like some books and a laptop. Each time you needed something, you had to go all the way to your bag, pick it up, and take it back once you were done with it. And if you needed that i...]]></description><link>https://blog.fortunealebiosu.dev/what-exactly-is-caching</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/what-exactly-is-caching</guid><category><![CDATA[System Design]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Wed, 13 Mar 2024 02:58:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/cp2HCVzguw4/upload/07fe7f560ae6dd4e410c37a7aa1b548b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-caching">What is Caching?</h2>
<p>Let's say you had a bad with a lot of items in it, like some books and a laptop. Each time you needed something, you had to go all the way to your bag, pick it up, and take it back once you were done with it. And if you needed that item again, you would have to go all the way back to your bag and pick it up again. Obviously, this would start to get annoying at some point. What if you could keep each item you used on a close by table when you were done with it, so if you needed it again, you could just pick it up from the table, instead of going all the way to your bag. That's caching right there!</p>
<p>Caching is a mechanism aimed at improving software performance by storing frequently accessed data for future requests of that same data.</p>
<p>But we're still storing the same frequently accessed data somewhere so how exactly does it make things faster? The frequently accessed data being stored is stored somewhere called a cache, and retrieving an item from a cache database, is much faster than retrieving an item from a traditional database. Why? Because a cache database stores items in memory and not in storage or on the disk. And memory is much faster than the disk.</p>
<h2 id="heading-why-should-we-cache-data">Why should we cache data?</h2>
<p>As explained earlier, we cache data to improve the performance of our application. Obtaining cached data takes less time to complete, and you potentially reduce the amount of load on your primary database.</p>
<h2 id="heading-when-should-we-cache-data">When should we cache data?</h2>
<p>Like every other tool and pattern, caching has where it shines. Caching is optimal when you have data that doesn't change frequently. If your data changes very frequently then caching would not be the best solution to improve performance because the data in the cache will constantly be stale (outdated).</p>
<h2 id="heading-caching-terminologies">Caching Terminologies</h2>
<ol>
<li><p>Cache Hit: When data is requested from a cache and the data is present in the cache, it's called a cache hit.</p>
</li>
<li><p>Cache Miss: When data is requested from a cache and the data is not present in the cache, it's called a cache miss.</p>
</li>
<li><p>Stale Data: When a price of data in the cache is outdated, the data is referred to as stale.</p>
</li>
<li><p>Invalidation: This is the process of declaring a particular piece of data as stale (and possibly re-fetching it).</p>
</li>
<li><p>Least Recently Used (LRU): This is the data in the cache that has not been requested for the longest.</p>
</li>
<li><p>Time-To-Live (TTL): This is the amount of time a piece of data can live in a cache.</p>
</li>
</ol>
<h2 id="heading-how-to-implement-caching">How to implement caching</h2>
<h3 id="heading-on-the-frontend-client-side">On the Frontend (Client-side)</h3>
<p>We can implement caching on the client side by using the <code>@tanstack/react-query</code> library as a wrapper around our API calls. It comes with an in-built cache.</p>
<p>In this example, the cache is identified by a key, which is 'users'. When the API request is made, it checks the cache to see if the data with that key is present. If it's not, it makes a request to the server and automatically caches the result.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchUsers = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/users'</span>);
  <span class="hljs-keyword">if</span> (!response.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Network response was not ok'</span>);
  }
  <span class="hljs-keyword">return</span> response.json();
};

<span class="hljs-keyword">const</span> UsersComponent = <span class="hljs-function">() =&gt;</span> {
     <span class="hljs-keyword">const</span> { isLoading, isError, data, error } = useQuery(<span class="hljs-string">'users'</span>, 
fetchUsers);
    <span class="hljs-comment">//Users compoenent implementation</span>
}
</code></pre>
<p>Tanstack Query allows you to customize your cache settings like the time before data is declared stale, or a mechanism to invalidate cached data. You can check them all in the official documentation <a target="_blank" href="https://tanstack.com/query/latest/docs/framework/react/overview">https://tanstack.com/query/latest/docs/framework/react/overview</a></p>
<h3 id="heading-on-the-backend-server-side">On The Backend (Server-side)</h3>
<p>On the server side of things, caching is mostly used when making calls to the database. We can implement caching by using an in-memory database called Redis.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> redis = <span class="hljs-built_in">require</span>(<span class="hljs-string">'redis'</span>);
<span class="hljs-keyword">const</span> { User } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./models'</span>)

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> client = redis.createClient();

<span class="hljs-comment">// Helper function to check cache and fetch data</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params">key, fetchData</span>) </span>{
  <span class="hljs-keyword">const</span> cachedData = <span class="hljs-keyword">await</span> client.get(key);

  <span class="hljs-comment">//If data is in the cache</span>
  <span class="hljs-keyword">if</span> (cachedData) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">JSON</span>.parse(cachedData);
  }

  <span class="hljs-comment">//Else</span>
  <span class="hljs-keyword">const</span> freshData = <span class="hljs-keyword">await</span> fetchData();
  client.set(key, <span class="hljs-built_in">JSON</span>.stringify(freshData));
  <span class="hljs-keyword">return</span> freshData;
}

<span class="hljs-comment">// Function to fetch data from database using Sequelize</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getDatabaseData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> Users.findAll();
}

<span class="hljs-comment">// API endpoint with cache</span>
app.get(<span class="hljs-string">'/api/data'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getData(<span class="hljs-string">'database-data-key'</span>, getDatabaseData);
    <span class="hljs-keyword">return</span> res.json(data);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">'Internal Server Error'</span>);
  }
});
</code></pre>
<p>In this example, we're using Redis with Node.js to cache calls from our SQL database (it can be any database of your choice). When the request is made to that endpoint, it checks the cache first. If the data is in the cache, it returns it from the cache, else it checks the database, and then updates that value in the cache (although this flow I just explained is not always the case, as there are different caching strategies).</p>
<p>I like to keep things short so that's it for today, if you liked this, be sure to leave a like or a comment and connect with me on LinkedIn at <a target="_blank" href="https://linkedin.com/in/fortunealebiosu">https://linkedin.com/in/fortunealebiosu</a> and stay tuned for the next part of this series.</p>
]]></content:encoded></item><item><title><![CDATA[Best Practices to make you the best React dev you can be (Part 2)]]></title><description><![CDATA[Avoiding useEffect as often as possible


The useEffect hook is used for side effects (data fetching, updating the DOM, subscribing to real-time events, etc). I'm sure you're aware of the second parameter of useEffect, the dependency array, which hol...]]></description><link>https://blog.fortunealebiosu.dev/react-best-practices-2</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/react-best-practices-2</guid><category><![CDATA[React]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Tue, 12 Mar 2024 06:25:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/L8KQIPCODV8/upload/b4b672c2c32f8e0a5f4b8a5b05d81d78.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<ol>
<li><h3 id="heading-avoiding-useeffect-as-often-as-possible">Avoiding useEffect as often as possible</h3>
</li>
</ol>
<p>The useEffect hook is used for side effects (data fetching, updating the DOM, subscribing to real-time events, etc). I'm sure you're aware of the second parameter of useEffect, the dependency array, which holds the state that useEffect will react to when that state changes. You might want certain code to run when that state is equal to a certain value, and if your first instinct is a useEffect, you'd want to look at things a different way. Let's say we have a state to track how many digits we've entered into an input.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> PinComponent = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> [pin, setPin] = useState(<span class="hljs-string">""</span>);

    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (pin.length &gt; <span class="hljs-number">4</span>) {
            alert(<span class="hljs-string">"PIN is already 4 digits"</span>)
        }
    }, [pin]);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
            <span class="hljs-attr">value</span>=<span class="hljs-string">{pin}</span> 
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPin(e.target.value)} 
        /&gt;</span>
    )
}
</code></pre>
<p>We can avoid the useEffect by checking the pin length inside the onChange function before a new digit is entered.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> PinComponent = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> [pin, setPin] = useState(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (pin.length &gt; <span class="hljs-number">4</span>) {
            alert(<span class="hljs-string">"PIN is already 4 digits"</span>)
        }
        setPin(e.target.value)
    }

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
            <span class="hljs-attr">value</span>=<span class="hljs-string">{pin}</span> 
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleClick}</span> 
        /&gt;</span></span>
    )
}
</code></pre>
<p>Also, note that whether the dependency array is empty or not, useEffect will run at least once (when your component is mounted). Keep that in mind to avoid unexpected results.</p>
<ol start="2">
<li><h3 id="heading-group-elements-that-need-certain-state-into-components">Group elements that need certain state into components.</h3>
</li>
</ol>
<p>I'm sure you remember one of the fundamentals of React, when a state changes your component re-renders. We might have a big component, with lots of elements like a whole page with several state, and when a single state changes, this whole component re-renders and this not performant at all. Let's take a login page, for example. We have email, and password as state. Whenever the user enters any character in the email or password field, the whole login page re-renders.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> LoginPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [rememberMe, setRememberMe] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> handleEmailChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setEmail(e.target.value);
  <span class="hljs-keyword">const</span> handlePasswordChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setPassword(e.target.value);
  <span class="hljs-keyword">const</span> handleRememberMeChange = <span class="hljs-function">() =&gt;</span> setRememberMe(!rememberMe);

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();

    <span class="hljs-comment">// Perform login logic here using 'email' and 'password'</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Logging in with:"</span>, email, password);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Remember Me:"</span>, rememberMe);
  };

  <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">h2</span>&gt;</span>Login Form<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <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">label</span>&gt;</span>
          Email:
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
            <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> 
            <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span> 
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleEmailChange}</span> 
            <span class="hljs-attr">required</span> 
           /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
          Password:
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> 
            <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span> 
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handlePasswordChange}</span> 
            <span class="hljs-attr">required</span> 
           /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <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">"checkbox"</span> 
            <span class="hljs-attr">checked</span>=<span class="hljs-string">{rememberMe}</span> 
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleRememberMeChange}</span> 
          /&gt;</span>
          Remember Me
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Login<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 class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/forgot-password"</span>&gt;</span>Forgot Password?<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> LoginForm;
</code></pre>
<p>We can improve this by creating a separate component for the from fiels and then using it inside the LoginPage component. As used below.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> LoginForm = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [rememberMe, setRememberMe] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> handleEmailChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setEmail(e.target.value);
  <span class="hljs-keyword">const</span> handlePasswordChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setPassword(e.target.value);
  <span class="hljs-keyword">const</span> handleRememberMeChange = <span class="hljs-function">() =&gt;</span> setRememberMe(!rememberMe);

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();

    <span class="hljs-comment">// Perform login logic here using 'email' and 'password'</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Logging in with:"</span>, email, password);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Remember Me:"</span>, rememberMe);
  };

  <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">label</span>&gt;</span>
          Email:
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
            <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> 
            <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span> 
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleEmailChange}</span> 
            <span class="hljs-attr">required</span> 
           /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
          Password:
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> 
            <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span> 
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handlePasswordChange}</span> 
            <span class="hljs-attr">required</span> 
           /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <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">"checkbox"</span> 
            <span class="hljs-attr">checked</span>=<span class="hljs-string">{rememberMe}</span> 
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleRememberMeChange}</span> 
          /&gt;</span>
          Remember Me
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Login<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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> LoginForm;
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> LoginPage = <span class="hljs-function">() =&gt;</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">h2</span>&gt;</span>Login Form<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">LoginForm</span>/&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/forgot-password"</span>&gt;</span>Forgot Password?<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> LoginForm;
</code></pre>
<ol start="3">
<li><h3 id="heading-using-ui-libraries-unjudiciously">Using UI libraries unjudiciously</h3>
<p>It's not uncommon to get help from a UI library to build out UI components like buttons, inputs, and the likes. Creating UI components from scratch can be very time-consuming and distracting from the actual task at hand. I have a LinkedIn post on the best UI libraries <a target="_blank" href="https://www.linkedin.com/posts/fortunealebiosu_react-react-frontend-activity-7148451239834320896-smzG?utm_source=share&amp;utm_medium=member_desktop">here</a>.
But you should know how to use UI libraries judiciously because UI libraries add a significant amount of JavaScript to your JavaScript bundle (higher bundle size leads to slower initial page load). 
Don't install a UI library just because of a single UI component, neither should you use more than one UI library in your project. Look at every option you have and pick according to your needs. If the UI library you use does not have the UI component you seek, look for code samples of people online who have created such a component, or install an NPM package for such a component (still adds to your bundle size but not as much).</p>
</li>
<li><h3 id="heading-knowing-when-to-not-use-react">Knowing when to not use React</h3>
<p>To be a better React developer, you should also know when not to use React. Yes, React is a great tool for building UI's on the web and it has great developer experience, but React should not be your go-to tool for everything. React just like every tool has its pros and cons, it's great for interactivity (although Solid.js beats it in this aspect), but it's bad for SEO by default, and SEO is a business-critical need. 
You might wonder how React is bad for SEO. React ships a lot of JavaScript to the browser by default, and that bundle slows down the initial page load of your webpage. Content rendered on the browser with React is not pure HTML, so it cannot be crawled by search engine bots making it not so good for Search Engine Optimization (SEO).
If you need to build a landing page or a static website (where SEO is critical) that just displays information, your go-to should be plain HTML, CSS, and JS. If you feel like you need something more sophisticated or with better developer experience, use frameworks like Qwik or Astro that ship little or no JavaScript to the browser by default.
But when you need to build a web app with highly interactive views, React (although Next.js is an even better choice) is your best bet.</p>
</li>
</ol>
<p>That's all for today, please leave a like and let me know in the comments if you enjoyed this. You can also reach out to me on <a target="_blank" href="https://twitter.com/alebiosu_thedev">Twitter</a> and <a target="_blank" href="https://linkedin.com/in/fortunealebiosu">LinkedIn</a>. Until next time, see you later friends.</p>
]]></content:encoded></item><item><title><![CDATA[Basics of Authentication]]></title><description><![CDATA[What is Authentication
Simply put, authentication is the process of identifying a user or a person when they try to access a resource. If you've ever had to show an ID before entering into a building, that's a form of authentication. Verifying if a u...]]></description><link>https://blog.fortunealebiosu.dev/basics-of-authentication</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/basics-of-authentication</guid><category><![CDATA[Web Development]]></category><category><![CDATA[authentication]]></category><category><![CDATA[Security]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Wed, 06 Mar 2024 02:27:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/8ZRg-PaDNDY/upload/02cd861d6386405df375a19ddd4ffe42.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-authentication">What is Authentication</h2>
<p>Simply put, authentication is the process of identifying a user or a person when they try to access a resource. If you've ever had to show an ID before entering into a building, that's a form of authentication. Verifying if a user is who they say they are. And if you're not who you say you are, well that would be rather unfortunate.</p>
<h3 id="heading-authentication-vs-authorization">Authentication vs Authorization</h3>
<p>There is always confusion about the difference between authentication and authorization. Some may even think they mean the same thing. They do not, authentication is verifying a user's identity while authorization is verifying if an authenticated user has permission to access a particular resource or perform a certain action.</p>
<p>For example, on the popular social media app WhatsApp, authentication happens when you sign in with your phone number and a token (the OTP). But even if you are authenticated, you will not be allowed to add users to a group chat if you are not an admin, because you have not been authorized to do so. That authorization will happen when you have been made an admin.</p>
<h3 id="heading-authentication-factors">Authentication Factors</h3>
<p>An authentication factor is a category of security credentials that is used to verify a user who is trying to access a particular resource (a resource could be a mobile app or a website). There are different authentication factors, which are:</p>
<ol>
<li><h4 id="heading-knowledge-factor">Knowledge Factor</h4>
<p> This is an authentication category that is based on what the user knows. For example: username/email and password, security questions, PIN, etc.</p>
</li>
<li><h4 id="heading-qualities-factor">Qualities Factor</h4>
<p> This is an authentication factor that is based on what qualities or attributes the user has. For example: facial recognition, voice recognition, fingerprint detection, etc.</p>
</li>
<li><h4 id="heading-possession-factor">Possession Factor</h4>
<p> This is an authentication factor that is based on what the user has in their possession. For example: a device to receive OTP, or a hardware device to generate a token to give access.</p>
</li>
<li><h4 id="heading-location-factor">Location Factor</h4>
<p> This is an authentication factor that is based on the location of the user trying to access the resource. For example: a mechanism that does not allow users from a specific location to use a website.</p>
</li>
</ol>
<p>Now you must know that each of these authentication factors can be compromised, or in other words have their risks. The knowledge factor can be compromised when users use passwords or PINs that are easy to guess by attackers. The possession factor can be compromised when the device which the user uses to authenticate is stolen. And the list goes on. So it is important, to know the pros and cons of each factor and use an appropriate factor of the kind of resource you are trying to protect.</p>
<h4 id="heading-multi-factor-authentication-mfa-vs-two-factor-authentication-2fa">Multi-Factor Authentication (MFA) vs Two-Factor Authentication (2FA)</h4>
<p>Before I continue, I must congratulate you on reading this far, a lot of people do not have this level of attention span.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709689632197/26d572a0-624e-4aa8-946e-1c7863fda2df.jpeg" alt class="image--center mx-auto" /></p>
<p>You might not have heard of MFA, but I'm sure you heard about 2FA, and after the previous section on authentication factors, I'm sure things are starting to click in your head at this very moment. If they're not, it's perfectly fine, let's hop to it.</p>
<p>Two-factor authentication involves using examples from 2 different authentication factors to verify a user, for example, using username and password from the knowledge factor and OTP from the possession factor.</p>
<p>While multi-factor authentication involves using 2 different examples from any authentication factor, for example, using both username and password &amp; security questions from the knowledge factor.</p>
<h3 id="heading-authentication-strategies">Authentication Strategies</h3>
<p>As a software engineer, there are different strategies for implementing authentication. These are the different auth strategies, they will be discussed in better detail in an upcoming article.</p>
<ol>
<li><p>Basic Authentication</p>
</li>
<li><p>Session Based</p>
</li>
<li><p>Token Based</p>
</li>
<li><p>JWT (JSON Web Tokens)</p>
</li>
<li><p>Single Sign On (SSO)</p>
</li>
<li><p>OAuth</p>
</li>
</ol>
<p>If you learned something new, or like content like this be sure to leave a like or a comment. Thanks for reading, and see you soon!</p>
]]></content:encoded></item><item><title><![CDATA[Best Practices to make you the best React dev you can be.]]></title><description><![CDATA[React has been the most popular frontend library for about the past decade and is used for building a wide range of interactive applications where user experience is key. But like any other tool, you can always get things wrong or do things better. S...]]></description><link>https://blog.fortunealebiosu.dev/react-best-practices</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/react-best-practices</guid><category><![CDATA[React]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Wed, 31 Jan 2024 13:38:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/XXMA-8fBB-g/upload/63cd04b93a52f25bfdc647659c32edd1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>React has been the most popular frontend library for about the past decade and is used for building a wide range of interactive applications where user experience is key. But like any other tool, you can always get things wrong or do things better. So without further ado, here are some of the best practices I believe every React developer should follow.</p>
<ol>
<li><h2 id="heading-not-using-useeffect-to-fetch-data">Not using useEffect to fetch data</h2>
<p> <code>useEffect</code> is a great hook (some might not agree), and while this isn't exactly bad, it is not recommended for apps in production. You can use this if you are just learning the basics of data fetching in React, but once you get comfortable with data fetching in React you should look to use a library to implement your data fetching.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705282480574/3b672bd4-cca9-4471-8ec1-29ed6e0559f9.png" alt="Fetching Data with use effect in react" class="image--center mx-auto" /></p>
</li>
</ol>
<p>You can a library like <code>@tanstack/react-query</code> or <code>SWR</code> to fetch data and they automatically give you loading and error states as well as a bunch of other helpers. My go-to is <code>@tanstack/react-query</code> , and here's how you can fetch the people data in the previous example.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705282514389/310d12a3-f971-4f05-8671-3d5fb000c59b.png" alt="fetching data with react query in react" class="image--center mx-auto" /></p>
<ol>
<li><h2 id="heading-using-custom-hooks-to-fetch-data">Using custom hooks to fetch data</h2>
<p> Using the previous example in #1, you might want to use this people data in another component, of course, it makes sense to just copy and paste from the previous component to the new component, right? Well, that's bad because you break the DRY (Don't Repeat Yourself) principle by doing that. When you realize you have the write the same piece of code more than once, always put that piece of code in a function.</p>
<p> In React, whenever you have to fetch data, always do so in a custom hook because you never know when you're going to use that data in a different component, and it creates a nice separation of concerns. You can create a custom hook in React by simply defining a function with a name beginning with <code>use</code> , for example, <code>usePeople</code> or <code>useCollection</code> . Custom Hooks cannot be async functions, and can only be used in a React component.</p>
<p> Here's how we create a custom hook for our people data below.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705282578560/28895bf9-01f0-4c2e-849a-65ae4469cab9.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<p>We can then use the <code>usePeople</code> hook in the people component, as well as any other component.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705282635884/09a4dadc-2a54-472f-a456-3136e0c53a9f.png" alt class="image--center mx-auto" /></p>
<ol>
<li><h2 id="heading-lazy-loading">Lazy Loading</h2>
<p> When you deploy a React app, that app gets built into a JavaScript bundle on whatever hosting platform you decide on. When you visit that app on the web, the JS bundle gets sent to and downloaded by the browser, along with the single <code>index.html</code> file and your minified CSS files all at once. The JS bundle takes longer to get downloaded, and content is not rendered on the screen till that bundle has been downloaded completely (the time to complete this is called initial page load).</p>
<p> But with lazy loading, the JS bundle is split into smaller chunks and is only downloaded and executed by the browser when it is needed.</p>
<p> Here's how to implement lazy loading. Below we have 3 pages: Home, About, and ForgotPassword.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705282665512/375f2c4f-d7cc-4080-a262-6d4d727010f4.png" alt class="image--center mx-auto" /></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705282679151/942c4a2d-a0b7-4a19-8255-be37c18530d9.png" alt class="image--center mx-auto" /></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705282706674/22fb31c3-a781-4c59-abc8-2f515d2702c9.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<p>Now we lazy load the About Page and Forgot Password Page, using <code>lazy()</code> . When we navigate to the Forgot Password Page or About Page, it will take a while to render because the browser is downloading the JS bundle for those pages. To render a fallback while the bundle is downloading, we use the <code>&lt;Suspense/&gt;</code> component with the <code>fallback</code> prop. The fallback component cannot be lazy-loaded.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705282732045/73b3d722-c36c-480c-8a04-4cb320c24b4b.png" alt class="image--center mx-auto" /></p>
<p>You can lazy load all the pages of your application if you have a very complex application, but generally, you'd want to use lazy loading for pages that would most likely never be navigated to like ForgotPassword Page, because it would not make sense for the bundle of the ForgotPassword Page to be downloaded if the page will not be navigated to.</p>
<ol>
<li><h2 id="heading-implement-error-boundaries">Implement Error Boundaries</h2>
<p> Sometimes your app can crash or run into unexpected errors while your users use it. To render a fallback UI and catch errors when they happen, implement an Error Boundary in your app. You can do so using the <code>react-error-boundary</code> package as done below. You can also use Error Boundaries to report errors to whatever error logging service you are using by passing in a function to the <code>onError</code> prop on the <code>ErrorBoundary</code> component.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705282769598/84c795c9-bda1-49b0-8528-1e3f58c5cae2.png" alt class="image--center mx-auto" /></p>
</li>
<li><h2 id="heading-use-typescript">Use Typescript</h2>
<p> This is 2024, if you're still not using Typescript in your React Apps, then I don't know what to tell you😐. Except you're maintaining legacy code that must be kept in JavaScript or you're a total beginner at React, I highly recommend you use Typescript in all your projects.</p>
</li>
</ol>
<p>That's all for today, please leave a like and let me know in the comments if you want a Part 2. You can also reach out to me on <a target="_blank" href="https://twitter.com/alebiosu_thedev">Twitter</a> and <a target="_blank" href="https://linkedin.com/in/fortunealebiosu">LinkedIn</a>. Until next time, see you later friends.</p>
]]></content:encoded></item><item><title><![CDATA[Level Up in your TS game with Utility Types]]></title><description><![CDATA[Typescript, the most unnecessary addition to web development, is what I would have said a few years ago. I know some of you think it’s a wannabe C# introduced by Microsoft to make our lives a living hell, but Typescript is quite cool actually, hear m...]]></description><link>https://blog.fortunealebiosu.dev/utility-types-ts</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/utility-types-ts</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[TypeScript Tutorial]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Mon, 10 Jul 2023 19:01:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/e_5NhSomvS4/upload/97b23bb0be0a10ef814884c84b9d8cbe.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Typescript, the most unnecessary addition to web development, is what I would have said a few years ago. I know some of you think it’s a wannabe C# introduced by Microsoft to make our lives a living hell, but Typescript is quite cool actually, hear me out.  Love it or hate it, it’s being used in modern codebases, and you must be up to speed with it if you want to be useful to a lot of teams.</p>
<p>Today I’m going to be sharing with you some typescript utility types you can use in your code to give you that senior developer feel, and also so you can stop sprinkling type <code>any</code> everywhere in your codebase.</p>
<p>Let's begin, shall we......</p>
<ol>
<li><h3 id="heading-partial"><code>Partial</code></h3>
</li>
</ol>
<p>So let's say you wanted to create a user object, as you know you can create a type or an interface for that object like below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688730992140/cbf5aab2-7e52-48bb-a503-3ff6e44c6216.png" alt class="image--center mx-auto" /></p>
<p>Let’s say you wanted to update some properties of this user object, you can define a function called update with a parameter of type <code>User</code>, and then spread the values of this parameter into the user object.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688731019551/2e6b3e7e-cdfe-4977-9460-dfbff6ff66d7.png" alt class="image--center mx-auto" /></p>
<p>If we try to use this function, you can see we get an error. The values in our parameter don’t match the <code>User</code> type, because <code>phone_number</code>, <code>id</code> and <code>password</code> fields are missing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688731082551/738274bc-5bf6-4fcb-903f-386cf3bacc73.png" alt class="image--center mx-auto" /></p>
<p>For a quick fix, you could make all the properties on the <code>User</code> type optional, but that is such a junior dev move. Now this is where the <code>Partial</code> utility types shines.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688731966441/fae5e1d0-f2a7-4cf8-bdaa-645a414a3c7d.png" alt class="image--center mx-auto" /></p>
<p><code>Partial</code> makes all your fields optional without actually modifying the existing <code>User</code> type, so you can calmly update your user object without the editor screaming at you.</p>
<ol>
<li><h3 id="heading-omit"><code>Omit</code></h3>
</li>
</ol>
<p>Sometimes you have to create a new user in your database and you send the created user to your server via POST request from your frontend, and then your server assigns an ID to your user before sending it to the database. This can be easily done by defining a createUser function from your front end.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688733490121/620b2f0b-6f9d-4291-bc59-fae0571350ee.png" alt class="image--center mx-auto" /></p>
<p>But here’s the problem, the ID is not given till it gets to the server, but we’re still gonna use the <code>User</code> type when we retrieve the user from the server, which would have been assigned an ID by then, so removing the <code>id</code> property is not an option.</p>
<p>You could easily make the id property optional, which is also such an amateur move, you can do better.</p>
<p>This is where the <code>Omit</code> utility shines. With the <code>Omit</code> utility, you can create a new type by removing 1 or more properties from a type you previously created.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688733533652/1db79f1d-a7b3-4715-bf65-02d84cee042f.png" alt class="image--center mx-auto" /></p>
<p>Now you can send that user to your back end without any fears or editor hell.</p>
<ol>
<li><h3 id="heading-pick"><code>Pick</code></h3>
</li>
</ol>
<p>Now, <code>Pick</code> is basically just the reverse of <code>Omit</code>. Assuming you wanted to create a new type that has some of the properties of a previous class you created. Instead of creating an entirely new type, you have the <code>Pick</code> utility types at your disposal. As it implies, this utility picks certain properties from an existing type, which are defined by you. For example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688734326710/6a4ed286-fe08-44c2-8e51-3751c88d479f.png" alt class="image--center mx-auto" /></p>
<p>This approach basically breaks the DRY rule(Don't Repeat Yourself), because both interfaces have almost the same properties.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688734397817/6a2931f4-b957-4db2-886a-3bc3f46a4c5a.png" alt class="image--center mx-auto" /></p>
<p>This is much better init😂</p>
<ol>
<li><h3 id="heading-returntype"><code>ReturnType</code></h3>
</li>
</ol>
<p>Let’s say you defined a function that returned a string or a number, like below. You can use the ReturnType utility to get the type of what the sayHello function returns.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688734497135/1a34ed69-5110-42e5-a9b3-39b2a635f1de.png" alt class="image--center mx-auto" /></p>
<p>This is extremely useful if you don’t want to create an entirely new type for what a function may return.</p>
<p>That’s all for this week guys, if you liked this article be sure to leave a reaction and a comment, and for tips and tricks like these be sure to follow me here on Hashnode and on my Twitter at <a target="_blank" href="https://twitter.com/alebiosu_thedev">@alebiosu_thedev</a>.</p>
<p>Alight till next week, and remember, stop sprinkling <code>any</code>😶</p>
]]></content:encoded></item><item><title><![CDATA[React Components: The right way?]]></title><description><![CDATA[Let's say you want to create a component in React, like a button. There are a few great tips I want you to keep in mind, that would help you write cleaner code for your React components and give you that senior dev feel🌚
If that sounds great, lets h...]]></description><link>https://blog.fortunealebiosu.dev/react-components-the-right-way</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/react-components-the-right-way</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Mon, 20 Feb 2023 15:00:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/c8h0n7fSTqs/upload/270b89ae6b06d7689c8ea16305b115b8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let's say you want to create a component in React, like a button. There are a few great tips I want you to keep in mind, that would help you write cleaner code for your React components and give you that senior dev feel🌚</p>
<p>If that sounds great, lets hop in!</p>
<h2 id="heading-1-using-typescript-tsx">1. Using TypeScript (TSX)</h2>
<p>If you are not using TSX by now, you're wrong fr.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676896705804/4e51abbd-5b03-4652-86e1-2a9b6c1c7d53.jpeg" alt class="image--center mx-auto" /></p>
<p>Except if you *just* started your React journey, it's completely understandable. If not, then I have no words😐. Do yourself a favour and pick up TypeScript. I'll be releasing a React with TypeScript post soon for that</p>
<h2 id="heading-2-defining-interfaces-correctly-for-your-props">2. Defining Interfaces correctly for your props</h2>
<p>Let's say we were creating an input component, using regular HTML input. We could define an interface to show what props the component would receive. For example, the interface below is receiving props for our Input Component.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676896313026/10ffab67-49a5-423f-a601-479255318a14.png" alt class="image--center mx-auto" /></p>
<p>This code isn't very flexible, if we needed to add more props like <code>disabled</code> or <code>required</code>. We would need to add them into the interface, increasing how much we'd have to write into the interface. I know some of you like typing a lot, but your typing is bad in this case💀.</p>
<p>Since our component is based on the HTML input, we could use the <code>React.HTMLProps</code> to simplify our work and make out code look a lot cleaner.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676897738616/f5a90421-9ad0-43a7-b4b4-82bc15ddc240.png" alt class="image--center mx-auto" /></p>
<p>We could go further to make our component, this looks very satisfying to look at. I mean look at how those props are spread so cleanly😮‍💨.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676897880080/0ed8a942-4413-43e1-b411-e0c18aa37f07.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-3-using-defaultprops">3. Using <code>defaultProps</code></h2>
<p>Sometimes you want some of your props to have a default value in case you didn't supply a value into them. For example, you create a button component with width and height as props.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676898055291/dbbe3cc9-2495-4767-834a-c66852fcc4de.png" alt class="image--center mx-auto" /></p>
<p>Here the width and the height would be optional, so using the ternary operator we could specify that if the width and height are undefined, they would have values of 200px and 50px respectively. There's one word to describe this approach. INELEGANT.</p>
<p>Let's try something else</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676898357057/d0986cb5-b5a7-4b8c-82d7-c42f99bedbef.png" alt class="image--center mx-auto" /></p>
<p>Using the nullish coalescing operator, we could make this look better. Just like in the previous code, if the width and height are not defined via props, they would have values of 200px and 50px respectively.</p>
<p>But come on, you can do better than that. You are a senior dev in the making🌚. Let's try an even better approach.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676898532406/45092919-9ba8-4a1d-b2e8-64b6fd294fd0.png" alt class="image--center mx-auto" /></p>
<p>Using the <code>defaultProps</code> object, we can define default values for our props in case they are not defined. Now doesn't this look clean👀. And it works for both JSX and TSX.</p>
<p>That's all for this week, if you like helpful tips like this don't forget to like this article and comment. You can also follow me on <a target="_blank" href="https://twitter.com/alebiosu_thedev">Twitter</a> and subscribe to my blog for more content like this.</p>
<p>Until next time, byeeeee</p>
]]></content:encoded></item><item><title><![CDATA[Awesome CSS pseudo-classes]]></title><description><![CDATA[I think we've established the fact that CSS is weird, annoying and makes you want to cry sometimes🙂💔.
In today's episode, we'll be looking at CSS pseudo-classes, but not just any psuedo-class. I've come across some really interesting ones that are ...]]></description><link>https://blog.fortunealebiosu.dev/awesome-css-pseudo-classes</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/awesome-css-pseudo-classes</guid><category><![CDATA[HTML5]]></category><category><![CDATA[CSS]]></category><category><![CDATA[pseudo elements]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Sat, 19 Nov 2022 18:07:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/SXihyA4oEJs/upload/v1668858339073/ooF0e0waA.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I think we've established the fact that CSS is weird, annoying and makes you want to cry sometimes🙂💔.
In today's episode, we'll be looking at CSS pseudo-classes, but not just any psuedo-class. I've come across some really interesting ones that are not talked about enough and should really be a part of your code montage especially as a novice(to give you that senior developer feel, ya get?🌚). </p>
<p>If that sounds interesting, let's jump right in!</p>
<p>Disclaimer: Some of these may make you cry even more, so grab a tissue.</p>
<p>Let's begin shall we!</p>
<h2 id="heading-invalid">:invalid</h2>
<p>This is used to style an <code>&lt;input&gt;</code> when it is invalid, for example when specify <code>&lt;input type="number"&gt;</code> and you type in text, the input is invalid.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668766406914/uYErLt3_F.png" alt="invalid.png" class="image--center mx-auto" />
The :invalid pseudoclass in action</p>
<h2 id="heading-disabled">:disabled</h2>
<p>The :disabled pseudoclass is used to style a <code>&lt;button&gt;</code> when the disabled attribute is set to true.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668767321457/_Xsh6RM73.png" alt="disabled.png" class="image--center mx-auto" /></p>
<h2 id="heading-first-of-typelast-of-type">:first-of-type/:last-of-type</h2>
<p>This is used when you want to style the first/last of a particular element, for example</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668768619539/JwT9DcbVk.png" alt="first of type.png" class="image--center mx-auto" />
:first-of-type</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668768149236/QicuoN_G_.png" alt="last-of-type.png" class="image--center mx-auto" />
:last-of-type</p>
<h2 id="heading-is">:is() 😅</h2>
<p>The :is() psuedo-class is used to style every element that matches the argument provided in the parantheses, for example </p>
<pre><code>:is(ul, ol){
  <span class="hljs-attr">color</span>: red;
}
</code></pre><p>This would style every ol and ul with the red color.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668768439378/Rowcd9Hs3.png" alt="is.png" class="image--center mx-auto" />
You can gain much more from the :is() pseudo-class when you try to style multiple children/descendants at once, as shown above.</p>
<p>Traditionally if we wanted to style the last list item of both ol and ul, we would have to do this</p>
<pre><code>ul &gt; li:last-<span class="hljs-keyword">of</span>-type, ol &gt; li:last-<span class="hljs-keyword">of</span>-type {
  <span class="hljs-attr">color</span>: red;
</code></pre><p>The first one seems much nicer, doesn't it😏</p>
<h2 id="heading-has">:has() 😅</h2>
<p>The :has() pseudo-class is used to style descendants of a particular element or possibly style a sibling element. Previously, if we wanted to style multiple descendants of an element, we would have to select each descendant separately, like this</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668775361774/pTrEN5B-A.png" alt="has-old.png" class="image--center mx-auto" />.</p>
<p>But now, we can use the :has(), to select both elements together
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668775491979/oeON_A2KD.png" alt="has.png" class="image--center mx-auto" />.</p>
<p>To style a sibling element, use the "+" operator together with the :has() pseudo-class, for example </p>
<pre><code>&lt;div&gt;
     <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
     <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>How are you<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><pre><code> h1:has(+ h2){
  <span class="hljs-attr">color</span>: red;
}
</code></pre><p>*😅 means the pseudo-class is not fully supported by all browsers, like Samsung Internet and Firefox(Android and Desktop)</p>
<p>That's all for this week. Don't forget to leave a like or a reaction and if you want to see related content, do give me a follow. Thank you!😄</p>
]]></content:encoded></item><item><title><![CDATA[How to not hate CSS]]></title><description><![CDATA[CSS, the styling language for the web. Things may seem easy at first, but when margins and padding step into the mix, things may start to get a little outta hand.
And with different browsers each implementing CSS in a different way, now you have to a...]]></description><link>https://blog.fortunealebiosu.dev/how-to-not-hate-css</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/how-to-not-hate-css</guid><category><![CDATA[HTML5]]></category><category><![CDATA[CSS]]></category><category><![CDATA[webdev]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[newbie]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Sat, 12 Nov 2022 18:04:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1668246049817/R6XW6Qhbb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>CSS, the styling language for the web. Things may seem easy at first, but when margins and padding step into the mix, things may start to get a little outta hand.
And with different browsers each implementing CSS in a different way, now you have to add these weird prefixes to make sure the 259 different properties work as expected.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668242873597/eWxOwzPPs.png" alt="Screenshot_20221101-112737.png" />
That enough to drive me nuts.</p>
<p>Today I'm going to give you some tips to make sure your CSS is CSS-ing. If that sounds interesting, let's jump right in.</p>
<h2 id="heading-tip-1-actually-learn-css">Tip 1: Actually Learn CSS…</h2>
<p>Not Tailwind, Not Bootstrap, but the OG CSS. A lot of devs skip learning the actual CSS, and jump into a commitment to some random CSS framework and its long ass class names👀. 
If you are under this category of developers, fall out😑</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668093498691/ZroSPX6gK.jpg" alt="seal of disapproval.jpg" class="image--center mx-auto" />
Why do you do the things that you do?</p>
<p>Please do yourself a favour and actually learn the fundamentals, because it teaches you how CSS actually works, plus you don’t have to keep bearing the pain of looking at Bootstrap’s horrible styling.
Enough said, next tipppp…….</p>
<h2 id="heading-tip-2-learn-the-box-model">Tip 2: Learn the Box-Model</h2>
<p>The box model is the most fundamental piece of information you need to know as someone who writes CSS because it illustrates how your HTML elements are styled with CSS. Incase you haven't heard of Box Model before or you're one of those guys who decided to skip it :/, I've got good news.
The Box Model is actually really easy to understand, and you're going to learn it right now.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668108014908/emAQvV7HX.png" alt="box-model" class="image--center mx-auto" /></p>
<p>Every element in your HTML code is a box (your h1, nav, div, etc).The content of the box is whatever you put inside that tag .You can give each box a width and a height. The box can also have a border of any thickness. If you want to make space around the box, you give it a margin, if you want to squeeze-in the contents of the box, give it some padding. And that all there is to it.
Seeeeee……that wasn’t bad, was it?😏</p>
<p>Quick heads up: Sometimes you may give an element some padding, and it seems as though the padding increased the width or the height of your element causing it to overflow, use <code>box-sizing: border-box;</code> to get it back to it's orginal size.</p>
<h2 id="heading-tip-3-display-flex-is-your-friend">Tip 3: display: flex; is your friend</h2>
<p>If you are trying to arrange some items on your webpage, display: flex; is always the way to go, except you’re trying to arrange it in rows and columns(then you use display: grid, more on that later). When you apply <code>display: flex</code> to an element or a container, the contents of that elements flow either horizontally or vertically(row or column respectively), but by default it is horizontally. You can control this with the <code>flex-direction</code> property. 
To arrange the items on the vertical axis, use the <code>align-items</code> property.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668108867035/orXYrvwNA.png" alt="align-items" class="image--center mx-auto" /></p>
<p>To arrange the items on the horizontal axis, use the <code>justify-content</code> property.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668109110420/VokUlQdKh.png" alt="justify-content" class="image--center mx-auto" /></p>
<p>This is just a fraction of what flexbox can do, for a complete guide on flex, click <a target="_blank" href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/">here</a>.
The most complete tutorial on flex I've seen.</p>
<h2 id="heading-tip-4-flex-vs-grid">Tip #4: flex vs grid??:</h2>
<p>Don’t know when to choose between display:flex and display:grid? Lemme help you out with that
You use display: grid when you are trying to arrange different boxes/items in rows and columns. Grid basically focuses on both row and colums. Unlike grid, flexbox(display: flex) arranges items in just one direction, either row or column. You can change this with the <code>flex-direction</code> property. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668093533951/inJ_DFV1W.png" alt="flex example.png" />
You can use flexbox for something like this.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668093506090/v3krhMtLa.png" alt="grid example.png" />
You can use grid for something like this.</p>
<h2 id="heading-tip-5-use-css-shorthands">Tip 5: Use CSS shorthands</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668093549041/m2sq2EtRd.png" alt="wtf vs good.png" class="image--center mx-auto" />
If you prefer the one at the left, well I got no words😐.</p>
<p>Basically I'm saying, you should learn to use CSS shorthands, so you don't end up overcomplicating things. This may not seem like a big deal, but in the long run, this would probably lead to a larger CSS file that the browser has to download when users visit your site.
If you find it difficult trying to memorize the order of the shorthand values, just think of clockwise rotation: top -&gt; right 
-&gt; bottom -&gt; left.
Therefore, <code>margin: 15px 10px 4px 8px;</code> means 15px for top margin, 10px for right, 4px for bottom, and 8px for left.</p>
<h2 id="heading-bonus-tip">Bonus Tip👀</h2>
<p>If you want an element to appear on top of another, use the <code>z-index</code> property. An element with higher z-index will appear on top of an element with a lower one.
i.e. An element with <code>z-index: 10;</code> will appear on top of another with<code>z-index: 3;</code></p>
<p>That's all for this week. Thank you for reading 🤭. If you liked this article, please drop a reaction and let me know in the comments if you want to see a part 2 of this article.</p>
<p>If you found this helpful, give me a follow for more related content.</p>
]]></content:encoded></item><item><title><![CDATA[The Perfect HTML markup (I think...)]]></title><description><![CDATA[HTML is easy, we get it. But are you writing it the right way👀.  A lot of times I see people writing HTML that looks really confusing and hard to read through, especially when it time to apply CSS styles to your elements. 
From what we know, div’s d...]]></description><link>https://blog.fortunealebiosu.dev/the-perfect-html-markup</link><guid isPermaLink="true">https://blog.fortunealebiosu.dev/the-perfect-html-markup</guid><category><![CDATA[HTML]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[Fortune Alebiosu]]></dc:creator><pubDate>Sat, 05 Nov 2022 18:01:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/u2Ru4QBXA5Q/upload/v1667660654702/ouyQLhAio.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>HTML is easy, we get it. But are you writing it the right way👀.  A lot of times I see people writing HTML that looks really confusing and hard to read through, especially when it time to apply CSS styles to your elements. </p>
<p>From what we know, div’s do not have any semantic meaning, so why do you keep spamming them in your code?🙂</p>
<p>Today I’m going to be sharing with you a foolproof way of writing a proper HTML markup, while using semantic tags as well, not the spamming of div’s that most beginners are used to.</p>
<h2 id="heading-tip-1">Tip #1:</h2>
<p>Separating your HTML body using header, main and footer tag.</p>
<p>You should always separate the contents of your body tag, using the header, main and footer tag. </p>
<p>Not just by using DIVS!!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667659521489/gxhEhTs-m.png" alt="just divs in body.png" />
This is.......eww</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667659488682/VxzCQSa4Q.png" alt="header,mainandfooter.png" />
Isn't this nicer?🙂</p>
<p>This helps anyone who looks at your code to understand what is fully going on.
Elements like nav should always go inside your header.
The main content of your website/webpage should go into your main.
And the footer of your website, clearly would go into the footer. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667660413043/WThLx4gqC.png" alt="picture of a footer.png" />
For those who <strong>may</strong> not know what a footer is.</p>
<h2 id="heading-tip-2">Tip #2:</h2>
<p>When making a navbar always use the nav tag.
This and indicates that the highlited section of code is what represents the navbar. Also use a div tag to wrap all the elements of your navbar together.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667659624268/q7VqeHTI2.png" alt="navbar.png" /></p>
<p>This prevents your navbar from overflowing when your give it some left and right padding.</p>
<h2 id="heading-tip-3">Tip #3:</h2>
<p>Use the section tag to separate or group similar contents of your webpage together.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667660312263/fVXjemSlC.png" alt="section.png" /></p>
<p>Every element inside the red rectangles should be wrapped with the section tag.</p>
<p>Again, stop using divs for this purpose.</p>
<h2 id="heading-tip-4">Tip #4:</h2>
<p>Use div’s as containers to hold 2 or more elements together. For example your want to hold two buttons together, or a h3 and a p tag together. </p>
<p>One thing I also see regularly which I feel is bad practice is using divs as buttons. We have the button tag for that. If you want to list items in a container, use the ol or ul tag. </p>
<p>If you don't want the bullet points on your ol and ul tags, you can always set the <code>list-style-type</code> property to <code>none</code> in your CSS</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667659726824/ZDQkjvs4O.png" alt="not this.png" />
Don't do this.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667660098355/Uwy8-7ajf.png" alt="do this.png" />
Do this instead</p>
<h2 id="heading-tip-5">Tip #5:</h2>
<p>Keep off Inline Styling</p>
<p>Like for real, stay away from it as much as possible. It makes your code look really unreadable and bloated in my opinion. Perhaps your could try internal styling (still bloats your code, not as bad as before) or even better, external css. Doing this keeps your HTML nice and clean, while separating concerns really well.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667659979508/oE8nFB677.png" alt="inline style.png" />
Look at how bloated this looks.</p>
<p>That's all for this week. Thank you for reading 🤭. And remember, cut it out with the div's!</p>
<p>If you found this helpful, give me a follow for more related content.</p>
<p>Also follow or send me a message on Twitter <a target="_blank" href="https://twitter.com/alebiosu_thedev?t=AZ1AqcCPTlCXy57j7Sf6ZA&amp;s=09">@alebiosu_thedev</a> to know more about me or for a collaboration. </p>
]]></content:encoded></item></channel></rss>