<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Programming Blogs - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Programming Blogs - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 20 May 2026 22:46:31 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/programming-blogs/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Convert Images to PDF in the Browser Using JavaScript – A Step-by-Step Guide ]]>
                </title>
                <description>
                    <![CDATA[ Whether it’s scanned documents, screenshots, receipts, notes, certificates, or multiple photos, users often need a quick way to combine images into a downloadable PDF. Modern browsers make this much e ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-convert-images-to-pdf-using-javascript/</link>
                <guid isPermaLink="false">69fe1ae5f239332df4ec3436</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pdf ]]>
                    </category>
                
                    <category>
                        <![CDATA[ webdev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Bhavin Sheth ]]>
                </dc:creator>
                <pubDate>Fri, 08 May 2026 17:18:29 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/8902fd4f-fcfa-4f7b-8baf-9b595239254f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Whether it’s scanned documents, screenshots, receipts, notes, certificates, or multiple photos, users often need a quick way to combine images into a downloadable PDF.</p>
<p>Modern browsers make this much easier than before.</p>
<p>Instead of uploading files to a server, we can now process images directly in the browser using JavaScript. This keeps the tool fast, private, and easy to use.</p>
<p>In this tutorial, you’ll build a browser-based Image to PDF converter using JavaScript.</p>
<p>The tool will support uploading multiple images, sorting files, choosing orientation and page size, configuring margins, and merging images into either a single PDF or separate PDF files. Users will also be able to preview and download the generated document directly in the browser.</p>
<p>Everything runs entirely client-side without any backend.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/b3742c45-abef-44a6-9703-ee1538fa4c68.png" alt="Convert Images to PDF" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a href="#heading-how-image-to-pdf-conversion-works">How Image to PDF Conversion Works</a></p>
</li>
<li><p><a href="#heading-project-setup">Project Setup</a></p>
</li>
<li><p><a href="#heading-what-library-are-we-using">What Library Are We Using?</a></p>
</li>
<li><p><a href="#heading-creating-the-upload-interface">Creating the Upload Interface</a></p>
</li>
<li><p><a href="#heading-reading-uploaded-images">Reading Uploaded Images</a></p>
</li>
<li><p><a href="#heading-generating-the-pdf">Generating the PDF</a></p>
</li>
<li><p><a href="#heading-handling-multiple-images">Handling Multiple Images</a></p>
</li>
<li><p><a href="#heading-configuring-pdf-settings">Configuring PDF Settings</a></p>
</li>
<li><p><a href="#heading-renaming-and-downloading-the-pdf">Renaming and Downloading the PDF</a></p>
</li>
<li><p><a href="#heading-demo-how-the-image-to-pdf-tool-works">Demo: How the Image to PDF Tool Works</a></p>
</li>
<li><p><a href="#heading-important-notes-from-real-world-use">Important Notes from Real-World Use</a></p>
</li>
<li><p><a href="#heading-common-mistakes-to-avoid">Common Mistakes to Avoid</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-how-image-to-pdf-conversion-works">How Image to PDF Conversion Works</h2>
<p>The browser can't directly combine images into a PDF by itself.</p>
<p>Instead, we'll use a JavaScript PDF library that creates pages, inserts images, and exports everything as a downloadable PDF document.</p>
<p>The process starts when users upload one or multiple images into the browser. JavaScript then reads the image data and prepares it for PDF generation. After that, the tool creates PDF pages, inserts the uploaded images into those pages, and finally exports everything as a downloadable PDF document.</p>
<p>Everything happens locally inside the browser.</p>
<p>This means users don’t need to upload private files to a server, which makes the process faster and more privacy-friendly.</p>
<h2 id="heading-project-setup">Project Setup</h2>
<p>This project is intentionally simple.</p>
<p>You only need:</p>
<ul>
<li><p>an HTML file</p>
</li>
<li><p>a JavaScript file</p>
</li>
<li><p>a PDF library</p>
</li>
</ul>
<p>No backend or database is required.</p>
<h2 id="heading-what-library-are-we-using">What Library Are We Using?</h2>
<p>We’ll use the jsPDF library. It allows us to generate PDF files directly in JavaScript.</p>
<p>Add it using a CDN:</p>
<pre><code class="language-html">&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"&gt;&lt;/script&gt;
</code></pre>
<p>Once loaded, we can create and export PDF files directly from the browser.</p>
<h2 id="heading-creating-the-upload-interface">Creating the Upload Interface</h2>
<p>Start with a basic upload area:</p>
<pre><code class="language-html">&lt;input type="file" id="upload" multiple accept="image/*"&gt;

&lt;button onclick="convertToPDF()"&gt;
  Convert to PDF
&lt;/button&gt;
</code></pre>
<p>This allows users to upload multiple image files and generate the PDF.</p>
<p>Here’s what the upload section looks like inside the tool:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/0d9e3a68-26cd-4b5e-83ed-93149fcffdd1.png" alt="Image upload interface for browser-based image to PDF converter tool" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>You can also expand the interface with additional controls for sorting, page settings, margins, and merge modes.</p>
<h2 id="heading-reading-uploaded-images">Reading Uploaded Images</h2>
<p>After users select files, we need to read them in JavaScript.</p>
<p>We can use <code>FileReader</code> for this:</p>
<pre><code class="language-javascript">const fileInput = document.getElementById("upload");

const files = fileInput.files;

for (const file of files) {
  const reader = new FileReader();

  reader.onload = function (e) {
    const imageData = e.target.result;

    console.log(imageData);
  };

  reader.readAsDataURL(file);
}
</code></pre>
<p>This converts uploaded images into readable Base64 data that can later be inserted into the PDF.</p>
<h2 id="heading-generating-the-pdf">Generating the PDF</h2>
<p>Now we can create the PDF document.</p>
<pre><code class="language-javascript">const { jsPDF } = window.jspdf;

const pdf = new jsPDF();
</code></pre>
<p>Once the PDF is created, images can be inserted into pages:</p>
<pre><code class="language-javascript">pdf.addImage(imageData, "JPEG", 10, 10, 180, 120);
</code></pre>
<p>This inserts the uploaded image into the PDF page at a specific position and size.</p>
<p>Finally, export the document:</p>
<pre><code class="language-javascript">pdf.save("images.pdf");
</code></pre>
<p>This downloads the generated PDF instantly.</p>
<h2 id="heading-handling-multiple-images">Handling Multiple Images</h2>
<p>If users upload multiple files, each image can be added to its own PDF page automatically.</p>
<p>For example:</p>
<pre><code class="language-javascript">files.forEach((file, index) =&gt; {

  if (index !== 0) {
    pdf.addPage();
  }

});
</code></pre>
<p>This creates a new page before inserting the next image into the document.</p>
<p>In some situations, users may also want multiple images on the same page instead of one image per page.</p>
<p>For example:</p>
<pre><code class="language-javascript">pdf.addImage(img1, "JPEG", 10, 20, 80, 80);

pdf.addImage(img2, "JPEG", 110, 20, 80, 80);
</code></pre>
<p>This allows more flexible layouts for galleries, reports, or grouped documents.</p>
<h2 id="heading-configuring-pdf-settings">Configuring PDF Settings</h2>
<p>Before generating the final PDF, users can customize several layout and output settings.</p>
<p>These settings improve document quality and give users more control over the generated file.</p>
<p>Here’s what the configuration panel looks like inside the tool:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/c13b5ba4-054b-4698-9ea8-48d932926c91.png" alt="allinonetools - image to pdf convertion setting" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-sorting-images">Sorting Images</h3>
<p>When multiple images are uploaded, organizing them properly becomes important before generating the PDF.</p>
<p>Users may want to sort images alphabetically, reverse the order, or arrange them based on file size.</p>
<p>For example, images can be sorted alphabetically like this:</p>
<pre><code class="language-javascript">files.sort((a, b) =&gt; a.name.localeCompare(b.name));
</code></pre>
<p>You can also sort files by size:</p>
<pre><code class="language-javascript">files.sort((a, b) =&gt; a.size - b.size);
</code></pre>
<p>Here’s an example of sorting options inside the tool:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/bd834efc-6a70-41be-8597-9cddbb20c5ae.png" alt="image to pdf convertion image sorting option" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>This helps users organize documents more efficiently before converting them into a PDF.</p>
<h3 id="heading-choosing-orientation">Choosing Orientation</h3>
<p>Different images work better in different page orientations.</p>
<p>Portrait orientation works well for vertical images, while landscape orientation is better for wider images.</p>
<p>For example:</p>
<pre><code class="language-javascript">const pdf = new jsPDF({
  orientation: "portrait"
});
</code></pre>
<p>You can also switch to <code>"landscape"</code> when needed.</p>
<p>Here’s an example of orientation options inside the tool:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/1c9edb6b-3c15-4246-a060-0834a05493bf.png" alt="image to pdf convertion image orientation option" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-selecting-page-size">Selecting Page Size</h3>
<p>PDF page size controls the dimensions of the generated document.</p>
<p>For example:</p>
<pre><code class="language-javascript">const pdf = new jsPDF({
  unit: "mm",
  format: "a4"
});
</code></pre>
<p>This creates an A4-sized PDF document using millimeter units.</p>
<p>Other formats like letter, legal, or custom page sizes can also be supported.</p>
<p>Here’s an example of selecting page size options inside the tool:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/72c06be9-12e5-4c55-937a-93420072ae04.png" alt="image to pdf convertion page size selection option" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-adding-margins">Adding Margins</h3>
<p>Margins create spacing between the image and the edges of the page.</p>
<p>Without margins, images may touch the borders and appear cramped.</p>
<p>For example:</p>
<pre><code class="language-javascript">const margin = 10;

pdf.addImage(imageData, "JPEG", margin, margin, 180, 120);
</code></pre>
<p>Here’s an example of margins options inside the tool:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/bd36e4aa-d65c-486f-970e-fdfc283235b7.png" alt="image to pdf convertion margin selection option" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>This creates cleaner spacing around the inserted image.</p>
<h3 id="heading-automatic-image-fitting">Automatic Image Fitting</h3>
<p>One common issue when generating PDFs from images is incorrect sizing.</p>
<p>If images are inserted with fixed dimensions, they may stretch, overflow outside the page, or appear distorted.</p>
<p>Instead, it’s better to calculate image dimensions dynamically.</p>
<p>For example:</p>
<pre><code class="language-javascript">const pageWidth = pdf.internal.pageSize.getWidth();

const imgWidth = pageWidth - 20;

const imgHeight = (image.height * imgWidth) / image.width;

pdf.addImage(imageData, "JPEG", 10, 10, imgWidth, imgHeight);
</code></pre>
<p>This automatically scales images proportionally while maintaining margins and layout consistency.</p>
<h3 id="heading-merge-options">Merge Options</h3>
<p>One useful feature is allowing different output modes.</p>
<p>For example, users may want to merge all uploaded images into a single PDF document when creating reports, notes, or combined files.</p>
<p>In some cases, users may prefer generating separate PDFs for each image instead of combining everything together. This can be useful when exporting individual documents or scanned pages.</p>
<p>Custom grouping is another helpful option because it allows users to combine selected images into multiple PDFs based on their own arrangement or categories.</p>
<p>These different output modes make the tool much more flexible for different real-world use cases.</p>
<p>A simple selection dropdown works well:</p>
<pre><code class="language-html">&lt;select id="mergeMode"&gt;
  &lt;option&gt;Merge all into Single PDF&lt;/option&gt;
  &lt;option&gt;Create Separate PDFs&lt;/option&gt;
  &lt;option&gt;Custom Grouping&lt;/option&gt;
&lt;/select&gt;
</code></pre>
<p>Once selected, JavaScript can apply different generation logic based on the chosen mode.</p>
<p>Here’s an example of merge mode options inside the tool:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/84dfc427-6037-4520-b3e3-accb3d0837db.png" alt="image to pdf convertion image merge option" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>This makes the tool more flexible for handling different document workflows.</p>
<h2 id="heading-renaming-and-downloading-the-pdf">Renaming and Downloading the PDF</h2>
<p>After generating the document, users may want to rename the file before downloading.</p>
<p>You can prompt for a filename like this:</p>
<pre><code class="language-javascript">const fileName = prompt("Enter PDF name:", "images");

pdf.save(`${fileName}.pdf`);
</code></pre>
<p>This gives users more control over the exported file.</p>
<p>Here’s an example of the rename popup inside the tool:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/6409dfec-8ee5-4437-b7ca-2f78b27323ec.png" alt="image to pdf convertion rename popup" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h2 id="heading-demo-how-the-image-to-pdf-tool-works">Demo: How the Image to PDF Tool Works</h2>
<h3 id="heading-step-1-upload-images">Step 1: Upload Images</h3>
<p>Users upload one or multiple image files into the browser-based tool.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/0d9e3a68-26cd-4b5e-83ed-93149fcffdd1.png" alt="Image upload interface for browser-based image to PDF converter tool" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>The tool supports common formats like JPG, PNG, and WEBP.</p>
<h3 id="heading-step-2-configure-pdf-settings">Step 2: Configure PDF Settings</h3>
<p>Users can customize layout settings before generating the PDF.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/4cab41c0-ffe7-4f07-9846-649d538628a9.png" alt="Image to PDF converter settings showing sorting, orientation, page size, margins, and uploaded image previews" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>This includes:</p>
<ul>
<li><p>sorting images</p>
</li>
<li><p>orientation</p>
</li>
<li><p>page size</p>
</li>
<li><p>margins</p>
</li>
<li><p>merge mode</p>
</li>
</ul>
<p>These settings help create cleaner PDF output.</p>
<h3 id="heading-step-3-generate-the-pdf">Step 3: Generate the PDF</h3>
<p>Once settings are configured, users click the convert button.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/1323e37f-5947-415b-a747-e471b3b5ac53.png" alt="Convert to PDF button in browser-based image to PDF tool" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>The browser processes all uploaded images locally and generates the PDF instantly.</p>
<h3 id="heading-step-4-rename-the-generated-file">Step 4: Rename the Generated File</h3>
<p>Before downloading, users can rename the generated PDF.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/620bfe32-903f-4fce-9228-2afc7f8940eb.png" alt="Rename generated PDF popup before downloading the converted file" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>This improves organization when exporting multiple documents.</p>
<h3 id="heading-step-5-download-the-pdf">Step 5: Download the PDF</h3>
<p>Finally, the generated PDF becomes available for download directly in the browser.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/a1c808d1-4af6-4ca8-9bfc-a6df158e7777.png" alt="PDF preview and download section showing generated image PDF file" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>The entire process works without uploading files to any server.</p>
<h2 id="heading-important-notes-from-real-world-use">Important Notes from Real-World Use</h2>
<p>When working with large images, performance and memory usage become important.</p>
<p>Large images can slow down PDF generation and create unnecessarily large output files.</p>
<p>For example, you can limit upload size before processing:</p>
<pre><code class="language-plaintext">const MAX_SIZE = 10 * 1024 * 1024;

if (file.size &gt; MAX_SIZE) {
  alert("Image is too large.");
  return;
}
</code></pre>
<p>Another useful optimization is resizing images before inserting them into the PDF.</p>
<p>For example:</p>
<pre><code class="language-plaintext">const canvas = document.createElement("canvas");

const ctx = canvas.getContext("2d");

canvas.width = image.width * 0.5;
canvas.height = image.height * 0.5;

ctx.drawImage(image, 0, 0, canvas.width, canvas.height);

const resizedImage = canvas.toDataURL("image/jpeg", 0.7);
</code></pre>
<p>This reduces image dimensions and compression quality before generating the PDF.</p>
<p>It also helps reduce memory usage and improves PDF generation speed for large files.</p>
<p>Since everything runs directly inside the browser, uploaded images never leave the user’s device, which improves privacy.</p>
<h2 id="heading-common-mistakes-to-avoid">Common Mistakes to Avoid</h2>
<p>One common mistake is not validating uploaded files before processing them.</p>
<p>For example, users may upload unsupported formats or attempt to generate a PDF without selecting images.</p>
<p>Always validate input before processing:</p>
<pre><code class="language-javascript">if (!fileInput.files.length) {
  alert("Please upload images first.");
  return;
}
</code></pre>
<p>Another issue is inserting very large images without resizing them first.</p>
<p>Large images can create oversized PDFs and reduce performance significantly.</p>
<p>Incorrect image positioning is also common.</p>
<p>If dimensions are hardcoded incorrectly, images may overflow outside the page or become distorted.</p>
<p>Using dynamic image sizing and margins helps prevent these layout issues.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you built a browser-based image to PDF converter using JavaScript.</p>
<p>You learned how to upload images, generate PDF documents, configure layout settings, and export files directly inside the browser.</p>
<p>More importantly, you saw how modern browsers can handle document generation locally without relying on a backend server.</p>
<p>This approach keeps the tool fast, private, and easy to use.</p>
<p>Once you understand this workflow, you can extend it further with features like compression, drag-and-drop sorting, watermarking, batch exports, or advanced PDF editing tools.</p>
<p>You can also try a full working version here:</p>
<p><a href="https://allinonetools.net/image-to-pdf-converter/">https://allinonetools.net/image-to-pdf-converter/</a></p>
<p>And that’s where things start getting really interesting.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Scoped Note-Taking API with Django Rest Framework and SimpleJWT ]]>
                </title>
                <description>
                    <![CDATA[ If you've built a Django API and you're wondering how to add authentication so that each user can only access their own data, you're in the right place. Most Django tutorials teach you session-based a ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-scoped-note-taking-api-with-django-rest-framework-and-simplejwt/</link>
                <guid isPermaLink="false">69fa4395a386d7f121cd3bfc</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Django ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ django rest framework ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Prabodh Tuladhar ]]>
                </dc:creator>
                <pubDate>Tue, 05 May 2026 19:23:01 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/36921ffa-4741-4e11-8f16-2c84322ebceb.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you've built a Django API and you're wondering how to add authentication so that each user can only access their own data, you're in the right place.</p>
<p>Most Django tutorials teach you session-based authentication. That works fine when your frontend and backend live on the same server. But the moment you separate them – say, a React app on Netlify talking to a Django API on PythonAnywhere – then sessions start to break down.</p>
<p>Cookies don't travel well across different domains, and suddenly your login system stops working.</p>
<p>That's where JSON Web Tokens (JWT) come in. JWTs give you a stateless, cookie-free way to authenticate users. They work seamlessly across domains, devices, and platforms. The server doesn't need to remember anything. It just verifies the token's signature and knows exactly who's making the request.</p>
<p>But authentication is only half the problem. Once you know who a user is, you still need to control what they can see. This is where <strong>scoping</strong> comes in.</p>
<p>Scoping means ensuring that each user can only access their own data. User A should never be able to read, edit, or delete User B's data (notes in our case), even if they somehow guess the right ID.</p>
<p>In this tutorial, you'll build a a personal note-taking API where users can register, log in with JWT tokens, and store notes that only they can access.</p>
<p>Along the way, you'll implement a custom user model, configure SimpleJWT for token-based authentication, and write scoped views that lock each user's data behind their own credentials.</p>
<h3 id="heading-what-well-cover">What We'll Cover:</h3>
<ul>
<li><p><a href="#heading-prerequisities">Prerequisities</a></p>
</li>
<li><p><a href="#heading-what-is-jwt-and-why-use-it-over-session-authentication">What is JWT and Why Use It Over Session Authentication</a>?</p>
<ul>
<li><p><a href="#heading-how-session-authentication-works">How Session Authentication Works</a></p>
</li>
<li><p><a href="#heading-how-jwt-authentication-works">How JWT Authentication Works</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-1-how-to-set-up-the-project-and-install-the-dependecies">Step 1: How to Set Up the Project and Install the Dependecies</a></p>
<ul>
<li><p><a href="#heading-11-how-to-create-the-project">1.1 How to Create the Project</a></p>
</li>
<li><p><a href="#heading-12-how-to-create-a-virtual-environment-and-install-the-required-dependencies">1.2 How to Create a Virtual Environment and Install the Required Dependencies</a></p>
</li>
<li><p><a href="#heading-13-how-to-create-the-project-and-the-app">1.3 How to Create the Project and the App</a></p>
</li>
<li><p><a href="#heading-14-how-to-register-the-app-and-django-rest-framework-drf">1.4 How to Register the App and Django Rest Framework (DRF)</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-2-how-to-create-a-custom-user-model">Step 2: How to Create a Custom User Model</a></p>
<ul>
<li><p><a href="#heading-21-how-to-define-the-custom-user-model">2.1 How to Define the Custom User Model</a></p>
</li>
<li><p><a href="#heading-22-how-to-tell-django-to-use-your-custom-user-model">2.2 How to Tell Django to Use Your Custom User Model</a></p>
</li>
<li><p><a href="#heading-23-how-to-run-migrations">2.3 How to Run Migrations</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-3-how-to-define-the-note-model">Step 3: How to Define the Note Model</a></p>
<ul>
<li><p><a href="#heading-32-how-to-apply-migration">3.2 How to Apply Migration</a></p>
</li>
<li><p><a href="#heading-33-how-to-register-models-in-the-admin">3.3 How to Register Models in the Admin</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-4-how-to-create-the-serializer">Step 4: How to Create the Serializer</a></p>
<ul>
<li><p><a href="#heading-41-how-to-create-userserializer">4.1 How to Create UserSerializer</a></p>
</li>
<li><p><a href="#heading-42-how-to-create-noteserializer">4.2 How to Create NoteSerializer</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-5-how-to-configure-simplejwt">Step 5: How to Configure SimpleJWT</a></p>
<ul>
<li><p><a href="#heading-51-how-to-update-rest-framework-settings">5.1 How to Update REST Framework Settings</a></p>
</li>
<li><p><a href="#heading-52-how-to-add-token-url-endpoints">5.2 How to Add Token URL Endpoints</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-6-how-to-build-the-authentication-logic">Step 6: How to Build the Authentication Logic</a></p>
</li>
<li><p><a href="#heading-step-7-how-to-implement-scoped-views">Step 7: How to Implement Scoped Views</a></p>
<ul>
<li><p><a href="#heading-71-how-to-create-a-noteviewset">7.1 How to Create a NoteViewSet</a></p>
</li>
<li><p><a href="#heading-72-why-this-matters-preventing-id-enumeration-attacks">7.2 Why This Matters: Preventing ID Enumeration Attacks</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-8-how-to-connect-a-url">Step 8: How to Connect a URL</a></p>
<ul>
<li><p><a href="#heading-81-how-to-create-app-level-urls">8.1 How to Create App-level URLs</a></p>
</li>
<li><p><a href="#heading-82-how-to-verify-the-project-level-urls">8.2 How to Verify the Project-Level URLs</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-9-how-to-test-the-apis-with-postman">Step 9: How to Test the APIs with Postman</a></p>
<ul>
<li><p><a href="#heading-91-how-to-register-a-user">9.1 How to Register a User</a></p>
</li>
<li><p><a href="#heading-92-how-to-obtain-access-and-refresh-tokens">9.2 How to Obtain Access and Refresh Tokens</a></p>
</li>
<li><p><a href="#heading-93-how-to-create-a-note">9.3 How to Create a Note</a></p>
</li>
<li><p><a href="#heading-94-how-to-list-your-notes">9.4 How to List Your Notes</a></p>
</li>
<li><p><a href="#heading-95-how-to-demostrate-scoping">9.5 How to Demostrate Scoping</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-10-how-to-handle-token-expiration-with-refresh-tokens">Step 10: How to Handle Token Expiration with Refresh Tokens</a></p>
</li>
<li><p><a href="#heading-how-you-can-improve-this-project">How You Can Improve This Project</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<p>Here's what this tutorial covers:</p>
<ol>
<li><p>How to set up a custom user model (and why you should always do this)</p>
</li>
<li><p>How to configure SimpleJWT for access and refresh token authentication</p>
</li>
<li><p>How to build serializers that protect sensitive fields</p>
</li>
<li><p>How to scope your API views so users only see their own data</p>
</li>
<li><p>How to test the entire flow using Postman</p>
</li>
</ol>
<p>Let's get started</p>
<h2 id="heading-prerequisities">Prerequisities</h2>
<p>Before you begin, make sure you're comfortable with the following:</p>
<ol>
<li><p><strong>Django fundamentals</strong>: You should understand how Django projects and apps work, including models, views, URLs, and migrations.</p>
</li>
<li><p><strong>Django REST Framework basics</strong>: You should be familiar with serializers, viewsets or API views, and how DRF handles requests and responses.</p>
</li>
<li><p><strong>Basic command line usage</strong>: You'll run commands in your terminal throughout this tutorial.</p>
</li>
</ol>
<p>Tools you'll need installed:</p>
<ul>
<li><p>Python 3.8 or higher</p>
</li>
<li><p>pip (Python's package manager)</p>
</li>
<li><p>A code editor like Visual Studio Code</p>
</li>
<li><p>Postman (or any API testing tool) for testing your endpoints. You'll use this to send requests to your API.</p>
</li>
</ul>
<h2 id="heading-what-is-jwt-and-why-use-it-over-session-authentication">What is JWT and Why Use It Over Session Authentication?</h2>
<p>Before you write any code, it's important to understand what problem JWTs solve and why Django's built-in session authentication isn't always enough.</p>
<h3 id="heading-how-session-authentication-work">How Session Authentication Work</h3>
<p>Django ships with a session-based authentication system. Here's how it works at a high level:</p>
<ol>
<li><p>A user sends their username and password to the server.</p>
</li>
<li><p>The server verifies the credentials and creates a <strong>session</strong> which is a small record stored in the server's database that says "this user is logged in."</p>
</li>
<li><p>The server sends back a <strong>session ID</strong> as a cookie. The browser stores this cookie automatically.</p>
</li>
<li><p>On every subsequent request, the browser sends the cookie back to the server. The server looks up the session ID in its database and says "ah, this is User A. Let them through."</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/2689a08a-f8a9-4b83-ad7b-cc4c2de90419.png" alt="The infographics shows the steps taken in Django session authentication" style="display:block;margin:0 auto" width="2708" height="1252" loading="lazy">

<p>This works perfectly when your frontend and backend live on the same domain. The browser handles cookies automatically, and Django manages sessions in the database without you thinking about it.</p>
<p>But this approach has some limitations.</p>
<ol>
<li><p><strong>The cross-domain problem:</strong> If your React frontend lives at app.example.com and your Django API lives at <a href="http://api.example.com">api.example.com</a>, cookies become tricky. Browsers enforce strict rules about which domains can send and receive cookies.</p>
<p>You can work around this with CORS (Cross-Origin Resource Sharing) headers and special cookie settings, but it adds complexity and can be fragile.</p>
</li>
<li><p><strong>The scalability problem:</strong> Every active session is stored in the server's database. If you have 10,000 users logged in at the same time, that's 10,000 session records the server has to look up on every single request. As your application grows, this lookup becomes a bottleneck.</p>
</li>
<li><p><strong>The mobile problem:</strong> Mobile apps don't handle cookies the same way browsers do. If you're building an API that will serve both a web app and a mobile app, session cookies create extra headaches.</p>
</li>
</ol>
<h3 id="heading-how-jwt-authentication-works">How JWT Authentication Works</h3>
<p>JWTs take a fundamentally different approach. Instead of storing session data on the server, they put the authentication information directly into the token itself.</p>
<p>Here's how the flow works:</p>
<ol>
<li><p>A user sends their username and password to the server.</p>
</li>
<li><p>The server verifies the credentials and creates a JWT – a long encoded string that contains information like the user's ID and when the token expires.</p>
</li>
<li><p>The server sends this token back to the client. The client stores it (usually in memory or local storage).</p>
</li>
<li><p>On every subsequent request, the client includes the token in the request header. The server reads the token, verifies its signature, and says "this is User A. Let them through."</p>
</li>
</ol>
<p>Notice the key difference: <strong>the server never stores anything</strong>.</p>
<p>It doesn't look up a session in a database. It simply reads the token, checks its cryptographic signature to make sure nobody tampered with it, and extracts the user information. That's why JWTs are called <strong>stateless</strong> – the server doesn't maintain any state about who is logged in.</p>
<p><strong>This solves the cross-domain problem</strong> because tokens are sent in the request header, not as cookies. Headers work the same way regardless of which domain the request comes from.</p>
<p><strong>This solves the scalability problem</strong> because the server doesn't store sessions. Verifying a token is a quick cryptographic check, not a database lookup.</p>
<p><strong>This solves the mobile problem</strong> because any client that can send HTTP headers can use JWT. Mobile apps, desktop apps, other servers – they all work the same way.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/41d60dbd-707c-4483-8374-8910024bda7f.png" alt="The infographics shows the steps taken in JWT authentication" style="display:block;margin:0 auto" width="2682" height="1272" loading="lazy">

<h2 id="heading-step-1-how-to-set-up-the-project-and-install-the-dependecies">Step 1: How to Set Up the Project and Install the Dependecies</h2>
<h3 id="heading-11-how-to-create-the-project">1.1 How to Create the Project</h3>
<p>Open your terminal, navigate to where you want your project to live, and run the following commands:</p>
<pre><code class="language-shell">mkdir notes-project

cd notes-project
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/594f6c90-ea92-4859-9d9b-442d2fd2f23d.png" alt="The image shows the creation of notes project folder" style="display:block;margin:0 auto" width="1642" height="429" loading="lazy">

<h3 id="heading-12-how-to-create-a-virtual-environment-and-install-the-required-dependencies">1.2 How to Create a Virtual Environment and Install the Required Dependencies</h3>
<p>You will create a virtual environment here. Type the following command:</p>
<pre><code class="language-shell">python3 -m venv venv
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/4c1c9c33-9ffb-433a-a8f0-60cf0f598e14.png" alt="The image shows the creation of the virtual environment folder after tying the command" style="display:block;margin:0 auto" width="1778" height="380" loading="lazy">

<p>The above command creates a virtual environment inside a folder called <code>venv</code>. The first <code>venv</code> is the command and the second <code>venv</code> represents the name of the folder. You can name the folder anything though <code>venv</code> is usually preferred.</p>
<p>To activate the virtual environment, we need to use the following command:</p>
<p>On macOS/Linux:</p>
<pre><code class="language-shell">source venv/bin/activate
</code></pre>
<p>On Windows:</p>
<pre><code class="language-shell">venv\Scripts\activate
</code></pre>
<p>You'll know it worked when you see <code>(venv)</code> at the beginning of your terminal prompt. From this point on, any Python packages you install will only exist inside this <strong>virtual environment</strong>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/0a58f106-684c-4286-91fc-3c60f6e45483.png" alt="The image shows virtual environment being activated" style="display:block;margin:0 auto" width="2072" height="558" loading="lazy">

<p>With the virutal environment activated, install Django, Django Rest Framework, and Simple JWT Framework using the command:</p>
<pre><code class="language-shell">pip install django djangorestframework djangorestframework-simplejwt 
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/af83ad3f-3201-4e59-9367-e95630ae3cb3.png" alt="The image shows the installation of the packages after running the pip command" style="display:block;margin:0 auto" width="2314" height="1326" loading="lazy">

<p>You can verify everything installed correctly by running:</p>
<pre><code class="language-shell">pip list
</code></pre>
<p>You should see all three packages listed along with their dependencies.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/b725778c-57ca-42cb-a0a2-486ec3e6286e.png" alt="The image shows a list of all the dependencies along with the dependencies installed just now" style="display:block;margin:0 auto" width="2316" height="1038" loading="lazy">

<h3 id="heading-13-how-to-create-the-project-and-the-app">1.3 How to Create the Project and the App</h3>
<p>Run the following command to create the Django project:</p>
<pre><code class="language-plaintext">django-admin startproject notes_core .
</code></pre>
<p>The dot at the end is important. It tells Django to create the project files in your current directory instead of creating an extra nested folder.</p>
<p>Now let's type this command to create the app:</p>
<pre><code class="language-shell">python manage.py startapp notes
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/f0f95ce1-b8b0-4acb-ae5a-194fa3d74e08.png" alt="The image shows the folder structure of django project and app" style="display:block;margin:0 auto" width="2860" height="1638" loading="lazy">

<h3 id="heading-14-how-to-register-the-app-and-django-rest-framework-drf">1.4 How to Register the App and Django Rest Framework (DRF)</h3>
<p>Open <code>notes_core/settings.py</code> and add <code>rest_framework</code> and <code>notes</code> in the <code>INSTALLED_APPS</code> list:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/35988eff-506c-43af-ac6c-ef698e843ad3.png" alt="The image show the DRF and notes app being added to installed app list" style="display:block;margin:0 auto" width="2740" height="1312" loading="lazy">

<p>Django now knows about your new app and the REST framework. Let's move on to the most important architectural decision you'll make for this project.</p>
<h2 id="heading-step-2-how-to-create-a-custom-user-model">Step 2: How to Create a Custom User Model</h2>
<p>If you've built Django projects before, you might have used Django's default User model. For quick prototypes, that works fine. But for any project you plan to grow or maintain, starting with a custom user model is a best practice you should never skip.</p>
<p>Here's why: Django's default <code>User</code> model uses a <code>username</code> field as the primary identifier. If you later decide you want users to log in with their email address instead, or you need to add a profile picture field, or a phone number, then you're stuck.</p>
<p>Using a custom user model gives you full control over what a "user" means in your app. Instead of being tied to a username, you can design login around something more practical, like email or phone_number for a fitness or mobile-based app. You can also include fields like role (doctor, patient, receptionist in a clinic system) or date of birth directly in the user model, instead of managing a separate profile.</p>
<p>It also helps future-proof your project. If you start with the default model and later decide to switch login from username to email, or add required fields, it becomes difficult and risky to change. Using a custom user model from the beginning avoids this problem and makes it much easier to adapt your authentication system as your app grows.</p>
<p>By creating a custom user model from the start, even if it's identical to the default one, you give yourself the freedom to make changes later without any of that pain.</p>
<h3 id="heading-21-how-to-define-the-custom-user-model">2.1 How to Define the Custom User Model</h3>
<p>Open <code>notes/models/py</code> and add the following code:</p>
<pre><code class="language-python">from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    pass
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/29310f13-cdc9-409a-9c36-23234882fd6e.png" alt="The image shows the code for the custom user model" style="display:block;margin:0 auto" width="2802" height="1194" loading="lazy">

<p>You are importing Django’s built-in <code>AbstractUser</code> class.</p>
<p>Think of <code>AbstractUser</code> as a ready-made blueprint for a user. It already includes fields like username, password, email, first name, last name , and authentication logic.</p>
<p>The <code>pass</code> statement means you're not adding any extra fields yet.</p>
<p>But the key point is that this model is yours. So this model behaves exactly like Django’s default user model, but with one <strong>big advantage</strong>: you now have the flexibility to customize it later.</p>
<p>If three months from now you need to add a <code>phone_number</code> field or switch to email-based login, you just add a field to this class and run a migration.</p>
<pre><code class="language-python">from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    phone_number = models.CharField(max_length=15)
</code></pre>
<p>You can also see all the fields that the <code>CustomUser</code> class has inherited from the <code>AbstractUser</code> class.</p>
<p>To do this we can use the Python shell. Type the following command:</p>
<pre><code class="language-shell">python manage.py shell
</code></pre>
<p>When you type this command, make sure that the virtual environment is active:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/3c958f7f-6403-4eaf-b339-43532a02af6a.png" alt="The image shows the command to enter into the python shell with the virtual environment being activated" style="display:block;margin:0 auto" width="2588" height="604" loading="lazy">

<p>After this, import the <code>CustomUser</code> model in the shell:</p>
<pre><code class="language-shell">from notes.models import CustomUser
</code></pre>
<p>After that, type the following code:</p>
<pre><code class="language-shell">[fields.name for field in CustomUser._meta.get_fields()]
</code></pre>
<p>The above statement lists out all the fields in the <code>CustomUser</code> class.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/5a1b3314-7b48-41f6-98a9-dc3133cfce4c.png" alt="The image shows the output of all the fileds inherited by the CustomUser model" style="display:block;margin:0 auto" width="2638" height="904" loading="lazy">

<h3 id="heading-22-how-to-tell-django-to-use-your-custom-user-model">2.2 How to Tell Django to Use Your Custom User Model</h3>
<p>Now comes the important bit. Open <code>notes_core/settings.py</code> and add this line:</p>
<pre><code class="language-python">AUTH_USER_MODEL = 'notes.CustomUser'
</code></pre>
<p>This setting tells Django to use your <code>CustomUser</code> model instead of the built-in one for everything authentication-related such as login, permissions, foreign keys, and so on.</p>
<p>There's no strict rule to where you need to add it, but the best practice is to add it near the end of the file.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/87c9b03c-908d-4b2d-a6d5-9528ff98d1ab.png" alt="The image shows the above code being added to the settings.py file" style="display:block;margin:0 auto" width="2870" height="1280" loading="lazy">

<p>You can see which user model Django is using by using the method <code>get_user_model()</code>.</p>
<p>Open the Python shell again and import the <code>get_user_model()</code> method:</p>
<pre><code class="language-shell">from django.contrib.auth import get_user_model 
</code></pre>
<p>Then use <code>get_user_model()</code> and print the output:</p>
<pre><code class="language-shell">user = get_user_model()
print(user)
</code></pre>
<p>You should see the name of our model being used:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/895d5bcc-6880-4c4d-9007-96d44e9fa496.png" alt="895d5bcc-6880-4c4d-9007-96d44e9fa496" style="display:block;margin:0 auto" width="1580" height="276" loading="lazy">

<p>If you hadn't added the <code>AUTH_USER_MODEL</code> in the <code>settings.py</code> file, then Django would have used the default user model:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/a89f013a-e5d8-4e59-90b8-7da594188c13.png" alt="The image shows the default user model being used by Django" style="display:block;margin:0 auto" width="1886" height="1126" loading="lazy">

<p><strong>Note:</strong> You'll need to do this before you run your first migration. If you run migrate before setting AUTH_USER_MODEL, Django creates tables for the default User model, and switching afterward becomes a headache.</p>
<h3 id="heading-23-how-to-run-migrations">2.3 How to Run Migrations</h3>
<p>Now create and apply the initial migrations:</p>
<pre><code class="language-shell">python manage.py makemigrations
python manage.py migrate
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/cbca499a-286c-4f07-9a3e-375a69b4c374.png" alt="The image shows the output after running the above commands" style="display:block;margin:0 auto" width="2072" height="1222" loading="lazy">

<p>Django will create the necessary tables for your custom user model along with all the built-in Django tables.</p>
<p>We can again peek under the hood to see the SQL queries that Django used to create the tables especially the <code>CustomUser</code> table.</p>
<p>Type this command:</p>
<pre><code class="language-shell">python manage.py sqlmigrate notes 0001
</code></pre>
<p>Here <code>notes</code> is the name of the app and <code>0001</code> represents the migration number.</p>
<p>And you should get this output:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/850bba6c-8e54-4beb-8b85-f30f193341d5.png" alt="The image shows the output after the sqlmigrate command is executed" style="display:block;margin:0 auto" width="2714" height="1486" loading="lazy">

<p>Let's also create a superuser so you can access the admin panel later for debugging:</p>
<pre><code class="language-shell">python manage.py createsuperuser
</code></pre>
<p>Fill in the username, email (optional), and password when prompted.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/43820470-86b4-4274-834a-19a97adbc208.png" alt="The image shows the super user being created" style="display:block;margin:0 auto" width="2172" height="596" loading="lazy">

<h2 id="heading-step-3-how-to-define-the-note-model">Step 3: How to Define the Note Model</h2>
<p>Now let's create the data model for the core of your application. First add a new import to use the <code>settings</code> object.</p>
<pre><code class="language-python">from django.conf import settings
</code></pre>
<p>Then add the following code below the <code>CustomUser</code> class:</p>
<pre><code class="language-python">class Notes(models.Model):
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='notes'
    )
    title = models.CharField(max_length=200)
    body = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    def __str__(self):
        return f"{self.title} (by {self.owner.username})"
</code></pre>
<p>Here's the complete <code>model.py</code> code:</p>
<pre><code class="language-python">from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings

class CustomUser(AbstractUser):
    pass

class Notes(models.Model):
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='notes'
    )
    title = models.CharField(max_length=200)
    body = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    def __str__(self):
        return f"{self.title} (by {self.owner.username})"
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/24f1c5e3-6f9a-4dce-a7dc-d5d17aecc202.png" alt="The image shows the complete models.py file" style="display:block;margin:0 auto" width="2728" height="1314" loading="lazy">

<p>Let's walk through each field:</p>
<ol>
<li><p><code>owner = models.ForeignKey(settings.AUTH_USER_MODEL, ...)</code>: Creates a relationship between each note and a user. The <code>ForeignKey</code> field tells Django that each note belogs to exactly one user but a user can have many notes.</p>
<p>Notice that we use <code>settings.AUTH_USER_MODEL</code> instead of directly importing <code>CustomUser</code>. This is the recommended practice because it keeps your code flexible. If you ever change the user model reference in settings, this foreign key adapts automatically.</p>
<p>The <code>on_delete=models.CASCADE</code> means that if a user is deleted, all their notes are deleted too.</p>
<p>The <code>related_name='notes'</code> lets you access a user's notes with <code>user.notes.all()</code>.</p>
</li>
<li><p><code>title = models.CharField(max_length=200)</code>: Creates a text field for the task name, limited to 200 characters.</p>
</li>
<li><p><code>body = models.TextField()</code>: Holds the actual note content. <code>TextField</code> has no character limit, so users can write as much as they need.</p>
</li>
<li><p><code>created_at = models.DateTimeField(auto_now_add=True)</code>: Automatically records the date and time when a task is created. You never need to set this manually.</p>
<p>The <code>__str__()</code> method gives each note a readable representation. Instead of seeing "Note object (1)" in the admin panel or during debugging, you'll see something like "Meeting Notes (by Solina)."</p>
</li>
</ol>
<h3 id="heading-32-how-to-apply-migration">3.2 How to Apply Migration</h3>
<p>Run the migration commands to create the Note table:</p>
<pre><code class="language-shell">python manage.py makemigrations
python manage.py migrate
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/bf4b3469-89d8-4f8b-8b0d-1ea24eda5e2e.png" alt="The image shows the result of migrating the notes model" style="display:block;margin:0 auto" width="2594" height="1304" loading="lazy">

<p>As before, we can see the exact SQL query Django used to create the <code>notes</code> table:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/606d0d20-7c4f-40fb-a37b-de623ccee574.png" alt="The image shows the SQL query to create the notes table  and reference to the custom user table created earlier" style="display:block;margin:0 auto" width="2700" height="634" loading="lazy">

<h3 id="heading-33-how-to-register-models-in-the-admin">3.3 How to Register Models in the Admin</h3>
<p>Open <code>notes/admin.py</code> and register both models so you can inspect data through the admin panel:</p>
<pre><code class="language-python">from django.contrib import admin
from .models import CustomUser, Notes

admin.site.register(CustomUser)
admin.site.register(Notes)
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/482fc6de-33d2-4d09-8c6f-ce3df684eaa3.png" alt="The image shows the code for admin.py" style="display:block;margin:0 auto" width="2376" height="736" loading="lazy">

<p>This is helpful during development when you want to quickly check whether data is being saved correctly.</p>
<h2 id="heading-step-4-how-to-create-the-serializer">Step 4: How to Create the Serializer</h2>
<p>In DRF, a serializer is like a bridge between your database and the internet.</p>
<p>Django models store data as Python objects. But when you want to send that data to a frontend application (like React or a mobile app), you can't send Python objects. You need to send a format that everyone understands which is usually JSON.</p>
<p>Serializers perform three main jobs:</p>
<ol>
<li><p><strong>Serialization:</strong> Converting complex Python objects (Models) into Python dictionaries (which can be easily rendered into JSON).</p>
</li>
<li><p><strong>Deserialization:</strong> Converting JSON data coming from a user back into complex Python objects.</p>
</li>
<li><p><strong>Validation:</strong> Checking if the incoming data is correct before saving it to the database.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/a7339d6d-e338-4e12-a837-a780e85752a6.png" alt="The image shows the serialization deserialization process" style="display:block;margin:0 auto" width="800" height="287" loading="lazy">

<h3 id="heading-41-how-to-create-userserializer">4.1 How to Create UserSerializer</h3>
<p>Create a new file called <code>notes/serializers.py</code> and add the following code:</p>
<pre><code class="language-python">from rest_framework import serializers
from django.contrib.auth import get_user_model

User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'password']

    def create(self, validated_data):
        user = User.objects.create_user(
            username=validated_data['username'],
            email=validated_data.get('email', ''),
            password=validated_data['password']
        )
        return user
</code></pre>
<p>Let's break down this serializer.</p>
<ol>
<li><p>The <code>UserSerializer</code> handles user registration.</p>
</li>
<li><p><code>User = get_user_model()</code> gets the user model that you're using and stores in the variable <code>User</code>. In our case, we're using the <code>CustomUser</code> model</p>
</li>
<li><p><code>class UserSerializer(serializers.ModelSerializer):</code>: Here you've created the UserSerializer class, which inherits <code>ModelSerializer</code>.</p>
<p>A <code>ModelSerializer</code> is a shortcut that automatically creates a serializers class with fields that are in the model class.</p>
<p>When we use a <code>ModelSerializer</code>, DRF inspects the model and automatically does these things:</p>
<p>1. Generates fields from the model so you don't have to<br>2. Automatically adds field validations that are present in the model<br>3. Implements <code>create()</code> and <code>update()</code> methods. A <code>ModelSerializer</code> knows which model to use and how to update and create it. You can override <code>create()</code> and <code>update()</code> methods if you need customized behaviors. <strong>You have overridden the</strong> <code>create()</code> <strong>method in the above code.</strong></p>
</li>
<li><p><code>password = serializers.CharField(write_only=True)</code>: This line is crucial. The <code>write_only=True</code> flag means the password will be accepted during registration but will <strong>never</strong> appear in any API response. Without this, your API would send back the password (even if hashed) every time user data is returned.</p>
<p>So users can create accounts, but their passwords are never exposed back.</p>
</li>
<li><p><code>class Meta</code>: Inside the <code>Meta</code> class, you tell the serializer which model to use. In this case, the model to use is <code>User</code> and the fields to be handled.</p>
</li>
<li><p>The <code>create()</code> method: This is the most important part. This method runs when we create a new user. Instead of using the default <code>.create()</code> method you have overridden it.</p>
<p>It's important to understand why we have overridden this method. The default <code>create()</code> method is not suitable for creating users securely.</p>
<p>By default this method stores the password in plain text format. This is a serious problem because passwords should never be stored in raw form. They need to be <strong>hashed</strong> so that even if the database is compromised, the passwords are never exposed.</p>
<p>Django provides a special method called <code>create_user()</code> that automatically handles this by <strong>hashing the password</strong> and setting up the user properly for authentication.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/c1246e5d-104d-486c-965c-8edb04c850dc.png" alt="The image shows the annoated explanation of the code above" style="display:block;margin:0 auto" width="2340" height="1280" loading="lazy">

<h3 id="heading-42-how-to-create-noteserializer">4.2 How to Create NoteSerializer</h3>
<p>After the <code>UserSerializer</code> class, let's create the <code>NoteSerializer</code> class. The <code>NoteSerializer</code> handles the notes data</p>
<p>First of all, you need to add an import to the <code>Notes</code> class. Add the line <code>from .models import Notes</code> at the end of the last import.</p>
<p>Put this code below the <code>UserSerializer</code> class:</p>
<pre><code class="language-python">class NoteSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    class Meta:
        model = Notes
        fields = ['id', 'owner', 'title', 'body', 'created_at']
</code></pre>
<p>Now let's break it down:</p>
<ol>
<li><p><code>owner = serializers.ReadOnlyField(source='owner.username')</code>: This is the most important line in the code. This makes the <code>owner</code> field <strong>read-only</strong>. That means the API will display who owns a note (showing their username), but no one can set or change the owner through the API.</p>
<p>Without this protection, a malicious user could send a POST request with <code>"owner": 5</code> and assign their note to someone else's account, or worse, modify someone else's notes by reassigning ownership.</p>
<p>The <code>source='owner.username'</code> part tells DRF to display the owner's username instead of their numeric ID, which makes the API responses more readable.</p>
</li>
<li><p><code>class Meta:</code> ...: As before the <code>Meta</code> class contains the model which the serializer use and the fields that the API will expose.</p>
<p>Here is the complete code in the <code>serializers.py</code> file</p>
</li>
</ol>
<pre><code class="language-python">from rest_framework import serializers
from django.contrib.auth import get_user_model
from .models import Notes

User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'password']

    def create(self, validated_data):
        user = User.objects.create_user(
            username=validated_data['username'],
            email=validated_data.get('email', ''),
            password=validated_data['password']
        )
        return user

class NoteSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    class Meta:
        model = Notes
        fields = ['id', 'owner', 'title', 'body', 'created_at']
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/3073f560-79dc-4950-8acb-96d871e0511c.png" alt="The image shows the complete code for the serializers.py file" style="display:block;margin:0 auto" width="2006" height="1310" loading="lazy">

<h2 id="heading-step-5-how-to-configure-simplejwt">Step 5: How to Configure SimpleJWT</h2>
<p>Now let's set up the authentication system. This is where you tell DRF to use JWT for authentication instead of sessions. This step is crucial because without it, DRF will default to session-based auth.</p>
<p>SimpleJWT provides a complete JWT implementation for DRF, so you don't have to build token generation, signing, or verification from scratch.</p>
<p>The access token is what your client sends with every API request. It's short-lived by design. Think of it like a visitor badge at an office building: it gets you through the door, but it expires at the end of the day. If someone steals it, the damage is limited because it stops working soon.</p>
<p>The refresh token is longer-lived and has a single purpose: getting a new access token when the current one expires. The client stores it securely and only sends it to one specific endpoint. Think of it like your employee ID card. You use it to get a new visitor badge each morning, but you don't flash it at every door.</p>
<p>This separation exists for security. If the short-lived access token is compromised (which is more likely since it's sent with every request), the attacker has a narrow window before it expires. The refresh token, which is sent less frequently, has a lower risk of interception.</p>
<p>Let's look at how the access and refresh token work together</p>
<ol>
<li><p>User logs in, server gives both access token and refresh token</p>
</li>
<li><p>User makes requests using the access token</p>
</li>
<li><p>Access token expires</p>
</li>
<li><p>App sends refresh token to server</p>
</li>
<li><p>Server checks it and gives a new access token</p>
</li>
<li><p>User continues without logging in again</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/9cf61a53-99c6-4665-bf5d-dccafa71ca8d.png" alt="The image shows the use of access and refresh tokens" style="display:block;margin:0 auto" width="1840" height="1006" loading="lazy">

<h3 id="heading-51-how-to-update-rest-framework-settings">5.1 How to Update REST Framework Settings</h3>
<p>Open <code>notes_core/settings.py</code> and add the following code:</p>
<pre><code class="language-python">from datetime import timedelta
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),

    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
}

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
}
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/54e89c41-b456-4bbb-a129-ac3e92a09a6d.png" alt="The image shows the code being added to settings.py file" style="display:block;margin:0 auto" width="2492" height="1528" loading="lazy">

<p>Let's unpack what each section does.</p>
<p>The <code>DEFAULT_AUTHENTICATION_CLASSES</code> setting tells DRF to use JWT as the authentication method for all API endpoints. Every incoming request will be checked for a valid JWT token in the Authorization header.</p>
<p>The <code>DEFAULT_PERMISSION_CLASSES</code> setting sets <code>IsAuthenticated</code> as the global permission policy. This means every endpoint in your API is locked down by default. Only users with a valid token can access any endpoint.</p>
<p>This is a secure-by-default approach: instead of remembering to protect each view individually, everything is protected, and you explicitly open up the endpoints that need to be public <em>(like the registration endpoint, which you'll handle in the next step).</em></p>
<p>The <code>SIMPLE_JWT</code> dictionary controls token behavior. The access token lasts 30 minutes. This is the token clients include in every request. If someone intercepts it, the damage is limited to a 30-minute window. The refresh token lasts one day.</p>
<p>When the access token expires, the client can use the refresh token to get a new access token without forcing the user to log in again. The duration of the refresh token is 1 day. This means after 1 day, the user must log in again with their username and password. You'll see exactly how this works later when you test with Postman.</p>
<h3 id="heading-52-how-to-add-token-url-endpoints">5.2 How to Add Token URL Endpoints</h3>
<p>SimpleJWT provides ready-made views for obtaining and refreshing tokens. You just need to wire them up to URLs.</p>
<p>Open <code>notes_core/urls.py</code> and update it with the following code:</p>
<pre><code class="language-python">from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('notes.urls')),
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
</code></pre>
<p>The <code>token/</code> endpoint accepts a username and password, and returns an access token and a refresh token.</p>
<p>The <code>token/refresh/</code> endpoint accepts a refresh token and returns a new access token. You'll see these in action during testing.</p>
<h2 id="heading-step-6-how-to-build-the-authentication-logic">Step 6: How to Build the Authentication Logic</h2>
<p>Open <code>notes/views.py</code> and add the following:</p>
<pre><code class="language-python">from rest_framework import generics, permissions
from django.contrib.auth import get_user_model
from .serializers import UserSerializer

User = get_user_model()

class RegisterView(generics.CreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [permissions.AllowAny]
</code></pre>
<p>Now let's walk through this code.</p>
<p>The first section are the imports and after that we have used the the <code>get_user_model()</code> method to get the <code>CustomUser</code> model.</p>
<p>Now the main part is <code>RegisterView</code> class. The class inherits from <code>generics.CreateAPIView</code> which is a built in DRF view designed specifically for handling POST requests that create new objects.</p>
<p>Because of this, you don’t have to manually write the logic for handling POST requests, validating data, or saving to the database. DRF does all of that for you behind the scenes.</p>
<p>Inside the class, <code>queryset = Users.objects.all()</code> defines the set of user objects this view can work with.</p>
<p>The <code>serializer_class = UserSerializer</code> tells the view which serializer to use for validating incoming data and creating the user.</p>
<p>Finally <code>permission_classes = [permissions.AllowAny]</code> overrides the global <code>IsAuthenticated</code> permission you set earlier in the value of <code>DEFAULT_PERMISSION_CLASSES</code> .</p>
<p>This means that anyone can access the registration endpoint, even if they aren't logged in. This makes sense for a registration endpoint because new users won’t have accounts yet.</p>
<p>Every other view in your API will inherit the global IsAuthenticated permission, so only this registration endpoint is open.</p>
<h2 id="heading-step-7-how-to-implement-scoped-views">Step 7: How to Implement Scoped Views</h2>
<p>This is the heart of the tutorial. You've set up authentication so the API knows <strong>who</strong> is making a request. Now you need to make sure each user can only interact with <strong>their</strong> <strong>own</strong> notes.</p>
<p>Think of it this way: authentication is the lock on the front door of an apartment building. It keeps strangers out. But scoping is the lock on each individual apartment. Just because you live in the building doesn't mean you can walk into your neighbor's apartment.</p>
<p>Without scoping, an authenticated user could potentially see every note in the database, or worse, modify notes that belong to someone else. Two method overrides on your viewset prevent this entirely.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/03747660-068c-4757-9fc2-d2a122f22f5f.png" alt="The image represents the differences of access resources with and without scoping" style="display:block;margin:0 auto" width="1024" height="559" loading="lazy">

<h3 id="heading-71-how-to-create-a-noteviewset">7.1 How to Create a NoteViewSet</h3>
<p>Now let's create the <code>NoteViewSet</code>. First add these imports to the top of the file. We're importing the viewsets, serializers, and model.</p>
<pre><code class="language-python">from .models import Note
from .serializers import UserSerializer, NoteSerializer
from rest_framework import generics, viewsets, permissions
</code></pre>
<p>Add the following to <code>notes/views.py</code>, below the RegisterView:</p>
<pre><code class="language-python">class NoteViewSet(viewsets.ModelViewSet):
    serializer_class = NoteSerializer

    def get_queryset(self):
        return Notes.objects.filter(owner=self.request.user).order_by('-created_at')

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)
</code></pre>
<p>Now let's talk about this code in detail.</p>
<p>You've created a new class called <code>NoteViewSet</code> which inherits from the DRF class <code>ModelViewSet</code>. This gives you full CRUD operations, meaning you can list notes and retrieve a single note, as well as create, update, and delete a note.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/25999ad8-3534-424a-ab35-cad9cecec8ef.png" alt="The image shows the Model Viewset being imported" style="display:block;margin:0 auto" width="1338" height="248" loading="lazy">

<p>The next part <code>serializer_class = NoteSerializer</code> tells Django to use the <code>NoteSerializer</code> class to convert between Python objects and JSON.</p>
<p>But the magic is the two methods that you are overriding: <code>get_queryset()</code> and <code>perform_create()</code>.</p>
<p>The <code>get_queryset()</code> method controls which notes the API returns. If you didn't override this method, it would return <code>Note.objects.all()</code> (which would give every user access to every note in the database).</p>
<p>But here, you've overridden this method so that it filters notes by the current user.</p>
<p>Next is the <code>perform_create()</code> method, which is called when the note is saved. You've overridden this method so that it saves the notes of the user who's currently logged in. If you hadn't overridden the this method, it would return all the notes regardless of the logged in user.</p>
<p>Notice that you have passed <code>self.request.user</code> parameters in to the <code>filter()</code> function. This is the code that attaches the logged-in user as the owner of the note.</p>
<p>Remember how you made the owner field read-only in the serializer? This is the other half of that security measure.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/6db94c2f-673f-480a-bf20-730ed4af4bdb.png" alt="6db94c2f-673f-480a-bf20-730ed4af4bdb" style="display:block;margin:0 auto" width="1718" height="710" loading="lazy">

<p>The user can't set the owner through the API request, and the server automatically sets it to whoever is authenticated. These two pieces work together to make ownership tamper-proof.</p>
<h3 id="heading-72-why-this-matters-preventing-id-enumeration-attacks">7.2 Why This Matters: Preventing ID Enumeration Attacks</h3>
<p>Without get_queryset filtering, your API might allow something like this: a user sends a GET request to <code>/api/notes/42/</code> and sees a note that belongs to someone else, simply because they guessed the ID.</p>
<p>This is called an <strong>ID enumeration attack</strong> — an attacker cycles through IDs (1, 2, 3, 4...) to discover and access other people's data.</p>
<p>With your scoped <code>get_queryset</code>, even if User B sends a request to <code>/api/notes/42/</code> and note 42 belongs to User A, the viewset won't find it in User B's filtered queryset. DRF will return a 404 — as far as User B is concerned, that note doesn't exist.</p>
<h2 id="heading-step-8-how-to-connect-a-url">Step 8: How to Connect a URL</h2>
<p>Now you need to wire up the views to URL paths so the API knows which view to call for each endpoint.</p>
<h3 id="heading-81-how-to-create-app-level-urls">8.1 How to Create App-level URLs</h3>
<p>Create a new file called <code>notes/urls.py</code> and add the following:</p>
<pre><code class="language-python">from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import RegisterView, NoteViewSet

router = DefaultRouter()
router.register(r'notes', NoteViewSet, basename='note')

urlpatterns = [
    path('register/', RegisterView.as_view(), name='register'),
    path('', include(router.urls)),
]
</code></pre>
<p>The <code>DefaultRouter</code> automatically generates URL patterns for the NoteViewSet. Since you're using a <code>ModelViewSet</code>, the router creates endpoints for listing all notes, creating a note, retrieving a single note, updating a note, and deleting a note — <strong>all from that single router.register call.</strong></p>
<p>The <code>basename='note'</code> parameter is required here because your viewset doesn't have a queryset attribute defined directly on the class <em>(you're using get_queryset instead)</em>. DRF uses the <code>basename</code> to generate the URL pattern names like <code>note-list</code> and <code>note-detail</code>.</p>
<h3 id="heading-82-how-to-verify-the-project-level-urls">8.2 How to Verify the Project-Level URLs</h3>
<p>Make sure your <code>notes_core/urls.py</code> looks like this (you set this up in Step 5, but let's confirm):</p>
<pre><code class="language-python">from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('notes.urls')),
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
</code></pre>
<p>Here's the full picture of your API's URL structure:</p>
<table>
<thead>
<tr>
<th><strong>Endpoint</strong></th>
<th><strong>Method</strong></th>
<th><strong>Description</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>api/register/</code></td>
<td><strong>POST</strong></td>
<td>Create a new user account</td>
</tr>
<tr>
<td><code>api/token/</code></td>
<td><strong>POST</strong></td>
<td>Get access and refresh tokens</td>
</tr>
<tr>
<td><code>api/token/refresh/</code></td>
<td><strong>POST</strong></td>
<td>Get a new access token using a refresh token</td>
</tr>
<tr>
<td><code>api/notes/</code></td>
<td><strong>GET</strong></td>
<td>List all notes for the authenticated user</td>
</tr>
<tr>
<td><code>api/notes/</code></td>
<td><strong>POST</strong></td>
<td>Create a new note</td>
</tr>
<tr>
<td><code>api/notes/&lt;id&gt;/</code></td>
<td><strong>GET</strong></td>
<td>Retrieve a specific note</td>
</tr>
<tr>
<td><code>api/notes/&lt;id&gt;/</code></td>
<td><strong>PUT/PATCH</strong></td>
<td>Update a specific note</td>
</tr>
<tr>
<td><code>api/notes/&lt;id&gt;/</code></td>
<td><strong>DELETE</strong></td>
<td>Delete a specific note</td>
</tr>
</tbody></table>
<p>Start the development server to make sure everything runs without errors:</p>
<pre><code class="language-shell">python manage.py runserver
</code></pre>
<p>If the server starts without complaints, your code is wired up correctly.</p>
<h2 id="heading-step-9-how-to-test-the-apis-with-postman">Step 9: How to Test the APIs with Postman</h2>
<p>Building the API is one thing. Proving it works is another. Let's walk through the entire flow using Postman, from registering a user to demonstrating that scoping actually works.</p>
<p>If you haven't used Postman before, it's a tool that lets you send HTTP requests to your API and inspect the responses. You can download it from <a href="https://www.postman.com/downloads/">postman.com/downloads</a>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/cc154f8b-d3db-4c48-b884-1dbd3d517209.png" alt="Postman software download page" style="display:block;margin:0 auto" width="2518" height="1552" loading="lazy">

<p>Alternatively, you can use curl from the command line or any other API testing tool you're comfortable with.</p>
<p>Make sure your development server is running before proceeding.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/90524445-9d7c-43d0-bcf7-105f54626d85.png" alt="python server running" style="display:block;margin:0 auto" width="2078" height="678" loading="lazy">

<h3 id="heading-91-how-to-register-a-user">9.1 How to Register a User</h3>
<p>Open Postman:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/8951a205-ee01-4646-8e0b-d1d16d21c749.png" alt="opening Postman" style="display:block;margin:0 auto" width="2764" height="1792" loading="lazy">

<p>Create a new request:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/register/</code></td>
</tr>
<tr>
<td><strong>Body tab</strong></td>
<td>Select "raw" and choose "JSON" from the dropdown</td>
</tr>
<tr>
<td><strong>Body Content</strong></td>
<td>{ "username": "priya", "email": "<a href="mailto:priya@example.com">priya@example.com</a>", "password": "securepassword123" }</td>
</tr>
</tbody></table>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/f043164f-184c-4f29-8a9f-55f604d521fb.png" alt="postman UI for registering a new user" style="display:block;margin:0 auto" width="1918" height="770" loading="lazy">

<p>Click <strong>Send</strong>. You should get a <code>201 Created</code> response with the user data <strong>(without the password</strong>, thanks to your <code>write_only=True</code> field) which you wrote in the <code>UserSerializer</code> class.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/021a79db-418f-4057-97f8-f3c5c4b9761c.png" alt="response of registering a user" style="display:block;margin:0 auto" width="2024" height="1240" loading="lazy">

<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/c8fd6b4e-f539-4f16-85c8-72515abadf8f.png" alt="The image describes the codes of the User serializer classs" style="display:block;margin:0 auto" width="2340" height="1280" loading="lazy">

<h3 id="heading-92-how-to-obtain-access-and-refresh-tokens">9.2 How to Obtain Access and Refresh Tokens</h3>
<p>Now log in to get your JWTs:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/token/</code></td>
</tr>
<tr>
<td><strong>Body</strong></td>
<td>{"username" : "priya", "password" : "securepassword123"}</td>
</tr>
</tbody></table>
<p>You'll get a response with access and refresh tokens.</p>
<p><strong>Copy the access token.</strong> You'll need it for every subsequent request. Also save the refresh token, as you'll use it later.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/e5667e26-b11a-463e-85d4-ba99082bee21.png" alt="The image shows the api returning access and refresh token" style="display:block;margin:0 auto" width="2016" height="1224" loading="lazy">

<p>A JWT is only encoded and not encrypted. The encoding is merely a way to transform the data into a safe, standard string format that can be easily transmitted over the internet.</p>
<p>Any one can peel through the encoding to see the data. This is done using base64url encoding.</p>
<p>We can use the Python library <code>pyjwt</code> to decode JWTs or use any of the online sites to decode. It's important to note that you should use online sites with caution since JWTs may contain sensitive information.</p>
<p>For this demo, we'll use site called <a href="https://www.jwt.io">jwt.io</a>.</p>
<p>Open the site and paste in the access token that you have just created:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/f8b9f3e0-db1e-49fb-82be-2b4d27adc8bd.png" alt="The image describes the various sections after decoding the JWT token" style="display:block;margin:0 auto" width="2448" height="1392" loading="lazy">

<p>The JWT has three parts: the header, the payload, and the signature.</p>
<p>The header sections tells you how the header is signed. In this case it is signed using the <strong>HS256</strong> algorithm.</p>
<p>The payload is where the actual data or claim lives. It contains standard claims such as token types, expiration time ( <code>exp</code> ), issued at time ( <code>iat</code> ), and custom claims.</p>
<p>The signature section is used to verify integrity. You <strong>can't decode it to meaningful data.</strong> This section ensures that the token wasn't tampered with.</p>
<h3 id="heading-93-how-to-create-a-note">9.3 How to Create a Note</h3>
<p>Now use the access token to create a note:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/notes/</code></td>
</tr>
<tr>
<td><strong>Header tab:</strong></td>
<td>Add a new header:</td>
</tr>
<tr>
<td>Key: Authorization, Value: Bearer</td>
<td></td>
</tr>
<tr>
<td><strong>Body</strong></td>
<td>{'title': 'My note', 'body': 'This contains secret information'}</td>
</tr>
</tbody></table>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/d04e2bfb-edc6-4c12-ac93-65611ed0d805.png" alt="The image shows adding new header into postman" style="display:block;margin:0 auto" width="1762" height="1084" loading="lazy">

<p>Notice that you don't include an owner field. That's handled automatically by perform_create. You should get a <code>201 Created response</code>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/19a8b564-4d49-4dc1-823c-d7d96fcb5319.png" alt="The image shows the output (response) after creating a note" style="display:block;margin:0 auto" width="1802" height="1494" loading="lazy">

<p>You can create a few more notes, so that we have some data to work with.</p>
<h3 id="heading-94-how-to-list-your-notes">9.4 How to List Your Notes</h3>
<p>Now to fetch all of Priya's notes:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>GET</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/notes/</code></td>
</tr>
<tr>
<td><strong>Header tab:</strong></td>
<td>Same Authorization: Bearer header</td>
</tr>
</tbody></table>
<p>You should see all the notes created, sorted by most recent first.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/8b7107e6-44ef-465c-b1aa-076ec9de1979.png" alt="The image shows the response of getting list of notes" style="display:block;margin:0 auto" width="2122" height="1634" loading="lazy">

<h3 id="heading-95-how-to-demonstrate-scoping">9.5 How to Demonstrate Scoping</h3>
<p>Let's prove that a second user can't view the first user's notes.</p>
<p>First, register the second user.</p>
<p>Send a POST request to <code>http://127.0.0.1/api/register</code> with the following data:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/register/</code></td>
</tr>
<tr>
<td><strong>Body tab</strong></td>
<td>Select "raw" and choose "JSON" from the dropdown</td>
</tr>
<tr>
<td><strong>Body Content</strong></td>
<td>{ "username": "sujan", "email": "<a href="mailto:sujan@example.com">sujan@example.com</a>", "password": "anotherpassword123" }</td>
</tr>
</tbody></table>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/094af273-4220-416a-9c8f-f33079badf83.png" alt="The image shows a new user being created" style="display:block;margin:0 auto" width="2028" height="994" loading="lazy">

<p>Then get tokens for Sujan by sending a POST request to <code>http://127.0.0.1:8000/api/token/</code> with Sujan's credentials (username and password) and then copy Sujan's access token.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/8fe22f1b-f36e-4b35-a478-1b48ea0218c3.png" alt="8fe22f1b-f36e-4b35-a478-1b48ea0218c3" style="display:block;margin:0 auto" width="2118" height="1274" loading="lazy">

<p>Now send a GET request to <code>http://127.0.0.1:8000/api/notes/</code> using Sujan's token in the Authorization header.</p>
<p>The response should be an empty list since this user hasn't created any notes:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/ef8e17d0-4f8f-4a51-8bfd-01c078247075.png" alt="The image shows the response of the get query new user's access token" style="display:block;margin:0 auto" width="2094" height="1352" loading="lazy">

<p>More importantly, Priya's notes are completely invisible to him. Even if Sujan tries to access a specific note by ID – say, <code>http://127.0.0.1:8000/api/notes/1/</code> – he'll get a <code>404 Not Found</code> response, not a <code>403 Forbidden</code>.</p>
<p>This is intentional. A <code>404 Not Found</code> doesn't reveal that the note exists, while a <code>403 Forbidden</code> would confirm its existence to a potential attacker.</p>
<p>A <code>403 Forbidden</code> response is like a door with a sign: <em>“Authorized personnel only”.</em> You now know something important is inside. A <code>404 Not Found</code> response is like a blank wall. You don’t even know a room exists.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/a4619fbb-42ce-4f80-9207-31eb81336c7c.png" alt="The image shows the difference between a 403 and 404 response code" style="display:block;margin:0 auto" width="1860" height="910" loading="lazy">

<p>Now that you know why we've used the <code>404</code> response instead of <code>403</code>, let's demonstrate this.</p>
<p>First, I'll access Priya's individual note using her credentials and her access token:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/e68e33cc-93a4-4eb5-99fe-934b283defeb.png" alt="The image shows the result of accessing individual note using the first user (Priya)" style="display:block;margin:0 auto" width="2116" height="1170" loading="lazy">

<p>Now, I'll change the access token and put Sujan's (new user) access token:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/e5a6d07c-a7f0-4a50-ba05-94cc5159489c.png" alt="The image shows the response of accessing the second note using the new user's (sujan) credentials" style="display:block;margin:0 auto" width="2110" height="1166" loading="lazy">

<p>You can see that using the new user's token to access the previous user's note leads to <code>404 Not Found</code> response.</p>
<h2 id="heading-step-10-how-to-handle-token-expiration-with-refresh-tokens">Step 10: How to Handle Token Expiration with Refresh Tokens</h2>
<p>Access tokens are deliberately short-lived (30 minutes in your configuration). This limits the window of damage if a token is stolen.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/b86f4f24-b8b0-45d0-bcee-5e39e2268e21.png" alt="b86f4f24-b8b0-45d0-bcee-5e39e2268e21" style="display:block;margin:0 auto" width="1330" height="870" loading="lazy">

<p>But you don't want users to re-enter their credentials every 30 minutes. That's what refresh tokens are for.</p>
<p>When Priya's access token expires, her API requests will start returning <code>401 Unauthorized</code> responses. Instead of logging in again, the client sends the refresh token to get a fresh access token.</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/token/refresh/</code></td>
</tr>
<tr>
<td><strong>Body tab</strong></td>
<td>Select "raw" and choose "JSON" from the dropdown</td>
</tr>
<tr>
<td><strong>Body Content</strong></td>
<td>{ refresh: &lt; Priya's refresh token &gt;}</td>
</tr>
</tbody></table>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/67d255ac-8696-45e6-be17-c80b2a6e8af0.png" alt="The image shows the response of getting a new access token using a refresh token" style="display:block;margin:0 auto" width="2110" height="1360" loading="lazy">

<p>Replace your old access token with this new one, and you're good for another 30 minutes. The refresh token itself lasts for one day, so the user only needs to fully log in again once every 24 hours.</p>
<p>In a real application, the frontend client handles this automatically. When an API call returns a <code>401</code>, the client catches it, sends the refresh token to get a new access token, and retries the original request — all without the user noticing.</p>
<p>Here's what that flow looks like in pseudocode:</p>
<ol>
<li><p>Client sends request with access token</p>
</li>
<li><p>Server responds with 401 (token expired)</p>
</li>
<li><p>Client sends refresh token to /api/token/refresh/</p>
</li>
<li><p>Server responds with a new access token</p>
</li>
<li><p>Client retries the original request with the new access token</p>
</li>
<li><p>Server responds with the data</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/f0fd3fd8-842b-4de3-8f5b-2f1d4ad2181f.png" alt="The image show the steps to get a new token after a previous one has expired" style="display:block;margin:0 auto" width="1868" height="906" loading="lazy"></li>
</ol>
<p>If the refresh token itself has expired (after 24 hours in your configuration), step 4 will also return a <code>401</code>. At that point, the user truly needs to log in again with their username and password. This is the intended behavior: it means even a stolen refresh token has a limited useful life.</p>
<h2 id="heading-how-you-can-improve-this-project">How You Can Improve This Project</h2>
<p>This API is functional and secure, but there's plenty of room to build on it. Here are some directions you could take.</p>
<ol>
<li><p><strong>Add search and filtering.</strong> Let users search their notes by title or body text. You can use DRF's SearchFilter and django-filter to add query parameters like <code>?search=meeting</code> to the notes list endpoint.</p>
</li>
<li><p><strong>Add categories or tags.</strong> Create a <code>Category</code> model and add a <strong>foreign key</strong> to <code>Note</code>, or use a many-to-many relationship for tags. This would let users organize their notes and filter by category.</p>
</li>
<li><p><strong>Add pagination.</strong> Once a user has hundreds of notes, returning them all in a single response becomes slow. DRF has built-in pagination classes that let you return notes in pages of 10, 20, or whatever size you choose.</p>
</li>
<li><p><strong>Deploy to a production server.</strong> The API currently runs on your local machine. You could deploy it to platforms like PythonAnywhere, Railway, or Render to make it accessible from anywhere. You'd need to configure a production database (like PostgreSQL), set a secure SECRET_KEY, and serve the application behind HTTPS.</p>
</li>
<li><p><strong>Build a frontend.</strong> Connect a React, Next.js, or Vue.js frontend to this API. Store the JWTs in the client and implement the token refresh flow so users stay logged in seamlessly.</p>
</li>
<li><p><strong>Add token blacklisting.</strong> SimpleJWT supports token blacklisting, which lets you invalidate refresh tokens when a user logs out. Without this, a refresh token remains valid until it expires, even after the user "logs out."</p>
</li>
</ol>
<p>Each of these improvements builds on the patterns you've already learned and will deepen your understanding of Django, DRF, and API design.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You've built a fully functional, secure note-taking API with Django, Django REST Framework, and SimpleJWT. Along the way, you learned some fundamental concepts that apply to any API you'll build in the future.</p>
<p>You started with a custom user model — a small decision at the beginning that saves you from a painful migration later. You configured JWT authentication so your API can serve mobile clients and decoupled frontends that can't rely on session cookies.</p>
<p>You built serializers that protect sensitive data by keeping passwords write-only and ownership read-only. Most importantly, you implemented scoped views that ensure each user's data is completely isolated from everyone else's.</p>
<p>The patterns you practiced here — overriding <code>get_queryset</code> to filter by the current user, overriding <code>perform_create</code> to assign ownership automatically, and using <code>read-only</code> fields to prevent data tampering — are the same patterns you'll use in production APIs handling real user data.</p>
<p>The best way to solidify what you've learned is to keep building. Try adding search and filtering, build a React frontend that consumes this API, or start a completely new project may be a task manager, a journal app, or a bookmarks API using the same JWT and scoping patterns. The core workflow stays the same. Only the models and business logic change.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build and Deploy a Fitness Tracker Using Python Django and PythonAnywhere - A Beginner Friendly Guide ]]>
                </title>
                <description>
                    <![CDATA[ If you've learned some Python basics but still feel stuck when it comes to building something real, you're not alone. Many beginners go through tutorials, learn about variables, functions, and loops,  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-and-deploy-a-fitness-tracker-using-python-django-and-pythonanywhere/</link>
                <guid isPermaLink="false">69cfff6ce466e2b762506a84</guid>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Django ]]>
                    </category>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Beginner Developers ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Prabodh Tuladhar ]]>
                </dc:creator>
                <pubDate>Fri, 03 Apr 2026 17:57:00 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/a1ae273b-9f92-4fc2-89aa-1452fc0df895.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you've learned some Python basics but still feel stuck when it comes to building something real, you're not alone. Many beginners go through tutorials, learn about variables, functions, and loops, and then hit a wall when they try to create an actual project.</p>
<p>The gap between "I know Python syntax" and "I can build a working web app" can feel enormous. But it does not have to be.</p>
<p>In this tutorial, you'll build a fitness tracker web application from scratch using Django, one of the most popular Python web frameworks. By the end, you'll have a fully functional app running live on the internet – something you can show to friends, add to your portfolio, or keep building on.</p>
<p>Here's what you'll learn:</p>
<ul>
<li><p>How Django projects and apps are structured</p>
</li>
<li><p>How to define database models to store workout data</p>
</li>
<li><p>How to create views that handle user requests</p>
</li>
<li><p>How to build HTML templates that display your data</p>
</li>
<li><p>How to connect URLs to views so users can navigate your app</p>
</li>
<li><p>How to deploy your finished app to PythonAnywhere so anyone can access it</p>
</li>
</ul>
<p>The app itself is straightforward: you can log a workout by entering an activity name, duration, and date. You can then view all your logged workouts on a separate page. It's simple, but it covers the core Django concepts you need to build much bigger things later.</p>
<p>Let's get started.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-what-you-are-going-build">What You Are Going Build</a></p>
</li>
<li><p><a href="#heading-step-1-how-to-set-up-your-django-project">Step 1: How to Set Up Your Django Project</a></p>
<ul>
<li><p><a href="#heading-1-1-how-to-create-a-virtual-environment">1. 1 How to create a virtual environment</a></p>
</li>
<li><p><a href="#heading-12-how-to-install-django">1.2 How to install Django</a></p>
</li>
<li><p><a href="#heading-13-how-to-create-the-project">1.3 How to Create the Project</a></p>
</li>
<li><p><a href="#heading-14-how-to-run-the-development-server">1.4 How to run the development server</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-2-how-to-create-a-django-app">Step 2: How to Create a Django App</a></p>
<ul>
<li><p><a href="#heading-21-how-to-generate-the-app">2.1 How to Generate the App</a></p>
</li>
<li><p><a href="#heading-22-how-to-register-the-app">2.2 How to Register the App</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-3-how-to-create-a-workout-model">Step 3: How to create a Workout Model</a></p>
<ul>
<li><a href="#heading-31-how-to-define-the-model">3.1 How to Define the Model</a></li>
</ul>
</li>
<li><p><a href="#heading-step-4-how-to-apply-migrations">Step 4: How to Apply Migrations</a></p>
<ul>
<li><p><a href="#heading-41-how-to-generate-the-migration">4.1 How to Generate the Migration</a></p>
</li>
<li><p><a href="#heading-42-how-to-apply-the-migration">4.2 How to Apply the Migration</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-5-how-to-register-the-model-in-the-admin-panel">Step 5: How to Register the Model in the Admin Panel</a></p>
<ul>
<li><p><a href="#heading-52-how-to-create-a-superuser">5.2 How to Create a Superuser</a></p>
</li>
<li><p><a href="#heading-53-how-to-access-the-admin-panel">5.3 How to Access the Admin Panel</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-6-how-to-create-views-for-the-app">Step 6: How to Create Views for the App</a></p>
<ul>
<li><p><a href="#heading-61-how-to-create-a-form-class">6.1 How to Create a Form Class</a></p>
</li>
<li><p><a href="#heading-62-how-to-write-views">6.2 How to Write Views</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-7-how-to-create-templates">Step 7: How to Create Templates</a></p>
<ul>
<li><p><a href="#heading-71-how-to-set-up-the-template-directory">7.1 How to Set Up the Template Directory</a></p>
</li>
<li><p><a href="#heading-72-how-to-create-the-workout-list-template">7.2 How to Create the Workout List Template</a></p>
</li>
<li><p><a href="#heading-73-how-to-create-add-workout-template">7.3 How to Create Add Workout Template</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-8-how-to-connect-urls">Step 8: How to Connect URLs</a></p>
<ul>
<li><p><a href="#heading-81-how-to-create-app-level-urls">8.1 How to Create App Level URLs</a></p>
</li>
<li><p><a href="#heading-82-how-to-link-app-urls-to-project">8.2 How to Link App URLs to project</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-9-how-to-test-the-application-locally">Step 9: How to Test the Application Locally</a></p>
</li>
<li><p><a href="#heading-step-10-how-to-prepare-for-deployment">Step 10: How to Prepare for Deployment</a></p>
<ul>
<li><a href="#heading-101-how-to-update-settings-for-production">10.1 How to Update Settings for Production</a></li>
</ul>
</li>
<li><p><a href="#heading-step-11-how-to-deploy-your-django-app-on-pythonanywhere">Step 11: How to Deploy Your Django App on PythonAnywhere</a></p>
<ul>
<li><p><a href="#heading-111-how-to-create-a-pythonanywhere-account">11.1 How to Create a PythonAnywhere Account</a></p>
</li>
<li><p><a href="#heading-112-how-to-upload-your-project-files">11.2 How to Upload Your Project Files</a></p>
</li>
<li><p><a href="#heading-113-how-to-set-up-a-virtual-environment-in-pythonanywhere">11.3 How to Set Up a Virtual Environment in PythonAnywhere</a></p>
</li>
<li><p><a href="#heading-114-how-to-run-migrations-and-create-a-superuser-on-pythonanywhere">11.4 How to Run Migrations and Create a SuperUser on PythonAnywhere</a></p>
</li>
<li><p><a href="#heading-114-how-to-configure-the-web-app-in-pythonanywhere">11.4 How to Configure the Web App in Pythonanywhere</a></p>
</li>
<li><p><a href="#heading-115-how-to-set-the-virtual-environment-path">11.5 How to Set the Virtual Environment Path</a></p>
</li>
<li><p><a href="#heading-116-how-to-configure-the-wsgi-file">11.6 How to Configure the WSGI file</a></p>
</li>
<li><p><a href="#heading-117-how-to-set-up-static-files">11.7 How to Set Up Static Files</a></p>
</li>
<li><p><a href="#heading-118-how-to-view-your-live-application">11.8 How to View Your Live Application</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-common-mistakes-and-how-to-fix-them">Common Mistakes and How to Fix Them</a></p>
</li>
<li><p><a href="#heading-how-you-can-improve-this-project">How You Can Improve This Project</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you begin, make sure you are comfortable with the following:</p>
<p><strong>Python fundamentals:</strong> You should understand variables, functions, lists, dictionaries, and basic control flow (if/else statements and loops).</p>
<p><strong>Basic command line usage:</strong> You'll be running commands in your terminal throughout this tutorial. You should know how to open a terminal, navigate between folders, and run commands. If you're on Windows, you can use Command Prompt or PowerShell. On macOS or Linux, the default Terminal app works well.</p>
<p><strong>Tools you'll need installed:</strong></p>
<ul>
<li><p><strong>Python 3.8 or higher.</strong> You can check your version by running <code>python --version</code> or <code>python3 --version</code> in your terminal.&nbsp; If you don't have Python installed, download it from <a href="https://www.python.org">python.org</a></p>
</li>
<li><p><strong>pip.</strong> This is Python's package manager. It usually comes bundled with Python. You can verify by running <code>pip --version</code> or pip3 --version. Note the commands <code>python3</code> and <code>pip3</code> tell the terminal that you are explicitly using <strong>Python Version 3</strong></p>
</li>
<li><p><strong>A code editor.</strong> Visual Studio Code is a great free option, but you can use any editor you're comfortable with.</p>
</li>
</ul>
<p>That's everything. You don't need prior Django experience or web development knowledge. This tutorial will walk you through each step.</p>
<h2 id="heading-what-you-are-going-build">What You Are Going Build</h2>
<p>The fitness tracker you will build has two main features:</p>
<ol>
<li><strong>A form to log workouts.</strong> You will enter the name of an activity (like "Running" or "Push-ups"), how long you did it (in minutes), and the date. When you submit the form, Django saves that workout to a database.</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/fe6b2a89-fc29-4710-a640-ce2757267e38.png" alt="The image shows a form to log workouts" style="display:block;margin:0 auto" width="1864" height="1544" loading="lazy">

<ol>
<li><strong>A page to view all your workouts.</strong> This page displays every workout you have logged, showing the activity, duration, and date in a clean list.</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/8f6bd09e-497a-4480-83e5-af162028a0a3.png" alt="The image shows a list of logged workouts" style="display:block;margin:0 auto" width="2144" height="1720" loading="lazy">

<p>Here's how data flows through the app at a high level:</p>
<ol>
<li><p>You fill out the workout form in your browser and click submit.</p>
</li>
<li><p>Your browser sends that data to Django.</p>
</li>
<li><p>Django's view function receives the data, validates it, and saves it to the database.</p>
</li>
<li><p>When you visit the workouts page, Django's view function pulls all saved workouts from the database.</p>
</li>
<li><p>Django passes that data to an HTML template, which renders it as a page your browser can display.</p>
</li>
</ol>
<img alt="The image shows the data flow of the fitness tracker app with 5 steps" style="display:block;margin-left:auto" width="600" height="400" loading="lazy">

<p>This request-response cycle is the foundation of how Django works. Once you understand it, you can build almost anything.</p>
<h2 id="heading-step-1-how-to-set-up-your-django-project">Step 1: How to Set Up Your Django Project</h2>
<p>Every Django project starts with a few setup steps. You'll create an isolated Python environment, install Django, and generate the initial project structure.</p>
<h3 id="heading-1-1-how-to-create-a-virtual-environment">1. 1 How to Create a Virtual Environment</h3>
<p>A virtual environment is a self-contained folder that contains its own Python interpreter and installed packages for a specific project. This keeps your project's dependencies separate from other Python projects on your computer. This separation prevents version conflicts and keeps setups consistent.</p>
<p>For example, one project might require an older version of Django, while another needs the latest version, and a virtual environment allows both to work smoothly on the same system.</p>
<p>Without it, global installations can clash, break projects, and make setups hard to reproduce. Over time, the system environment becomes cluttered with unused or incompatible packages making debugging and maintenance more difficult.</p>
<p>Now let's set it up.</p>
<p>Open your terminal, and navigate to where you want your project to live and run the following command</p>
<pre><code class="language-shell">mkdir fitness-tracker
cd fitness-tracker
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/b4715e51-c2e3-4e97-ad7b-b41066aeefd9.png" alt="An image of the terminal showing the commands mkdir (make directory) and cd (change directory) being typed " style="display:block;margin:0 auto" width="2442" height="542" loading="lazy">

<p>The first command creates a new folder called <code>fitness-tracker</code>. The second command moves you into that folder.</p>
<p>You'll create the Python virutal environment here.</p>
<pre><code class="language-shell">python3 -m venv venv
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/3d1723ae-d069-48fd-9954-440a191f585f.png" alt="The image shows the command to create the python virtual enviroment." style="display:block;margin:0 auto" width="2374" height="512" loading="lazy">

<p>The above command creates a virtual environment inside a folder called <code>venv</code>. The first <code>venv</code> is the command and the second <code>venv</code> represents the name of the folder. You can name the folder anything though <code>venv</code> is usually preferred.</p>
<p>By using the <code>ls</code> command, you can see that we've created the virtual environment folder.</p>
<p>To activate the virtual environment, we need to use the following command:</p>
<p>On macOS/Linux:</p>
<pre><code class="language-shell">source venv/bin/activate
</code></pre>
<p>On Windows:</p>
<pre><code class="language-shell">venv\Scripts\activate
</code></pre>
<p>You'll know it worked when you see <code>(venv)</code> at the beginning of your terminal prompt. From this point on, any Python packages you install will only exist inside this <strong>virtual environment</strong>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/dabe362d-2f50-4745-a0bc-e57ad3536723.png" alt="The image shows the virtual environment being activated" style="display:block;margin:0 auto" width="2434" height="1066" loading="lazy">

<h3 id="heading-12-how-to-install-django">1.2 How to Install Django</h3>
<p>With your virtual environment activated, install Django using pip:</p>
<pre><code class="language-shell">pip install django
</code></pre>
<p>This downloads and installs the latest stable version of Django. You can verify the installation by running:</p>
<pre><code class="language-shell">python3 -m django --version
</code></pre>
<p>After running both these commands, you should see Django being installed and the version number:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/bda2ed0d-44bf-439b-a9fd-1cf3fcaf35ca.png" alt="The image shows django being installed and the version of django that has been installed" style="display:block;margin:0 auto" width="2818" height="968" loading="lazy">

<h3 id="heading-13-how-to-create-the-project">1.3 How to Create the Project</h3>
<p>We have finished installing Django. Now let's create a Django project. Django provides a command line utility that generates the boilerplate files that you need. Type the following command:</p>
<pre><code class="language-shell">django-admin startproject fitness_project .
</code></pre>
<p>The command creates a folder named <code>fitness-project</code>. Notice the dot at the end of the command. The dot at the end is important. It tells Django to create the project files in your current directory instead of creating an extra nested folder.</p>
<p>Now that we've created our Django project, let's open the project in your favourite text editor and look at folder structure.</p>
<p>You'll notice that the folder already comes with a bunch of files.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/eaffe95e-7078-4c2e-91f4-88a6c3696e88.png" alt="The image show the list of files created by the django-admin startproject command" width="2362" height="1488" loading="lazy">

<h3 id="heading-14-how-to-run-the-development-server">1.4 How to Run the Development Server</h3>
<p>Now let's make sure everything is working. You'll need to run a server for this. Type the following command:</p>
<pre><code class="language-shell">python manage.py runserver
</code></pre>
<p>You can type this command in the terminal with the virtual environment activated or you can use the integrated terminal if you're using VS Code. I'll be using the integrated terminal from this point on.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/53dbba38-9863-4972-a899-1e6ff66fb3f5.png" alt="This is an image of the server running after typing the runserver command" style="display:block;margin:0 auto" width="2870" height="1662" loading="lazy">

<p>Open your browser and go to <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>. You should see Django's default welcome page with a rocket ship graphic confirming that your project is set up correctly.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/25d2e3ce-ce72-44f6-9f5f-78aeaeb88b3e.png" alt="This is an image of Django's default homepage" style="display:block;margin:0 auto" width="2872" height="1788" loading="lazy">

<p>Press <code>Ctrl + C</code> in your terminal to stop the server when you're ready to move on.</p>
<h2 id="heading-step-2-how-to-create-a-django-app">Step 2: How to Create a Django App</h2>
<p>In Django, a project is the overall container for your entire web application, while an app is a smaller, self-contained module inside that project that focuses on a specific piece of functionality.</p>
<p>A useful way to picture this is to think of a house. The project is the whole house. Each app is like a room inside that house. One room might be a kitchen, another a bedroom, each designed with a clear purpose. In the same way, a Django app is built to handle one responsibility, such as authentication, payments, or in this case, workout tracking.</p>
<p>Now, here's the important part: why not just put everything into one big project instead of using apps? You technically could, especially for very small projects. But as your application grows, that approach quickly becomes difficult to manage.</p>
<p>By using apps, you naturally separate concerns. It also makes collaboration smoother, since different people can work on different apps without constantly stepping on each other’s code.</p>
<p>Another major benefit is reusability. Since apps are modular, you can take an app from one project and reuse it in another.</p>
<p>For example, if you build a workout tracking app once, you could plug it into a completely different Django project later without rebuilding it from scratch. Later, you might create a completely different project, say a fitness coaching platform or a health dashboard. Instead of rebuilding the tracking feature from scratch, you can reuse the same app.</p>
<p>For this project, you'll create a single app called <code>tracker</code> that handles everything related to logging and displaying workouts.</p>
<h3 id="heading-21-how-to-generate-the-app">2.1 How to Generate the App</h3>
<p>Make sure you're in the same directory as the <code>manage.py</code> file, then run the following code:</p>
<pre><code class="language-shell">python manage.py startapp tracker
</code></pre>
<p>This create a new folder called tracker with the following following structure:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/cb07105a-6e65-49f9-9c7a-d5a64db42b49.png" alt="The image shows the folder strucutre created by after running the startapp command" style="display:block;margin:0 auto" width="2860" height="1250" loading="lazy">

<p>Each file has its own purpose. You'll work with <code>models.py</code>, <code>views.py</code> and <code>admin.py</code> throughout this project.</p>
<h3 id="heading-22-how-to-register-the-app">2.2 How to Register the App</h3>
<p>Django doesn't automatically know about your new app. You need to tell it by adding the app to the <code>INSTALLED_APPS</code> list in <code>settings.py</code> file.</p>
<p>Open <code>fitness_project/settings.py</code> and find the <code>INSTALLED_APPS</code> list. Add the name of the app, that is <code>tracker</code>, to the end of the list:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/eec90a01-5219-449e-97f8-97465e4ac23f.png" alt="eec90a01-5219-449e-97f8-97465e4ac23f" style="display:block;margin:0 auto" width="2868" height="1306" loading="lazy">

<p>You'll notice that a number of apps have already been installed automatically by Django. This is part of Django’s “batteries-included” philosophy, where many common features are ready to use out of the box.</p>
<p>Here is a short summary of what each of the apps does.</p>
<table>
<thead>
<tr>
<th><strong>App Name</strong></th>
<th><strong>Purpose</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>django.contrib.admin</strong></td>
<td>Powers the built-in admin dashboard, letting you manage your data through a web interface.</td>
</tr>
<tr>
<td><strong>django.contrib.auth</strong></td>
<td>Handles users, login systems, permissions, and password management.</td>
</tr>
<tr>
<td><strong>django.contrib.contenttypes</strong></td>
<td>Helps Django track and manage relationships between different models.</td>
</tr>
<tr>
<td><strong>django.contrib.sessions</strong></td>
<td>Stores user session data, so users stay logged in across requests.</td>
</tr>
<tr>
<td><strong>django.contrib.messages</strong></td>
<td>Lets you show temporary notifications like success or error messages.</td>
</tr>
<tr>
<td><strong>django.contrib.staticfiles</strong></td>
<td>Manages static assets such as CSS, JavaScript, and images</td>
</tr>
</tbody></table>
<p>Now Django knows your <code>tracker</code> app exists and will include it when running the project.</p>
<h2 id="heading-step-3-how-to-create-a-workout-model">Step 3: How to Create a Workout Model</h2>
<p>A model in Django is a Python class that defines the structure of your data. Each model maps directly to a table in your database. Each attribute on the model becomes a column in that table.</p>
<p>Think of a model as a blueprint for a spreadsheet. The class name is the name of the spreadsheet, and each field is a column header. Every time you save a new workout, Django creates a new row in that spreadsheet.</p>
<h3 id="heading-31-how-to-define-the-model">3.1 How to Define the Model</h3>
<p>Open <code>tracker/models.py</code> and replace its contents with this code:</p>
<pre><code class="language-python">from django.db import models

class Workout(models.Model):
    activity = models.CharField(max_length=200)
    duration = models.IntegerField(help_text="Duration in minutes")
    date = models.DateField()

    def __str__(self):
        return f"{self.activity} - {self.duration} min on {self.date}"
</code></pre>
<p>Let's discuss what each part does:</p>
<ul>
<li><p><code>activity = models.CharField(max_length=200)</code> creates a text fields that can hold up to 200 characters. This is where you'll store the name of the exercise like "Running" or "Cycling".</p>
</li>
<li><p><code>duration = models.IntegerField(help_text="Duration in minutes")</code> creates a whole number field for storing how many minutes the workout lasted. The <code>help_text</code> parameter adds a hint that will appear in forms and the admin panel.</p>
</li>
<li><p><code>date = models.DateField()</code> creates a date field for recording when the workout happened.</p>
</li>
</ul>
<p>The <code>__str__()</code> method defines how a Workout object appears when printed or displayed in the admin panel. Instead of seeing something unhelpful like "<strong>Workout object (1)</strong>," you will see "<strong>Running - 30 min on 2025-03-15.</strong>"</p>
<h2 id="heading-step-4-how-to-apply-migrations">Step 4: How to Apply Migrations</h2>
<p>You've defined your model, but Django hasn't created the actual database table yet. To do that, you need to run migrations.</p>
<p>Migrations are Django's way of translating your Python model definitions into database instructions. Migrations are done in two steps.</p>
<p>When you change a model – maybe by adding a field, removing a field, or renaming one – you create a new migration that describes that change. You can do this using the <code>makemigrations</code> command.</p>
<p>Then you apply the migration using the <code>migrate</code> command and Django updates the database to match.</p>
<p>This two-step process of first detecting the change and then applying the change gives you a reliable record of every change to your database structure over time.</p>
<h3 id="heading-41-how-to-generate-the-migration">4.1 How to Generate the Migration</h3>
<p>Run the following command in the integrated terminal:</p>
<pre><code class="language-shell">python manage.py makemigrations
</code></pre>
<p>You should see output like this:</p>
<pre><code class="language-shell">Migrations for 'tracker': tracker/migrations/0001_initial.py 
    + Create model Workout
</code></pre>
<p>Django inspected your Workout model and created a migration file that describes how to build the corresponding database table. You can find this file at <code>tracker/migrations/0001_initial.py</code> if you want to look at it, but you don't need to edit it.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/fa46eed5-6ef3-408a-8c23-f39518b117f4.png" alt="The image shows the file creating after makemigrations command runs" style="display:block;margin:0 auto" width="2880" height="1424" loading="lazy">

<h3 id="heading-42-how-to-apply-the-migration">4.2 How to Apply the Migration</h3>
<p>Now tell Django to execute that migration and actually create the table in the database:</p>
<pre><code class="language-shell">python manage.py migrate
</code></pre>
<p>You'll see several lines of output as Django applies not just your migration, but also the default migrations for Django's built-in apps (authentication, sessions, and so on).</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/fcaae5fe-0cc7-4c1f-b4c3-a3b173fd2551.png" alt="The image shows the output after applying migrations" style="display:block;margin:0 auto" width="2864" height="1650" loading="lazy">

<p>When it finishes, your database has a table ready to store workouts.</p>
<p>When the migrate command runs, we can see the exact SQL commands that Django used to build and change the database. Though this isn't required for creating the application, it's always good to know what's happening under hood.</p>
<p>Run this command:</p>
<pre><code class="language-shell">python manage.py sqlmigrate tracker 001
</code></pre>
<p>And you should get this output:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/016b0a33-06d0-47e8-97de-580e79a7d0e3.png" alt="The image shows the command to view sql queries created by django" style="display:block;margin:0 auto" width="2824" height="1628" loading="lazy">

<p>The <code>001</code> you added at the end is the migration number and represents first version of the database schema.</p>
<p>In practice, your workflow usually looks like this: you change your models, run <code>makemigrations</code> to generate the migration files, and then run the <code>migrate</code> command to apply those changes to the database.</p>
<h2 id="heading-step-5-how-to-register-the-model-in-the-admin-panel">Step 5: How to Register the Model in the Admin Panel</h2>
<p>Django comes with a powerful admin interface built in. It gives you a graphical way to view, add, edit, and delete records in your database without writing any extra code. This is incredibly useful during development because you can quickly test your models and see your data.</p>
<p>But by default, it doesn’t know:</p>
<ul>
<li><p>Which models you want to manage</p>
</li>
<li><p>How you want them displayed</p>
</li>
</ul>
<p>So you <em>register</em> models in <code>admin.py</code> to tell Django to include the specific model in the admin interface.</p>
<h3 id="heading-51-how-to-add-model-to-admin">5.1 How to Add Model to Admin</h3>
<p>Open <code>tracker/admin.py</code> and add the following code:</p>
<pre><code class="language-python">from django.contrib import admin
from .models import Workout

admin.site.register(Workout)
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/ad017508-993a-4c28-ade1-8e73fa0c6a4a.png" alt="ad017508-993a-4c28-ade1-8e73fa0c6a4a" style="display:block;margin:0 auto" width="2854" height="816" loading="lazy">

<p>This single line tells Django to include the <code>Workout</code> model in the admin interface.</p>
<h3 id="heading-52-how-to-create-a-superuser">5.2 How to Create a Superuser</h3>
<p>To access the admin panel, you need an admin account. Create one by running:</p>
<pre><code class="language-python">python manage.py createsuperuser
</code></pre>
<p>Django will prompt you for a username, email address, and password. Choose something you will remember. The email is optional – you can press Enter to skip it.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/4bbc7a15-682e-497d-a4a4-3e2dc4b848ac.png" alt="The image shows the superuser being created by adding username, email and password" style="display:block;margin:0 auto" width="2878" height="1362" loading="lazy">

<h3 id="heading-53-how-to-access-the-admin-panel">5.3 How to Access the Admin Panel</h3>
<p>Start the development server:</p>
<pre><code class="language-python">python manage.py runserver
</code></pre>
<p>Then navigate to <a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin/</a> in your browser. Log in with the credentials you just created.</p>
<p>You should see the Django administration dashboard with a "<strong>Tracker</strong>" section containing your "<strong>Workouts</strong>" model.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/a1e576bf-45f6-40dc-b6b9-69899b2df9d5.png" alt="The image shows the Django admin panel and the Worker model of the Tracker app being added to the admin panel" style="display:block;margin:0 auto" width="2860" height="1406" loading="lazy">

<p>Try clicking "Add" to create a couple of test workouts. This will confirm that your model is working correctly before you build the rest of the app.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/944ea6a4-bc6f-4321-87c0-5c7bcb267e26.png" alt="The image show some workouts (running and cycling) being added to the admin panel" style="display:block;margin:0 auto" width="2876" height="1146" loading="lazy">

<h2 id="heading-step-6-how-to-create-views-for-the-app">Step 6: How to Create Views for the App</h2>
<p>A view in Django is a Python function (or class) that receives a web request and returns a web response. That response could be an HTML page, a redirect, a 404 error, or anything else a browser can handle.</p>
<p>Views are where your application logic lives. They decide what data to fetch, what processing to do, and what to show the user.</p>
<p>For this app, you need two views: one to display the form where users add a workout, and one to display the list of all saved workouts.</p>
<h3 id="heading-61-how-to-create-a-form-class">6.1 How to Create a Form Class</h3>
<p>Before writing the views, you need a Django form that handles the workout input.</p>
<p>Django forms are a built-in way to handle user input like login forms, contact forms, or anything that collects data from a user. Instead of manually writing HTML, validating inputs, and handling errors, Django gives you a structured way to do all of that in one place.</p>
<p>Most user inputs are based on the models you’ve created, and Django can automatically generate forms from those models using <code>ModelForms</code>, which speeds things up significantly.</p>
<p>Let's create a new file called <code>forms.py</code> in the <code>tracker</code> folder and add the following code:</p>
<pre><code class="language-python">from django import forms
from .models import Workout

class WorkoutForm(forms.ModelForm):

    class Meta:
        model = Workout
        fields = ['activity', 'duration', 'date']
        widgets = {
            'date': forms.DateInput(attrs={'type': 'date'}),
        }
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/e8bce19c-7184-45b3-9afe-3a5f73cff43b.png" alt="The image shows the file location of forms.py as well the code for forms.py file" style="display:block;margin:0 auto" width="2866" height="1232" loading="lazy">

<p>In the above code, the <code>ModelForm</code> automatically generates form fields based on the <code>Workout</code> model. The <code>widgets</code> dictionary tells Django to render the date field as an HTML date picker instead of a plain text input.</p>
<p>We can actually see the forms being automatically created by Django. For this we need to enter the shell. In the terminal, type the following command:</p>
<pre><code class="language-shell">python manage.py shell
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/951829fb-98e8-48f5-8187-80cc98346e06.png" alt="The image shows the python shell being activated" style="display:block;margin:0 auto" width="2244" height="932" loading="lazy">

<p>Now lets import the <code>WorkoutForm</code> class that we just created.</p>
<p>Type the following code:</p>
<pre><code class="language-shell">from tracker.forms import WorkoutForm
</code></pre>
<p>Notice that we've given the <strong>name of the app</strong> as well when we imported the form.</p>
<p>Then create an object of the <code>WorkoutForm</code> class and print it.</p>
<pre><code class="language-shell">from tracker.forms import WorkoutForm
workoutform = WorkoutForm()
print(workoutform) 
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/b81265a2-7c21-453b-ae57-3cfec97fbaf9.png" alt="The image shows the command to open the python shell where you can execute python statement throught the terminal" style="display:block;margin:0 auto" width="2236" height="652" loading="lazy">

<p>You should get the following output:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/094b0d89-b003-49b6-939d-07eacfb0c745.png" alt="This image shows the html generated from ModelForm" style="display:block;margin:0 auto" width="936" height="632" loading="lazy">

<p>You can see that all the model fields have been renderd as HTML forms and the date field has been created as a date type that is <code>type="date"</code> instead of plain text.</p>
<h3 id="heading-62-how-to-write-views">6.2 How to Write Views</h3>
<p>As we've discussed above, our project has two views: one to add a workout and the other to display all the saved workouts.</p>
<p>First, let's create a view to add a workout. In the <code>tracker/views.py</code> file, type the following code:</p>
<pre><code class="language-python">from django.shortcuts import render, redirect
from .models import Workout

# view to list all workouts
def workout_list(request):
    workouts = Workout.objects.all().order_by('-date')
    return render(request, 'tracker/workout_list.html', {'workouts': workouts})
</code></pre>
<p>Let's walk through this view:</p>
<ul>
<li><p>The <code>workout_list</code> view handles the page that displays all workouts.</p>
</li>
<li><p>It queries the database for every <code>Workout</code> object, orders them by date (most recent first, thanks to the <code>-</code> prefix), and passes that list to a template called <code>workout_list.html</code>.</p>
</li>
<li><p>The <code>render</code> function combines the template with the data and returns the finished HTML page.</p>
</li>
</ul>
<p>To create the logic to add a workout, first add the <code>Workout</code> form import at the end of the import section. Then add the following code after the <code>workout_list</code> view:</p>
<pre><code class="language-python">from django.shortcuts import render, redirect
from .models import Workout
from .forms import WorkoutForm

# view to list all the workouts
def workout_list(request):
    workouts = Workout.objects.all().order_by('-date')
    return render(request, 'tracker/workout_list.html', {'workouts': workouts})

# view to add a workout
def add_workout(request):
    if request.method == 'POST':
        form = WorkoutForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('workout_list')
    else:
        form = WorkoutForm()
    return render(request, 'tracker/add_workout.html', {'form': form})
</code></pre>
<ul>
<li><p>The <code>add_workout</code> view handles both displaying the empty form and processing submitted form data.</p>
</li>
<li><p>When a user first visits the page, the request method is GET, so Django creates a blank form and renders it.</p>
</li>
<li><p>When the user fills out the form and clicks submit, the request method is POST. Django then validates the submitted data, saves it to the database if everything is correct, and redirects the user to the workout list page.</p>
</li>
<li><p>If the data isn't valid, Django re-renders the form with error messages.</p>
</li>
</ul>
<p>Here is the complete views code:</p>
<pre><code class="language-python">from django.shortcuts import render, redirect
from .models import Workout
from .forms import WorkoutForm

# view to list all workouts
def workout_list(request):
    workouts = Workout.objects.all().order_by('-date')
    return render(request, 'tracker/workout_list.html', {'workouts': workouts})

# view to add a workout
def add_workout(request):
    if request.method == 'POST':
        form = WorkoutForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('workout_list')
    else:
        form = WorkoutForm()
    return render(request, 'tracker/add_workout.html', {'form': form})

</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/8a0878c1-f029-49a4-8a7f-308cdb843b62.png" alt="The image shows the complete code for views.py with explanation about the add workout view" style="display:block;margin:0 auto" width="2316" height="1076" loading="lazy">

<h2 id="heading-step-7-how-to-create-templates">Step 7: How to Create Templates</h2>
<p>Templates are HTML files that Django fills in with dynamic data. They're the front end of your application: the part users actually see in their browser.</p>
<h3 id="heading-71-how-to-set-up-the-template-directory">7.1 How to Set Up the Template Directory</h3>
<p>Django looks for templates inside a <code>templates</code> folder within each app. Create the following folder structure inside your <code>tracker</code> app.</p>
<p><code>tracker/templates/tracker</code></p>
<p>The double <code>tracker</code> folder name might look redundant, but it's a Django convention called <strong>template namespacing</strong>. It prevents naming conflicts if you have multiple apps with templates that share the same filename.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/cfbe85c3-36dc-413e-918a-aa64d706d2fc.png" alt="The image shows folder structure of the templates folder" style="display:block;margin:0 auto" width="832" height="474" loading="lazy">

<h3 id="heading-72-how-to-create-the-workout-list-template">7.2 How to Create the Workout List Template</h3>
<p>Create a file called <code>tracker/templates/tracker/workout_list.html</code> and add the following code:</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;title&gt;My Workouts&lt;/title&gt;
    &lt;style&gt;
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            background-color: #f5f7fa;
            color: #333;
            line-height: 1.6;
            padding: 2rem;
        }

        .container {
            max-width: 700px;
            margin: 0 auto;
        }

        h1 {
            font-size: 1.8rem;
            margin-bottom: 1rem;
            color: #1a1a2e;
        }

        .add-link {
            display: inline-block;
            background-color: #4361ee;
            color: white;
            padding: 0.6rem 1.2rem;
            border-radius: 6px;
            text-decoration: none;
            margin-bottom: 1.5rem;
            font-size: 0.95rem;
        }

        .add-link:hover {
            background-color: #3a56d4;

        }

        .workout-card {
            background: white;
            border-radius: 8px;
            padding: 1rem 1.2rem;
            margin-bottom: 0.8rem;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
            display: flex;
            justify-content: space-between;
            align-items: center;

        }

        .workout-activity {
            font-weight: 600;
            font-size: 1.05rem;

        }

        .workout-details {
            color: #666;
            font-size: 0.9rem;

        }

        .empty-state {
            text-align: center;
            padding: 3rem 1rem;
            color: #888;

        }

    &lt;/style&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div class="container"&gt;
        &lt;h1&gt;My Workouts&lt;/h1&gt;
        &lt;a href="{% url 'add_workout' %}" class="add-link"&gt;+ Log a Workout&lt;/a&gt;
        {% if workouts %}
            {% for workout in workouts %}
                &lt;div class="workout-card"&gt;
                    &lt;div&gt;
                        &lt;div class="workout-activity"&gt;{{ workout.activity }}&lt;/div&gt;
                        &lt;div class="workout-details"&gt;{{ workout.duration }} minutes&lt;/div&gt;
                    &lt;/div&gt;
                    &lt;div class="workout-details"&gt;{{ workout.date }}&lt;/div&gt;
                &lt;/div&gt;
            {% endfor %}

        {% else %}
            &lt;div class="empty-state"&gt;
                &lt;p&gt;No workouts logged yet. Start by adding one!&lt;/p&gt;
            &lt;/div&gt;
        {% endif %}
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>There are a few things worth noting here:</p>
<p>If you look closely at the HTML, you'll spot some weird-looking tags wrapped in curly braces ( <code>{% %}</code> and <code>{{ }}</code> ). Think of them as special instructions for Django.</p>
<p>You use the double curly braces (<code>{{ }}</code>) when you want to output or display a piece of data directly on the page.</p>
<p>On the other hand, you use the brace-and-percent-sign combo ( <code>{% %}</code> ) when you need Django to actually perform an action or apply logic, like running a loop or checking a condition.</p>
<p>They allow us to inject dynamic data straight from our Python backend right into our otherwise static HTML.</p>
<p>Lets look at this code snippet for the <code>workout_list.html</code></p>
<pre><code class="language-html">&lt;body&gt;
    &lt;div class="container"&gt;
        &lt;h1&gt;My Workouts&lt;/h1&gt;
        &lt;a href="{% url 'add_workout' %}" class="add-link"&gt;+ Log a Workout&lt;/a&gt;
        {% if workouts %}
            {% for workout in workouts %}
                &lt;div class="workout-card"&gt;
                    &lt;div&gt;
                        &lt;div class="workout-activity"&gt;{{ workout.activity }}&lt;/div&gt;
                        &lt;div class="workout-details"&gt;{{ workout.duration }} minutes&lt;/div&gt;
                    &lt;/div&gt;
                    &lt;div class="workout-details"&gt;{{ workout.date }}&lt;/div&gt;
                &lt;/div&gt;
            {% endfor %}

        {% else %}
            &lt;div class="empty-state"&gt;
                &lt;p&gt;No workouts logged yet. Start by adding one!&lt;/p&gt;
            &lt;/div&gt;
        {% endif %}
    &lt;/div&gt;
&lt;/body&gt;
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/864ed3dc-ceda-44f8-ba3d-b061222714c7.png" alt="The image shows the the body section of the workout_list.html with the focus on django template tags" style="display:block;margin:0 auto" width="1988" height="1160" loading="lazy">

<p>There are a few things worth noting here.</p>
<p>Right under the main heading, you'll see this line:<br><code>&lt;a href="{% url 'add_workout' %}"&gt;</code></p>
<p>Instead of hardcoding a web link like <code>href="/add-workout/"</code>, Django uses the <code>{% url %}</code> tag to generate the link dynamically. You pass it the name of the route (in this case, <code>add_workout</code>), and Django automatically figures out the correct URL path.</p>
<p>If you ever change the URL structure in your Python code later, Django updates this link automatically. You never have to hunt through HTML files to fix broken links!</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/2dc56430-d146-4fc9-8ae5-a3fb5a0d7dd1.png" alt="The image highlights the code that generates dynamic url" style="display:block;margin:0 auto" width="1748" height="632" loading="lazy">

<p>The <code>{% if workouts %}</code> block checks whether there are any workouts to display. If the list is empty, it shows a friendly message instead of a blank page.</p>
<p>The <code>{% for workout in workouts %}</code> loop iterates over every workout in the list and renders a card for each one. The double curly braces <code>{{ workout.activity }}</code> insert the value of each field into the HTML</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/f75b5c7e-5cd0-457c-901f-e489c26a8175.png" alt="f75b5c7e-5cd0-457c-901f-e489c26a8175" style="display:block;margin:0 auto" width="2012" height="1002" loading="lazy">

<p>Inside the loop, you'll notice tags that look like this:</p>
<ul>
<li><p><code>{{ workout.activity }}</code></p>
</li>
<li><p><code>{{ workout.duration }}</code></p>
</li>
<li><p><code>{{ workout.date }}</code></p>
</li>
</ul>
<p>As Django loops through each workout object, it uses dot notation to peek inside that specific object and grab its details. It grabs the activity type (like "Running"), the duration ("30"), and the date ("March 30"), and prints that exact text directly onto the webpage for the user to see.</p>
<h3 id="heading-73-how-to-create-add-workout-template">7.3 How to Create Add Workout Template</h3>
<p>Create a file called <code>tracker/templates/tracker/add_workout.html</code> and add the following code:</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;title&gt;Log a Workout&lt;/title&gt;
    &lt;style&gt;
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;

        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            background-color: #f5f7fa;
            color: #333;
            line-height: 1.6;
            padding: 2rem;
        }

        .container {
            max-width: 500px;
            margin: 0 auto;

        }

        h1 {
            font-size: 1.8rem;
            margin-bottom: 1.5rem;
            color: #1a1a2e;
        }

        .form-group {
            margin-bottom: 1.2rem;
        }

        label {
            display: block;
            margin-bottom: 0.3rem;
            font-weight: 600;
            font-size: 0.95rem;

        }

        input[type="text"],
        input[type="number"],
        input[type="date"] {
            width: 100%;
            padding: 0.6rem 0.8rem;
            border: 1px solid #ddd;
            border-radius: 6px;
            font-size: 1rem;
            transition: border-color 0.2s;
        }

        input:focus {
            outline: none;
            border-color: #4361ee;

        }

        .btn {
            background-color: #4361ee;
            color: white;
            padding: 0.7rem 1.5rem;
            border: none;
            border-radius: 6px;
            font-size: 1rem;
            cursor: pointer;
            margin-right: 0.5rem;
        }

        .btn:hover {
            background-color: #3a56d4;
        }

        .back-link {
            color: #4361ee;
            text-decoration: none;
            font-size: 0.95rem;
        }

        .back-link:hover {
            text-decoration: underline;
        }

        .actions {
            display: flex;
            align-items: center;
            gap: 1rem;
            margin-top: 0.5rem;
        }

        .error-list {
            color: #e74c3c;
            font-size: 0.85rem;
            margin-top: 0.3rem;

        }

    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class="container"&gt;
       &lt;h1&gt;Log a Workout&lt;/h1&gt;
        &lt;form method="post"&gt;
            {% csrf_token %}
            &lt;div class="form-group"&gt;
                &lt;label for="id_activity"&gt;Activity&lt;/label&gt;
                {{ form.activity }}
                {% if form.activity.errors %}
                    &lt;div class="error-list"&gt;{{ form.activity.errors }}&lt;/div&gt;
                {% endif %}
            &lt;/div&gt;
            &lt;div class="form-group"&gt;
                &lt;label for="id_duration"&gt;Duration (minutes)&lt;/label&gt;
                {{ form.duration }}
                {% if form.duration.errors %}
                    &lt;div class="error-list"&gt;{{ form.duration.errors }}&lt;/div&gt;
                {% endif %}
            &lt;/div&gt;

            &lt;div class="form-group"&gt;
                &lt;label for="id_date"&gt;Date&lt;/label&gt;
                {{ form.date }}
                {% if form.date.errors %}
                    &lt;div class="error-list"&gt;{{ form.date.errors }}&lt;/div&gt;
                {% endif %}
            &lt;/div&gt;

            &lt;div class="actions"&gt;
                &lt;button type="submit" class="btn"&gt;Save Workout&lt;/button&gt;
                &lt;a href="{% url 'workout_list' %}" class="back-link"&gt;Cancel&lt;/a&gt;
            &lt;/div&gt;
        &lt;/form&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>In the previous template, we learned how to display data. Now, we're looking at a form that actually collects data. Handling forms manually in web development can get messy, but Django provides some powerful template tags to do the heavy lifting for us.</p>
<p>Let's look at the Django-specific logic powering this form:</p>
<p>First, right after opening the <code>&lt;form&gt;</code> tag, you'll spot a very important line: <code>{% csrf_token %}</code>. Whenever you submit data to a server using a "POST" method, malicious sites can potentially intercept or forge that request.</p>
<p>By including this <code>{% csrf_token %}</code>, you tell Django to generate a unique, hidden security key for the form. When the user clicks "Save Workout," Django checks this token to guarantee the request is legitimate. <strong>If you forget this tag, Django will simply reject your form!</strong></p>
<pre><code class="language-html">&lt;form method="post"&gt;
            {% csrf_token %}
            &lt;div class="form-group"&gt;
                &lt;label for="id_activity"&gt;Activity&lt;/label&gt;
                {{ form.activity }}
                {% if form.activity.errors %}
                    &lt;div class="error-list"&gt;{{ form.activity.errors }}&lt;/div&gt;
                {% endif %}
            &lt;/div&gt;
            &lt;div class="form-group"&gt;
                &lt;label for="id_duration"&gt;Duration (minutes)&lt;/label&gt;
                {{ form.duration }}
                {% if form.duration.errors %}
                    &lt;div class="error-list"&gt;{{ form.duration.errors }}&lt;/div&gt;
                {% endif %}
            &lt;/div&gt;

            &lt;div class="form-group"&gt;
                &lt;label for="id_date"&gt;Date&lt;/label&gt;
                {{ form.date }}
                {% if form.date.errors %}
                    &lt;div class="error-list"&gt;{{ form.date.errors }}&lt;/div&gt;
                {% endif %}
            &lt;/div&gt;

            &lt;div class="actions"&gt;
                &lt;button type="submit" class="btn"&gt;Save Workout&lt;/button&gt;
                &lt;a href="{% url 'workout_list' %}" class="back-link"&gt;Cancel&lt;/a&gt;
            &lt;/div&gt;
        &lt;/form&gt;
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/4ca2a034-119c-4dc7-a14a-cd0a81815c58.png" alt="The image shows a screenshot of the code and highlight the csrf token tag" style="display:block;margin:0 auto" width="1580" height="824" loading="lazy">

<p>Now let's talk about automatically generating the form fields. Instead of manually typing out all the HTML <code>&lt;input&gt;</code> tags for the activity, duration, and date, we let Django do it for us using display tags (<code>{{ }}</code>).</p>
<p>Each <code>{{ form.activity }}</code>, <code>{{ form.duration }}</code>, and <code>{{ form.date }}</code> tag renders the corresponding form input. Django handles the HTML attributes, input types, and validation for you based on the model and form definitions.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/c2403685-b78d-4aa7-876d-63ca53481e37.png" alt="This image shows the code that automatically generates HTML forms" style="display:block;margin:0 auto" width="936" height="572" loading="lazy">

<p>The error blocks below each field display validation messages if a user submits invalid data, like entering text in the duration field instead of a number. Users make mistakes. They might leave a required field blank or type text into a number field. Fortunately, Django validates the data for you and sends back errors if something goes wrong.</p>
<p>Underneath each input field, we use a logic block that looks like this:<br><code>{% if form.activity.errors %}</code></p>
<p>This code checks a simple condition: Did the user mess up this specific field? If Django found an error with the "activity" input, the code drops into the if block and uses<code>{{ form.activity.errors }}</code> block to print the exact error message (like "<strong>This field is required</strong>") right below the input box.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/97a61f9d-faf6-4ddd-ab17-d53da88e0d07.png" alt="This image displays the error blocks" style="display:block;margin:0 auto" width="1908" height="1116" loading="lazy">

<p>You may notice that both templates include inline CSS rather than a separate stylesheet. For a small project like this, inline styles keep things simple and self-contained. In a larger project, you would use Django's static files system to manage CSS separately.</p>
<h2 id="heading-step-8-how-to-connect-urls">Step 8: How to Connect URLs</h2>
<p>You have views and templates, but Django doesn't know when to use them yet. You need to map URLs to views so that visiting a specific address in the browser triggers the right view function.</p>
<h3 id="heading-81-how-to-create-app-level-urls">8.1 How to Create App Level URLs</h3>
<p>Create a new file called <code>tracker/urls.py</code> and add the following code:</p>
<pre><code class="language-python">from django.urls import path
from . import views

urlpatterns = [ 
    path('', views.workout_list, name='workout_list'), 
    path('add/', views.add_workout, name='add_workout'), 
]
</code></pre>
<p>Each path function takes three arguments.</p>
<p>The first is the route string that represents a URL pattern (an empty string means the root of the app).</p>
<p>The second is the view function to call when that URL is visited.</p>
<p>The third is a name you can use to reference this URL elsewhere in your code, like in the <code>{% url %}</code> template tags you used earlier.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/d9128270-eec3-43af-93de-08780b4a53f5.png" alt="The image contains the description of three arguments of the path function" style="display:block;margin:0 auto" width="2864" height="1056" loading="lazy">

<h3 id="heading-82-how-to-link-app-urls-to-project">8.2 How to Link App URLs to project</h3>
<p>Now that your app-level URLs are set up, the next step is to connect them to the main project so Django knows where to start routing requests. Think of it like linking a smaller map (your app) to a bigger map (your project), so everything works together smoothly.</p>
<p>Open <code>fitness_project.urls.py</code> and update it to include your app's URLs:</p>
<pre><code class="language-python">from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('tracker.urls')),
]
</code></pre>
<p>The <code>include()</code> function tells Django to look at the URL patterns defined in the <code>tracker/urls.py</code> file whenever someone visits your site. The empty string prefix means your tracker app handles requests at the root of the site.</p>
<p>Here's the full picture of how a request flows through the URL system.</p>
<p>When someone visits <a href="http://127.0.0.1:8000/add/">http://127.0.0.1:8000/add/</a>, Django first checks <code>fitness_project/urls.py</code>. It matches the empty prefix and delegates to <code>tracker/urls.py</code>. There, it matches <code>add/</code> and calls the <code>add_workout view</code>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/4590c4e3-0d32-4865-90db-a6504ee508c1.png" alt="The image shows the how the URL flows through the system" style="display:block;margin:0 auto" width="2764" height="1146" loading="lazy">

<h2 id="heading-step-9-how-to-test-the-application-locally">Step 9: How to Test the Application Locally</h2>
<p>At this point, your app has everything it needs to work. Let's test it.</p>
<p>Start the development server by running the command:</p>
<pre><code class="language-shell">python manage.py runserver
</code></pre>
<p>Open your browser and visit <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>. You should see the workout list page with the heading "<strong>My Workouts</strong>" and a button that says "<strong>+ Log a Workout</strong>."</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/e15dc4cf-09b0-4ba9-95b1-baba32ce929f.png" alt="The image shows the My Workouts image with the button to log a workout" style="display:block;margin:0 auto" width="2186" height="1006" loading="lazy">

<p>Click that button. You should see the workout form with fields for activity, duration, and date.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/d9790d3e-0b6a-4e1b-b3d9-f305bc254cfc.png" alt="The image shows an empty form to log a workout" style="display:block;margin:0 auto" width="1146" height="838" loading="lazy">

<p>Fill in some test data:</p>
<ul>
<li><p>Activity: Skipping</p>
</li>
<li><p>Duration: 25</p>
</li>
<li><p>Date: Pick today's date from the date picker</p>
</li>
</ul>
<p>Click "<strong>Save Workout</strong>" You should be redirected back to the workout list page, and your new workout should appear as a card.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/3f1dbf8f-3547-45ec-961d-cff75092ec02.png" alt="The image shows the workout list after adding a new workout" style="display:block;margin:0 auto" width="1656" height="1042" loading="lazy">

<p>Try adding a few more workouts with different activities and dates. Make sure they all show up on the list page in the correct order (most recent first).</p>
<p>This is also a good time to experiment. Try submitting the form with missing fields and see how Django handles validation.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/542e32cf-abf5-4f11-9d4e-0733697c591b.png" alt="The image shows an incomplete form being submitted and a correspoding error message" style="display:block;margin:0 auto" width="1284" height="1012" loading="lazy">

<p>Try accessing the admin panel at <a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin/</a> to see your workouts there as well.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/cdfbcbf3-f7b6-4b97-92ee-dcc27e2ce60c.png" alt="This image shows the added workouts in Django admin" style="display:block;margin:0 auto" width="2876" height="848" loading="lazy">

<p>If everything works as expected, you're ready to put your app on the internet.</p>
<h2 id="heading-step-10-how-to-prepare-for-deployment">Step 10: How to Prepare for Deployment</h2>
<p>Running your app on localhost is great for development, but nobody else can see it. Deployment means putting your app on a server that's accessible from anywhere on the internet.</p>
<p>Before you deploy, you'll need to make a few changes to your project's settings.</p>
<h3 id="heading-101-how-to-update-settings-for-production">10.1 How to Update Settings for Production</h3>
<p>Open <code>fitness_project/settings.py</code> and make the following changes.</p>
<p>First, set <code>DEBUG</code> to <code>False</code>.</p>
<p>During development, <code>DEBUG = True</code> shows detailed error pages that help you fix problems. In production, these error pages would expose sensitive information about your code and server to anyone who triggers an error.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/6b8b491e-d0ae-4a93-80bf-92134e46ff22.png" alt="The image shows the DEBUG being set to False in the settings.py file" style="display:block;margin:0 auto" width="2866" height="1348" loading="lazy">

<p>Next, update <code>ALLOWED_HOSTS</code> to include <strong>PythonAnywhere's</strong> <strong>domain</strong>.</p>
<p>This setting tells Django which domain names are allowed to serve your app. Replace yourusername with the actual PythonAnywhere username you will create in the next step.</p>
<pre><code class="language-python">ALLOWED_HOSTS = ['yourusername.pythonanywhere.com']
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/050746f6-d076-41de-8810-08bf539bfda5.png" alt="The image shows the allowed host list being updated to add the pythonanywhere domain" style="display:block;margin:0 auto" width="1622" height="1068" loading="lazy">

<p>Finally, add a <code>STATIC_ROOT</code> setting so Django knows where to collect your static files (CSS, JavaScript, images) for production:</p>
<pre><code class="language-python">import os
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/712e0514-42f6-4292-ae52-99f49b6f162b.png" alt="The image shows the code to collect static files" style="display:block;margin:0 auto" width="2862" height="1054" loading="lazy">

<p>These are the minimum changes needed for a basic deployment.</p>
<p>💡 For a production app handling real user data, you would also want to set a secure SECRET_KEY, configure a proper database like PostgreSQL, and set up HTTPS. But for a learning project, these changes are enough.</p>
<h2 id="heading-step-11-how-to-deploy-your-django-app-on-pythonanywhere">Step 11: How to Deploy Your Django App on PythonAnywhere</h2>
<p>PythonAnywhere is a hosting platform designed specifically for Python web applications. It offers a free tier that's perfect for beginner projects, and it handles much of the server configuration that would otherwise be complex to set up on your own.</p>
<h3 id="heading-111-how-to-create-a-pythonanywhere-account">11.1 How to Create a PythonAnywhere Account</h3>
<p>Go to <a href="http://pythonanywhere.com">pythonanywhere.com</a> and sign up for a free "Beginner" account. Remember the username you choose, because your app will be available at <a href="http://yourusername.pythonanywhere.com"><strong>yourusername.pythonanywhere.com</strong></a><strong>.</strong></p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/e64e7ca4-7d7d-40a7-a56b-259bb706461f.png" alt="The image shows the homepage of pythonanywhere" style="display:block;margin:0 auto" width="2854" height="1782" loading="lazy">

<p>Now signup to the website. Fill in the username, email and password and click on the free tier or now.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/fde55ec6-16f4-4a4f-8927-7b01d3e36a96.png" alt="The image shows the various tiers of python anywhere websites" style="display:block;margin:0 auto" width="2758" height="1418" loading="lazy">

<h3 id="heading-112-how-to-upload-your-project-files">11.2 How to Upload Your Project Files</h3>
<p>After logging in, you have two options for getting your project files onto PythonAnywhere.</p>
<h4 id="heading-option-a-upload-using-git">Option A: Upload using Git</h4>
<p>If your project is in a Git repository, open a Bash console from the PythonAnywhere dashboard by clicking "Consoles" and then "Bash." Then clone your repository:</p>
<p>git clone <a href="https://github.com/yourusername/fitness-tracker.git">https://github.com/yourusername/fitness-tracker.git</a></p>
<p>In this tutorial, we won't be using Git. Instead we'll follow the second option.</p>
<h4 id="heading-option-b-upload-files-manually">Option B: Upload files manually</h4>
<p>First go your project folder in your computer and created a compressed version of the project.</p>
<p>IMPORTANT NOTE: When you create the compressed file, make sure to first create a copy of the project somewhere and remove the venv and pycache folder before you compress it.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/169dcd52-50f0-44c0-82d4-1dea1196ac88.png" alt="The image shows the project folder being compressed" style="display:block;margin:0 auto" width="1564" height="422" loading="lazy">

<p>Navigate to your home directory and click on upload file tab and upload the compressed file.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/633c7b1f-0088-4d2d-8911-b45e86aa39c2.png" alt="The image shows the compressed file being uploaded to pythonanywhere" style="display:block;margin:0 auto" width="2668" height="1096" loading="lazy">

<p>Now we need to unzip the compressed file. To do this, go to the Consoles tab and click on Bash console.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/7774a88e-362e-4680-a19d-32e0ef09fe04.png" alt="The image shows the Consoles tab and bash option" style="display:block;margin:0 auto" width="2692" height="1198" loading="lazy">

<p>The bash console should open. Then type the following command in the console to unzip the folder:</p>
<pre><code class="language-shell">unzip fitness-tracker.zip
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/1ae044ad-8996-4191-868a-33566c2483d9.png" alt="The image shows the result of the unzip command" style="display:block;margin:0 auto" width="2330" height="1078" loading="lazy">

<h3 id="heading-113-how-to-set-up-a-virtual-environment-in-pythonanywhere">11.3 How to Set Up a Virtual Environment in PythonAnywhere</h3>
<p>Open a Bash console from the PythonAnywhere dashboard. Navigate to your project directory and create a fresh virtual environment:</p>
<pre><code class="language-shell">cd fitness-tracker
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/c8113d5d-68a6-400f-ab9f-7c8903485eda.png" alt="The image shows changing the directory to fitness tracker" style="display:block;margin:0 auto" width="2852" height="468" loading="lazy">

<p>Type the following command to install a virtual environment as we've done before and then activate the virtual environment:</p>
<pre><code class="language-shell">python3 -m venv venv

source venv/bin/activate
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/724767df-181c-4fcf-91e0-77c6dac566b0.png" alt="The image shows the virtual environment being created and activated" style="display:block;margin:0 auto" width="2108" height="624" loading="lazy">

<p>Now install Django as before using <code>pip install django</code> command:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/d6c37d87-7497-4ca1-a90f-6cd66422c2e5.png" alt="The image shows django being installed" style="display:block;margin:0 auto" width="1980" height="952" loading="lazy">

<h3 id="heading-114-how-to-run-migrations-and-create-a-superuser-on-pythonanywhere">11.4 How to Run Migrations and Create a SuperUser on PythonAnywhere</h3>
<p>While you're still in the Bash console with your virtual environment activated, run the migrations to create the database tables on the server:</p>
<pre><code class="language-shell">python manage.py makemigrations

python manage.py migrate

python manage.py createsuperuser
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/0b763118-5a1c-4c3f-87f4-693cc7de0da2.png" alt="The image shows the make migrations and migrate commands running" style="display:block;margin:0 auto" width="2026" height="768" loading="lazy">

<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/77183d3c-b4bc-40b7-b00f-5f03d2aea2ab.png" alt="The image shows the super user being created" style="display:block;margin:0 auto" width="1814" height="506" loading="lazy">

<h3 id="heading-114-how-to-configure-the-web-app-in-pythonanywhere">11.4 How to Configure the Web App in Pythonanywhere</h3>
<p>Go to the "Web" tab on the PythonAnywhere dashboard and click "Add a new web app." Follow the setup wizard:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/e1296e93-3e52-4327-b12a-4d4555e80845.png" alt="The image shows the web tab and add a new web app button" style="display:block;margin:0 auto" width="2880" height="846" loading="lazy">

<p>Click "Next" on the domain name step (<em>remember the free tier uses</em> <a href="http://yourusername.pythonanywhere.com"><em>yourusername.pythonanywhere.com</em></a>).</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/24495b99-e1dc-437d-8ce8-47c0c962349f.png" alt="The image shows the web console where you specify the domain name" style="display:block;margin:0 auto" width="2870" height="1302" loading="lazy">

<p>Select "Manual configuration" (not "Django" – the manual option gives you more control).</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/db470bd1-bbd1-4c61-b846-b7147d8f820f.png" alt="The image highlight the manual configuration option which should be selected" style="display:block;margin:0 auto" width="2872" height="1326" loading="lazy">

<p>Then choose the Python version that matches what you installed. In my case it's 3.13, so I'll choose 3.13</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/dc51d44e-531c-4871-a225-e68b2db5dc65.png" alt="The image shows the Python version what is being selected" style="display:block;margin:0 auto" width="2780" height="1384" loading="lazy">

<p>Click on Next button and a WSGI (Web Server Gateway Interface) will be created.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/3565512b-9c84-4b0d-82d9-3964cb0ff46b.png" alt="The image shows the final page before the web app is created" style="display:block;margin:0 auto" width="2878" height="1422" loading="lazy">

<p>With this we've created the web app:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/eda9fe63-01f4-48bc-98f1-07696bb798bf.png" alt="The image shows the final creation of the web app" style="display:block;margin:0 auto" width="2874" height="1568" loading="lazy">

<p>After you've set up the web app, you have to do two more things:</p>
<ul>
<li><p>Set the virtual environment path</p>
</li>
<li><p>Configure the WSGI file</p>
</li>
</ul>
<h3 id="heading-115-how-to-set-the-virtual-environment-path">11.5 How to Set the Virtual Environment Path</h3>
<p>On the <strong>Web</strong> tab, scroll down to the "<strong>Virtualenv</strong>" section and enter the path to your virtual enviroment. The path to the file should be like this:</p>
<pre><code class="language-shell">/home/yourusername/fitness-tracker/venv
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/413ed047-ecc1-440f-a931-4a57aa91348b.png" alt="The image shows the added path of virtual environment" style="display:block;margin:0 auto" width="2878" height="994" loading="lazy">

<h3 id="heading-116-how-to-configure-the-wsgi-file">11.6 How to Configure the WSGI file</h3>
<p>Still on the Web tab, scroll to the code section and click on the WSGI configuration file link:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/934d1542-79d6-4140-8bb2-a4389fc17770.png" alt="The image shows the Code section and the WSGI configuration file path" style="display:block;margin:0 auto" width="2264" height="548" loading="lazy">

<p>Delete all the contents and replace them with the content below and save the file:</p>
<pre><code class="language-python">import os
import sys
path = '/home/prabodhtuladhardev/fitness-tracker' #replace with your username
if path not in sys.path:
    sys.path.append(path)

os.environ['DJANGO_SETTINGS_MODULE'] = 'fitness_project.settings'

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/416adac6-61d7-464d-b91f-b3b35272ef08.png" alt="The image shows the edited wsgi.py file and the highlights the save button" style="display:block;margin:0 auto" width="1812" height="986" loading="lazy">

<h3 id="heading-117-how-to-set-up-static-files">11.7 How to Set Up Static Files</h3>
<p>Still on the "Web" tab, scroll down to the "Static files" section. Add an entry:</p>
<ul>
<li><p>URL: <code>/static/</code></p>
</li>
<li><p>Directory: <code>/home/yourusername/fitness-tracker/staticfiles</code></p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/f128dbd2-4acc-4387-89f8-d79de8c1e66e.png" alt="The image shows the static files section of the Web tab" style="display:block;margin:0 auto" width="2488" height="728" loading="lazy">

<p>Then go back to your Bash console and run the following command:</p>
<pre><code class="language-shell">python manage.py collectstatic
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/207f8e67-2679-4ccc-8ebf-7d8aae5d7494.png" alt="The image shows the results of the collect static command" style="display:block;margin:0 auto" width="2448" height="600" loading="lazy">

<p>This copies all static files to the staticfiles directory so PythonAnywhere can serve them directly.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/a14b75c4-cc1e-48ad-baf2-cf4f00906b85.png" alt="The image shows the folder named static files that was created" style="display:block;margin:0 auto" width="2720" height="1026" loading="lazy">

<p>Go back to the "Web" tab and click the green "Reload" button at the top. This restarts your app with all the new configuration.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/08fab36e-8c8d-4d1b-8342-6e340fcf45d4.png" alt="The image shows the web tab with the reload button" style="display:block;margin:0 auto" width="2874" height="1046" loading="lazy">

<h3 id="heading-118-how-to-view-your-live-application">11.8 How to View Your Live Application</h3>
<p>Open a new browser tab and visit <a href="https://yourusername.pythonanywhere.com">https://yourusername.pythonanywhere.com</a>. You should see your fitness tracker, live on the internet.</p>
<p>Try adding a workout.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/db67dbb1-3cb9-4b86-bfaa-67427ef5eac0.png" alt="The image shows the workout list view being opened in python anywhere" style="display:block;margin:0 auto" width="2290" height="1278" loading="lazy">

<p>Visit the admin panel at <a href="https://yourusername.pythonanywhere.com/admin/">https://yourusername.pythonanywhere.com/admin/</a>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/bd80d1e8-cf23-4ac2-b6a7-35bfdf61d023.png" alt="The image shows the workout django admin being opened in pythonanywhere" style="display:block;margin:0 auto" width="2128" height="1310" loading="lazy">

<p>Everything should work just as it did on your local machine, but now anyone with the link can access it.</p>
<p>This is a meaningful milestone. You've gone from zero to a deployed Django application. Share the link with a friend or post it in a coding community. Seeing your work live on the internet is one of the most motivating experiences in learning to code.</p>
<h2 id="heading-common-mistakes-and-how-to-fix-them">Common Mistakes and How to Fix Them</h2>
<p>Even when you follow each step carefully, things can go wrong. Here are the most common issues beginners run into and how to solve them.</p>
<p><strong>"ModuleNotFoundError: No module named 'django'"</strong> – This usually means your virtual environment isn't activated. Run <code>source venv/bin/activate</code> (macOS/Linux) or <code>venv\Scripts\activate</code> (Windows) and try again. On PythonAnywhere, make sure the <strong>virtualenv</strong> path in the "<strong>Web</strong>" tab points to the correct location.</p>
<p><strong>"DisallowedHost" error</strong> – You forgot to add your domain to <code>ALLOWED_HOSTS</code> in <code>settings.py</code>, or there's a typo. Double-check that it matches your PythonAnywhere URL exactly.</p>
<p><strong>Static files not loading in production</strong> – Make sure you ran <code>python manage.py collectstatic</code> and that the static file mapping on PythonAnywhere points to the <strong>correct staticfiles</strong> directory. Also verify that <code>STATIC_ROOT</code> is set in <code>settings.py</code>.</p>
<p><strong>"No such table" or migration errors</strong> – You probably forgot to run <code>python manage.py migrate</code> after cloning or uploading your project to PythonAnywhere. Run the <code>migrate</code> command in the Bash console.</p>
<p><strong>Changes not showing up on PythonAnywhere</strong> – After making any code changes, you must click the "<strong>Reload</strong>" button on the "<strong>Web</strong>" tab. PythonAnywhere does not automatically detect file changes.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/08fab36e-8c8d-4d1b-8342-6e340fcf45d4.png" alt="The image shows the web tab and the reload buttton" style="display:block;margin:0 auto" width="2874" height="1046" loading="lazy">

<h2 id="heading-how-you-can-improve-this-project">How You Can Improve This Project</h2>
<p>The fitness tracker you built is intentionally simple. That's a feature, not a limitation. A working simple project is the perfect foundation for learning more.</p>
<p>Here are some ideas for expanding it.</p>
<ol>
<li><p><strong>Add user authentication:</strong> Right now, anyone who visits the site sees the same workout data. Django has a built-in authentication system that lets you add registration, login, and logout. Each user could then have their own private list of workouts.</p>
</li>
<li><p><strong>Add the ability to edit and delete workouts.</strong> Currently, once a workout is saved, there's no way to change or remove it from the interface (you can do it through the admin panel, but not the main app). Try creating new views and templates for editing and deleting.</p>
</li>
<li><p><strong>Add workout categories or tags.</strong> Let users categorize their workouts as "Cardio," "Strength," "Flexibility," and so on. This would involve adding a new field to the model or creating a separate Category model with a foreign key relationship.</p>
</li>
<li><p><strong>Add charts and progress tracking.</strong> Use a JavaScript charting library like Chart.js to display workout trends over time. For example, you could show a bar chart of total minutes exercised per week.</p>
</li>
<li><p><strong>Build an API with Django REST Framework.</strong> If you want to learn about building APIs, try installing Django REST Framework (DRF) and creating API endpoints for your workouts. This would let you build a mobile app or a separate front end that communicates with your Django back end.</p>
</li>
</ol>
<p>Each of these improvements will teach you something new about Django while building on the foundation you already have.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You've built a fully functional fitness tracker web app with Django and deployed it to the internet. That's no small achievement.</p>
<p>Along the way, you learned how Django projects and apps are structured, how models define the shape of your data, how migrations translate those models into database tables, how views handle the logic of your application, how templates render dynamic HTML, and how URLs tie everything together. You also went through the entire deployment process on PythonAnywhere.</p>
<p>These are the core building blocks of Django development. The patterns you practiced here – defining a model, creating a form, writing a view, building a template, and connecting a URL – are the same patterns you will use in every Django project, no matter how complex.</p>
<p>The best way to solidify what you have learned is to keep building. Try one of the improvements mentioned above, or start a completely new project. A calorie tracker, a habit tracker, an expense tracker, or a personal journal would all use the same Django concepts with slightly different models and views.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Passing by Object Reference Works in Python ]]>
                </title>
                <description>
                    <![CDATA[ If you've ever modified a variable inside a Python function and been surprised or confused by what happened to it outside the function, you're not alone. This tripped me up for a long time. Coming fro ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-passing-by-object-reference-works-in-python/</link>
                <guid isPermaLink="false">69c5415810e664c5dadbf6e0</guid>
                
                    <category>
                        <![CDATA[ python beginner ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ functions ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mokshita V P ]]>
                </dc:creator>
                <pubDate>Thu, 26 Mar 2026 14:23:20 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/0fb11934-22c6-4304-948c-54c7d423c79d.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you've ever modified a variable inside a Python function and been surprised or confused by what happened to it outside the function, you're not alone. This tripped me up for a long time.</p>
<p>Coming from tutorials that talked about "call by value" and "call by reference," I assumed Python must follow one of those two models. It doesn't. Python does something slightly different, and once you understand it, a lot of previously confusing behavior will suddenly click.</p>
<p>In this article, you'll learn:</p>
<ul>
<li><p>What calling by value and calling by reference mean</p>
</li>
<li><p>How other languages like C handle this</p>
</li>
<li><p>What Python actually does (passing by object reference)</p>
</li>
<li><p>How mutable and immutable types affect behavior inside functions</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-call-by-value-and-call-by-reference-explained">Call by Value and Call by Reference Explained</a></p>
</li>
<li><p><a href="#heading-how-it-works-in-c-with-examples">How It Works in C (with Examples)</a></p>
</li>
<li><p><a href="#heading-what-python-does-instead">What Python Does Instead</a></p>
</li>
<li><p><a href="#heading-mutable-vs-immutable-types">Mutable vs Immutable Types</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-call-by-value-and-call-by-reference-explained">Call by Value and Call by Reference Explained</h2>
<p>Before we get to Python, let's quickly define these two terms.</p>
<p><strong>Call by value</strong> means a copy of the variable is passed to the function. Whatever you do to it inside the function, the original stays unchanged.</p>
<p><strong>Call by reference</strong> means the actual memory location of the variable is passed. Changes inside the function directly affect the original variable.</p>
<p>Many languages support one or both of these models. Python, however, uses neither – at least not in the traditional sense.</p>
<h3 id="heading-how-it-works-in-c-with-examples">How It Works in C (with Examples)</h3>
<p>C is a good example of a language that supports both models explicitly.</p>
<p>Here's how you call by value in C. The original variable is unaffected:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;

void modify(int *n) {

*n = *n + 10;

printf("Inside function: %d\n", *n); }

int main() {

int x = 5;

modify(&amp;x);

printf("Outside function: %d\n", x);

return 0; }
</code></pre>
<p>Output:</p>
<p>Inside function: 15</p>
<p>Outside function: 15 ← original changed!</p>
<p>In C, you explicitly choose the behavior by deciding whether to pass a pointer or a plain value. Python doesn't give you that choice, but what it does instead is actually quite logical.</p>
<h2 id="heading-what-python-does-instead">What Python Does Instead</h2>
<p>Python uses a model called <strong>passing by object reference</strong> (sometimes called passing by assignment).</p>
<p>When you pass a variable to a function in Python, you're passing a reference to the object that variable points to, not a copy of the value, and not the variable itself.</p>
<p>What happens next depends entirely on whether that object is <strong>mutable</strong> (can be changed in place) or <strong>immutable</strong> (cannot be changed in place).</p>
<h3 id="heading-mutable-vs-immutable-types">Mutable vs Immutable Types</h3>
<p><strong>Immutable types</strong> in Python include <code>int</code>, <code>float</code>, <code>str</code>, and <code>tuple</code>. These objects cannot be modified in place. When you "change" one inside a function, Python creates a brand new object and the original is left untouched.</p>
<pre><code class="language-python">def modify_number(n):
     n = n + 10
     print("Inside function:", n)

x = 5

modify_number(x)

print("Outside function:", x)
</code></pre>
<p>Output:</p>
<p>Inside function: 15</p>
<p>Outside function: 15 ← original unchanged</p>
<p><strong>Mutable types</strong> include <code>list</code>, <code>dict</code>, and <code>set</code>. These can be changed in place. When you modify one inside a function, you're modifying the same object the caller is holding a reference to.</p>
<pre><code class="language-python">def modify_list(items):

    items.append(99)

    print("Inside function:", items)

my_list = [1, 2, 3]

modify_list(my_list)

print("Outside function:", my_list)
</code></pre>
<p>Output:</p>
<p>Inside function: [1, 2, 3, 99]</p>
<p>Outside function: [1, 2, 3, 99] ← original changed!</p>
<p>This is the key insight: Python doesn't decide behavior based on how you pass something, it decides based on what type of object you're passing.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Python doesn't use call by value or call by reference. It <strong>passes by object reference</strong>, where the function receives a reference to the object, and whether that object can be modified in place determines what happens next.</p>
<p>To recap:</p>
<ul>
<li><p><strong>Immutable types</strong> (<code>int</code>, <code>str</code>, <code>tuple</code>): a new object is created inside the function, original stays the same</p>
</li>
<li><p><strong>Mutable types</strong> (<code>list</code>, <code>dict</code>, <code>set</code>): the original object is modified directly</p>
</li>
</ul>
<p>Once this clicked for me, a lot of the "why is Python doing this?" moments started making sense. If you're just getting started with functions in Python, keep this in the back of your mind, it'll save you a lot of debugging headaches.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Get Started Coding in Golang ]]>
                </title>
                <description>
                    <![CDATA[ In the world of Software Engineering, there are plenty of programming languages to learn. And there are both low-level and high-level options. I’ve tried my hand at a few of them, and the one language ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-get-started-coding-in-golang/</link>
                <guid isPermaLink="false">69b2e2251be92d8f177786a8</guid>
                
                    <category>
                        <![CDATA[ Go Language ]]>
                    </category>
                
                    <category>
                        <![CDATA[ golang ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Njong Emy ]]>
                </dc:creator>
                <pubDate>Thu, 12 Mar 2026 15:56:21 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/a429db13-593a-4afe-be02-2c94ae1f246f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the world of Software Engineering, there are plenty of programming languages to learn. And there are both low-level and high-level options.</p>
<p>I’ve tried my hand at a few of them, and the one language that feels like it touches both worlds is Golang – popularly known as Go. Although Go is a high-level language, it has pretty amazing performance that brings it close to the low-level edge.</p>
<p>Go is a fast, statically typed programming language. Types are declared at compile time, and you don’t need to run the code before catching errors. It’s also a general-purpose language that you can use for backend, cloud, servers, and more.</p>
<p>Go has built-in testing support, so you don’t need to install extra testing libraries. Go also has some features of object-oriented languages, but in its own way. It mirrors some OOP concepts, but also uses concepts like interfaces, structs, and so on.</p>
<p>In this tutorial, we're going to be looking at a few basic concepts you need to know when getting started in any programming language. A few of them are generic to many programming languages, but some of them are concepts specific to the Go programming language. We'll take a look at:</p>
<ul>
<li><p>Variables</p>
</li>
<li><p>Formatting strings</p>
</li>
<li><p>Arrays and slices</p>
</li>
<li><p>Loops</p>
</li>
<li><p>Functions</p>
</li>
<li><p>Maps</p>
</li>
<li><p>Structs, and</p>
</li>
<li><p>Package scope</p>
</li>
</ul>
<p>By the end of the article, you'll be grounded in the pure basics of Go, and we'll run a few examples to see how these work on the command line.</p>
<h3 id="heading-what-well-cover">What we'll cover:</h3>
<ol>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-how-to-install-go">How to Install Go</a></p>
</li>
<li><p><a href="#heading-how-to-write-your-first-go-program">How to Write Your First Go Program</a></p>
</li>
<li><p><a href="#heading-how-to-work-with-variables-and-numbers-in-go">How to Work with Variables and Numbers in Go</a></p>
</li>
<li><p><a href="#heading-how-to-format-strings-in-go">How to Format Strings in Go</a></p>
</li>
<li><p><a href="#heading-how-to-work-with-arrays-and-slices-in-go">How to Work with Arrays and Slices in Go</a></p>
</li>
<li><p><a href="#heading-how-to-work-with-loops-in-go">How to Work with Loops in Go</a></p>
</li>
<li><p><a href="#heading-how-to-work-with-functions-in-go">How to Work with Functions in Go</a></p>
</li>
<li><p><a href="#heading-how-to-work-with-maps-in-go">How to Work with Maps in Go</a></p>
</li>
<li><p><a href="#heading-how-to-work-with-structs-in-go">How to Work with Structs in Go</a></p>
</li>
<li><p><a href="#heading-package-scope-in-go">Package Scope in Go</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial, it’ll be helpful if you know the basics of any programming language, such as variables, data types, and data structures. I’ll assume that you’ve worked with at least one programming language before.</p>
<h2 id="heading-how-to-install-go">How to Install Go</h2>
<p>To install Go, head to <a href="http://golang.org/">golang.org</a>. Depending on what OS you are running, the documentation provides different installation options.</p>
<p>In my case, I’m using <strong>WSL</strong> (Windows Subsystem for Linux) with Ubuntu, so I’ll install Go inside that environment.</p>
<p>First, update your package list:</p>
<pre><code class="language-plaintext">sudo apt update
sudo apt upgrade -y
</code></pre>
<p>Next, install a tool to download files from the internet. We’ll use <strong>wget</strong>:</p>
<pre><code class="language-plaintext">sudo apt install -y wget
</code></pre>
<p>Now download the Go binary package:</p>
<pre><code class="language-plaintext">wget https://dl.google.com/go/go1.24.2.linux-amd64.tar.gz
</code></pre>
<p>Extract the archive to <code>/usr/local</code>:</p>
<pre><code class="language-plaintext">sudo tar -C /usr/local -xzf go1.24.2.linux-amd64.tar.gz
</code></pre>
<p>After installing Go, add the Go binary directory to your <strong>PATH</strong> so the <code>go</code> command is available in the terminal:</p>
<pre><code class="language-ruby">export PATH=$PATH:/usr/local/go/bin
</code></pre>
<p>You can make this change permanent by adding the line above to your <code>~/.bashrc</code> or <code>~/.profile</code>.</p>
<p>To confirm Go was installed successfully, run:</p>
<pre><code class="language-go">go version
</code></pre>
<p>You should see the installed Go version printed in the terminal.</p>
<p>If you use VS Code, you can also install the Go extension for syntax highlighting.</p>
<h2 id="heading-how-to-write-your-first-go-program">How to Write Your First Go Program</h2>
<p>Before we get into writing our first program, we need to establish how Go puts its code together. In Go, every file or code is part of a package.</p>
<p>In this example, we’ll create a file called <code>main.go</code>. The name isn’t special to Go, but it’s a common convention for the file that contains the program’s entry point.</p>
<pre><code class="language-go">package main

import "fmt"

func main() {
	fmt.Println("Hello, ninjas")
}
</code></pre>
<p>This is the most important file in our project. We'll begin by making the code we’ll write in this file part of a package we call <code>main</code>.</p>
<p>The <code>fmt</code> import is a package from the Go standard library. <code>fmt</code> is for formatting strings and outputting to the console. Notice that the <code>Println</code> function starts with a capital letter, because within the <code>fmt</code> package, the method is exported. Variables or methods that are exported in Go should begin with capital letters. The <code>Println</code> prints a line to the console.</p>
<p>The <code>main</code> function serves as the entry point of a Go program. A compiled Go program must contain <strong>exactly one</strong> <code>main</code> <strong>function inside a</strong> <code>package main</code>. (A larger codebase can still contain multiple programs, each in its own directory with its own <code>package main</code>.)</p>
<p>So when you run a Go program, the Go toolchain builds all files in the same package together and then starts execution from the <code>main()</code> function. The filename <code>main.go</code> does not determine execution order – it’s simply a common naming convention.</p>
<p>Unlike other custom packages, which are used to bundle application logic into libraries or reusable code, the <code>main</code> package is used to specify that a program is a standalone executable.</p>
<p>To run the code, you can simply type <code>go run main.go</code>, specifying the Go file that we want to execute.</p>
<pre><code class="language-go">Hello, ninjas
</code></pre>
<h2 id="heading-how-to-work-with-variables-and-numbers-in-go">How to Work with Variables and Numbers in Go</h2>
<h3 id="heading-how-to-declare-variables">How to Declare Variables</h3>
<p>A variable is just a store for data. Go does not allow unused local variables. If you declare a variable inside a function and never use it, the compiler will raise an error. This helps prevent cluttered code and unused definitions.</p>
<p>Let’s see how to declare variables in Go by declaring a string</p>
<pre><code class="language-go">package main

import "fmt"

func main() {

	// strings
	var nameOne string = "emy"

	fmt.Println(nameOne)
}
</code></pre>
<p>Because Go is a statically typed language, every variable must have a type at compile time. Here, we have a variable <code>nameOne</code>, it’s type, and then an initial value assigned to it.</p>
<p>But what if we don't want to state the variable type ourselves? Fortunately, Go lets us define variables without a type stated at compile time</p>
<pre><code class="language-go">// strings
var nameOne string = "emy"
var nameTwo = "blessing"
var nameThree string
</code></pre>
<p>For <code>nameTwo</code>, we don’t need to explicitly state the type because Go directly infers it. If you hover above the variable, you can see that Go already tells you the type. The third variable, <code>nameThree</code>, has no value assigned to it just yet. We’ve only just declared it.</p>
<p>If you log the output to the console, you can see <code>nameOne</code> and <code>nameTwo</code> displayed, but you can’t see <code>nameThree</code>. It’s also logged, you just can’t see it because it has no value.</p>
<pre><code class="language-go">emy blessing 
</code></pre>
<p>There’s an even shorter and simpler way to declare variables in Go:</p>
<pre><code class="language-go">nameFour := "peaches"
</code></pre>
<p>Here, Go also infers the variable type based on the value assigned to it. Notice how we also didn’t use the <code>var</code> keyword. You can use this method inside any function, not just in <code>main</code>. Just keep in mind that you can't use this method of declaring variables when reassigning or updating a variable, declaring constants, or declaring safe types.</p>
<h3 id="heading-how-to-declare-integers">How to Declare Integers</h3>
<p>When it comes to declaring integers, we pretty much use the same technique as above:</p>
<pre><code class="language-go">var ageOne int = 20
var ageTwo = 30
ageThree := 40

fmt.Println(ageOne, ageTwo, ageThree)
</code></pre>
<p>When declaring integers, we can specify the amount of memory or the bit size we want an integer to have. We can declare the integer as <code>int8</code>, <code>int16</code>, or <code>int64</code>.</p>
<p>Each of these memory sizes can hold a specific range of numbers. <code>int8</code>, for example, can only hold integers between -128 and 127. Anything bigger than that would throw an error:</p>
<pre><code class="language-go">// bits and memory
	var numOne int8 = 25
	var numTwo int8 = -128

	var numThree int8 = 129 // will throw an error
</code></pre>
<p>Another type of integer in Go is the unsigned integer, declared with <code>uint</code>. You’ll use this to declare only positive integers – you can’t use it to store negative values.</p>
<p><code>uint</code>, just like the <code>int</code> type, can also be associated with bit sizes. You could have a <code>uint8</code>, <code>uint16</code>, and so on. But the ranges for these are different. You can check the complete list of bit sizes for the integer type and their ranges on this <a href="https://go.dev/ref/spec#Numeric_types">Go page</a>.</p>
<p><code>int</code> is specifically used to declare whole integer numbers. To declare decimal numbers, you can use a float. The concept is the same with <code>int</code>, where you can have floats with different bit sizes. But you can only have <code>float32</code> and <code>float64</code>, where the latter can store bigger numbers than the former.</p>
<h2 id="heading-how-to-format-strings-in-go">How to Format Strings in Go</h2>
<h3 id="heading-printing-strings-to-the-console">Printing Strings to the Console</h3>
<p>We came across the <code>fmt</code> package at the beginning of the article. Let’s go through some of the methods this package exposes.</p>
<p>First, we have the <code>Print()</code> method which logs some output the console. This method is used to log simple strings to the command line when we just want to see the output of something, and don’t really care about the readability.</p>
<p>If we have two simple strings as shown below;</p>
<pre><code class="language-go">// Print
fmt.Print("Hello, ")
fmt.Print("world!")

// Output: Hello, world!
</code></pre>
<p>You can see that the code above is not on separate lines, and this is the downside of the <code>Print</code> function. If we had multiple things to log to the command line, this function would just lump them together and readability could suffer.</p>
<p>But we can enforce a new line with <code>Print()</code> by using the escape character <code>\\n</code> .</p>
<pre><code class="language-go">fmt.Print("hello! \\n")
fmt.Print("new line \\n")

/*
	hello! 
	new line 
*/
</code></pre>
<p>Using escape characters throughout our code can get tiring very quickly. Luckily for us, Go has a function that helps us achieve the perfect separate line formatting we are looking for. We don’t need to use escape characters when we use <code>Println</code> .</p>
<pre><code class="language-go">fmt.Println("Hello, friends.")
fmt.Println("How are you?")

/*
	Hello, friends.
	How are you?
*/
</code></pre>
<h3 id="heading-format-specifiers">Format Specifiers</h3>
<p>Sometimes, you may want to log a string to the console, but you may also want to have variables within that string. This is called a formatted string, and we can achieve this with the help of format specifiers. These format specifiers are reserved characters that Go uses at runtime to position variables within strings.</p>
<p>Let’s use a concrete example to see the concept better,</p>
<pre><code class="language-go">name := "Emy"
age := 27

fmt.Printf("my age is %v and my name is %v", age, name)

// Output: my age is Emy and my name is 27
</code></pre>
<p>The format specifier <code>%v</code> is the default format specifier that stands for variable. We can see that in the position of the format specifiers, Go has placed the values of the arguments we passed to the <code>Printf</code> (<code>age</code> and <code>name</code>). It's important to note that the order in which we pass these arguments is important.</p>
<p>As we just saw above, the output of this code:</p>
<pre><code class="language-go">name := "Emy"
age := 27

fmt.Printf("my age is %v and my name is %v", name, age)
</code></pre>
<p>Would be <code>my age is Emy and my name is 27</code>. The order in which we pass the arguments is the same way in which the compiler will replace the format specifier within our string.</p>
<p>Something new you might also notice is that we didn't use <code>Print</code> or <code>Println</code> in this code like we did before. When working with formatted directives, Go puts the functions <code>Printf</code>, <code>Sprintf</code>, and <code>Appendf</code> at our disposal.</p>
<ul>
<li><p><code>Printf</code> directs the output to the console, as we’ve seen.</p>
</li>
<li><p>With <code>Sprintf</code>, we don't direct the output to the command line, but we can store it in a variable and then use that variable somewhere else in our code.</p>
</li>
<li><p>It gets a little more complex when working with <code>Appendf</code>, which formats according to a format specifier and appends the result to a byte slice (bytes are a bit out of the scope of this article, so we won’t dwell on them).</p>
</li>
</ul>
<p>Besides the <code>%v</code> format specifier, we can also use <code>%q</code> if we want the embedded variable to have quotes around it.</p>
<pre><code class="language-go">// strings
	name := "Emy"

	fmt.Printf("my name is %q", name)

// output: my name is "Emy"
</code></pre>
<p>This will work for the <code>name</code> variable, but not really for the <code>age</code> because it’s an integer.</p>
<pre><code class="language-go">name := "Emy"
age := 27

fmt.Printf("my age is %q and my name is %q", name, age)

//Output: my age is '\\\\x1b' and my name is "Emy"
</code></pre>
<p>We also have the <code>%T</code> specifier, which is used to output the type of a variable.</p>
<p>If we wanted to get the type of <code>age</code>:</p>
<pre><code class="language-go">fmt.Printf("This is a variable of type %T", age)
</code></pre>
<p>The output of this would be:</p>
<pre><code class="language-go">This is a variable of type int
</code></pre>
<p>You can check out other format specifiers on the official <a href="https://pkg.go.dev/fmt">fmt package page</a>.</p>
<h2 id="heading-how-to-work-with-arrays-and-slices-in-go">How to Work with Arrays and Slices in Go</h2>
<h3 id="heading-arrays-in-go">Arrays in Go</h3>
<p>Arrays in Go are a little bit of a mouthful. Let’s take a look at how to define an array:</p>
<pre><code class="language-go">var ages = [3]int{20, 25, 30}
</code></pre>
<p>In this code, we have the variable name on the left side as is typical. On the right side, we have <code>[3]</code> to specify the size of the array, the type as <code>int</code> , and the values for the array inside the squiggly braces.</p>
<p>Once we declare an array, we can never change its size. This is kind of a bummer if you ask me, because during coding, you don’t always know the size of an array when you declare it (more on this below when we talk about slices).</p>
<p>Arrays in Go also can’t contain multiple types. The array we declared above can’t also contain a string, for example.</p>
<p>If we log the array to the console alongside its length with <code>fmt.Println(ages, len(ages))</code>, on the console we get:</p>
<pre><code class="language-go">[20 25 30] 3
</code></pre>
<h3 id="heading-slices-in-go">Slices in Go</h3>
<p>If you need to define an array where you don’t know or don’t want to specify the size during declaration, you can use a slice. Slices are abstractions of arrays, and are more flexible than arrays because they have dynamic sizing.</p>
<pre><code class="language-go">var scores = []int{100, 50, 60} // we don't specify the size
scores[2] = 25 // to update a value
scores = append(scores, 50) // returns a new scores slice with 50 appended to it  (you cannot do this with arrays)
fmt.Println(scores, len(scores)) // [100 50 60 50] 4
</code></pre>
<p>An important part of working with arrays, slices, or any data structures that store data is knowing how to get the elements we want. We may only want to grab data that belongs to a certain range, or data at certain positions, based on certain conditions, and so on.</p>
<p>When it comes to dealing with ranges, say you want to output the slice elements from position 1 (that is, <a href="https://en.wikipedia.org/wiki/Zero-based_numbering">index 0</a>, the first element) right up to the third position (index 2).</p>
<pre><code class="language-go">rangeOne := scores[0:3] // [100 50 60]
</code></pre>
<p>The range <code>scores[0:3]</code> indicates that the code should list the scores from index 0 up to index 3 minus 1. So it doesn’t include the element at index 3.</p>
<p>If you wanted to log from index 2 in the slice right up to the end, for example, you’d write <code>scores[2:]</code> . Similarly, you could log from the beginning of the slice up to and excluding some position (in this case, index 3) like so, <code>scores[:3]</code> .</p>
<h2 id="heading-how-to-work-with-loops-in-go">How to Work with Loops in Go</h2>
<h3 id="heading-how-to-iterate-loops">How to Iterate Loops</h3>
<p>Loops in Go are similar to loops in other programming languages. The difference is that Go focuses on the <code>for</code> loop and doesn’t really dwell on <code>while</code>, <code>do-while</code>, or <code>for-each</code>.</p>
<pre><code class="language-go">x := 0
for x &lt; 5 {
	fmt.Println("the value of x is", x)
	x++
}
</code></pre>
<p>The loop above is straightforward and just prints the value of <code>x</code> from 0 to 4.</p>
<p>To create a loop that uses an iterator, you can write this:</p>
<pre><code class="language-go">for i := 0; i &lt; 5; i++ {
	fmt.Println("value of i is", i)
}
    /*
		value of i is 0
		value of i is 1
		value of i is 2
		value of i is 3
		value of i is 4
	*/
</code></pre>
<p>It does pretty much the same thing as the loop above it, but we declared the iterator, it’s range, and we iterate over it in the same expression.</p>
<p>What if you wanted to iterate or loop over a slice, for example? We can also use an iterator to achieve this as we have above.</p>
<pre><code class="language-go">names := []string{"emy", "ble", "winkii"}

for i := 0; i &lt; len(names); i++ {
		fmt.Println(names[i])
}
</code></pre>
<h3 id="heading-how-to-use-the-range-keyword">How to Use the <code>range</code> Keyword</h3>
<p>Another interesting keyword related to iterations is <code>range</code>. Using the <code>range</code> keyword, you can use loops to perform actions on elements in a slice. <code>range</code> provides the index and value of the element in a slice, and allows you to access those within the loop.</p>
<pre><code class="language-go">for index, value := range names {
		fmt.Printf("the position of %v is %v \\\\n", value, index)
	}
</code></pre>
<p>What if you didn’t want to use the index and only the value? Well, <code>range</code> requires that you define an index and a value. So if you rewrite your loop like this:</p>
<pre><code class="language-go">for index, value := range names {
		fmt.Printf("the value is %v \\\\n", value)
}
</code></pre>
<p>Go is going to throw an error because you’re declaring the <code>index</code> but not using it.</p>
<p>Luckily, there’s a way to bypass this, and Go does it neatly using the blank identifier, <code>_</code>. We use this identifier when a method or function expects that you define a return value that you don't need.</p>
<pre><code class="language-go">for _, value := range names {
		fmt.Printf("the value is %v \\\\n", value)
}
</code></pre>
<p>You could apply the same strategy if you wanted only the index, but not the value.</p>
<pre><code class="language-go">for index, _ := range names {
		fmt.Printf("the index is %v \\\\n", index)
}
</code></pre>
<h2 id="heading-how-to-work-with-functions-in-go">How to Work with Functions in Go</h2>
<p>A function is a reusable block of code. Functions in Go are mostly created outside the <code>main</code> function. This way, other files can access and use them.</p>
<pre><code class="language-go">package main

import (
	"fmt"
)

func sayGreeting(n string){
	fmt.Printf("Good morning")
}

func main() {
	sayGreeting("emy")
}
</code></pre>
<p>Go also allows you to pass functions as parameters to other functions.</p>
<pre><code class="language-go">func cycleNames(n []string, f func(string)) {
	for _, value := range n {
		f(value)
	}
}
</code></pre>
<p>The function above takes a slice and a function as parameters. The function passed as a parameter in turn takes a string. You could pass a slice of names alongside the greeting function, so that for each name in the slice, you run the greeting function to print a greeting for that name.</p>
<pre><code class="language-go">func main(){
	cycleNames([]string{"emy", "pearl"}, sayGreeting)
}
</code></pre>
<p>When passing the <code>sayGreeting</code> function as a parameter, you don’t invoke it immediately because that’s done within the <code>cycleNames</code> function already. You only pass its reference.</p>
<h3 id="heading-functions-with-return-values">Functions with <code>return</code> Values</h3>
<p>Functions may also need to have a return value. So, how does Go handle that? Let’s see a small example:</p>
<pre><code class="language-go">package main

import "fmt"

func sayHello(name string) string {
	fmt.Printf("Hello %v", name)
	return name
}

func main() {
	sayHello("Emy")
}

// Output: Hello Emy
</code></pre>
<p>Just like with variables, we must specify the data type for every function parameter, and also specify the data type of the expected return value. In the example above, our function <code>sayHello</code> takes a string and returns a string.</p>
<p>Functions can also have multiple return values, as we see in the example below:</p>
<pre><code class="language-jsx">package main

import "fmt"

func sayHello(name string, age int) (string, int) {
	fmt.Printf("Hello %v, you are %v years old", name, age)
	return name, age
}

func main() {
	sayHello("Emy", 27)
}
</code></pre>
<p>Just like the previous example, we have to specify data types for our function parameters and return values.</p>
<h2 id="heading-how-to-work-with-maps-in-go">How to Work with Maps in Go</h2>
<p>A map in Go is a built-in, unordered collection of unique key-value pairs, similar to dictionaries in Python or hash tables in other languages. Maps provide fast lookups, insertions, and deletions.</p>
<p>With maps, all the keys must be of the same data type, and so must the values. If one key is a string, then all the other keys must also be strings. The same concept applies for values.</p>
<pre><code class="language-go">scores := map[string]float64{
		"maths":           20,
		"english":         15,
		"french":          14,
		"spanish":         12,
	}

	fmt.Println(scores)
	fmt.Println(scores["maths"])

	/*
	map[english:15 french:14 maths:20 spanish:12]
	20
	*/
</code></pre>
<p>You can also loop through maps to get their keys and corresponding values:</p>
<pre><code class="language-go">// loops maps
	for key, value := range scores {
		fmt.Println(key, "-", value)
	}

	/*
	french - 14
	spanish - 12
	maths - 20
	english - 15
	*/
</code></pre>
<p>When it comes to mutating maps, it's important to note that maps are reference types. Reference types are types whose variables don’t store the actual data, but rather an internal pointer to the actual data. This means that if the same data is assigned to multiple variables, when one instance gets modified, the original gets modified as well.</p>
<p>Let’s understand this with an example;</p>
<pre><code class="language-go">package main

import "fmt"

func main() {
	scores := map[string]float64{
		"maths":   20,
		"english": 15,
		"french":  14,
		"spanish": 12,
	}

	scores2 := scores

	scores2["maths"] = 15
	fmt.Println(scores)
}

// Output: map[english:15 french:14 maths:15 spanish:12]
</code></pre>
<p>If you check out the output, you can see that we modified the math score for <code>scores2</code>, but that modification also affected the original map, <code>scores</code> .</p>
<h2 id="heading-how-to-work-with-structs-in-go">How to Work with Structs in Go</h2>
<p>A big downside of using maps is that we can only store one data type for keys and one data type for values. This feels restrictive. We need a data structure that lets us store a collection of data with different data types. This is where structs (or structures) come in.</p>
<p>Let’s look at an example:</p>
<pre><code class="language-go">type Book struct {
	ID     uint
	Title  string
	Author string
	Year   int
	UserID uint
}
</code></pre>
<p>Here we have a Book struct. Structs are defined by specifying the key of the data you want the struct to carry, and the data type associated with that key.</p>
<pre><code class="language-go">package main

import "fmt"

type Book struct {
	ID     uint
	Title  string
	Author string
	Year   int
    UserID uint
}

func main() {

	var book1 Book

	book1 = Book{1, "Jane Eyre", "Jane Austen", 1990, 6}

	fmt.Println(book1)
}
</code></pre>
<p>We initialised the <code>Book</code> struct by providing it with the data we stated in its definition. If you check the output of this (and ignore that Jane Austen didn’t write Jane Eyre, of course):</p>
<pre><code class="language-go">{1 Jane Eyre Jane Austen 1990 6}
</code></pre>
<p>If you look closely, structs resemble classes from the OOP languages. They define properties (just as with methods, properties starting with a capital letter are public and can be exported), and these properties can be used within methods or functions. The difference comes at the level of inheritance, because structs, unlike classes, support only composition and not inheritance.</p>
<p>We can also individually modify the properties of a struct using dot notation, like so:</p>
<pre><code class="language-go">	var book1 Book

	book1 = Book{1, "Jane Eyre", "Jane Austen", 1990, 6}

	book1.Title = "Things Fall Apart"
	book1.Author = "Chinua Achebe"

	fmt.Println(book1)
</code></pre>
<p>If you check the output again, you can see that what you initialised the struct to contain has been modified at the level of the <code>Title</code> and <code>Author</code>.</p>
<pre><code class="language-go">{1 Things Fall Apart Chinua Achebe 1990 6}
</code></pre>
<p>When working with real systems, structs come in very handy when creating models or designing the structure of data you want to store in your database.</p>
<h2 id="heading-package-scope-in-go">Package Scope in Go</h2>
<h3 id="heading-importing-functions-within-the-same-package">Importing Functions Within the Same Package</h3>
<p>When coding real applications, it's uncommon to write all our application files in one file. This can get messy very quickly. Normally, we would write a function in one file and then call it from another file.</p>
<p>In this case, you can declare variables and functions in other files and still use them in your entry point file. Say you create another <code>greetings.go</code> file and declared some variable and method in it like this:</p>
<pre><code class="language-go">// greetings.go
package main

import "fmt"

var points = []int{20, 90, 100, 45, 70}

func sayHello(n string) {
	fmt.Println("Hello", n)
}
</code></pre>
<p>Notice that there is no <code>func main()</code> in this file (remember that we can have only one throughout our application).</p>
<p>Now, in your <code>main.go</code> file, you can reference the <code>sayHello()</code> function and <code>points</code> variable you created.</p>
<pre><code class="language-go">// main.go
func main() {
	sayHello("emy")

	for _, v := range points {
		fmt.Println(v)
	}
}
</code></pre>
<p>To run this, you’ll need to have both files running at the same time. That is:</p>
<pre><code class="language-bash">go run main.go greetings.go
</code></pre>
<p>You can see that the output is the result of running the <code>sayHello()</code> function and looping over the <code>points</code> slice.</p>
<p>You could also define functions and variables in the <code>main.go</code> file and pass them to the <code>greetings.go</code> file. Remember that all these functions and variables passed between files must be declared outside the <code>main()</code> function.</p>
<h3 id="heading-importing-functions-across-different-packages">Importing Functions Across Different Packages</h3>
<p>What if your application has, say, 100 files? Will you run all those files simultaneously? No, you won't. Since our Go code can be organised in packages, we can import a function from one package within another package. Let’s rewrite our code above, but using two different packages.</p>
<p>In our <code>greetings.go</code> file, we now have our code under a new package, <code>greetings</code> , and our <code>SayHello</code> function begins with a capital letter so that other files can import and use it.</p>
<pre><code class="language-jsx">// greetings.go
package greetings

import "fmt"

var Points = []int{20, 90, 100, 45, 70}

func SayHello(n string) {
	fmt.Println("Hello", n)
}
</code></pre>
<p>In our <code>main.go</code> file,</p>
<pre><code class="language-jsx">// main.go
package main

import (
	"fmt"
	"greetings"
)

func main() {
	greetings.SayHello("emy")

	for _, v := range points {
		fmt.Println(v)
	}
}
</code></pre>
<p>As you can see, we’ve imported the <code>greetings</code> package we declared in another file, and we can access the <code>SayHello()</code> method from it with dot notation.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you’ve learned some key Go concepts. You’re now familiar with how variables, strings, arrays and slices, loops, functions, maps, structs, and package scope works in Go.</p>
<p>At this point, you should try to take that further by building something a little bigger so you can see just how powerful and amazing Golang is.</p>
<p>The official <a href="https://go.dev/tour/welcome/1">Tour of Go</a> website is also an amazing resource to reference if you want to explore these concepts a little deeper.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ OSS Pull Request Therapy: Learning to Enjoy Code Reviews with npmx ]]>
                </title>
                <description>
                    <![CDATA[ For years, I thought Open Source Software (OSS) just wasn’t for me. I had no plans to join any OSS communities on top of my existing developer community obligations. Curious about the hype I saw on Bl ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learning-to-enjoy-code-reviews-with-npmx/</link>
                <guid isPermaLink="false">69a6f99556428acc6fef7fbc</guid>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Open Source ]]>
                    </category>
                
                    <category>
                        <![CDATA[ open source ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abbey Perini ]]>
                </dc:creator>
                <pubDate>Tue, 03 Mar 2026 15:09:09 +0000</pubDate>
                <media:content url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5e1e335a7a1d3fcc59028c64/5765f28c-0d0e-46be-bc60-972a4d879b7e.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>For years, I thought Open Source Software (OSS) just wasn’t for me. I had no plans to join any OSS communities on top of my existing developer community obligations.</p>
<p>Curious about the hype I saw on <a href="https://bsky.app/">Bluesky</a>, I recently joined the <a href="https://npmx.dev/">npmx</a> Discord server on a whim. My journey from lurker to contributor taught me a lot about OSS and gave me new confidence going into code reviews.</p>
<p>In this article, I’ll walk you through my journey to give you a little insight into the process of getting involved in Open Source.</p>
<h3 id="heading-heres-what-ill-cover">Here’s what I’ll cover:</h3>
<ul>
<li><p><a href="#heading-my-struggles-with-pull-requests">My Struggles with Pull Requests</a></p>
</li>
<li><p><a href="#heading-my-former-view-of-oss">My Former View of OSS</a></p>
<ul>
<li><p><a href="#heading-the-basics-of-oss">The Basics of OSS</a></p>
</li>
<li><p><a href="#heading-the-dark-side-of-oss">The Dark Side of OSS</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-getting-started-with-npmx">Getting Started with npmx</a></p>
</li>
<li><p><a href="#heading-the-not-so-perfect-pr">The Not So Perfect PR</a></p>
</li>
<li><p><a href="#heading-collaboration-over-perfection">Collaboration Over Perfection</a></p>
</li>
<li><p><a href="#heading-my-current-view-of-oss">My Current View of OSS</a></p>
</li>
<li><p><a href="#heading-tips-for-pr-authors-and-reviewers">Tips for PR Authors and Reviewers</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-my-struggles-with-pull-requests">My Struggles with Pull Requests</h2>
<p>I’ll admit, I’ve always had a hard time with code reviews. I can be quite the perfectionist. I’ll entertain every nitpick and only hear the criticism.</p>
<p>If reviews go on for days, I easily get overwhelmed. I enjoy pairing and co-working. I want to enjoy Pull Request (PRs), but addressing PR comments takes a lot out of me.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771264593124/b5674020-6b0d-4ad2-bb92-921d05ebecc7.png" alt="Me looking at the bugs that my colleagues pointed out in my pull request Patrick Star from Spongebob looking absolutely horrified and staring at a computer" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Some of my struggle is a need for <a href="https://askjan.org/disabilities/Attention-Deficit-Hyperactivity-Disorder-AD-HD.cfm#spy-scroll-heading-2">accommodations</a> that I rarely get. I also have plenty of lived experience with how hostile code reviews can become (even in a professional setting). Finally, there’s how I was introduced to PR reviews.</p>
<p>Outside of work, I had only ever experienced perfunctory PRs – I’d receive at most one suggestion, but usually just got a “LGTM” (Looks Good to Me) comment. Professionally, I went from no code reviews to incredibly detailed code reviews basically overnight. I still feel like I’m playing catch up.</p>
<p>On the one hand, thinking deeply about every suggestion has made me a better developer. I thrive in collaborative environments with thoughtful code reviews. Developers who have worked with me have told me that they benefit from answering all my “why?” questions.</p>
<p>On the other hand, I demand compliments, gifs, and video calls from my reviewers. I don’t do well with a bombardment of vague comments on my PRs. I’ve spent a lot of time documenting code guidelines and review processes that other people seem to understand and remember much more easily than I do.</p>
<p>Developer communities have helped me navigate all of this. Community is a priceless resource for career changers and new grads. When everyone shares their experience, the uninitiated learn about how things could be and what kinds of things aren’t normal (like very hostile code reviews).</p>
<h2 id="heading-my-former-view-of-oss">My Former View of OSS</h2>
<p>When I’ve talked and written about developer community, I’ve recommended online networking communities, going to meetups, tech conferences, social media, writing, and posting your writing online. The one thing I haven’t written about? OSS.</p>
<p>My first real introduction to OSS was through the online networking group <a href="https://virtualcoffee.io/">Virtual Coffee</a>. By the end of my first <a href="https://hacktoberfest.com/">Hacktoberfest</a>, I knew the basics.</p>
<h3 id="heading-the-basics-of-oss">The Basics of OSS</h3>
<ul>
<li><p>Find a project that interests you.</p>
</li>
<li><p>Check the Contributing Guide.</p>
</li>
<li><p>Claim an issue.</p>
</li>
<li><p>Following the Contributing Guide, make a fork, write the code, and open a PR.</p>
</li>
<li><p>The maintainer merges it.</p>
</li>
<li><p>You did it! That’s OSS.</p>
</li>
</ul>
<h3 id="heading-the-dark-side-of-oss">The Dark Side of OSS</h3>
<p>Over time, I couldn’t help but see the “dark side” of OSS – maintainers <a href="https://github.com/zloirock/core-js/blob/master/docs/2023-02-14-so-whats-next.md">burning out</a>, <a href="https://github.com/tailwindlabs/tailwindcss.com/pull/2388#issuecomment-3717222957">friction between users and maintainers</a>, corporations suddenly trying to assert control over OSS (for example, <a href="https://www.cmswire.com/digital-experience/whats-with-the-open-source-drama-between-wordpress-and-wp-engine/">Wordpress</a>, <a href="https://dev.to/cseeman/what-just-happened-to-rubygems-31n9">Ruby</a>), and the thankless, frustrating job of maintaining a package that everyone uses but no one wants to pay for.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771191134959/871a6a8d-85ea-402a-950e-ec25d4738859.png" alt="A large structure made out of building blocks labelled All Modern Digital Infrastructure. One tiny, integral block is labelled A project some random person in Nebraska has been thanklessly maintaining since 2003" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>I have to be honest: I had begun to think of open source maintainers as <a href="https://www.youtube.com/watch?v=mm8R3u_b0yU">Roz from Monsters Inc.</a> – justifiably fed up with the extra work dumped on them by unappreciative people.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770053555027/4f38e415-3100-4737-af1c-947725c60b23.png" alt="A slug person wearing a cardigan, holding a pencil and clipboard with the Monsters Inc. logo. She's wearing glasses and lipstick. Her grey hair is styled straight up, she has a mole on her bottom lip. She currently looks disgusted." style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Meeting maintainers in-person didn’t contradict my view. Every single one had a story about <a href="https://medium.com/@sohail_saifii/the-open-source-maintainer-burnout-crisis-nobodys-fixing-5cf4b459a72b">burnout and lack of funding</a>. I started to assume that anyone excited about OSS just hadn’t been in it long enough</p>
<p>…so my friends were quite surprised when I suddenly announced that I had joined the OSS project <a href="https://npmx.dev/">npmx</a>.</p>
<h2 id="heading-getting-started-with-npmx">Getting Started with npmx</h2>
<p>It wasn’t the first mention of the npmx project that interested me. It wasn’t the second. It was a <a href="https://bsky.app/profile/erus.dev/post/3mdicpnmijk2o">meme</a>. I’ve known <a href="https://roe.dev/">Daniel Roe</a> long enough to know that he is brilliant. I like learning from people who are smarter than I am.</p>
<p>I reached out to <a href="https://bsky.app/profile/patak.dev">Patak</a>, and got an invite to the <a href="https://chat.npmx.dev/">npmx Discord server</a>. I was amazed by what I saw: a rapidly growing, excited, and inclusive community. I realized that I had only ever contributed to communities with at most a handful of people. My view of OSS immediately changed.</p>
<p>This was it. I was finally going to have fun doing PRs.</p>
<p>So I hopped into the <a href="https://github.com/npmx-dev/npmx.dev">npmx GitHub repository</a> and tried to get my bearings. Very quickly, I was overwhelmed. The project moves <em>so fast.</em> I tried to do step 3 – claim a ticket. As far as I could tell, all the tickets were being claimed in Discord before or as they were being written.</p>
<p><a href="https://bsky.app/profile/jonathanyeong.com">Jono</a> kindly welcomed me into his fork for working on the blog page, but I ran into frustrating and weird issues with running the repository (repo) locally and the pre-commit hooks. Multiple people tried to help me debug and were just as stumped as I was.</p>
<p>The next day, <a href="https://bsky.app/profile/whitep4nth3r.com">Salma</a> arrived. The day after, she was in charge of outreach, and asked me to write a blog. Then life got in the way. I couldn’t keep my promise to <a href="https://www.software.com/devops-guides/context-switching">context switch</a> into a feature branch in a new repo. I felt like my only contribution was going to be a single line change on the blog page and a blog.</p>
<p>It didn’t help that I wasn’t happy with the blog I had started writing. I gave up on keeping up and lurked in the Discord channels. I chimed in on a few conversations, and offered to help with things like failing accessibility tests.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771190012891/ac34a318-46f7-45d8-90c3-10837627ad17.png" alt="check @AbbeyPerini's reaction here, if we manage to set an example on how good an app can be with good #a11y, great #perf, and a good #test story, listening to the #e18e folks on keeping deps clean, the npmx repo will be a great learning resource for folks learning how to build websites Salma If anything I made it MORE accessible with a this react Abbey Perini let me run it locally and see if I can spot something with 3 purple heart reacts God it's nice to look at a repo where a11y wasn't an afterthought 6 100 reacts" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Four days later, the project was officially two weeks old. The maintainers announced a mandatory week of vacation – community members experienced with burnout had seen the writing on the wall. Vacation would start in 10 days, so that’s basically how long I had to get a contribution in before the alpha release.</p>
<h2 id="heading-the-not-so-perfect-pr">The Not So Perfect PR</h2>
<p>An hour later, I finally saw it – my chance to contribute code. <a href="https://bsky.app/profile/alexdln.com">Alex</a> needed <a href="https://github.com/npmx-dev/npmx.dev/issues/1028">a toggle re-written as a checkbox</a>. It was my time to shine. I commented on the ticket to claim it as soon as it was written. I slapped up a draft PR to show I was working on it. Predictably, my focus was once again pulled away from the repo.</p>
<p>A couple days later, <a href="https://bsky.app/profile/knowler.dev">Knowler</a> reviewed my draft PR, and all my PR anxieties came tumbling back. This was going to be The Perfect PR. How dare anyone look at it before I was ready to defend my work. What would they think about my abilities looking at my old copy and pasted portfolio site code that I hadn’t even finished translating from <a href="https://react.dev/">React</a> to <a href="https://vuejs.org/">Vue</a>? I was legitimately embarrassed someone was looking at my code in that state.</p>
<p>Fueled by embarrassment and productive procrastination, I sprung into action. In what little free time I had, I must have toggled my toggle a thousand times. Three days later, it was finally in a state I was happy with. It was time to open up my PR for review.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771263500393/64bc78f5-dd9c-48b7-805b-fcba0456753a.png" alt=" Mona-Lisa Saperstein, played by Jenny Slate, hand outstretched, saying &quot;money please,&quot; but the meme is captioned &quot;review please&quot;" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>A couple dozen comments came in. Overwhelmed, I tried to remember that I had asked for this. I resolved most of the comments and left a comment saying I’d get to the last item, <a href="https://polypane.app/blog/forced-colors-explained-a-practical-guide/">forced colors mode</a>, in the morning. Frustrated with the code for the forced colors and myself for forgetting a few tiny things, I went to play games with friends.</p>
<p>A few hours later, I got a DM from Daniel. He had some code for my PR. I agreed with his reasoning for all the changes and found out an entire tooltip had been added while I was blissfully ignoring the rest of the repo. (I’m confident in my ability to merge or rebase my way out of any situation.)</p>
<p>Splitting my attention between <a href="https://store.steampowered.com/app/1203620/Enshrouded/">Enshrouded</a> and talking to Daniel, I felt defeated. I knew I finish the forced colors fix the next day, but also adding a tooltip felt daunting. Still, it felt like I needed to do it all.</p>
<h2 id="heading-collaboration-over-perfection">Collaboration Over Perfection</h2>
<p>And then I remembered, this wasn’t work and it wasn’t going to come up on a performance review. I wasn’t alone – Knowler and Daniel were taking the time to help me get this PR merged because they wanted to. I had the opportunity to collaborate with some brilliant people and see how they would write the same thing.</p>
<p>So I pushed through my perfectionism, demanded compliments, and asked Daniel to push his changes. I told him I’d review them in the morning.</p>
<p>Reviewing Daniel’s code, I found that he had forgotten a couple tiny things, just like I had. The code I was frustrated with the night before was legitimately frustrating. <a href="https://cssence.com/2024/forced-colors-mode-strategies/">Emulating forced colors on a Mac</a> was giving me weird and contradictory results. I needed to test on a Windows machine to finally get it right.</p>
<p>Then, six days after I opened the PR, I finally merged it. I was on top of the world. I had gotten my contribution in before our vacation (and more importantly, I had received multiple compliments). Finally, I knew what to write this blog about.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771191470445/caeb7ab5-d54b-4dd9-907c-a95a85e650b1.png" alt="Abbey Perini Bluesky Elder I'd like to thank @knowler.dev and @danielroe.dev and my confidence in my git skills because this is the fastest moving repo I've ever been in. Quoted post - npmx @npmx.dev @abbeyperini.dev at chat.npmx.dev#contributing. A screenshot of the npmx Discord server. The npmx APP posted @Abbey Perini (abbeyperini) is now a contributor! Abbey Perini NERD responds with a gif of Jim Carrey as the Mask giving an acceptance speech and saying Thank You! with 6 raised hands reacts, 2 trophy reacts, and 2 clapping hands reacts 4:10 PM Feb 11, 2026" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h2 id="heading-my-current-view-of-oss">My Current View of OSS</h2>
<p>When you’re looking for a project that interests you, the code isn’t the only thing to evaluate. Early in my career, I learned three rules for evaluating software tools.</p>
<ol>
<li><p>Check the date of the last update to make sure it’s actively maintained.</p>
</li>
<li><p>Look at the documentation. Is it up to date and easy to follow?</p>
</li>
<li><p>Check out the community. Do people get fairly quick responses to their questions?</p>
</li>
</ol>
<p>After joining npmx, I’ve discovered that, with a few tweaks, these rules also apply to evaluating an OSS project.</p>
<ol>
<li><p>Check out the last few tickets and PRs to see how fast the repo moves. If it’s fairly slow, you can probably claim an issue in GitHub easily. If it’s rapid, start by getting to know the community and how they’re assigning tickets.</p>
</li>
<li><p>You should always check the repo for a code of conduct, contributing guide, and sufficient documentation. Also evaluate the tickets. Are contributors expected to research solutions on their own or given strict requirements? How do maintainers respond to comments on issues?</p>
</li>
<li><p>Check out the community. An active, inclusive community makes contributing a lot more fun.</p>
</li>
</ol>
<p>Now, my view of OSS is much more nuanced. Yes, there are issues with OSS as whole, but there’s a reason people want to fix them. OSS can be collaborative, inspirational, and enjoyable.</p>
<h2 id="heading-tips-for-pr-authors-and-reviewers">Tips for PR Authors and Reviewers</h2>
<p>People underestimate the importance of the relationship between PR author and reviewer. A collaborative OSS code review process doesn’t happen in a vacuum. It takes careful cultivation by the PR author, PR reviewer, and project community.</p>
<p>For a long time, I focused on the responsibility of the reviewer to make the PR author comfortable (for example, compliments, gifs). Don’t get me wrong – I think one of the most important parts of a senior developer’s job is to provide constructive, actionable feedback.</p>
<p>But I now understand that the PR author’s sense of agency and desire to learn are just as important.</p>
<p>A sense of agency is a sense of control over actions and consequences. In other words, the PR author needs to feel that they have control over what goes into their PR. Before npmx, I understood this a little bit. I always ask “why?” because I’m not putting my name on code that I don’t understand and agree with. I have counseled my own junior developer that it’s his job to get PRs he’s authored reviewed and merged.</p>
<p>After experiencing an in-depth code review outside of work, I finally understand that a PR is a process. Reviews exist to get consensus, so “perfect” is far more subjective than I originally thought. There’s a reason you get a conversation, not a grade.</p>
<p>Maybe I’ll even ignore some nitpicks in the future.</p>
<p>A desire to learn makes remaining open to a reviewer’s suggestions and requests a lot easier. During my first npmx PR, it was only when my desire to learn outweighed my desire to prove something that I started having fun.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Today, March 3rd, 2026, is <a href="https://npmx.dev/blog/alpha-release">the alpha release of npmx</a>, and I am very proud to be a contributor and member of the community.</p>
<p>I look forward to learning about OSS from Patak, fancy, smart code from Daniel, outreach from Salma, and accessibility from Knowler. I know I’ll learn many things outside of that list, too. I’m grateful I’m not the smartest person in the room and that I finally get to have fun with Pull Requests.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Production-Grade Distributed Chatroom in Go [Full Handbook] ]]>
                </title>
                <description>
                    <![CDATA[ If you've ever wondered how chat applications like Slack, Discord, or WhatsApp work behind the scenes, this tutorial will show you. You'll build a real-time chat server from scratch using Go, learning the fundamental concepts that power modern commun... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-production-grade-distributed-chatroom-in-go-full-handbook/</link>
                <guid isPermaLink="false">698f4ea5c4c4900d2483651c</guid>
                
                    <category>
                        <![CDATA[ distributed system ]]>
                    </category>
                
                    <category>
                        <![CDATA[ golang ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Destiny Erhabor ]]>
                </dc:creator>
                <pubDate>Fri, 13 Feb 2026 16:17:41 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770999686180/3bccee22-e7e9-477f-8a5f-50800896e972.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you've ever wondered how chat applications like Slack, Discord, or WhatsApp work behind the scenes, this tutorial will show you. You'll build a real-time chat server from scratch using Go, learning the fundamental concepts that power modern communication systems.</p>
<p>By the end of this guide, you'll have built a working chatroom that supports unlimited concurrent users chatting in real-time, message persistence that survives server crashes, session management so users can reconnect after network interruptions, private messaging between users, and graceful handling of slow or disconnected clients.</p>
<p>More importantly, you'll understand the fundamental concepts behind distributed systems. You'll learn concurrent programming with goroutines and channels, TCP socket programming for network communication, write-ahead logging for data durability, state management with mutexes, and how to design systems that degrade gracefully under failure. These concepts power everything from databases to message queues to web servers.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-a-distributed-chatroom">What is a Distributed Chatroom</a>?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-youll-learn">What You'll Learn</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tutorial-overview">Tutorial Overview</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-architecture-overview">Architecture Overview</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-core-concepts-you-need-to-know">Core Concepts You Need to Know</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-the-project-structure">How to Set Up the Project Structure</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-define-core-data-types">How to Define Core Data Types</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-initialize-the-server">How to Initialize the Server</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-event-loop">How to Build the Event Loop</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-handle-client-connections">How to Handle Client Connections</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-message-broadcasting">How to Implement Message Broadcasting</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-persistence-with-wal-and-snapshots">How to Add Persistence with WAL and Snapshots</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-session-management">How to Implement Session Management</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-command-system">How to Build the Command System</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-the-client">How to Create the Client</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-your-chatroom">How to Test Your Chatroom</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-deploy-your-server">How to Deploy Your Server</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-enhancements-you-can-add">Enhancements You Can Add</a></p>
</li>
<li><p><a target="_blank" href="https://hashnode.com/draft/696aa5b42b74f2bf9668a223#heading-enhancement-you-could-add">Conclusion</a></p>
</li>
</ol>
<p>The complete source code for this project is available on <a target="_blank" href="https://github.com/Caesarsage/distributed-system/tree/main/chatroom-with-broadcast">GitHub</a> if you'd like to reference it while following along.</p>
<h2 id="heading-what-is-a-distributed-chatroom">What is a Distributed Chatroom?</h2>
<p>A chatroom is a server that lets multiple users connect simultaneously and exchange messages in real-time. When we say "production-grade," we mean it includes features you'd expect in a real application: it persists data so messages aren't lost when the server restarts, it handles network failures gracefully, and it can support many concurrent users without slowing down.</p>
<p>The "distributed" aspect refers to how the system manages multiple clients connecting from different locations, all trying to send and receive messages at the same time. This introduces interesting challenges: how do you ensure everyone sees messages in the same order? How do you handle clients with slow internet connections? What happens when someone disconnects unexpectedly?</p>
<p>These aren't just theoretical problems. Every networked application deals with concurrency, state management, and failure handling. Whether you're building a chat app, a multiplayer game, a collaborative editor, or a trading platform, you'll face similar challenges. The patterns you'll learn here apply broadly across distributed systems.</p>
<p>Chat applications are excellent learning projects because they combine several challenging problems in one place. You need to manage concurrent connections safely, broadcast messages to multiple clients without blocking, handle unreliable networks, persist data durably, and ensure the system recovers gracefully from crashes. Each of these topics could be its own tutorial, but here you'll see how they work together in a real application.</p>
<h2 id="heading-what-youll-learn">What You'll Learn</h2>
<p>This tutorial demonstrates several important concepts that are fundamental to building distributed systems. Here's what you'll learn:</p>
<h3 id="heading-1-tcp-socket-programming-in-go">1. TCP Socket Programming in Go</h3>
<p>You'll learn how to accept incoming TCP connections, read and write data over network sockets, and handle connection failures gracefully. These skills are essential for any networked application, from web servers to database clients.</p>
<h3 id="heading-2-concurrent-programming-with-goroutines-and-channels">2. Concurrent Programming with Goroutines and Channels</h3>
<p>Go's concurrency model is one of its strongest features. You'll see how to use goroutines to handle multiple clients simultaneously without blocking. You'll use channels to coordinate between goroutines safely, avoiding the common pitfalls of shared memory concurrency like race conditions and deadlocks.</p>
<h3 id="heading-3-state-management-in-distributed-systems">3. State Management in Distributed Systems</h3>
<p>Managing shared state across concurrent operations is tricky. You'll learn when to use mutexes versus channels, how to design lock granularity to avoid bottlenecks, and how to ensure data consistency when multiple goroutines access the same data.</p>
<h3 id="heading-4-write-ahead-logging-wal-for-durability">4. Write-Ahead Logging (WAL) for Durability</h3>
<p>Databases use WAL to ensure data isn't lost during crashes. You'll implement the same pattern, learning how to balance durability with performance. You'll see why fsync is critical, understand the trade-offs of different persistence strategies, and learn how to recover state after unexpected shutdowns.</p>
<h3 id="heading-5-session-management-and-reconnection">5. Session Management and Reconnection</h3>
<p>Networks are unreliable. Users disconnect, WiFi drops, mobile connections switch towers. You'll build a token-based session system that lets users reconnect seamlessly, preserving their chat history and identity without requiring passwords or complex authentication.</p>
<h3 id="heading-6-graceful-degradation-and-fault-tolerance">6. Graceful Degradation and Fault Tolerance</h3>
<p>Perfect reliability is impossible, so you need to design for partial failures. You'll learn how to prevent slow clients from affecting fast ones, how to continue operating when persistence fails, and how to clean up resources properly when things go wrong.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To get the most out of this tutorial, you should have some foundational knowledge. You don't need to be an expert, but you should be comfortable with the basics.</p>
<ul>
<li><p>Go basics (goroutines, channels, interfaces)</p>
</li>
<li><p>TCP/IP networking fundamentals</p>
</li>
<li><p>Basic concurrency concepts</p>
</li>
<li><p>File I/O operations</p>
</li>
</ul>
<h2 id="heading-tutorial-overview">Tutorial Overview</h2>
<p>This tutorial takes you through building a production-ready chatroom step by step.</p>
<p>You'll start by exploring the overall architecture to understand how components fit together. Then you'll learn about core concepts like concurrency models and persistence strategies.</p>
<p>Next, you'll set up your project structure and define the core data types that represent clients, messages, and the chatroom. Then you'll implement the server initialization and event loop, which is where all coordination happens.</p>
<p>After that, you'll build the networking layer to handle client connections, implement message broadcasting so messages reach all users, and add persistence using write-ahead logging and snapshots.</p>
<p>You'll then implement session management for reconnection, build a command system for user actions, and create a simple client application to test your server.</p>
<p>Finally, you’ll learn how to test and deploy your chatroom, and review key lessons from building a distributed system.</p>
<p>By the end, you'll have a complete, working chatroom and understand how distributed systems handle concurrency, persistence, and failure recovery.</p>
<h2 id="heading-architecture-overview">Architecture Overview</h2>
<p>The system follows a client-server architecture with internal components that work together to provide a robust chat experience.</p>
<h3 id="heading-high-level-architecture">High-Level Architecture</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770347113467/2ca609e9-c902-4311-a571-e9c3b1280786.jpeg" alt="Chatroom broadcast architecture diagram" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-component-breakdown">Component Breakdown</h3>
<h4 id="heading-1-network-layer">1. <strong>Network Layer</strong></h4>
<ul>
<li><p><strong>TCP Listener</strong>: Accepts incoming connections on port 9000</p>
</li>
<li><p><strong>Connection Handler</strong>: Manages individual client connections with dedicated goroutines</p>
</li>
<li><p><strong>Protocol</strong>: Simple newline-delimited text protocol</p>
</li>
</ul>
<h4 id="heading-2-client-management">2. <strong>Client Management</strong></h4>
<p>Each client connection spawns two goroutines:</p>
<ul>
<li><p><strong>Read Goroutine</strong>: Receives messages from client</p>
</li>
<li><p><strong>Write Goroutine</strong>: Sends messages to client (non-blocking with buffered channels)</p>
</li>
</ul>
<h4 id="heading-3-chatroom-core">3. <strong>ChatRoom Core</strong></h4>
<p>This is the heart of the system – a single goroutine running an event loop:</p>
<pre><code class="lang-go"><span class="hljs-keyword">for</span> {
    <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> client := &lt;-cr.join:
            <span class="hljs-comment">// Handle new client</span>
        <span class="hljs-keyword">case</span> client := &lt;-cr.leave:
            <span class="hljs-comment">// Handle disconnection</span>
        <span class="hljs-keyword">case</span> message := &lt;-cr.broadcast:
            <span class="hljs-comment">// Broadcast to all clients</span>
        <span class="hljs-keyword">case</span> client := &lt;-cr.listUsers:
            <span class="hljs-comment">// Send user list</span>
        <span class="hljs-keyword">case</span> dm := &lt;-cr.directMessage:
            <span class="hljs-comment">// Handle private message</span>
    }
}
</code></pre>
<h4 id="heading-4-state-management">4. <strong>State Management</strong></h4>
<p>We have three synchronized data structures:</p>
<ul>
<li><p><code>clients map[*Client]bool</code>: Active connections (mutex-protected)</p>
</li>
<li><p><code>sessions map[string]*SessionInfo</code>: User sessions for reconnection</p>
</li>
<li><p><code>messages []Message</code>: In-memory message history</p>
</li>
</ul>
<h4 id="heading-5-persistence-layer">5. <strong>Persistence Layer</strong></h4>
<p>Two-tier approach:</p>
<ul>
<li><p><strong>Write-Ahead Log (WAL)</strong>: Immediate append-only log for durability</p>
</li>
<li><p><strong>Snapshots</strong>: Periodic full state dumps for faster recovery</p>
</li>
</ul>
<h4 id="heading-6-session-management">6. <strong>Session Management</strong></h4>
<p>This enables reconnection with token-based authentication:</p>
<ul>
<li><p>Generates unique tokens per user</p>
</li>
<li><p>1-hour session timeout</p>
</li>
<li><p>Preserves chat history for returning users</p>
</li>
</ul>
<h3 id="heading-message-flow">Message Flow</h3>
<p>Here's how a message travels through the system:</p>
<pre><code class="lang-bash">User Input → Client Read → Server Receive → Broadcast Channel 
    → ChatRoom Loop → Persist to WAL → Fan-out to All Clients
    → Client Write Goroutines → TCP Send → User Display
</code></pre>
<p>The broadcast channel acts as a synchronization point, ensuring total message ordering.</p>
<h2 id="heading-core-concepts-you-need-to-know">Core Concepts You Need to Know</h2>
<h3 id="heading-understanding-the-concurrency-model">Understanding the Concurrency Model</h3>
<p>This chatroom uses Go's CSP (Communicating Sequential Processes) model. This is a fundamentally different approach to concurrency than you might be used to from other languages.</p>
<p>In traditional concurrent programming, you protect shared memory with locks (mutexes). Multiple threads access the same data structure, and you use locks to ensure only one thread modifies it at a time. This works, but it's error-prone. Forget a lock, and you have a race condition. Hold locks too long, and you have deadlocks.</p>
<p>Go encourages a different approach: instead of communicating by sharing memory, you share memory by communicating. You pass data between goroutines through channels. Only one goroutine owns the data at a time, eliminating many concurrency bugs by design.</p>
<p>Channels provide several advantages. They eliminate most race conditions by design, because if only one goroutine owns the data at a time, there's no race to access it. They provide natural flow control since channels can block when full (back pressure) or block when empty (waiting for data). They make it easier to reason about message flow because you can trace how data moves through your system by following the channels. And they offer better composability since you can combine channels with select statements to coordinate multiple operations.</p>
<p>That said, we’ll still use mutexes in this project. Channels aren't always the right tool. We’ll use mutexes when multiple goroutines need quick, frequent access to shared data structures like maps. And we’ll use channels when we want to coordinate behavior or transfer ownership of data.</p>
<p>Here's how the chatroom uses channels to coordinate everything:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> ChatRoom <span class="hljs-keyword">struct</span> {
    join          <span class="hljs-keyword">chan</span> *Client        <span class="hljs-comment">// New connections</span>
    leave         <span class="hljs-keyword">chan</span> *Client        <span class="hljs-comment">// Disconnections</span>
    broadcast     <span class="hljs-keyword">chan</span> <span class="hljs-keyword">string</span>         <span class="hljs-comment">// Messages to all</span>
    listUsers     <span class="hljs-keyword">chan</span> *Client        <span class="hljs-comment">// User list requests</span>
    directMessage <span class="hljs-keyword">chan</span> DirectMessage  <span class="hljs-comment">// Private messages</span>

    <span class="hljs-comment">// Shared state (mutex-protected)</span>
    clients    <span class="hljs-keyword">map</span>[*Client]<span class="hljs-keyword">bool</span>
    mu         sync.Mutex

    <span class="hljs-comment">// Message history (separate mutex)</span>
    messages   []Message
    messageMu  sync.Mutex
}
</code></pre>
<p>Notice that we have five channels for different types of events. The main event loop receives from all these channels using a select statement. This means all state changes happen sequentially in one place, making the system much easier to reason about.</p>
<p>We could have used one channel that accepts different message types, but separate channels make the code clearer. When you send to <code>chatRoom.join</code>, it's obvious what you're doing. When you send to <code>chatRoom.broadcast</code>, same thing.</p>
<p>The mutexes protect data that many goroutines read frequently. The <code>clients</code> map needs to be accessed every time we broadcast a message. Using a mutex for quick read access is more efficient than passing the entire map through a channel.</p>
<h3 id="heading-understanding-the-persistence-strategy">Understanding the Persistence Strategy</h3>
<p>When your server crashes (and it will eventually), you need to recover the chat history. Users expect their messages to be there when the server restarts. But persistence is expensive: writing to disk is thousands of times slower than writing to memory. So you need a strategy that balances durability with performance.</p>
<p>We’ll use a two-tier approach that's similar to what real databases use: WAL (Write-ahead log) and snapshots.</p>
<p>The WAL is your primary durability mechanism. Here's how it works: every message is immediately appended to a file called <code>messages.wal</code>. This file is append-only, which means we only write to the end. Append-only writes are fast because the disk doesn't need to seek to different locations.</p>
<p>Each message is written as a single line of JSON. After writing each message, we call <code>fsync</code>. This tells the operating system to actually write the data to the physical disk right now, not just buffer it in memory. Without fsync, the OS might lose your data if the power fails before it gets around to writing.</p>
<p>The WAL is append-only and never modified. This makes it very reliable. If the server crashes mid-write, the worst case is one corrupted line at the end, which we can detect and skip during recovery.</p>
<p>The problem with a write-ahead log is that it grows forever. If you have a million messages, you need to replay a million log entries every time you restart the server. That's slow.</p>
<p>Snapshots solve this problem. Every 5 minutes, if there are more than 100 new messages, we write the entire message history to a separate file called <code>snapshot.json</code>. This is the complete state of the chat at that moment.</p>
<p>After creating a snapshot, we truncate (empty) the WAL. New messages continue to append to the WAL, but now we only need to replay messages since the last snapshot.</p>
<p>When the server starts, it first loads the snapshot file (if it exists). This gives us the state from the last snapshot, which might be 100,000 messages. Loading this takes about 100ms. Then it replays all entries from the WAL. This gives us messages written since the last snapshot, which might be only 50 messages. Replaying this takes milliseconds. Finally, it resumes normal operation.</p>
<p>Total recovery time is a few hundred milliseconds instead of several minutes.</p>
<p>This two-tier system gives us the best of both worlds: fast writes during normal operation with the append-only WAL, fast recovery after crashes with snapshot plus small WAL replay, guaranteed durability through fsync after every message, and bounded recovery time because the WAL never grows too large.</p>
<p>The trade-off is that snapshots use more disk space temporarily since you have both the snapshot and the WAL. But disk space is cheap, and correctness is expensive.</p>
<p>Now that you understand the key concepts behind the chatroom's design, it's time to start building. You'll begin by setting up your project structure and creating the necessary directories and files.</p>
<h2 id="heading-how-to-set-up-the-project-structure">How to Set Up the Project Structure</h2>
<p>First, create the directory structure for your project. You will create their files as we walk through the tutorial:</p>
<pre><code class="lang-bash">mkdir -p chatroom-with-broadcast/cmd/server
mkdir -p chatroom-with-broadcast/cmd/client
mkdir -p chatroom-with-broadcast/internal/chatroom
mkdir -p chatroom-with-broadcast/pkg/token
mkdir -p chatroom-with-broadcast/chatdata
<span class="hljs-built_in">cd</span> chatroom-with-broadcast
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770347289299/82f067a8-2cd0-49f0-8338-a002846e618b.png" alt="Chatroom project structure" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Then initialize the Go module.</p>
<p>Note that you’ll need Go 1.23.2 or later installed on your machine. Earlier versions might work, but the code examples assume features available in Go 1.23 and above. This version includes improvements to the standard library that make concurrent programming more efficient.</p>
<pre><code class="lang-bash">go mod init github.com/yourusername/chatroom
</code></pre>
<p>Your <code>go.mod</code> file should look like this:</p>
<pre><code class="lang-go">module github.com/yourusername/chatroom

<span class="hljs-keyword">go</span> <span class="hljs-number">1.23</span><span class="hljs-number">.2</span>
</code></pre>
<p>With your project structure in place, you're ready to start writing code. The first step is defining the data types that will represent the core components of your chatroom: messages, clients, and the chatroom itself.</p>
<h2 id="heading-how-to-define-core-data-types">How to Define Core Data Types</h2>
<p>Create a new file <code>internal/chatroom/types.go</code> to define your core data structures. These types form the foundation of your chatroom, so it's important to understand what each one represents and why it's designed the way it is.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> chatroom

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"net"</span>
    <span class="hljs-string">"os"</span>
    <span class="hljs-string">"sync"</span>
    <span class="hljs-string">"time"</span>
)

<span class="hljs-comment">// Message represents a single chat message with metadata</span>
<span class="hljs-keyword">type</span> Message <span class="hljs-keyword">struct</span> {
    ID        <span class="hljs-keyword">int</span>       <span class="hljs-string">`json:"id"`</span>
    From      <span class="hljs-keyword">string</span>    <span class="hljs-string">`json:"from"`</span>
    Content   <span class="hljs-keyword">string</span>    <span class="hljs-string">`json:"content"`</span>
    Timestamp time.Time <span class="hljs-string">`json:"timestamp"`</span>
    Channel   <span class="hljs-keyword">string</span>    <span class="hljs-string">`json:"channel"`</span> <span class="hljs-comment">// "global" or "private:username"</span>
}

<span class="hljs-comment">// Client represents a connected user</span>
<span class="hljs-keyword">type</span> Client <span class="hljs-keyword">struct</span> {
    conn         net.Conn      <span class="hljs-comment">// TCP connection</span>
    username     <span class="hljs-keyword">string</span>        <span class="hljs-comment">// Display name</span>
    outgoing     <span class="hljs-keyword">chan</span> <span class="hljs-keyword">string</span>   <span class="hljs-comment">// Buffered channel for writes</span>
    lastActive   time.Time     <span class="hljs-comment">// For idle detection</span>
    messagesSent <span class="hljs-keyword">int</span>           <span class="hljs-comment">// Statistics</span>
    messagesRecv <span class="hljs-keyword">int</span>
    isSlowClient <span class="hljs-keyword">bool</span>          <span class="hljs-comment">// Testing flag</span>

    reconnectToken <span class="hljs-keyword">string</span>
    mu             sync.Mutex   <span class="hljs-comment">// Protects stats fields</span>
}

<span class="hljs-comment">// ChatRoom is the central coordinator</span>
<span class="hljs-keyword">type</span> ChatRoom <span class="hljs-keyword">struct</span> {
    <span class="hljs-comment">// Communication channels</span>
    join          <span class="hljs-keyword">chan</span> *Client
    leave         <span class="hljs-keyword">chan</span> *Client
    broadcast     <span class="hljs-keyword">chan</span> <span class="hljs-keyword">string</span>
    listUsers     <span class="hljs-keyword">chan</span> *Client
    directMessage <span class="hljs-keyword">chan</span> DirectMessage

    <span class="hljs-comment">// State</span>
    clients       <span class="hljs-keyword">map</span>[*Client]<span class="hljs-keyword">bool</span>
    mu            sync.Mutex
    totalMessages <span class="hljs-keyword">int</span>
    startTime     time.Time

    <span class="hljs-comment">// Message history</span>
    messages      []Message
    messageMu     sync.Mutex
    nextMessageID <span class="hljs-keyword">int</span>

    <span class="hljs-comment">// Persistence</span>
    walFile       *os.File
    walMu         sync.Mutex
    dataDir       <span class="hljs-keyword">string</span>

    <span class="hljs-comment">// Sessions</span>
    sessions      <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]*SessionInfo
    sessionsMu    sync.Mutex
}

<span class="hljs-comment">// SessionInfo tracks reconnection data</span>
<span class="hljs-keyword">type</span> SessionInfo <span class="hljs-keyword">struct</span> {
    Username       <span class="hljs-keyword">string</span>
    ReconnectToken <span class="hljs-keyword">string</span>
    LastSeen       time.Time
    CreatedAt      time.Time
}

<span class="hljs-comment">// DirectMessage represents a private message</span>
<span class="hljs-keyword">type</span> DirectMessage <span class="hljs-keyword">struct</span> {
    toClient *Client
    message  <span class="hljs-keyword">string</span>
}
</code></pre>
<h4 id="heading-understanding-the-message-type">Understanding the Message Type</h4>
<p>The <code>Message</code> struct stores everything we need to know about a chat message. The <code>ID</code> field uniquely identifies each message and ensures messages stay in order. The <code>Timestamp</code> lets us show when messages were sent, which is important for chat history.</p>
<p>The <code>Channel</code> field is interesting. Right now, we only use "global" for public messages, but this design lets us add private channels or chat rooms later without changing the data structure. Good data structures anticipate future needs.</p>
<h4 id="heading-understanding-the-client-type">Understanding the Client Type</h4>
<p>Each connected user is represented by a <code>Client</code> struct. The <code>conn</code> field is their TCP connection – this is how we send and receive data.</p>
<p>The <code>outgoing</code> channel is crucial for performance. Notice it's a <code>chan string</code>, which means it's a channel of strings. We'll make this a buffered channel (size 10). This buffer means we can queue up 10 messages for this client without blocking. If a client is slow to read, we can keep sending to other clients.</p>
<p>Without this buffer, one slow client would block the entire broadcast. With the buffer, slow clients just miss messages if they can't keep up, which is much better than slowing everyone down.</p>
<p>The <code>lastActive</code> timestamp helps us detect idle users. If someone hasn't sent a message in 5 minutes, we can disconnect them to free up resources.</p>
<p>The <code>mu</code> mutex protects the statistics fields. Multiple goroutines will update <code>messagesSent</code> and <code>messagesRecv</code>, so we need a mutex to prevent race conditions.</p>
<h4 id="heading-understanding-the-chatroom-type">Understanding the ChatRoom Type</h4>
<p>This is the heart of the system. Notice that we have two kinds of fields: channels and protected state.</p>
<p>The five channels (<code>join</code>, <code>leave</code>, <code>broadcast</code>, <code>listUsers</code>, <code>directMessage</code>) are how different parts of the system communicate with the main event loop. When a new client connects, we send them to the <code>join</code> channel. When someone sends a message, it goes to the <code>broadcast</code> channel.</p>
<p>These channels are unbuffered (capacity 0) because we want synchronization. When you send to an unbuffered channel, you block until someone receives. This ensures the event loop processes events in order.</p>
<p>The protected state (maps and slices) needs mutexes because multiple goroutines access it. Notice that we use separate mutexes for different data. The <code>mu</code> mutex protects the <code>clients</code> map. The <code>messageMu</code> mutex protects the <code>messages</code> slice. The <code>sessionsMu</code> mutex protects the <code>sessions</code> map.</p>
<p>Why separate mutexes? Performance. If we used one mutex for everything, broadcasting a message would lock all the data, preventing new clients from joining. Separate mutexes mean different operations can happen concurrently.</p>
<p>The WAL file (<code>walFile</code>) also has its own mutex (<code>walMu</code>) because writing to disk is slow. We don't want to hold the main mutex while waiting for disk I/O.</p>
<p>With your data types defined, the next step is creating a function to initialize the server. This function will set up all your data structures, restore any persisted state from previous runs, and start background workers.</p>
<h2 id="heading-how-to-initialize-the-server">How to Initialize the Server</h2>
<p>Server initialization is critical because you need to set up all your data structures in the right order. If you restore state after opening the WAL, you might replay messages twice. If you start accepting connections before loading history, users won't see old messages.</p>
<p>Create a file <code>internal/chatroom/run.go</code> to bootstrap the server:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> chatroom

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"net"</span>
    <span class="hljs-string">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewChatRoom</span><span class="hljs-params">(dataDir <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(*ChatRoom, error)</span></span> {
    cr := &amp;ChatRoom{
        clients:       <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[*Client]<span class="hljs-keyword">bool</span>),
        join:          <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> *Client),
        leave:         <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> *Client),
        broadcast:     <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">string</span>),
        listUsers:     <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> *Client),
        directMessage: <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> DirectMessage),
        sessions:      <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]*SessionInfo),
        messages:      <span class="hljs-built_in">make</span>([]Message, <span class="hljs-number">0</span>),
        startTime:     time.Now(),
        dataDir:       dataDir,
    }

    <span class="hljs-comment">// Restore from snapshot if available</span>
    <span class="hljs-keyword">if</span> err := cr.loadSnapshot(); err != <span class="hljs-literal">nil</span> {
        fmt.Printf(<span class="hljs-string">"Failed to load snapshot: %v\n"</span>, err)
    }

    <span class="hljs-comment">// Initialize WAL for new messages</span>
    <span class="hljs-keyword">if</span> err := cr.initializePersistence(); err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, err
    }

    <span class="hljs-comment">// Start background snapshot worker</span>
    <span class="hljs-keyword">go</span> cr.periodicSnapshots()

    <span class="hljs-keyword">return</span> cr, <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">periodicSnapshots</span><span class="hljs-params">()</span></span> {
    ticker := time.NewTicker(<span class="hljs-number">5</span> * time.Minute)
    <span class="hljs-keyword">defer</span> ticker.Stop()

    <span class="hljs-keyword">for</span> <span class="hljs-keyword">range</span> ticker.C {
        cr.messageMu.Lock()
        messageCount := <span class="hljs-built_in">len</span>(cr.messages)
        cr.messageMu.Unlock()

        <span class="hljs-keyword">if</span> messageCount &gt; <span class="hljs-number">100</span> {
            <span class="hljs-keyword">if</span> err := cr.createSnapshot(); err != <span class="hljs-literal">nil</span> {
                fmt.Printf(<span class="hljs-string">"Snapshot failed: %v\n"</span>, err)
            }
        }
    }
}
</code></pre>
<p>Let's break down what happens during initialization:</p>
<h4 id="heading-1-creating-data-structures">1. Creating Data Structures</h4>
<p>We start by creating all the maps and channels. The <code>make</code> function initializes these properly. For maps, this creates an empty map ready to use. For channels, this creates an unbuffered channel (capacity 0).</p>
<p>Notice we create the <code>messages</code> slice with initial capacity 0 but room to grow: <code>make([]Message, 0)</code>. This is more efficient than starting with <code>nil</code> because the slice is ready to append immediately without allocation.</p>
<h4 id="heading-2-loading-the-snapshot">2. Loading the Snapshot</h4>
<p>Before we accept any connections, we try to load a snapshot from disk. This restores the chat history from the last time the server ran. If the snapshot doesn't exist (first run) or fails to load (corrupted file), we just continue with an empty history.</p>
<p>This step must happen before initializing the WAL. If we opened the WAL first, we might replay messages that are already in the snapshot, creating duplicates.</p>
<h4 id="heading-3-initializing-the-wal">3. Initializing the WAL</h4>
<p>The <code>initializePersistence()</code> function opens the WAL file in append mode. It also replays any entries in the WAL that happened after the last snapshot. This ensures we don't lose any messages that were written to the WAL but not yet included in a snapshot.</p>
<p>If this step fails, we return an error and refuse to start. Why? Because if we can't write to the WAL, we can't guarantee durability. It's better to refuse to start than to lie to users by accepting messages we can't persist.</p>
<h4 id="heading-4-starting-background-workers">4. Starting Background Workers</h4>
<p>The <code>periodicSnapshots()</code> function runs in a separate goroutine. It wakes up every 5 minutes and checks if we need to create a snapshot. Notice the <code>defer ticker.Stop()</code> – this is important. If we forget to stop the ticker, it leaks a goroutine and wastes resources.</p>
<p>The goroutine acquires the <code>messageMu</code> lock just to read the message count, then releases it immediately. We don't hold the lock during the snapshot creation because that's slow and would block message broadcasting.</p>
<h4 id="heading-why-5-minutes-and-100-messages">Why 5 Minutes and 100 Messages?</h4>
<p>These are tunable parameters. 5 minutes means recovery never needs to replay more than 5 minutes of messages. 100 messages means we don't create snapshots too frequently during quiet periods.</p>
<p>In a production system, you might make these configurable. A high-traffic chat might want shorter intervals. A low-traffic chat might want longer intervals to reduce disk I/O.</p>
<p>Now that your server is initialized with all the necessary data structures and background workers, you need to build the core coordination mechanism. The event loop is where all state changes happen in your chatroom. It's the heartbeat that keeps everything synchronized.</p>
<h2 id="heading-how-to-build-the-event-loop">How to Build the Event Loop</h2>
<p>The event loop is the heart of your chatroom. Every client connection, message, and disconnection flows through this single point. This might seem like it could be a bottleneck, but it's actually what makes the system simple and safe.</p>
<p>The <code>Run()</code> method is the server's heartbeat. This is where all the magic happens. Every event in the system flows through this loop. Add this to <code>run.go</code>:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">Run</span><span class="hljs-params">()</span></span> {
    fmt.Println(<span class="hljs-string">"ChatRoom heartbeat started..."</span>)
    <span class="hljs-keyword">go</span> cr.cleanupInactiveClients()

    <span class="hljs-keyword">for</span> {
        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> client := &lt;-cr.join:
            cr.handleJoin(client)

        <span class="hljs-keyword">case</span> client := &lt;-cr.leave:
            cr.handleLeave(client)

        <span class="hljs-keyword">case</span> message := &lt;-cr.broadcast:
            cr.handleBroadcast(message)

        <span class="hljs-keyword">case</span> client := &lt;-cr.listUsers:
            cr.sendUserList(client)

        <span class="hljs-keyword">case</span> dm := &lt;-cr.directMessage:
            cr.handleDirectMessage(dm)
        }
    }
}
</code></pre>
<h4 id="heading-understanding-the-select-statement">Understanding the Select Statement</h4>
<p>The <code>select</code> statement is one of Go's most powerful concurrency features. It's like a switch statement for channels. The select waits until one of its cases can proceed, then it executes that case.</p>
<p>Here's what happens: The loop blocks on the select statement, waiting for data on any of the five channels. When data arrives on any channel, that case executes. After the case completes, the loop goes back to waiting.</p>
<p>For example, when a new client connects, code elsewhere in your program sends that client to <code>cr.join</code>. The select receives it and executes <code>cr.handleJoin(client)</code>. Once that finishes, the loop goes back to waiting.</p>
<h4 id="heading-why-use-a-single-event-loop">Why Use a Single Event Loop?</h4>
<p>This might seem like a bottleneck. You have one goroutine processing all events sequentially. Why not process events in parallel?</p>
<p>The answer is consistency. Here's what you gain from sequential processing:</p>
<p><strong>1. No Race Conditions on State</strong></p>
<p>Only one goroutine modifies the <code>clients</code> map, the <code>messages</code> slice, and the <code>sessions</code> map. You never need to worry about two operations interfering with each other. When you add a client in <code>handleJoin</code>, you know for certain that no other code is simultaneously removing clients or broadcasting messages.</p>
<p>This is incredibly powerful. Most bugs in concurrent systems come from unexpected interleaving of operations. By processing events sequentially, you eliminate an entire class of bugs.</p>
<p><strong>2. Total Ordering of Events</strong></p>
<p>Messages are broadcast in the order they arrive. This seems obvious, but it's important. If Alice sends "Hello" and then Bob sends "Hi", you can guarantee everyone sees them in that order. With parallel processing, you'd need additional synchronization to maintain ordering.</p>
<p><strong>3. Simple State Transitions</strong></p>
<p>You can reason about your system state as a series of transitions. "After this join event, the client is in the map. After this leave event, the client is removed." You don't need to worry about concurrent state changes making your reasoning invalid.</p>
<p><strong>4. Easy to Debug</strong></p>
<p>When something goes wrong, you can add logging to the event loop and see exactly what sequence of events led to the problem. With parallel processing, the order of events depends on thread scheduling, making bugs hard to reproduce.</p>
<h4 id="heading-is-this-actually-a-bottleneck">Is This Actually a Bottleneck?</h4>
<p>You might worry that sequential processing limits performance. In practice, it's fine for this workload. Here's why:</p>
<p>The handlers are fast. They do simple things like adding to a map, removing from a map, or forwarding a message to channels. These operations take microseconds. The event loop can process thousands of events per second.</p>
<p>The slow operations (writing to disk, sending to client connections) happen in other goroutines. The event loop doesn't wait for them. It just sends data to a channel or adds work to a queue, then immediately moves to the next event.</p>
<p>If you needed higher throughput, you could shard your chat into multiple rooms, each with its own event loop. But for a single chatroom, sequential processing is both simpler and fast enough.</p>
<h4 id="heading-understanding-the-cleanup-worker">Understanding the Cleanup Worker</h4>
<p>Notice the line <code>go cr.cleanupInactiveClients()</code> before the loop. This starts a background goroutine that periodically checks for idle clients.</p>
<p>Why not include this in the event loop? Because it's time-based, not event-based. The cleanup worker wakes up every 30 seconds and sends disconnect events for idle clients. These events flow through the normal event loop, maintaining our single-threaded state mutation property.</p>
<p>Now add the <code>runServer()</code> function and shutdown handler:</p>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> (
    <span class="hljs-string">"os"</span>
    <span class="hljs-string">"os/signal"</span>
    <span class="hljs-string">"syscall"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">runServer</span><span class="hljs-params">()</span></span> {
    chatRoom, err := NewChatRoom(<span class="hljs-string">"./chatdata"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        fmt.Printf(<span class="hljs-string">"Failed to initialize: %v\n"</span>, err)
        <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">defer</span> chatRoom.shutdown()

    <span class="hljs-comment">// Set up signal handling for graceful shutdown</span>
    sigChan := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> os.Signal, <span class="hljs-number">1</span>)
    signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

    <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        &lt;-sigChan
        fmt.Println(<span class="hljs-string">"\nReceived shutdown signal"</span>)
        chatRoom.shutdown()
        os.Exit(<span class="hljs-number">0</span>)
    }()

    <span class="hljs-keyword">go</span> chatRoom.Run()

    listener, err := net.Listen(<span class="hljs-string">"tcp"</span>, <span class="hljs-string">":9000"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        fmt.Println(<span class="hljs-string">"Error starting server:"</span>, err)
        <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">defer</span> listener.Close()

    fmt.Println(<span class="hljs-string">"Server started on :9000"</span>)

    <span class="hljs-keyword">for</span> {
        conn, err := listener.Accept()
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            fmt.Println(<span class="hljs-string">"Error accepting connection:"</span>, err)
            <span class="hljs-keyword">continue</span>
        }
        fmt.Println(<span class="hljs-string">"New connection from:"</span>, conn.RemoteAddr())
        <span class="hljs-keyword">go</span> handleClient(conn, chatRoom)
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">shutdown</span><span class="hljs-params">()</span></span> {
    fmt.Println(<span class="hljs-string">"\nShutting down..."</span>)
    <span class="hljs-keyword">if</span> err := cr.createSnapshot(); err != <span class="hljs-literal">nil</span> {
        fmt.Printf(<span class="hljs-string">"Final snapshot failed: %v\n"</span>, err)
    }
    <span class="hljs-keyword">if</span> cr.walFile != <span class="hljs-literal">nil</span> {
        cr.walFile.Close()
    }
    fmt.Println(<span class="hljs-string">"Shutdown complete"</span>)
}
</code></pre>
<p>The <code>runServer()</code> function ties everything together:</p>
<ol>
<li><p>Create the chatroom with <code>NewChatRoom()</code></p>
</li>
<li><p>Defer the shutdown function so it runs when the function exits</p>
</li>
<li><p>Start the event loop in a separate goroutine with <code>go chatRoom.Run()</code></p>
</li>
<li><p>Listen for TCP connections on port 9000</p>
</li>
<li><p>For each connection, spawn a goroutine with <code>go handleClient()</code></p>
</li>
</ol>
<p>The defer statement is important. No matter how the function exits (normal return, panic, error), the shutdown function runs. This ensures we create a final snapshot and close the WAL file cleanly.</p>
<p>The signal handling goroutine listens for SIGINT (Ctrl+C) or SIGTERM (system shutdown). When it receives one, it calls <code>shutdown()</code> and exits gracefully. This means when you press Ctrl+C, the server saves its state before stopping.</p>
<p>With your event loop running and listening for connections, the next step is handling what happens when a client actually connects. This involves reading their username, creating a session, and setting up the communication channels.</p>
<h2 id="heading-how-to-handle-client-connections">How to Handle Client Connections</h2>
<p>When a client connects to your server, several things need to happen: you need to establish the TCP connection, prompt for a username, create a Client object to represent them, start goroutines to read and write messages, and handle both normal disconnections and unexpected failures.</p>
<p>Create a file <code>internal/chatroom/io.go</code> for managing client connections. When a client connects, <code>handleClient()</code> manages the entire lifecycle:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> chatroom

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"bufio"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"math/rand"</span>
    <span class="hljs-string">"net"</span>
    <span class="hljs-string">"strings"</span>
    <span class="hljs-string">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">handleClient</span><span class="hljs-params">(conn net.Conn, chatRoom *ChatRoom)</span></span> {
    <span class="hljs-keyword">defer</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">if</span> r := <span class="hljs-built_in">recover</span>(); r != <span class="hljs-literal">nil</span> {
            fmt.Printf(<span class="hljs-string">"Panic in handleClient: %v\n"</span>, r)
        }
        conn.Close()
    }()

    <span class="hljs-comment">// Set initial timeout for username entry</span>
    conn.SetReadDeadline(time.Now().Add(<span class="hljs-number">30</span> * time.Second))

    reader := bufio.NewReader(conn)

    <span class="hljs-comment">// Prompt for username or reconnection</span>
    conn.Write([]<span class="hljs-keyword">byte</span>(<span class="hljs-string">"Enter username (or 'reconnect:&lt;username&gt;:&lt;token&gt;'): \n"</span>))

    input, err := reader.ReadString(<span class="hljs-string">'\n'</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        fmt.Println(<span class="hljs-string">"Failed to read username:"</span>, err)
        <span class="hljs-keyword">return</span>
    }
    input = strings.TrimSpace(input)

    <span class="hljs-keyword">var</span> username <span class="hljs-keyword">string</span>
    <span class="hljs-keyword">var</span> reconnectToken <span class="hljs-keyword">string</span>
    <span class="hljs-keyword">var</span> isReconnecting <span class="hljs-keyword">bool</span>

    <span class="hljs-comment">// Parse reconnection attempt</span>
    <span class="hljs-keyword">if</span> strings.HasPrefix(input, <span class="hljs-string">"reconnect:"</span>) {
        parts := strings.Split(input, <span class="hljs-string">":"</span>)
        <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(parts) == <span class="hljs-number">3</span> {
            username = parts[<span class="hljs-number">1</span>]
            reconnectToken = parts[<span class="hljs-number">2</span>]
            isReconnecting = <span class="hljs-literal">true</span>
        } <span class="hljs-keyword">else</span> {
            conn.Write([]<span class="hljs-keyword">byte</span>(<span class="hljs-string">"Invalid format. Use: reconnect:&lt;username&gt;:&lt;token&gt;\n"</span>))
            <span class="hljs-keyword">return</span>
        }
    } <span class="hljs-keyword">else</span> {
        username = input
    }

    <span class="hljs-comment">// Generate guest name if empty</span>
    <span class="hljs-keyword">if</span> username == <span class="hljs-string">""</span> {
        username = fmt.Sprintf(<span class="hljs-string">"Guest%d"</span>, rand.Intn(<span class="hljs-number">1000</span>))
    }

    <span class="hljs-comment">// Validate reconnection or check for duplicate</span>
    <span class="hljs-keyword">if</span> isReconnecting {
        <span class="hljs-keyword">if</span> chatRoom.validateReconnectToken(username, reconnectToken) {
            fmt.Printf(<span class="hljs-string">"%s reconnected successfully\n"</span>, username)
            conn.Write([]<span class="hljs-keyword">byte</span>(fmt.Sprintf(<span class="hljs-string">"Welcome back, %s!\n"</span>, username)))
        } <span class="hljs-keyword">else</span> {
            conn.Write([]<span class="hljs-keyword">byte</span>(<span class="hljs-string">"Invalid token or session expired.\n"</span>))
            <span class="hljs-keyword">return</span>
        }
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// Prevent duplicate logins</span>
        <span class="hljs-keyword">if</span> chatRoom.isUsernameConnected(username) {
            conn.Write([]<span class="hljs-keyword">byte</span>(<span class="hljs-string">"Username already connected. Use reconnect if you lost connection.\n"</span>))
            <span class="hljs-keyword">return</span>
        }

        <span class="hljs-comment">// Create or retrieve session</span>
        chatRoom.sessionsMu.Lock()
        existingSession := chatRoom.sessions[username]
        chatRoom.sessionsMu.Unlock()

        <span class="hljs-keyword">if</span> existingSession != <span class="hljs-literal">nil</span> {
            token := existingSession.ReconnectToken
            msg := fmt.Sprintf(<span class="hljs-string">"Tip: Save this token: %s\n"</span>, token)
            msg += fmt.Sprintf(<span class="hljs-string">"To reconnect: reconnect:%s:%s\n"</span>, username, token)
            conn.Write([]<span class="hljs-keyword">byte</span>(msg))
        } <span class="hljs-keyword">else</span> {
            session := chatRoom.createSession(username)
            token := session.ReconnectToken
            msg := fmt.Sprintf(<span class="hljs-string">"Your token: %s\n"</span>, token)
            msg += fmt.Sprintf(<span class="hljs-string">"To reconnect: reconnect:%s:%s\n"</span>, username, token)
            conn.Write([]<span class="hljs-keyword">byte</span>(msg))
        }
    }

    <span class="hljs-comment">// Create client object</span>
    client := &amp;Client{
        conn:           conn,
        username:       username,
        outgoing:       <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">string</span>, <span class="hljs-number">10</span>), <span class="hljs-comment">// Buffered</span>
        lastActive:     time.Now(),
        reconnectToken: reconnectToken,
        isSlowClient:   rand.Float64() &lt; <span class="hljs-number">0.1</span>, <span class="hljs-comment">// 10% chance for testing</span>
    }

    <span class="hljs-comment">// Clear timeout for normal operation</span>
    conn.SetReadDeadline(time.Time{})

    <span class="hljs-comment">// Notify chatroom</span>
    chatRoom.join &lt;- client

    <span class="hljs-comment">// Send welcome message</span>
    welcomeMsg := buildWelcomeMessage(username)
    conn.Write([]<span class="hljs-keyword">byte</span>(welcomeMsg))

    <span class="hljs-comment">// Start read/write loops</span>
    <span class="hljs-keyword">go</span> readMessages(client, chatRoom)
    writeMessages(client) <span class="hljs-comment">// Blocks until disconnect</span>

    <span class="hljs-comment">// Update session on disconnect</span>
    chatRoom.updateSessionActivity(username)
    chatRoom.leave &lt;- client
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">buildWelcomeMessage</span><span class="hljs-params">(username <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">string</span></span> {
    msg := fmt.Sprintf(<span class="hljs-string">"Welcome, %s!\n"</span>, username)
    msg += <span class="hljs-string">"Commands:\n"</span>
    msg += <span class="hljs-string">"  /users - List all users\n"</span>
    msg += <span class="hljs-string">"  /history [N] - Show last N messages\n"</span>
    msg += <span class="hljs-string">"  /msg &lt;user&gt; &lt;msg&gt; - Private message\n"</span>
    msg += <span class="hljs-string">"  /token - Show your reconnect token\n"</span>
    msg += <span class="hljs-string">"  /stats - Show your stats\n"</span>
    msg += <span class="hljs-string">"  /quit - Leave\n"</span>
    <span class="hljs-keyword">return</span> msg
}
</code></pre>
<p>The initial 30-second timeout prevents connection exhaustion by disconnecting clients who don't enter a username quickly. The buffered <code>outgoing</code> channel prevents slow clients from blocking the broadcaster. Token-based reconnection lets users resume their session without complex authentication. The dual goroutine design means reading and writing happen independently, so a slow write doesn't block incoming messages.</p>
<h3 id="heading-how-to-read-messages-from-clients">How to Read Messages from Clients</h3>
<p>Add the <code>readMessages()</code> goroutine to handles all incoming data:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">readMessages</span><span class="hljs-params">(client *Client, chatRoom *ChatRoom)</span></span> {
    <span class="hljs-keyword">defer</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">if</span> r := <span class="hljs-built_in">recover</span>(); r != <span class="hljs-literal">nil</span> {
            fmt.Printf(<span class="hljs-string">"Panic in readMessages for %s: %v\n"</span>, client.username, r)
        }
    }()

    reader := bufio.NewReader(client.conn)

    <span class="hljs-keyword">for</span> {
        <span class="hljs-comment">// Set 5-minute idle timeout</span>
        client.conn.SetReadDeadline(time.Now().Add(<span class="hljs-number">5</span> * time.Minute))

        message, err := reader.ReadString(<span class="hljs-string">'\n'</span>)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">if</span> netErr, ok := err.(net.Error); ok &amp;&amp; netErr.Timeout() {
                fmt.Printf(<span class="hljs-string">"%s timed out\n"</span>, client.username)
            } <span class="hljs-keyword">else</span> {
                fmt.Printf(<span class="hljs-string">"%s disconnected: %v\n"</span>, client.username, err)
            }
            <span class="hljs-keyword">return</span>
        }

        client.markActive() <span class="hljs-comment">// Update activity timestamp</span>

        message = strings.TrimSpace(message)
        <span class="hljs-keyword">if</span> message == <span class="hljs-string">""</span> {
            <span class="hljs-keyword">continue</span>
        }

        client.mu.Lock()
        client.messagesRecv++
        client.mu.Unlock()

        <span class="hljs-comment">// Process commands vs. regular messages</span>
        <span class="hljs-keyword">if</span> strings.HasPrefix(message, <span class="hljs-string">"/"</span>) {
            handleCommand(client, chatRoom, message)
            <span class="hljs-keyword">continue</span>
        }

        <span class="hljs-comment">// Regular message - format and broadcast</span>
        formatted := fmt.Sprintf(<span class="hljs-string">"[%s]: %s\n"</span>, client.username, message)
        chatRoom.broadcast &lt;- formatted
    }
}
</code></pre>
<p>5 minutes of idle time triggers auto-disconnect. This prevents zombie connections from consuming resources.</p>
<h3 id="heading-how-to-write-messages-to-clients">How to Write Messages to Clients</h3>
<p>Add the <code>writeMessages()</code> function to drain the client's <code>outgoing</code> channel:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeMessages</span><span class="hljs-params">(client *Client)</span></span> {
    <span class="hljs-keyword">defer</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">if</span> r := <span class="hljs-built_in">recover</span>(); r != <span class="hljs-literal">nil</span> {
            fmt.Printf(<span class="hljs-string">"Panic in writeMessages for %s: %v\n"</span>, client.username, r)
        }
    }()

    writer := bufio.NewWriter(client.conn)

    <span class="hljs-keyword">for</span> message := <span class="hljs-keyword">range</span> client.outgoing {
        <span class="hljs-comment">// Simulate slow client (testing mode)</span>
        <span class="hljs-keyword">if</span> client.isSlowClient {
            time.Sleep(time.Duration(rand.Intn(<span class="hljs-number">500</span>)) * time.Millisecond)
        }

        _, err := writer.WriteString(message)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            fmt.Printf(<span class="hljs-string">"Write error for %s: %v\n"</span>, client.username, err)
            <span class="hljs-keyword">return</span>
        }

        err = writer.Flush()
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            fmt.Printf(<span class="hljs-string">"Flush error for %s: %v\n"</span>, client.username, err)
            <span class="hljs-keyword">return</span>
        }
    }
}
</code></pre>
<p>Real-world clients have varying network speeds. A client with a slow internet connection shouldn't block message delivery to other users. This is a fundamental challenge in any system that broadcasts to multiple recipients.</p>
<p>To handle this, we use two techniques. First, the <code>outgoing</code> channel is buffered with a size of 10. This means the system can queue up 10 messages for a client without blocking. If a client temporarily slows down (maybe they're loading a large webpage in another tab), the buffer absorbs the slowdown.</p>
<p>Second, when broadcasting messages (which you'll see in the next section), we use non-blocking sends. If a client's buffer is full because they're consistently too slow, we skip sending to them rather than blocking everyone else. The slow client misses some messages, but everyone else continues normally. This is called graceful degradation: the system continues working even when parts of it have problems.</p>
<p>With client connections handled, the next step is implementing the core feature of any chat system: broadcasting messages to all connected users. Broadcasting means taking one message and sending it to many recipients efficiently and safely.</p>
<h2 id="heading-how-to-implement-message-broadcasting">How to Implement Message Broadcasting</h2>
<p>Broadcasting is the heart of a chat application. When one user sends a message, it needs to reach everyone else instantly. But this is trickier than it sounds because you need to persist the message for durability, send it to clients at different speeds without blocking, and maintain message ordering across all clients.</p>
<p>Create <code>internal/chatroom/handlers.go</code> to handle events.</p>
<p>The <code>handleBroadcast()</code> method is where messages reach all users:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> chatroom

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"strings"</span>
    <span class="hljs-string">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">handleBroadcast</span><span class="hljs-params">(message <span class="hljs-keyword">string</span>)</span></span> {
    <span class="hljs-comment">// Parse message metadata</span>
    parts := strings.SplitN(message, <span class="hljs-string">": "</span>, <span class="hljs-number">2</span>)
    from := <span class="hljs-string">"system"</span>
    actualContent := message

    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(parts) == <span class="hljs-number">2</span> {
        from = strings.Trim(parts[<span class="hljs-number">0</span>], <span class="hljs-string">"[]"</span>)
        actualContent = parts[<span class="hljs-number">1</span>]
    }

    <span class="hljs-comment">// Create persistent message record</span>
    cr.messageMu.Lock()
    msg := Message{
        ID:        cr.nextMessageID,
        From:      from,
        Content:   actualContent,
        Timestamp: time.Now(),
        Channel:   <span class="hljs-string">"global"</span>,
    }
    cr.nextMessageID++
    cr.messages = <span class="hljs-built_in">append</span>(cr.messages, msg)
    cr.messageMu.Unlock()

    <span class="hljs-comment">// Persist to WAL</span>
    <span class="hljs-keyword">if</span> err := cr.persistMessage(msg); err != <span class="hljs-literal">nil</span> {
        fmt.Printf(<span class="hljs-string">"Failed to persist: %v\n"</span>, err)
        <span class="hljs-comment">// Continue anyway - availability over consistency</span>
    }

    <span class="hljs-comment">// Collect current clients</span>
    cr.mu.Lock()
    clients := <span class="hljs-built_in">make</span>([]*Client, <span class="hljs-number">0</span>, <span class="hljs-built_in">len</span>(cr.clients))
    <span class="hljs-keyword">for</span> client := <span class="hljs-keyword">range</span> cr.clients {
        clients = <span class="hljs-built_in">append</span>(clients, client)
    }
    cr.totalMessages++
    cr.mu.Unlock()

    fmt.Printf(<span class="hljs-string">"Broadcasting to %d clients: %s"</span>, <span class="hljs-built_in">len</span>(clients), message)

    <span class="hljs-comment">// Fan-out to all clients</span>
    <span class="hljs-keyword">for</span> _, client := <span class="hljs-keyword">range</span> clients {
        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> client.outgoing &lt;- message:
            client.mu.Lock()
            client.messagesSent++
            client.mu.Unlock()
        <span class="hljs-keyword">default</span>:
            fmt.Printf(<span class="hljs-string">"Skipped %s (channel full)\n"</span>, client.username)
        }
    }
}
</code></pre>
<h4 id="heading-consistency-trade-off">Consistency Trade-off:</h4>
<p>If a WAL write fails, you still broadcast the message. Why? Because availability is more important than perfect consistency for a chat application. Users get their messages immediately, and you can handle WAL repair manually if needed.</p>
<h3 id="heading-how-to-handle-join-and-leave-events">How to Handle Join and Leave Events</h3>
<p>Add these handlers to <code>handlers.go</code>:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">handleJoin</span><span class="hljs-params">(client *Client)</span></span> {
    cr.mu.Lock()
    cr.clients[client] = <span class="hljs-literal">true</span>
    cr.mu.Unlock()

    client.markActive()

    fmt.Printf(<span class="hljs-string">"%s joined (total: %d)\n"</span>, client.username, <span class="hljs-built_in">len</span>(cr.clients))

    cr.sendHistory(client, <span class="hljs-number">10</span>)

    announcement := fmt.Sprintf(<span class="hljs-string">"*** %s joined the chat ***\n"</span>, client.username)
    cr.handleBroadcast(announcement)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">handleLeave</span><span class="hljs-params">(client *Client)</span></span> {
    cr.mu.Lock()
    <span class="hljs-keyword">if</span> !cr.clients[client] {
        cr.mu.Unlock()
        <span class="hljs-keyword">return</span>
    }
    <span class="hljs-built_in">delete</span>(cr.clients, client)
    cr.mu.Unlock()

    fmt.Printf(<span class="hljs-string">"%s left (total: %d)\n"</span>, client.username, <span class="hljs-built_in">len</span>(cr.clients))

    <span class="hljs-comment">// Close channel safely</span>
    <span class="hljs-keyword">select</span> {
    <span class="hljs-keyword">case</span> &lt;-client.outgoing:
        <span class="hljs-comment">// Already closed</span>
    <span class="hljs-keyword">default</span>:
        <span class="hljs-built_in">close</span>(client.outgoing)
    }

    announcement := fmt.Sprintf(<span class="hljs-string">"*** %s left the chat ***\n"</span>, client.username)
    cr.handleBroadcast(announcement)
}
</code></pre>
<p>The <code>handleJoin</code> function adds the client to the active clients map, marks them as active for idle tracking, sends them the last 10 messages so they can see recent conversation, and broadcasts an announcement so everyone knows they joined.</p>
<p>The <code>handleLeave</code> function removes the client from the map, closes their outgoing channel safely (the select checks if it's already closed to avoid a panic), and broadcasts a departure announcement.</p>
<h3 id="heading-how-to-send-user-lists-and-history">How to Send User Lists and History</h3>
<p>Add these helper functions to <code>handlers.go</code>:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">sendHistory</span><span class="hljs-params">(client *Client, count <span class="hljs-keyword">int</span>)</span></span> {
    cr.messageMu.Lock()
    <span class="hljs-keyword">defer</span> cr.messageMu.Unlock()

    start := <span class="hljs-built_in">len</span>(cr.messages) - count
    <span class="hljs-keyword">if</span> start &lt; <span class="hljs-number">0</span> {
        start = <span class="hljs-number">0</span>
    }

    historyMsg := <span class="hljs-string">"Recent messages:\n"</span>
    <span class="hljs-keyword">for</span> i := start; i &lt; <span class="hljs-built_in">len</span>(cr.messages); i++ {
        msg := cr.messages[i]
        historyMsg += fmt.Sprintf(<span class="hljs-string">" [%s]: %s\n"</span>, msg.From, msg.Content)
    }

    <span class="hljs-keyword">select</span> {
    <span class="hljs-keyword">case</span> client.outgoing &lt;- historyMsg:
    <span class="hljs-keyword">default</span>:
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">sendUserList</span><span class="hljs-params">(client *Client)</span></span> {
    cr.mu.Lock()
    <span class="hljs-keyword">defer</span> cr.mu.Unlock()

    list := <span class="hljs-string">"Users online:\n"</span>
    <span class="hljs-keyword">for</span> c := <span class="hljs-keyword">range</span> cr.clients {
        status := <span class="hljs-string">""</span>
        <span class="hljs-keyword">if</span> c.isInactive(<span class="hljs-number">1</span> * time.Minute) {
            status = <span class="hljs-string">" (idle)"</span>
        }
        list += fmt.Sprintf(<span class="hljs-string">"  - %s%s\n"</span>, c.username, status)
    }

    list += fmt.Sprintf(<span class="hljs-string">"\nTotal messages: %d\n"</span>, cr.totalMessages)
    list += fmt.Sprintf(<span class="hljs-string">"Uptime: %s\n"</span>, time.Since(cr.startTime).Round(time.Second))

    <span class="hljs-keyword">select</span> {
    <span class="hljs-keyword">case</span> client.outgoing &lt;- list:
    <span class="hljs-keyword">default</span>:
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">handleDirectMessage</span><span class="hljs-params">(dm DirectMessage)</span></span> {
    <span class="hljs-keyword">select</span> {
    <span class="hljs-keyword">case</span> dm.toClient.outgoing &lt;- dm.message:
        dm.toClient.mu.Lock()
        dm.toClient.messagesSent++
        dm.toClient.mu.Unlock()
    <span class="hljs-keyword">default</span>:
        fmt.Printf(<span class="hljs-string">"Couldn't deliver DM to %s\n"</span>, dm.toClient.username)
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">findClientByUsername</span><span class="hljs-params">(username <span class="hljs-keyword">string</span>)</span> *<span class="hljs-title">Client</span></span> {
    cr.mu.Lock()
    <span class="hljs-keyword">defer</span> cr.mu.Unlock()

    <span class="hljs-keyword">for</span> client := <span class="hljs-keyword">range</span> cr.clients {
        <span class="hljs-keyword">if</span> client.username == username {
            <span class="hljs-keyword">return</span> client
        }
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(c *Client)</span> <span class="hljs-title">markActive</span><span class="hljs-params">()</span></span> {
    c.mu.Lock()
    <span class="hljs-keyword">defer</span> c.mu.Unlock()
    c.lastActive = time.Now()
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(c *Client)</span> <span class="hljs-title">isInactive</span><span class="hljs-params">(timeout time.Duration)</span> <span class="hljs-title">bool</span></span> {
    c.mu.Lock()
    <span class="hljs-keyword">defer</span> c.mu.Unlock()
    <span class="hljs-keyword">return</span> time.Since(c.lastActive) &gt; timeout
}
</code></pre>
<p>You now have a working chat system where clients can connect and exchange messages.</p>
<p>But there's a critical problem: if the server crashes or restarts, all messages are lost. The next step is adding persistence so messages survive failures.</p>
<h2 id="heading-how-to-add-persistence-with-wal-and-snapshots">How to Add Persistence with WAL and Snapshots</h2>
<p>Persistence ensures your chat history survives server crashes and restarts. Without it, users would lose all their conversations every time the server goes down.</p>
<p>You'll implement this using two complementary mechanisms: a write-ahead log for immediate durability and snapshots for fast recovery.</p>
<p>Create <code>internal/chatroom/persistence.go</code> to handle data durability.</p>
<p>The WAL ensures messages survive crashes:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> chatroom

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"bufio"</span>
    <span class="hljs-string">"encoding/json"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"io"</span>
    <span class="hljs-string">"os"</span>
    <span class="hljs-string">"path/filepath"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">initializePersistence</span><span class="hljs-params">()</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-keyword">if</span> err := os.MkdirAll(cr.dataDir, <span class="hljs-number">0755</span>); err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"create data dir: %w"</span>, err)
    }

    walPath := filepath.Join(cr.dataDir, <span class="hljs-string">"messages.wal"</span>)

    <span class="hljs-keyword">if</span> err := cr.recoverFromWAL(walPath); err != <span class="hljs-literal">nil</span> {
        fmt.Printf(<span class="hljs-string">"Recovery failed: %v\n"</span>, err)
    }

    file, err := os.OpenFile(walPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, <span class="hljs-number">0644</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"open wal: %w"</span>, err)
    }

    cr.walFile = file
    fmt.Printf(<span class="hljs-string">"WAL initialized: %s\n"</span>, walPath)
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">recoverFromWAL</span><span class="hljs-params">(walPath <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">error</span></span> {
    file, err := os.Open(walPath)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">if</span> os.IsNotExist(err) {
            fmt.Println(<span class="hljs-string">"No WAL found (fresh start)"</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
        }
        <span class="hljs-keyword">return</span> err
    }
    <span class="hljs-keyword">defer</span> file.Close()

    scanner := bufio.NewScanner(file)
    recovered := <span class="hljs-number">0</span>

    <span class="hljs-keyword">for</span> scanner.Scan() {
        line := scanner.Text()
        <span class="hljs-keyword">if</span> line == <span class="hljs-string">""</span> {
            <span class="hljs-keyword">continue</span>
        }

        <span class="hljs-keyword">var</span> msg Message
        <span class="hljs-keyword">if</span> err := json.Unmarshal([]<span class="hljs-keyword">byte</span>(line), &amp;msg); err != <span class="hljs-literal">nil</span> {
            fmt.Printf(<span class="hljs-string">"Skipping corrupt line: %s\n"</span>, line)
            <span class="hljs-keyword">continue</span>
        }

        cr.messages = <span class="hljs-built_in">append</span>(cr.messages, msg)

        <span class="hljs-keyword">if</span> msg.ID &gt;= cr.nextMessageID {
            cr.nextMessageID = msg.ID + <span class="hljs-number">1</span>
        }
        recovered++
    }

    fmt.Printf(<span class="hljs-string">"Recovered %d messages\n"</span>, recovered)
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">persistMessage</span><span class="hljs-params">(msg Message)</span> <span class="hljs-title">error</span></span> {
    cr.walMu.Lock()
    <span class="hljs-keyword">defer</span> cr.walMu.Unlock()

    data, err := json.Marshal(msg)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    _, err = cr.walFile.Write(<span class="hljs-built_in">append</span>(data, <span class="hljs-string">'\n'</span>))
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    <span class="hljs-keyword">return</span> cr.walFile.Sync()
}
</code></pre>
<p>Each line is a JSON-encoded message:</p>
<pre><code class="lang-json">{<span class="hljs-attr">"id"</span>:<span class="hljs-number">1</span>,<span class="hljs-attr">"from"</span>:<span class="hljs-string">"Alice"</span>,<span class="hljs-attr">"content"</span>:<span class="hljs-string">"Hello world"</span>,<span class="hljs-attr">"timestamp"</span>:<span class="hljs-string">"2024-02-06T10:00:00Z"</span>,<span class="hljs-attr">"channel"</span>:<span class="hljs-string">"global"</span>}
{<span class="hljs-attr">"id"</span>:<span class="hljs-number">2</span>,<span class="hljs-attr">"from"</span>:<span class="hljs-string">"Bob"</span>,<span class="hljs-attr">"content"</span>:<span class="hljs-string">"Hi Alice!"</span>,<span class="hljs-attr">"timestamp"</span>:<span class="hljs-string">"2024-02-06T10:00:05Z"</span>,<span class="hljs-attr">"channel"</span>:<span class="hljs-string">"global"</span>}
</code></pre>
<p>The <code>Sync()</code> call is critical for durability. Without it, the OS might buffer writes in memory, losing them on a crash. The trade-off is that <code>Sync()</code> is expensive (about 1-10ms per call). Production systems might batch multiple messages to improve throughput.</p>
<h3 id="heading-how-to-create-and-load-snapshots">How to Create and Load Snapshots</h3>
<p>Add snapshot functionality to <code>persistence.go</code>:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">createSnapshot</span><span class="hljs-params">()</span> <span class="hljs-title">error</span></span> {
    snapshotPath := filepath.Join(cr.dataDir, <span class="hljs-string">"snapshot.json"</span>)
    tempPath := snapshotPath + <span class="hljs-string">".tmp"</span>

    file, err := os.Create(tempPath)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }
    <span class="hljs-keyword">defer</span> file.Close()

    cr.messageMu.Lock()
    data, err := json.MarshalIndent(cr.messages, <span class="hljs-string">""</span>, <span class="hljs-string">"  "</span>)
    cr.messageMu.Unlock()

    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    <span class="hljs-keyword">if</span> _, err := file.Write(data); err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    <span class="hljs-keyword">if</span> err := file.Sync(); err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    file.Close()

    <span class="hljs-keyword">if</span> err := os.Rename(tempPath, snapshotPath); err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    fmt.Printf(<span class="hljs-string">"Snapshot created (%d messages)\n"</span>, <span class="hljs-built_in">len</span>(cr.messages))
    <span class="hljs-keyword">return</span> cr.truncateWAL()
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">truncateWAL</span><span class="hljs-params">()</span> <span class="hljs-title">error</span></span> {
    cr.walMu.Lock()
    <span class="hljs-keyword">defer</span> cr.walMu.Unlock()

    <span class="hljs-keyword">if</span> cr.walFile != <span class="hljs-literal">nil</span> {
        cr.walFile.Close()
    }

    walPath := filepath.Join(cr.dataDir, <span class="hljs-string">"messages.wal"</span>)
    file, err := os.OpenFile(walPath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, <span class="hljs-number">0644</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }
    cr.walFile = file
    fmt.Println(<span class="hljs-string">"WAL truncated"</span>)
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">loadSnapshot</span><span class="hljs-params">()</span> <span class="hljs-title">error</span></span> {
    snapshotPath := filepath.Join(cr.dataDir, <span class="hljs-string">"snapshot.json"</span>)
    file, err := os.Open(snapshotPath)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">if</span> os.IsNotExist(err) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
        }
        <span class="hljs-keyword">return</span> err
    }
    <span class="hljs-keyword">defer</span> file.Close()

    data, err := io.ReadAll(file)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    cr.messageMu.Lock()
    err = json.Unmarshal(data, &amp;cr.messages)
    cr.messageMu.Unlock()

    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    <span class="hljs-keyword">for</span> _, msg := <span class="hljs-keyword">range</span> cr.messages {
        <span class="hljs-keyword">if</span> msg.ID &gt;= cr.nextMessageID {
            cr.nextMessageID = msg.ID + <span class="hljs-number">1</span>
        }
    }

    fmt.Printf(<span class="hljs-string">"Loaded %d messages from snapshot\n"</span>, <span class="hljs-built_in">len</span>(cr.messages))
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}
</code></pre>
<p>Writing to <code>.tmp</code> then renaming ensures you never have a half-written snapshot. Even if power fails mid-write, the old snapshot remains valid.</p>
<h4 id="heading-recovery-flow">Recovery Flow</h4>
<p>When the server starts, it first loads the snapshot if it exists, which might contain 100K messages and takes about 100ms. Then it replays WAL entries written since the snapshot, which might be only recent messages. Total recovery time is seconds instead of minutes.</p>
<p>With persistence in place, your messages are safe. But network connections are unreliable. Users get disconnected when their WiFi drops, their phone switches towers, or their laptop goes to sleep. The next step is implementing session management so users can reconnect without losing their identity or chat history.</p>
<h2 id="heading-how-to-implement-session-management">How to Implement Session Management</h2>
<p>Session management lets users reconnect to your server after network interruptions without needing to create a new account or re-enter credentials. You'll implement this using cryptographically secure tokens that persist across connections.</p>
<p>Create <code>internal/chatroom/session.go</code> for reconnection handling.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> chatroom

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"github.com/yourusername/chatroom/pkg/token"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">createSession</span><span class="hljs-params">(username <span class="hljs-keyword">string</span>)</span> *<span class="hljs-title">SessionInfo</span></span> {
    cr.sessionsMu.Lock()
    <span class="hljs-keyword">defer</span> cr.sessionsMu.Unlock()

    tok := token.GenerateToken()

    session := &amp;SessionInfo{
        Username:       username,
        ReconnectToken: tok,
        LastSeen:       time.Now(),
        CreatedAt:      time.Now(),
    }

    cr.sessions[username] = session

    fmt.Printf(<span class="hljs-string">"Created session for %s (token: %s...)\n"</span>, username, tok[:<span class="hljs-number">8</span>])

    <span class="hljs-keyword">return</span> session
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">validateReconnectToken</span><span class="hljs-params">(username, token <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">bool</span></span> {
    cr.sessionsMu.Lock()
    <span class="hljs-keyword">defer</span> cr.sessionsMu.Unlock()

    session, exists := cr.sessions[username]
    <span class="hljs-keyword">if</span> !exists {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
    }

    <span class="hljs-keyword">if</span> session.ReconnectToken != token {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
    }

    <span class="hljs-keyword">if</span> time.Since(session.LastSeen) &gt; <span class="hljs-number">1</span>*time.Hour {
        <span class="hljs-built_in">delete</span>(cr.sessions, username)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
    }

    session.LastSeen = time.Now()

    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">updateSessionActivity</span><span class="hljs-params">(username <span class="hljs-keyword">string</span>)</span></span> {
    cr.sessionsMu.Lock()
    <span class="hljs-keyword">defer</span> cr.sessionsMu.Unlock()

    <span class="hljs-keyword">if</span> session, exists := cr.sessions[username]; exists {
        session.LastSeen = time.Now()
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">isUsernameConnected</span><span class="hljs-params">(username <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">bool</span></span> {
    cr.mu.Lock()
    <span class="hljs-keyword">defer</span> cr.mu.Unlock()

    <span class="hljs-keyword">for</span> client := <span class="hljs-keyword">range</span> cr.clients {
        <span class="hljs-keyword">if</span> client.username == username {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
        }
    }

    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cr *ChatRoom)</span> <span class="hljs-title">cleanupInactiveClients</span><span class="hljs-params">()</span></span> {
    ticker := time.NewTicker(<span class="hljs-number">30</span> * time.Second)
    <span class="hljs-keyword">defer</span> ticker.Stop()

    <span class="hljs-keyword">for</span> <span class="hljs-keyword">range</span> ticker.C {
        cr.mu.Lock()
        <span class="hljs-keyword">var</span> toRemove []*Client

        <span class="hljs-keyword">for</span> client := <span class="hljs-keyword">range</span> cr.clients {
            <span class="hljs-keyword">if</span> client.isInactive(<span class="hljs-number">5</span> * time.Minute) {
                fmt.Printf(<span class="hljs-string">"Removing inactive: %s\n"</span>, client.username)
                toRemove = <span class="hljs-built_in">append</span>(toRemove, client)
            }
        }
        cr.mu.Unlock()

        <span class="hljs-keyword">for</span> _, client := <span class="hljs-keyword">range</span> toRemove {
            cr.leave &lt;- client
        }
    }
}
</code></pre>
<h3 id="heading-how-to-generate-secure-tokens">How to Generate Secure Tokens</h3>
<p>Create <code>pkg/token/token.go</code> for token generation:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> token

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"crypto/rand"</span>
    <span class="hljs-string">"encoding/hex"</span>
)

<span class="hljs-comment">// GenerateToken returns a secure random 16-byte hex token</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GenerateToken</span><span class="hljs-params">()</span> <span class="hljs-title">string</span></span> {
    b := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">byte</span>, <span class="hljs-number">16</span>)
    _, _ = rand.Read(b)
    <span class="hljs-keyword">return</span> hex.EncodeToString(b)
}
</code></pre>
<p>Tokens here are transmitted in plaintext over TCP. For production use, you should use TLS encryption to protect tokens in transit, hash tokens before storage so a database breach doesn't expose them, and implement rate limiting on reconnection attempts to prevent brute force attacks.</p>
<p>Your chatroom now supports basic messaging and reconnection. But users need ways to interact with the system beyond just sending messages. The command system provides features like listing users, viewing history, and sending private messages.</p>
<h2 id="heading-how-to-build-the-command-system">How to Build the Command System</h2>
<p>Commands are messages that start with a forward slash and perform special actions instead of being broadcast to everyone. This is a pattern used by many chat applications like Slack and Discord. You'll implement several useful commands that enhance the user experience.</p>
<p>Add command handling to <code>io.go</code>:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">handleCommand</span><span class="hljs-params">(client *Client, chatRoom *ChatRoom, command <span class="hljs-keyword">string</span>)</span></span> {
    parts := strings.Fields(command)
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(parts) == <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span>
    }

    <span class="hljs-keyword">switch</span> parts[<span class="hljs-number">0</span>] {
    <span class="hljs-keyword">case</span> <span class="hljs-string">"/users"</span>:
        chatRoom.listUsers &lt;- client

    <span class="hljs-keyword">case</span> <span class="hljs-string">"/stats"</span>:
        client.mu.Lock()
        stats := fmt.Sprintf(<span class="hljs-string">"Your Stats:\n"</span>)
        stats += fmt.Sprintf(<span class="hljs-string">"  Messages sent: %d\n"</span>, client.messagesSent)
        stats += fmt.Sprintf(<span class="hljs-string">"  Messages received: %d\n"</span>, client.messagesRecv)
        stats += fmt.Sprintf(<span class="hljs-string">"  Last active: %s ago\n"</span>, 
            time.Since(client.lastActive).Round(time.Second))
        client.mu.Unlock()

        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> client.outgoing &lt;- stats:
        <span class="hljs-keyword">default</span>:
        }

    <span class="hljs-keyword">case</span> <span class="hljs-string">"/msg"</span>:
        <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(parts) &lt; <span class="hljs-number">3</span> {
            <span class="hljs-keyword">select</span> {
            <span class="hljs-keyword">case</span> client.outgoing &lt;- <span class="hljs-string">"Usage: /msg &lt;username&gt; &lt;message&gt;\n"</span>:
            <span class="hljs-keyword">default</span>:
            }
            <span class="hljs-keyword">return</span>
        }

        targetUsername := parts[<span class="hljs-number">1</span>]
        messageText := strings.Join(parts[<span class="hljs-number">2</span>:], <span class="hljs-string">" "</span>)

        targetClient := chatRoom.findClientByUsername(targetUsername)
        <span class="hljs-keyword">if</span> targetClient == <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">select</span> {
            <span class="hljs-keyword">case</span> client.outgoing &lt;- fmt.Sprintf(<span class="hljs-string">"User '%s' not found\n"</span>, targetUsername):
            <span class="hljs-keyword">default</span>:
            }
            <span class="hljs-keyword">return</span>
        }

        privateMsg := fmt.Sprintf(<span class="hljs-string">"[From %s]: %s\n"</span>, client.username, messageText)
        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> targetClient.outgoing &lt;- privateMsg:
        <span class="hljs-keyword">default</span>:
            <span class="hljs-keyword">select</span> {
            <span class="hljs-keyword">case</span> client.outgoing &lt;- fmt.Sprintf(<span class="hljs-string">"%s's inbox is full\n"</span>, targetUsername):
            <span class="hljs-keyword">default</span>:
            }
            <span class="hljs-keyword">return</span>
        }

        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> client.outgoing &lt;- fmt.Sprintf(<span class="hljs-string">"Message sent to %s\n"</span>, targetUsername):
        <span class="hljs-keyword">default</span>:
        }

    <span class="hljs-keyword">case</span> <span class="hljs-string">"/history"</span>:
        count := <span class="hljs-number">20</span>
        <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(parts) &gt; <span class="hljs-number">1</span> {
            fmt.Sscanf(parts[<span class="hljs-number">1</span>], <span class="hljs-string">"%d"</span>, &amp;count)
        }
        <span class="hljs-keyword">if</span> count &gt; <span class="hljs-number">100</span> {
            count = <span class="hljs-number">100</span>
        }
        cr.sendHistory(client, count)

    <span class="hljs-keyword">case</span> <span class="hljs-string">"/token"</span>:
        chatRoom.sessionsMu.Lock()
        session := chatRoom.sessions[client.username]
        chatRoom.sessionsMu.Unlock()

        <span class="hljs-keyword">if</span> session != <span class="hljs-literal">nil</span> {
            msg := fmt.Sprintf(<span class="hljs-string">"Your reconnect token:\n"</span>)
            msg += fmt.Sprintf(<span class="hljs-string">"   reconnect:%s:%s\n"</span>, client.username, session.ReconnectToken)
            <span class="hljs-keyword">select</span> {
            <span class="hljs-keyword">case</span> client.outgoing &lt;- msg:
            <span class="hljs-keyword">default</span>:
            }
        }

    <span class="hljs-keyword">case</span> <span class="hljs-string">"/quit"</span>:
        announcement := fmt.Sprintf(<span class="hljs-string">"%s left the chat\n"</span>, client.username)
        chatRoom.broadcast &lt;- announcement

        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> client.outgoing &lt;- <span class="hljs-string">"Goodbye!\n"</span>:
        <span class="hljs-keyword">default</span>:
        }

        time.Sleep(<span class="hljs-number">100</span> * time.Millisecond)
        client.conn.Close()

    <span class="hljs-keyword">default</span>:
        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> client.outgoing &lt;- fmt.Sprintf(<span class="hljs-string">"Unknown: %s\n"</span>, parts[<span class="hljs-number">0</span>]):
        <span class="hljs-keyword">default</span>:
        }
    }
}
</code></pre>
<p>Your server is now complete with all the core features: connection handling, message broadcasting, persistence, session management, and commands. But to actually use your chatroom, you need a client application. The client is much simpler than the server because it just needs to connect and relay messages.</p>
<h2 id="heading-how-to-create-the-client">How to Create the Client</h2>
<p>The client application provides the user interface for your chatroom. It connects to the server, displays incoming messages, and sends outgoing messages typed by the user. While the server is complex with many concurrent components, the client is straightforward</p>
<p>Create <code>internal/chatroom/client.go</code> for the client implementation.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> chatroom

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"bufio"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"net"</span>
    <span class="hljs-string">"os"</span>
    <span class="hljs-string">"strings"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">StartClient</span><span class="hljs-params">()</span></span> {
    conn, err := net.Dial(<span class="hljs-string">"tcp"</span>, <span class="hljs-string">":9000"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        fmt.Println(<span class="hljs-string">"Error connecting:"</span>, err)
        <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">defer</span> conn.Close()

    fmt.Println(<span class="hljs-string">"Connected to chat server"</span>)

    <span class="hljs-comment">// Background goroutine: read from server</span>
    <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        reader := bufio.NewReader(conn)
        <span class="hljs-keyword">for</span> {
            message, err := reader.ReadString(<span class="hljs-string">'\n'</span>)
            <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
                fmt.Println(<span class="hljs-string">"Disconnected from server."</span>)
                os.Exit(<span class="hljs-number">0</span>)
            }
            <span class="hljs-comment">// Clear current prompt line and print message</span>
            fmt.Print(<span class="hljs-string">"\r"</span> + message)
            fmt.Print(<span class="hljs-string">"&gt;&gt; "</span>)
        }
    }()

    <span class="hljs-comment">// Main goroutine: read from stdin</span>
    inputReader := bufio.NewReader(os.Stdin)
    fmt.Println(<span class="hljs-string">"Welcome to the chat server!"</span>)

    <span class="hljs-keyword">for</span> {
        fmt.Print(<span class="hljs-string">"&gt;&gt; "</span>)
        message, _ := inputReader.ReadString(<span class="hljs-string">'\n'</span>)
        message = strings.TrimSpace(message)

        <span class="hljs-keyword">if</span> message == <span class="hljs-string">""</span> {
            <span class="hljs-keyword">continue</span>
        }

        conn.Write([]<span class="hljs-keyword">byte</span>(message + <span class="hljs-string">"\n"</span>))
    }
}
</code></pre>
<h4 id="heading-how-the-client-works">How the Client Works:</h4>
<p>The client uses two goroutines to handle communication simultaneously. The main goroutine reads from stdin (your keyboard) and sends messages to the server. When you type a message and press Enter, it gets sent over the TCP connection immediately.</p>
<p>The background goroutine continuously reads from the server. Whenever a message arrives, it prints it to your screen. The <code>\r</code> (carriage return) clears the current <code>&gt;&gt;</code> prompt before printing the message, so new messages don't appear on the same line as your input. After printing the message, it reprints the prompt so you can continue typing.</p>
<p>This dual-goroutine design means you can receive messages while typing. If someone sends a message while you're in the middle of typing yours, their message appears immediately and your prompt reappears below it.</p>
<p>The <code>defer conn.Close()</code> ensures the connection is properly closed when the function exits. If the server disconnects, the read goroutine gets an error and calls <code>os.Exit(0)</code> to terminate the entire client program gracefully.</p>
<h3 id="heading-how-to-create-entry-points">How to Create Entry Points</h3>
<p>Create <code>cmd/server/main.go</code>:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"os"</span>

    <span class="hljs-string">"github.com/yourusername/chatroom/internal/chatroom"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    fmt.Println(<span class="hljs-string">"Starting server from cmd/server..."</span>)
    chatroom.StartServer()
    os.Exit(<span class="hljs-number">0</span>)
}
</code></pre>
<p>Create <code>cmd/client/main.go</code>:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"github.com/yourusername/chatroom/internal/chatroom"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    fmt.Println(<span class="hljs-string">"Starting client from cmd/client..."</span>)
    chatroom.StartClient()
}
</code></pre>
<p>Add a wrapper function in <code>internal/chatroom/server.go</code>:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> chatroom

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">StartServer</span><span class="hljs-params">()</span></span> {
    runServer()
}
</code></pre>
<p>With all your entry points created, your chatroom is complete and ready to test. The next step is learning how to test your implementation to ensure everything works correctly.</p>
<h2 id="heading-how-to-test-your-chatroom">How to Test Your Chatroom</h2>
<p>Testing a concurrent system like a chatroom requires a different approach than testing typical sequential code. You need to verify that goroutines coordinate correctly, messages arrive in the right order, and the system handles edge cases like disconnections.</p>
<h3 id="heading-how-to-write-unit-tests">How to Write Unit Tests</h3>
<p>Unit tests verify individual components in isolation. For your chatroom, the most important test is verifying that messages broadcast correctly to all connected clients.</p>
<p>Create <code>internal/chatroom/chatroom_test.go</code>:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> chatroom

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"testing"</span>
    <span class="hljs-string">"strings"</span>
    <span class="hljs-string">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestBroadcast</span><span class="hljs-params">(t *testing.T)</span></span> {
    cr, _ := NewChatRoom(<span class="hljs-string">"./testdata"</span>)
    <span class="hljs-keyword">defer</span> cr.shutdown()

    <span class="hljs-keyword">go</span> cr.Run()

    <span class="hljs-comment">// Create mock clients</span>
    client1 := &amp;Client{
        username: <span class="hljs-string">"Alice"</span>,
        outgoing: <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">string</span>, <span class="hljs-number">10</span>),
    }
    client2 := &amp;Client{
        username: <span class="hljs-string">"Bob"</span>,
        outgoing: <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">string</span>, <span class="hljs-number">10</span>),
    }

    <span class="hljs-comment">// Join clients</span>
    cr.join &lt;- client1
    cr.join &lt;- client2
    time.Sleep(<span class="hljs-number">100</span> * time.Millisecond)

    <span class="hljs-comment">// Broadcast message</span>
    cr.broadcast &lt;- <span class="hljs-string">"[Alice]: Hello!"</span>

    <span class="hljs-comment">// Verify both receive it</span>
    <span class="hljs-keyword">select</span> {
    <span class="hljs-keyword">case</span> msg := &lt;-client1.outgoing:
        <span class="hljs-keyword">if</span> !strings.Contains(msg, <span class="hljs-string">"Hello!"</span>) {
            t.Fatal(<span class="hljs-string">"Client1 didn't receive correct message"</span>)
        }
    <span class="hljs-keyword">case</span> &lt;-time.After(<span class="hljs-number">1</span> * time.Second):
        t.Fatal(<span class="hljs-string">"Client1 didn't receive message"</span>)
    }

    <span class="hljs-keyword">select</span> {
    <span class="hljs-keyword">case</span> msg := &lt;-client2.outgoing:
        <span class="hljs-keyword">if</span> !strings.Contains(msg, <span class="hljs-string">"Hello!"</span>) {
            t.Fatal(<span class="hljs-string">"Client2 didn't receive correct message"</span>)
        }
    <span class="hljs-keyword">case</span> &lt;-time.After(<span class="hljs-number">1</span> * time.Second):
        t.Fatal(<span class="hljs-string">"Client2 didn't receive message"</span>)
    }
}
</code></pre>
<h4 id="heading-understanding-the-test">Understanding the Test:</h4>
<p>This test creates a chatroom instance and starts its event loop with <code>go cr.Run()</code>. Then it creates two mock clients. Notice these aren't real TCP connections – they're just Client structs with outgoing channels. This lets you test the broadcast logic without needing actual network connections.</p>
<p>The test sends both clients to the join channel, waits 100 milliseconds for them to be processed, then broadcasts a message. The <code>select</code> statements with timeout are crucial. They try to receive from each client's outgoing channel, but if nothing arrives within 1 second, the test fails. This prevents the test from hanging forever if something goes wrong.</p>
<p>The <code>time.Sleep(100 * time.Millisecond)</code> gives the event loop time to process the join events before broadcasting. In a real system, you'd use channels to synchronize, but for tests, a small sleep is acceptable.</p>
<p>Run tests with:</p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> test ./internal/chatroom -v
</code></pre>
<p>The <code>-v</code> flag shows verbose output, printing each test as it runs. You'll see whether the broadcast test passes and how long it took. Below is the output showing that the test passed:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770480869735/1102c089-1d10-43fc-bd7f-5571283213a0.png" alt="Chatroom unit test" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-do-integration-testing">How to Do Integration Testing</h3>
<p>Integration tests verify the entire system working together – the real server, real clients, and real network connections. Unlike unit tests that mock components, integration tests exercise the full stack.</p>
<p>Test the full client-server flow:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Terminal 1: Start server</span>
go run cmd/server/main.go

<span class="hljs-comment"># Terminal 2: Client 1</span>
go run cmd/client/main.go
<span class="hljs-comment"># Enter username: Alice</span>

<span class="hljs-comment"># Terminal 3: Client 2  </span>
go run cmd/client/main.go
<span class="hljs-comment"># Enter username: Bob</span>

<span class="hljs-comment"># Terminal 4: Client 3  </span>
go run cmd/client/main.go
<span class="hljs-comment"># Enter username: John</span>

<span class="hljs-comment"># Test messaging between clients</span>
</code></pre>
<h4 id="heading-what-to-test">What to Test:</h4>
<p>Once you have the server running and multiple clients connected, you can verify all the features you built. Here's what a complete test session looks like:</p>
<ol>
<li><p><strong>Basic Messaging:</strong> Send a message from Alice and verify Bob and John both receive it. You should see the message appear in all client windows with the sender's username in brackets. Try sending from each client to verify the broadcast works in all directions.</p>
</li>
<li><p><strong>Join and Leave Announcements:</strong> When a new client connects, all existing clients should see a "joined the chat" announcement. When someone disconnects (either with <code>/quit</code> or by closing their terminal), everyone should see a "left the chat" message. This confirms your join and leave handlers work correctly.</p>
</li>
<li><p><strong>Private Messaging:</strong> Use <code>/msg Bob this is a private message</code> from Alice's client. The message should appear only in Bob's window, not in John's or Alice's. Try sending private messages between different pairs of users to verify the routing works correctly. The sender should receive a confirmation that the message was sent.</p>
</li>
<li><p><strong>User List:</strong> Run <code>/users</code> from any client. You should see a list of all connected users. If someone has been idle for over a minute, they should show an "(idle)" status. The command should also display total message count and server uptime.</p>
</li>
<li><p><strong>Chat History:</strong> New clients should automatically receive the last 10 messages when they join. You can also use <code>/history 20</code> to request the last 20 messages. This verifies your message persistence is working.</p>
</li>
<li><p><strong>Session Reconnection:</strong> From one client, use <code>/token</code> to get your reconnection token. It will look something like <code>reconnect:Alice:338f04ca...</code>. Copy this token, disconnect the client with Ctrl+C, start a new client, and paste the reconnection string when prompted. You should rejoin the chat with your previous identity, and other users won't see duplicate join announcements.</p>
</li>
<li><p><strong>Statistics:</strong> Use <code>/stats</code> to see how many messages you've sent and received, and when you were last active. This verifies the client-side statistics tracking works.</p>
</li>
<li><p><strong>Error Handling:</strong> Try connecting with a username that's already in use – you should be rejected. Try sending a private message to a non-existent user – you should get an error. Try using an invalid reconnection token – you should be denied. These tests verify your validation logic works.</p>
</li>
</ol>
<p>Look at the server terminal to see the server's perspective. You'll see connection logs, broadcast confirmations, and any errors. When clients disconnect, you should see their sessions being updated. When the server creates snapshots, you'll see those logged, too.</p>
<p>Integration testing catches problems that unit tests miss, like network timeouts, message ordering issues across multiple clients, or problems with how the WAL file is created and locked. The screenshot below shows a successful integration test with three clients (Alice, Bob, and John) all communicating successfully, with private messages, public broadcasts, and proper join/leave handling.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770348441963/d66bb2da-088b-4b9c-95a2-e5f401c5f49e.png" alt="chatroom broadcast test" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-deploy-your-server">How to Deploy Your Server</h2>
<p>Deploying your chatroom means running it on a server that stays up 24/7, automatically restarts if it crashes, and starts when the server boots. There are several approaches depending on your infrastructure.</p>
<h3 id="heading-how-to-use-systemd">How to Use Systemd</h3>
<p>Systemd is the standard init system on most Linux distributions. It manages services, handles restarts, and ensures your chatroom starts on boot.</p>
<p>Create <code>/etc/systemd/system/chatroom.service</code>:</p>
<pre><code class="lang-ini"><span class="hljs-section">[Unit]</span>
<span class="hljs-attr">Description</span>=Chatroom Server
<span class="hljs-attr">After</span>=network.target

<span class="hljs-section">[Service]</span>
<span class="hljs-attr">Type</span>=simple
<span class="hljs-attr">User</span>=chatroom
<span class="hljs-attr">WorkingDirectory</span>=/opt/chatroom
<span class="hljs-attr">ExecStart</span>=/opt/chatroom/server
<span class="hljs-attr">Restart</span>=<span class="hljs-literal">on</span>-failure
<span class="hljs-attr">RestartSec</span>=<span class="hljs-number">5</span>s

<span class="hljs-section">[Install]</span>
<span class="hljs-attr">WantedBy</span>=multi-user.target
</code></pre>
<h4 id="heading-understanding-the-configuration">Understanding the Configuration:</h4>
<p>The <code>[Unit]</code> section describes the service and its dependencies. <code>After=network.target</code> ensures the network is up before starting your chatroom.</p>
<p>The <code>[Service]</code> section defines how to run your server. <code>Type=simple</code> means systemd should just run the command and consider it started. <code>User=chatroom</code> runs the server as a dedicated user (not root) for security. <code>WorkingDirectory</code> sets where the server runs, which is important because your WAL and snapshot files are created relative to this directory.</p>
<p><code>Restart=on-failure</code> tells systemd to automatically restart your server if it crashes. <code>RestartSec=5s</code> waits 5 seconds before restarting, preventing rapid restart loops if there's a persistent problem.</p>
<p>The <code>[Install]</code> section makes your service start at boot when you enable it.</p>
<h4 id="heading-deploying-your-server">Deploying Your Server:</h4>
<p>First, build your server binary:</p>
<pre><code class="lang-bash">go build -o server cmd/server/main.go
</code></pre>
<p>Then copy it to the deployment location:</p>
<pre><code class="lang-bash">sudo mkdir -p /opt/chatroom
sudo cp server /opt/chatroom/
sudo mkdir -p /opt/chatroom/chatdata
</code></pre>
<p>Create a dedicated user for running the service:</p>
<pre><code class="lang-bash">sudo useradd -r -s /bin/<span class="hljs-literal">false</span> chatroom
sudo chown -R chatroom:chatroom /opt/chatroom
</code></pre>
<p>Enable and start the service:</p>
<pre><code class="lang-bash">sudo systemctl <span class="hljs-built_in">enable</span> chatroom
sudo systemctl start chatroom
</code></pre>
<p>Check that it's running:</p>
<pre><code class="lang-bash">sudo systemctl status chatroom
</code></pre>
<p>You can view logs with:</p>
<pre><code class="lang-bash">sudo journalctl -u chatroom -f
</code></pre>
<p>The <code>-f</code> flag follows the logs in real-time, similar to <code>tail -f</code>.</p>
<h3 id="heading-how-to-use-docker">How to Use Docker</h3>
<p>Docker packages your application with all its dependencies, making it easy to deploy anywhere that runs Docker.</p>
<p>Create a <code>Dockerfile</code>:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> golang:<span class="hljs-number">1.23</span>-alpine AS builder
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
<span class="hljs-keyword">COPY</span><span class="bash"> go.mod go.sum ./</span>
<span class="hljs-keyword">RUN</span><span class="bash"> go mod download</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
<span class="hljs-keyword">RUN</span><span class="bash"> go build -o server cmd/server/main.go</span>

<span class="hljs-keyword">FROM</span> alpine:latest
<span class="hljs-keyword">RUN</span><span class="bash"> apk --no-cache add ca-certificates</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /root/</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=builder /app/server .</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=builder /app/chatdata ./chatdata</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">9000</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"./server"</span>]</span>
</code></pre>
<h4 id="heading-understanding-the-dockerfile">Understanding the Dockerfile:</h4>
<p>This uses a multi-stage build. The first stage (<code>builder</code>) uses the full Go image to compile your server. The second stage uses a minimal Alpine Linux image and copies only the compiled binary. This keeps the final image small (about 20MB instead of 800MB).</p>
<p><code>EXPOSE 9000</code> documents which port the container uses. <code>CMD ["./server"]</code> specifies what command runs when the container starts.</p>
<p>Build and Run:</p>
<pre><code class="lang-bash">docker build -t chatroom .
docker run -p 9000:9000 -v $(<span class="hljs-built_in">pwd</span>)/chatdata:/root/chatdata chatroom
</code></pre>
<p>The <code>-p 9000:9000</code> maps port 9000 in the container to port 9000 on your host, making the chatroom accessible. The <code>-v $(pwd)/chatdata:/root/chatdata</code> mounts your local chatdata directory into the container, so messages persist even if you stop and remove the container.</p>
<h4 id="heading-running-in-production">Running in Production:</h4>
<p>For production, you'd typically use Docker Compose or Kubernetes. Here's a simple <code>docker-compose.yml</code>:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">'3.8'</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">chatroom:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">.</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"9000:9000"</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./chatdata:/root/chatdata</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span>
</code></pre>
<p>Run with:</p>
<pre><code class="lang-bash">docker-compose up -d
</code></pre>
<p>The <code>restart: unless-stopped</code> policy ensures your container restarts automatically if it crashes or if the Docker daemon restarts</p>
<h2 id="heading-enhancements-you-could-add">Enhancements You Could Add</h2>
<h3 id="heading-1-multi-room-support">1. Multi-Room Support</h3>
<p>You could add the concept of channels/rooms like this:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> ChatRoom <span class="hljs-keyword">struct</span> {
    rooms <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]*Room
}

<span class="hljs-keyword">type</span> Room <span class="hljs-keyword">struct</span> {
    name    <span class="hljs-keyword">string</span>
    clients <span class="hljs-keyword">map</span>[*Client]<span class="hljs-keyword">bool</span>
    history []Message
}
</code></pre>
<h3 id="heading-2-user-authentication">2. User Authentication</h3>
<p>You could replace simple usernames with proper authentication for added security:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
    ID           <span class="hljs-keyword">int</span>
    Username     <span class="hljs-keyword">string</span>
    PasswordHash <span class="hljs-keyword">string</span>
    Email        <span class="hljs-keyword">string</span>
    CreatedAt    time.Time
}
</code></pre>
<h3 id="heading-3-file-sharing">3. File Sharing</h3>
<p>You could allow users to upload files:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> FileMessage <span class="hljs-keyword">struct</span> {
    Message
    FileName <span class="hljs-keyword">string</span>
    FileSize <span class="hljs-keyword">int64</span>
    FileURL  <span class="hljs-keyword">string</span>
}
</code></pre>
<h3 id="heading-4-websocket-support">4. WebSocket Support</h3>
<p>You could add HTTP/WebSocket endpoint for web clients.</p>
<h3 id="heading-5-horizontal-scaling">5. Horizontal Scaling</h3>
<p>For massive scale, you could shard across multiple servers using Redis pub/sub or NATS for inter-server communication.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You've now built a production-ready distributed chatroom from scratch. This project demonstrates important distributed systems concepts including concurrency patterns, network programming, state management, persistence, and fault tolerance.</p>
<p>Additional resources:</p>
<ul>
<li><p><strong>Go Concurrency</strong>: "Concurrency in Go" by Katherine Cox-Buday</p>
</li>
<li><p><strong>Distributed Systems</strong>: "Designing Data-Intensive Applications" by Martin Kleppmann</p>
</li>
<li><p><strong>Networking</strong>: "Unix Network Programming" by Stevens</p>
</li>
</ul>
<p>The full source code is available on <a target="_blank" href="https://github.com/Caesarsage/distributed-system/tree/main/chatroom-with-broadcast">GitHub</a>. Feel free to open issues or contribute improvements.</p>
<p>As always, I hope you enjoyed this guide and learned something. If you want to stay connected or see more hands-on DevOps content, you can follow me on <a target="_blank" href="https://www.linkedin.com/in/destiny-erhabor">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Polars Library in Python for Data Analysis ]]>
                </title>
                <description>
                    <![CDATA[ In this article, I’ll give you a beginner-friendly introduction to the Polars library in Python. Polars is an open-source library, originally written in Rust, which makes data wrangling easier in Python. The syntax of Polars is very similar to Pandas... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-the-polars-library-in-python-for-data-analysis/</link>
                <guid isPermaLink="false">6939b88a5a4b3354fde8c07b</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ python beginner ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Polars ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dataset ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dataframe ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sara Jadhav ]]>
                </dc:creator>
                <pubDate>Wed, 10 Dec 2025 18:14:34 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765325732081/94ab547b-fdaf-41bb-ae60-ad03be31211a.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, I’ll give you a beginner-friendly introduction to the Polars library in Python.</p>
<p>Polars is an open-source library, originally written in Rust, which makes data wrangling easier in Python. The syntax of Polars is very similar to Pandas, so if you’ve worked with Pandas or the PySpark library before, using Polars should be a breeze.</p>
<p>Polars excels at giving fast results. It’s also memory efficient and helps you optimize your code using parallelism. It also lets you convert data from and to various libraries like NumPy, Pandas, and others.</p>
<p>In this tutorial, we’ll be learning about the Polars Library from absolute scratch, from installing and importing the library on the system, to manipulating data in a dataset with the help of this library.</p>
<p>First, we’ll look at Polars basic functions. We’ll be also writing some practical code, which will help you apply what you’ve learned. Finally, we’ll be working with an example dataset to solidify some more key Polars concepts. Let’s dive in.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-installing-and-importing-the-polars-library">Installing and Importing the Polars Library</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-series">What is a Series?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-dataframe">What is a DataFrame?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-read-csv-files-with-polars">How to Read CSV Files with Polars</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-some-other-important-functions">Some other Important Functions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Even though this tutorial is beginner-friendly, having some basic knowledge of the following areas will help you understand this article better:</p>
<ul>
<li><p>Basic Python syntax</p>
</li>
<li><p>Data structures</p>
</li>
<li><p>Ability to import libraries and knowledge of using functions and methods</p>
</li>
<li><p>Basics of NumPy and Pandas will come in handy (not necessary).</p>
</li>
</ul>
<p>Now, that you’re aware of the prior requirements to follow along, let’s get started with our tutorial.</p>
<h2 id="heading-installing-and-importing-the-polars-library">Installing and Importing the Polars Library</h2>
<p>To install the Polars library, you can use the following command in your terminal:</p>
<p><code>pip install polars</code></p>
<p>Now, this works if you already have the pip package manager on your system. If you’re on a conda environment, you can work with this:</p>
<p><code>conda install -c conda-forge polars</code></p>
<p>But I strongly recommend using the pip package manager to avoid various inconveniences.</p>
<p>Let’s import Polars in our program. We’ll follow the same process as we use for importing other libraries in Python:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl <span class="hljs-comment"># pl is a conventional alias</span>
</code></pre>
<p>While creating a Polars object with the data, it’s important to know the size of our data. Polars has the capacity to have 2³² rows in the DataFrame. To load more data, use the following command to install the Polars library:</p>
<p><code>pip install polars[rt64]</code></p>
<p>If you want to use the Polars library right away without actually installing it on your system, using a Google Colab notebook is the best option. When using a Google Colab Notebook, you can directly import and start using Polars in your program. I’ll be using Google Colab Notebook for this tutorial.</p>
<h2 id="heading-what-is-a-series">What is a Series?</h2>
<p>A series is a fundamental element of a DataFrame. It’s a 1-dimensional data-structure that you can correlate with a ‘list’ in Python or a ‘1-D array’ in NumPy. But the difference between a series and a 1-D array is that the former is labeled while the later is not. Many series come together to form a DataFrame.</p>
<p>We can create a series with homogenous data as well as heterogenous data.</p>
<h3 id="heading-creating-a-series-with-homogenous-data">Creating a Series with Homogenous Data</h3>
<p>In a series, the datatype of all the elements should be the same. If it’s not, an error is thrown.</p>
<p>The syntax to define a Polars series is as follows:</p>
<p><code>var_name = pl.Series(“column_name”, [values])</code></p>
<p>The following code shows an example of a homogenous series definition in Python:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
series_homo = pl.Series(<span class="hljs-string">"Numbers"</span>, [<span class="hljs-string">'One'</span>, <span class="hljs-string">'Two'</span>, <span class="hljs-string">'Three'</span>, <span class="hljs-string">'Four'</span>, <span class="hljs-string">'Five'</span>])
print(series_homo)
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (5,)
Series: 'Numbers' [str]
[
    "One"
    "Two"
    "Three"
    "Four"
    "Five"
]
</code></pre>
<p>In the above code, we first imported the Polars library using the <code>pl</code> alias to start using it throughout the code. Using aliases is a matter of choice, but <code>pl</code> is a conventional one (like <code>np</code> for NumPy and <code>pd</code> for Pandas). The benefit of using conventional aliases is that when you hand over the code to someone else, it’s easy for them to follow along.</p>
<p>Next, we used the <code>pl.Series()</code> function to create a Polars series object. As its first parameter, we passed the label for our series (<code>Numbers</code> in this case). Then we passed the values to be stores in the form of a list. Remember that the list of values that we pass acts as a single argument. Finally, we printed our series.</p>
<p>We can see that the output tells us about the dimensions of the the Polars object as well as the datatype of the series. The shape (rows, columns) tells us about the the number of rows and columns present in the Polars object.</p>
<p>We can find the data-type of a homogenous series explicitly by using the <code>dtype</code> method.</p>
<pre><code class="lang-python">print(series_homo.dtype)
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">String
</code></pre>
<h3 id="heading-creating-a-series-with-heterogenous-data">Creating a Series with Heterogenous Data</h3>
<p>Heterogenous data means that the data-type of all the elements is not the same. The syntax to define a series with heterogenous data is as follows:</p>
<p><code>var_name = pl.Series(“Column_name”, [values], strict=False)</code></p>
<p>So you’re probably wondering, based on what I said above: how can we have a series with heterogenous data? Well, one thing to note is that a series is always homogenous irrespective of the data that is fed to it. I’ll explain below - first let’s look at this code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl

series_hetero = pl.Series(<span class="hljs-string">"Numbers"</span>, [<span class="hljs-number">1</span>, <span class="hljs-string">"Two"</span>, <span class="hljs-number">3</span>, <span class="hljs-string">"Four"</span>], strict=<span class="hljs-literal">False</span>)
print(series_hetero)
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (4,)
Series: 'Numbers' [str]
[
    "1"
    "Two"
    "3"
    "Four"
]
</code></pre>
<p>Here, we created a series object using the <code>pl.Series()</code> function, labelled it, and passed the values that we want in our series.</p>
<p>But you’ll notice that we have provided heterogenous data (data that doesn’t have the same datatype) to the function. Usually, this throws an error. But as we have set the <code>strict</code> parameter as False, the function now becomes lenient with the schema of the series. (The schema is just the expected data-type of the values that are to be recorded in the series.)</p>
<p>If no particular schema is defined for a series that’s fed heterogenous data, <code>pl.Series()</code> sets the schema to <code>pl.Utf8</code> (string datatype). You can see this automatic fixing of the schema in the above example. This prevents the program from bugging, as a string datatype can comprehend characters – numbers as well as symbols.</p>
<p>Also, we can see that datatype of all elements is the same (<code>pl.Utf8</code>). This means that the series is homogenous, even though we put heterogenous data in it.</p>
<p>If we define a schema for the series, then the Polars library converts all the records – which show a different datatype than the defined schema – to null objects. This should be clear in the following example:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-comment"># defined the schema as Integer bit 32</span>
series = pl.Series(<span class="hljs-string">"ints"</span>, [<span class="hljs-number">1</span>, <span class="hljs-number">-2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'Thirteen'</span>, <span class="hljs-string">'Fourteen'</span>], dtype=pl.Int32, strict=<span class="hljs-literal">False</span>)
print(series)
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (7,)
Series: 'ints' [i32]
[
    1
    -2
    3
    4
    5
    null
    null
]
</code></pre>
<p>Here, we can see that the last two entities were ‘String’, but since we set the schema as ‘Integer’, they were reflected as null records.</p>
<p>So as you can see, the leniency of the program depends on whether you set the <code>strict</code> parameter to True of False. If we set it as True, we enforce the schema to the data strictly. Upon failing to obey the schema, the program raises an exception. On the other hand, if we set the <code>strict</code> parameter as False, the series still preserves its homogenous nature by turning schema-disobeying elements to null.</p>
<p>Now that you understand how series work, we’re ready to move on to DataFrames.</p>
<h2 id="heading-what-is-a-dataframe">What is a DataFrame?</h2>
<p>A DataFrame is a two-dimensional data structure that you can use to store large numbers of related parameters of the collected data. It’s also useful for analyzing that data. A DataFrame is nothing more than the collection of many series, each labelled differently to store different aspects of data.</p>
<p>Here’s the syntax to create a Polars DataFrame object:</p>
<p><code>var_name = pl.DataFrame({key: value pairs}, schema)</code></p>
<p>The following example shows you how to define a DataFrame object in Python:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

schema = {<span class="hljs-string">"Number"</span>: pl.UInt32, <span class="hljs-string">"Natural Log"</span>: <span class="hljs-literal">None</span>, <span class="hljs-string">"Log Base 10"</span>: <span class="hljs-literal">None</span>}

df = pl.DataFrame(
    {
        <span class="hljs-string">"Number"</span> : np.arange(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>),
        <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)],
        <span class="hljs-string">'Log Base 10'</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)]
        },
    schema=schema
    )
print(df)
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (10, 3)
┌────────┬─────────────┬─────────────┐
│ Number ┆ Natural Log ┆ Log Base 10 │
│ ---    ┆ ---         ┆ ---         │
│ u32    ┆ f64         ┆ f64         │
╞════════╪═════════════╪═════════════╡
│ 1      ┆ 0.0         ┆ 0.0         │
│ 2      ┆ 0.693147    ┆ 0.30103     │
│ 3      ┆ 1.098612    ┆ 0.477121    │
│ 4      ┆ 1.386294    ┆ 0.60206     │
│ 5      ┆ 1.609438    ┆ 0.69897     │
│ 6      ┆ 1.791759    ┆ 0.778151    │
│ 7      ┆ 1.94591     ┆ 0.845098    │
│ 8      ┆ 2.079442    ┆ 0.90309     │
│ 9      ┆ 2.197225    ┆ 0.954243    │
│ 10     ┆ 2.302585    ┆ 1.0         │
└────────┴─────────────┴─────────────┘
</code></pre>
<p>Above, we created a Polars DataFrame object with the <code>pl.DataFrame()</code> function. In the function, we created a dictionary as an argument for passing the values of the DataFrame.</p>
<p>In the dictionary, each key-value pair represents a series. Each key represents the label of the series, whereas its value represent the values of the series. The values are passed in the form of a list as each key can map to only one value.</p>
<p>Then we defined the schema for the DataFrame. Again, the schema is a dictionary, where each key-value pair corresponds to the schema of the series. In the schema, every key represents the label of the series (to map the schema to the correct series) and its value represents the schema.</p>
<p>In the output, we can see that we got a nice table representing our data. The labels are neatly separated from the data and below them, their schema is also represented.</p>
<h3 id="heading-what-is-a-schema">What is a Schema?</h3>
<p>A schema refers to the definition of the datatype of the series. We fix a particular datatype to the homogenous series to avoid getting in mixed-data.</p>
<p>For example, in the above code, we set the datatype of the column <code>Number</code> to <code>Unsigned Integer - 32 bit (pl.UInt32)</code> as we don’t want to put negative integers in our NumPy logarithm function.</p>
<p>Now, if we want to hide the datatype (that’s written below each label), we can use the following function:</p>
<pre><code class="lang-python">pl.Config.set_tbl_hide_column_data_types(active=<span class="hljs-literal">True</span>)
</code></pre>
<h3 id="heading-the-head-tail-and-glimpse-functions">The Head, Tail, and Glimpse Functions</h3>
<p>The <code>head()</code>, <code>tail()</code> and <code>glimpse()</code> functions are used to have a quick look at the data by reviewing certain records (rows). These are useful especially for large datasets for taking a look at the data, for example to see which columns are present, what type of data is present in each column, and so on.</p>
<p>The <code>head()</code> function prints the given number of rows (passed as the argument of the <code>head()</code> function) from the top of the DataFrame. If no argument is passed, it prints the first five rows of the DataFrame.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

schema = {<span class="hljs-string">"Number"</span>: pl.UInt32, <span class="hljs-string">"Natural Log"</span>: <span class="hljs-literal">None</span>, <span class="hljs-string">"Log Base 10"</span>: <span class="hljs-literal">None</span>}

df = pl.DataFrame(
    {
        <span class="hljs-string">"Number"</span> : np.arange(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>),
        <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)],
        <span class="hljs-string">'Log Base 10'</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)]
        },
    schema=schema
    )
pl.Config.set_tbl_hide_column_data_types(active=<span class="hljs-literal">True</span>)
print(df.head(<span class="hljs-number">3</span>))
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (3, 3)
┌────────┬─────────────┬─────────────┐
│ Number ┆ Natural Log ┆ Log Base 10 │
╞════════╪═════════════╪═════════════╡
│ 1      ┆ 0.0         ┆ 0.0         │
│ 2      ┆ 0.693147    ┆ 0.30103     │
│ 3      ┆ 1.098612    ┆ 0.477121    │
└────────┴─────────────┴─────────────┘
</code></pre>
<p>In this example, we have the used the same DataFrame that we just created. Then we used the <code>head()</code> function to output the first three rows of the DataFrame. Also, you may now notice that the schema representation under column names has disappeared. This is because we used <code>pl.Config.set_tbl_hide_column_data_types(active=True)</code>.</p>
<p>The <code>glimpse()</code> function presents the data briefly and in a horizontal manner (rows are represented as columns and columns are represented as rows) for better readability.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

schema = {<span class="hljs-string">"Number"</span>: pl.UInt32, <span class="hljs-string">"Natural Log"</span>: <span class="hljs-literal">None</span>, <span class="hljs-string">"Log Base 10"</span>: <span class="hljs-literal">None</span>}

df = pl.DataFrame(
    {
        <span class="hljs-string">"Number"</span> : np.arange(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>),
        <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)],
        <span class="hljs-string">'Log Base 10'</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)]
        },
    schema=schema
    )
pl.Config.set_tbl_hide_column_data_types(active=<span class="hljs-literal">True</span>)
print(df.glimpse())
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">Rows: 10
Columns: 3
$ Number      &lt;u32&gt; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
$ Natural Log &lt;f64&gt; 0.0, 0.6931471805599453, 1.0986122886681098, 1.3862943611198906, 1.6094379124341003, 1.791759469228055, 1.9459101490553132, 2.0794415416798357, 2.1972245773362196, 2.302585092994046
$ Log Base 10 &lt;f64&gt; 0.0, 0.3010299956639812, 0.47712125471966244, 0.6020599913279624, 0.6989700043360189, 0.7781512503836436, 0.8450980400142568, 0.9030899869919435, 0.9542425094393249, 1.0

None
</code></pre>
<p>Here, we used the <code>glimpse()</code> function on our previously created DataFrame <code>df</code>. We can see the output as our transposed DataFrame. Also, <code>None</code> is returned. This is because, by default, <code>glimpse()</code> sets its <code>return_as_string</code> parameter to <code>None</code>. To change it to string, we can set the <code>return_as_string</code> parameter to True. The following example shows how to do it:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

schema = {<span class="hljs-string">"Number"</span>: pl.UInt32, <span class="hljs-string">"Natural Log"</span>: <span class="hljs-literal">None</span>, <span class="hljs-string">"Log Base 10"</span>: <span class="hljs-literal">None</span>}

df = pl.DataFrame(
    {
        <span class="hljs-string">"Number"</span> : np.arange(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>),
        <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)],
        <span class="hljs-string">'Log Base 10'</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)]
        },
    schema=schema
    )
pl.Config.set_tbl_hide_column_data_types(active=<span class="hljs-literal">True</span>)
print(<span class="hljs-string">f'Returned as String: \n<span class="hljs-subst">{df.glimpse(return_as_string=<span class="hljs-literal">True</span>)}</span>'</span>)
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">Returned as String: 
Rows: 10
Columns: 3
$ Number      &lt;u32&gt; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
$ Natural Log &lt;f64&gt; 0.0, 0.6931471805599453, 1.0986122886681098, 1.3862943611198906, 1.6094379124341003, 1.791759469228055, 1.9459101490553132, 2.0794415416798357, 2.1972245773362196, 2.302585092994046
$ Log Base 10 &lt;f64&gt; 0.0, 0.3010299956639812, 0.47712125471966244, 0.6020599913279624, 0.6989700043360189, 0.7781512503836436, 0.8450980400142568, 0.9030899869919435, 0.9542425094393249, 1.0
</code></pre>
<p>In the above code, we can see that the DataFrame is returned as a string and <code>None</code> is not returned.</p>
<p>Finally, the <code>tail()</code> function outputs the given number of rows (passed as the argument of the <code>tail()</code> function) from the bottom of the dataset. When no argument is passed, it outputs the last 5 rows by default.</p>
<p>This is useful for checking if our data was completely loaded. Checking the first few records using the <code>head()</code> function and the last few records with the <code>tail()</code> function ensures that the data is correctly and totally loaded.</p>
<p>Also, we can check if there are any empty records at the end of the dataset. Having empty records at the end of the dataset can be fatal in some cases. For example, if you have to train an ML model on a dataset and you split the dataset statically into testing and training datasets, the empty rows at the end are going to cause an issue. So, checking our data beforehand is a best practice, and these functions help us do it.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

schema = {<span class="hljs-string">"Number"</span>: pl.UInt32, <span class="hljs-string">"Natural Log"</span>: <span class="hljs-literal">None</span>, <span class="hljs-string">"Log Base 10"</span>: <span class="hljs-literal">None</span>}

df = pl.DataFrame(
    {
        <span class="hljs-string">"Number"</span> : np.arange(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>),
        <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)],
        <span class="hljs-string">'Log Base 10'</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)]
        },
    schema=schema
    )
pl.Config.set_tbl_hide_column_data_types(active=<span class="hljs-literal">True</span>)
print(df.tail(<span class="hljs-number">3</span>))
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (3, 3)
┌────────┬─────────────┬─────────────┐
│ Number ┆ Natural Log ┆ Log Base 10 │
╞════════╪═════════════╪═════════════╡
│ 8      ┆ 2.079442    ┆ 0.90309     │
│ 9      ┆ 2.197225    ┆ 0.954243    │
│ 10     ┆ 2.302585    ┆ 1.0         │
└────────┴─────────────┴─────────────┘
</code></pre>
<p>In the above code, we used the <code>tail()</code> function on the dataset (that we created earlier) and passed ‘3’ as our argument. Thus our program returned the last three rows of the dataset.</p>
<h3 id="heading-the-sample-function">The Sample Function</h3>
<p>The <code>sample()</code> function returns a given number of random rows in random order based on their occurrence in the DataFrame. This helps to avoid biased sampling of data.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

schema = {<span class="hljs-string">"Number"</span>: pl.UInt32, <span class="hljs-string">"Natural Log"</span>: <span class="hljs-literal">None</span>, <span class="hljs-string">"Log Base 10"</span>: <span class="hljs-literal">None</span>}

df = pl.DataFrame(
    {
        <span class="hljs-string">"Number"</span> : np.arange(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>),
        <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)],
        <span class="hljs-string">'Log Base 10'</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)]
        },
    schema=schema
    )
pl.Config.set_tbl_hide_column_data_types(active=<span class="hljs-literal">True</span>)
print(df.sample(<span class="hljs-number">3</span>))
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (3, 3)
┌────────┬─────────────┬─────────────┐
│ Number ┆ Natural Log ┆ Log Base 10 │
╞════════╪═════════════╪═════════════╡
│ 6      ┆ 1.791759    ┆ 0.778151    │
│ 5      ┆ 1.609438    ┆ 0.69897     │
│ 10     ┆ 2.302585    ┆ 1.0         │
└────────┴─────────────┴─────────────┘
</code></pre>
<p>We can see in the output that we got random rows of the data in a random order of their occurrence in the dataset (row 5 comes before row 6 in the DataFrame, yet by sampling we got row 5 after row 6.) Sampling is a good practice as it helps avoid overfitting in ML in some cases and gives us a general idea about the entire dataset.</p>
<h3 id="heading-concatenating-two-dataframes">Concatenating Two DataFrames</h3>
<p>In a nutshell, ‘concatenating’ simply means ‘linking’. Adding or linking one dataset to another – basically, stacking one on top of another – is concatenating the two datasets.</p>
<p>For example, in the previous DataFrame, we had numbers from 1 to 10 and their logarithms. Now, if we want to make it 1 to 20, we have to concatenate a different dataset containing numbers 11 to 20 to the former dataset.</p>
<p>The following code shows how this works:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

schema = {<span class="hljs-string">"Number"</span>: pl.UInt32, <span class="hljs-string">"Natural Log"</span>: <span class="hljs-literal">None</span>, <span class="hljs-string">"Log Base 10"</span>: <span class="hljs-literal">None</span>}

df = pl.DataFrame(
    {
        <span class="hljs-string">"Number"</span> : np.arange(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>),
        <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)],
        <span class="hljs-string">'Log Base 10'</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)]
        },
    schema=schema
    )
pl.Config.set_tbl_hide_column_data_types(active=<span class="hljs-literal">True</span>)

<span class="hljs-comment"># new dataset created for concatenation</span>
df1 = pl.DataFrame({
    <span class="hljs-string">"Number"</span> : [x <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">11</span>, <span class="hljs-number">21</span>)],
    <span class="hljs-string">"Log Base 10"</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">11</span>,<span class="hljs-number">21</span>)],
    <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">11</span>, <span class="hljs-number">21</span>)]
}, schema=schema)

print(pl.concat([df, df1], how=<span class="hljs-string">'vertical'</span>)) <span class="hljs-comment"># concatenating the two datasets</span>
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (20, 3)
┌────────┬─────────────┬─────────────┐
│ Number ┆ Natural Log ┆ Log Base 10 │
╞════════╪═════════════╪═════════════╡
│ 1      ┆ 0.0         ┆ 0.0         │
│ 2      ┆ 0.693147    ┆ 0.30103     │
│ 3      ┆ 1.098612    ┆ 0.477121    │
│ 4      ┆ 1.386294    ┆ 0.60206     │
│ 5      ┆ 1.609438    ┆ 0.69897     │
│ …      ┆ …           ┆ …           │
│ 16     ┆ 2.772589    ┆ 1.20412     │
│ 17     ┆ 2.833213    ┆ 1.230449    │
│ 18     ┆ 2.890372    ┆ 1.255273    │
│ 19     ┆ 2.944439    ┆ 1.278754    │
│ 20     ┆ 2.995732    ┆ 1.30103     │
└────────┴─────────────┴─────────────┘
</code></pre>
<p>In this code, we first created the DataFrame <code>df</code>. Then we created another DataFrame <code>df1</code>. Next, we used <code>pl.concat()</code> to concatenate the DataFrames.</p>
<p>The first argument that we passed is the list of the DataFrames that are to be linked. The <code>how</code> parameter defines the manner of concatenation. ‘Vertical’ in this context means that we are linking DataFrames vertically (adding more rows).</p>
<p>The important thing to note here is that schema incompatibility may raise an exception. If the DataFrames that are to be concatenated have different schemas, there will be a schema incompatibility problem. So it’s better to keep the schemas of both the datasets (that are to be concatenated) the same.</p>
<p>Here, we introduced a variable named <code>schema</code> containing the schema parameter of the DataFrame and we applied it to both the DataFrames to avoid schema incompatibility.</p>
<p>Also, concatenation occurs in the order of the passed arguments. For example, in the above code, <code>df</code> appears prior to <code>df1</code>, thus in the linked DataFrame, <code>df</code> appears first and then <code>df1</code>. If we had changed the sequence of values, the concatenated DataFrame would start from <code>df1</code> and then <code>df</code>.</p>
<p>The following code explains that:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

schema = {<span class="hljs-string">"Number"</span>: pl.UInt32, <span class="hljs-string">"Natural Log"</span>: <span class="hljs-literal">None</span>, <span class="hljs-string">"Log Base 10"</span>: <span class="hljs-literal">None</span>}

df = pl.DataFrame(
    {
        <span class="hljs-string">"Number"</span> : np.arange(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>),
        <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)],
        <span class="hljs-string">'Log Base 10'</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)]
        },
    schema=schema
    )
pl.Config.set_tbl_hide_column_data_types(active=<span class="hljs-literal">True</span>)

<span class="hljs-comment"># new dataset created for concatenation</span>
df1 = pl.DataFrame({
    <span class="hljs-string">"Number"</span> : [x <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">11</span>, <span class="hljs-number">21</span>)],
    <span class="hljs-string">"Log Base 10"</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">11</span>,<span class="hljs-number">21</span>)],
    <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">11</span>, <span class="hljs-number">21</span>)]
}, schema=schema)

print(pl.concat([df1, df], how=<span class="hljs-string">'vertical'</span>)) <span class="hljs-comment"># sequence changed from [df,df1] to [df1, df]</span>
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (20, 3)
┌────────┬─────────────┬─────────────┐
│ Number ┆ Natural Log ┆ Log Base 10 │
╞════════╪═════════════╪═════════════╡
│ 11     ┆ 2.397895    ┆ 1.041393    │
│ 12     ┆ 2.484907    ┆ 1.079181    │
│ 13     ┆ 2.564949    ┆ 1.113943    │
│ 14     ┆ 2.639057    ┆ 1.146128    │
│ 15     ┆ 2.70805     ┆ 1.176091    │
│ …      ┆ …           ┆ …           │
│ 6      ┆ 1.791759    ┆ 0.778151    │
│ 7      ┆ 1.94591     ┆ 0.845098    │
│ 8      ┆ 2.079442    ┆ 0.90309     │
│ 9      ┆ 2.197225    ┆ 0.954243    │
│ 10     ┆ 2.302585    ┆ 1.0         │
└────────┴─────────────┴─────────────┘
</code></pre>
<p>Here, we can see that the <code>df1</code> appears first and then <code>df</code> appears (unlike the previous example). Thus, the sequence of the values matters.</p>
<h3 id="heading-how-to-join-two-dataframes">How to Join Two DataFrames</h3>
<p><strong>Joining</strong> datasets and <strong>concatenating</strong> datasets are two different concepts. While concatenating means ‘linking’ two separate datasets, <a target="_blank" href="https://www.freecodecamp.org/news/understanding-sql-joins/">joining</a> refers to combining datasets based on a shared column (a key).<br>The computer matches rows from both datasets where the key values are the same.</p>
<p>In the above dataset ‘df’, we’ll add a new column by joining the dataset ‘df’ with another DataFrame.</p>
<pre><code class="lang-python"><span class="hljs-comment"># new dataframe</span>
new_col = pl.DataFrame({
    <span class="hljs-string">"Number"</span> : [x <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>)],
    <span class="hljs-string">"Log Base 2"</span> : [np.log2(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>)]
})

new_data = df.join(new_col, on=<span class="hljs-string">"Number"</span>, how=<span class="hljs-string">"left"</span>) <span class="hljs-comment"># Both have one column same to map values</span>

print(new_data.head())
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (5, 4)
┌────────┬─────────────┬─────────────┬────────────┐
│ Number ┆ Natural Log ┆ Log Base 10 ┆ Log Base 2 │
╞════════╪═════════════╪═════════════╪════════════╡
│ 1      ┆ 0.0         ┆ 0.0         ┆ 0.0        │
│ 2      ┆ 0.693147    ┆ 0.30103     ┆ 1.0        │
│ 3      ┆ 1.098612    ┆ 0.477121    ┆ 1.584963   │
│ 4      ┆ 1.386294    ┆ 0.60206     ┆ 2.0        │
│ 5      ┆ 1.609438    ┆ 0.69897     ┆ 2.321928   │
└────────┴─────────────┴─────────────┴────────────┘
</code></pre>
<p>In this example, we used the join function on <code>df</code> and passed <code>new_col</code> as its argument. This is why the columns of the <code>df</code> function occur prior to the column of the <code>new_col</code> dataset. The parameter <code>on</code> should be given a column name on the basis of which the two datasets are to be joined.</p>
<p>Here, we first mapped the elements of the column <code>Number</code> and its corresponding rows and joined the DataFrames accordingly.</p>
<p>If we used the <code>join()</code> function on the <code>new_col</code> DataFrame, the columns of <code>df</code> would appear later than the column in <code>new_col</code>. The following code will make it clear:</p>
<pre><code class="lang-python"><span class="hljs-comment"># new dataframe</span>
new_col = pl.DataFrame({
    <span class="hljs-string">"Number"</span> : [x <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>)],
    <span class="hljs-string">"Log Base 2"</span> : [np.log2(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>)]
})

new_data = new_col.join(df, on=<span class="hljs-string">"Number"</span>, how=<span class="hljs-string">"left"</span>) <span class="hljs-comment"># passed df as argument</span>

print(new_data.head())
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (5, 4)
┌────────┬────────────┬─────────────┬─────────────┐
│ Number ┆ Log Base 2 ┆ Natural Log ┆ Log Base 10 │
╞════════╪════════════╪═════════════╪═════════════╡
│ 1      ┆ 0.0        ┆ 0.0         ┆ 0.0         │
│ 2      ┆ 1.0        ┆ 0.693147    ┆ 0.30103     │
│ 3      ┆ 1.584963   ┆ 1.098612    ┆ 0.477121    │
│ 4      ┆ 2.0        ┆ 1.386294    ┆ 0.60206     │
│ 5      ┆ 2.321928   ┆ 1.609438    ┆ 0.69897     │
└────────┴────────────┴─────────────┴─────────────┘
</code></pre>
<p>You can notice that the column ‘Log Base 2’ appears prior to other columns (unlike in the previous example). Thus this change is significant.</p>
<h3 id="heading-how-to-use-the-withcolumns-function">How to Use the <code>with_columns()</code> Function</h3>
<p>The <code>with_columns()</code> function enables us to make changes to the column and print it as a new column with existing columns from the original dataset. This is similar to the <code>join()</code> function.</p>
<p>The following example will make it clear:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

df = pl.DataFrame(
    {
        <span class="hljs-string">"Number"</span> : np.arange(<span class="hljs-number">1</span>, <span class="hljs-number">11</span>),
        <span class="hljs-string">"Natural Log"</span> : [np.log(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)],
        <span class="hljs-string">'Log Base 10'</span> : [np.log10(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)]
        },
    schema=schema
    )
new_data = df.with_columns((np.log2(pl.col(<span class="hljs-string">"Number"</span>))).alias(<span class="hljs-string">"Log Base 2"</span>))

print(new_data.head())
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (5, 4)
┌────────┬─────────────┬─────────────┬────────────┐
│ Number ┆ Natural Log ┆ Log Base 10 ┆ Log Base 2 │
╞════════╪═════════════╪═════════════╪════════════╡
│ 1      ┆ 0.0         ┆ 0.0         ┆ 0.0        │
│ 2      ┆ 0.693147    ┆ 0.30103     ┆ 1.0        │
│ 3      ┆ 1.098612    ┆ 0.477121    ┆ 1.584963   │
│ 4      ┆ 1.386294    ┆ 0.60206     ┆ 2.0        │
│ 5      ┆ 1.609438    ┆ 0.69897     ┆ 2.321928   │
└────────┴─────────────┴─────────────┴────────────┘
</code></pre>
<p>In this example, we have a DataFrame <code>df</code>. To add a column to it , we use the <code>with_columns()</code> function. In this function, we selected column named ‘Number’ using the <code>pl.col()</code> function and put it inside the <code>np.log2()</code> to get the log base 2 value for every record. Finally, to label the new column, we used the <code>alias()</code> function, with the label passed to it as an argument.</p>
<p>Now that we know about the basics of DataFrames, let’s look at how we can work with CSV files.</p>
<h2 id="heading-how-to-read-csv-files-with-polars">How to Read CSV Files with Polars</h2>
<p>Reading CSV files with Polars is extremely similar to how it works in Pandas. For this tutorial, I’ll be using the Titanic Dataset. Here’s the <a target="_blank" href="https://www.kaggle.com/datasets/yasserh/titanic-dataset?select=Titanic-Dataset.csv">link to the dataset</a> so you can download it. In this part of the tutorial, we’ll be mainly talking about column selection (useful in feature selection) and filtering the data.</p>
<p>Here’s the syntax for reading a CSV file:</p>
<p><code>var_name = pl.read_csv(“path_dataset“)</code></p>
<p>Example code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl

data = pl.read_csv(<span class="hljs-string">"/titanic_dataset.csv"</span>)
print(data.head())
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (5, 12)
┌─────────────┬──────────┬────────┬─────────────────────┬───┬─────────┬─────────┬───────┬──────────┐
│ PassengerId ┆ Survived ┆ Pclass ┆ Name                ┆ … ┆ Ticket  ┆ Fare    ┆ Cabin ┆ Embarked │
╞═════════════╪══════════╪════════╪═════════════════════╪═══╪═════════╪═════════╪═══════╪══════════╡
│ 892         ┆ 0        ┆ 3      ┆ Kelly, Mr. James    ┆ … ┆ 330911  ┆ 7.8292  ┆ null  ┆ Q        │
│ 893         ┆ 1        ┆ 3      ┆ Wilkes, Mrs. James  ┆ … ┆ 363272  ┆ 7.0     ┆ null  ┆ S        │
│             ┆          ┆        ┆ (Ellen Need…        ┆   ┆         ┆         ┆       ┆          │
│ 894         ┆ 0        ┆ 2      ┆ Myles, Mr. Thomas   ┆ … ┆ 240276  ┆ 9.6875  ┆ null  ┆ Q        │
│             ┆          ┆        ┆ Francis             ┆   ┆         ┆         ┆       ┆          │
│ 895         ┆ 0        ┆ 3      ┆ Wirz, Mr. Albert    ┆ … ┆ 315154  ┆ 8.6625  ┆ null  ┆ S        │
│ 896         ┆ 1        ┆ 3      ┆ Hirvonen, Mrs.      ┆ … ┆ 3101298 ┆ 12.2875 ┆ null  ┆ S        │
│             ┆          ┆        ┆ Alexander (Helg…    ┆   ┆         ┆         ┆       ┆          │
└─────────────┴──────────┴────────┴─────────────────────┴───┴─────────┴─────────┴───────┴──────────┘
</code></pre>
<p>We can get the statistical analysis of the data by using the <code>describe()</code> function.</p>
<pre><code class="lang-python">print(data.describe())
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (9, 13)
┌────────────┬─────────────┬──────────┬──────────┬───┬─────────────┬───────────┬───────┬──────────┐
│ statistic  ┆ PassengerId ┆ Survived ┆ Pclass   ┆ … ┆ Ticket      ┆ Fare      ┆ Cabin ┆ Embarked │
╞════════════╪═════════════╪══════════╪══════════╪═══╪═════════════╪═══════════╪═══════╪══════════╡
│ count      ┆ 418.0       ┆ 418.0    ┆ 418.0    ┆ … ┆ 418         ┆ 417.0     ┆ 91    ┆ 418      │
│ null_count ┆ 0.0         ┆ 0.0      ┆ 0.0      ┆ … ┆ 0           ┆ 1.0       ┆ 327   ┆ 0        │
│ mean       ┆ 1100.5      ┆ 0.363636 ┆ 2.26555  ┆ … ┆ null        ┆ 35.627188 ┆ null  ┆ null     │
│ std        ┆ 120.810458  ┆ 0.481622 ┆ 0.841838 ┆ … ┆ null        ┆ 55.907576 ┆ null  ┆ null     │
│ min        ┆ 892.0       ┆ 0.0      ┆ 1.0      ┆ … ┆ 110469      ┆ 0.0       ┆ A11   ┆ C        │
│ 25%        ┆ 996.0       ┆ 0.0      ┆ 1.0      ┆ … ┆ null        ┆ 7.8958    ┆ null  ┆ null     │
│ 50%        ┆ 1101.0      ┆ 0.0      ┆ 3.0      ┆ … ┆ null        ┆ 14.4542   ┆ null  ┆ null     │
│ 75%        ┆ 1205.0      ┆ 1.0      ┆ 3.0      ┆ … ┆ null        ┆ 31.5      ┆ null  ┆ null     │
│ max        ┆ 1309.0      ┆ 1.0      ┆ 3.0      ┆ … ┆ W.E.P. 5734 ┆ 512.3292  ┆ G6    ┆ S        │
└────────────┴─────────────┴──────────┴──────────┴───┴─────────────┴───────────┴───────┴──────────┘
</code></pre>
<h3 id="heading-how-to-select-columns-from-the-dataset">How to Select Columns from the Dataset</h3>
<p>Now we’re going to learn how to select certain columns from the dataset and transform those columns into a new DataFrame. This can be useful if we want to train an ML model based on only certain columns and not the entire dataset (that is, using feature selection).</p>
<p>Let’s first look at the code below:</p>
<pre><code class="lang-python">new_df = data.select(
    pl.col(<span class="hljs-string">"Survived"</span>),
    pl.col(<span class="hljs-string">"Name"</span>),
    pl.col(<span class="hljs-string">"Age"</span>),
    pl.col(<span class="hljs-string">"Sex"</span>)
)

print(new_df.head())
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (5, 4)
┌──────────┬─────────────────────────────────┬──────┬────────┐
│ Survived ┆ Name                            ┆ Age  ┆ Sex    │
╞══════════╪═════════════════════════════════╪══════╪════════╡
│ 0        ┆ Kelly, Mr. James                ┆ 34.5 ┆ male   │
│ 1        ┆ Wilkes, Mrs. James (Ellen Need… ┆ 47.0 ┆ female │
│ 0        ┆ Myles, Mr. Thomas Francis       ┆ 62.0 ┆ male   │
│ 0        ┆ Wirz, Mr. Albert                ┆ 27.0 ┆ male   │
│ 1        ┆ Hirvonen, Mrs. Alexander (Helg… ┆ 22.0 ┆ female │
└──────────┴─────────────────────────────────┴──────┴────────┘
</code></pre>
<p>In the code above, we selected four columns using the <code>select()</code> and <code>pl.col()</code> functions from the Titanic Dataset and transformed them into a new DataFrame called <code>new_df</code>.</p>
<p>Now, we can filter this data however we want. Let’s make a new DataFrame by filtering out only surviving passengers from the dataset:</p>
<pre><code class="lang-python">survived_data = data.select(
    pl.col(<span class="hljs-string">"Survived"</span>),
    pl.col(<span class="hljs-string">"Name"</span>),
    pl.col(<span class="hljs-string">"Age"</span>),
    pl.col(<span class="hljs-string">"Sex"</span>)
).filter(pl.col(<span class="hljs-string">"Survived"</span>)==<span class="hljs-number">1</span>)

print(survived_data.head())
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (5, 4)
┌──────────┬─────────────────────────────────┬──────┬────────┐
│ Survived ┆ Name                            ┆ Age  ┆ Sex    │
╞══════════╪═════════════════════════════════╪══════╪════════╡
│ 1        ┆ Wilkes, Mrs. James (Ellen Need… ┆ 47.0 ┆ female │
│ 1        ┆ Hirvonen, Mrs. Alexander (Helg… ┆ 22.0 ┆ female │
│ 1        ┆ Connolly, Miss. Kate            ┆ 30.0 ┆ female │
│ 1        ┆ Abrahim, Mrs. Joseph (Sophie H… ┆ 18.0 ┆ female │
│ 1        ┆ Snyder, Mrs. John Pillsbury (N… ┆ 23.0 ┆ female │
└──────────┴─────────────────────────────────┴──────┴────────┘
</code></pre>
<p>In the above code, we used the <code>filter()</code> function. This function helps us gather data that applies to our given condition. In the above example, we added the condition that, “Every element in the column named ‘Survived’ should be equal to 1”. Hence, we got our required data.</p>
<h2 id="heading-some-other-important-functions">Some Other Important Functions</h2>
<h3 id="heading-how-to-print-the-names-of-the-columns-of-a-dataset">How to Print the Names of the Columns of a Dataset</h3>
<p>You can print the names of a column using the <code>columns</code> method. The following code shows how to use the columns method:</p>
<pre><code class="lang-python">print(data.columns) <span class="hljs-comment"># data --&gt; Titanic Dataset</span>
</code></pre>
<p><strong>Output:</strong></p>
<blockquote>
<p>['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked']</p>
</blockquote>
<h3 id="heading-how-to-index-a-dataset">How to Index a Dataset</h3>
<p>Indexing a dataset means adding an index column to the existing dataset. It can prove useful in keeping track of the rows of the dataset.</p>
<p>We can index the dataset using the <code>with_row_index()</code> function. Inside this function, we can pass the argument to name this new index column. If we don’t pass any argument, the index column name is set as ‘index’ by default.</p>
<pre><code class="lang-python">data = pl.read_csv(<span class="hljs-string">"/titanic_dataset.csv"</span>).with_row_index(<span class="hljs-string">'#'</span>) <span class="hljs-comment"># naming the index column as '#'</span>
print(data.head())
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (5, 13)
┌─────┬─────────────┬──────────┬────────┬───┬─────────┬─────────┬───────┬──────────┐
│ #   ┆ PassengerId ┆ Survived ┆ Pclass ┆ … ┆ Ticket  ┆ Fare    ┆ Cabin ┆ Embarked │
│ --- ┆ ---         ┆ ---      ┆ ---    ┆   ┆ ---     ┆ ---     ┆ ---   ┆ ---      │
│ u32 ┆ i64         ┆ i64      ┆ i64    ┆   ┆ str     ┆ f64     ┆ str   ┆ str      │
╞═════╪═════════════╪══════════╪════════╪═══╪═════════╪═════════╪═══════╪══════════╡
│ 0   ┆ 892         ┆ 0        ┆ 3      ┆ … ┆ 330911  ┆ 7.8292  ┆ null  ┆ Q        │
│ 1   ┆ 893         ┆ 1        ┆ 3      ┆ … ┆ 363272  ┆ 7.0     ┆ null  ┆ S        │
│ 2   ┆ 894         ┆ 0        ┆ 2      ┆ … ┆ 240276  ┆ 9.6875  ┆ null  ┆ Q        │
│ 3   ┆ 895         ┆ 0        ┆ 3      ┆ … ┆ 315154  ┆ 8.6625  ┆ null  ┆ S        │
│ 4   ┆ 896         ┆ 1        ┆ 3      ┆ … ┆ 3101298 ┆ 12.2875 ┆ null  ┆ S        │
└─────┴─────────────┴──────────┴────────┴───┴─────────┴─────────┴───────┴──────────┘
</code></pre>
<h3 id="heading-how-to-rename-columns-in-the-dataset">How to Rename Columns in the Dataset</h3>
<p>Lastly, to rename columns in the Dataset, we use the <code>rename()</code> function.</p>
<pre><code class="lang-python">data = pl.read_csv(<span class="hljs-string">"/titanic_dataset.csv"</span>).with_row_index(<span class="hljs-string">'#'</span>).rename({<span class="hljs-string">'PassengerId'</span>:<span class="hljs-string">'renamed_col'</span>})
print(data.head())
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-plaintext">shape: (5, 13)
┌─────┬─────────────┬──────────┬────────┬───┬─────────┬─────────┬───────┬──────────┐
│ #   ┆ renamed_col ┆ Survived ┆ Pclass ┆ … ┆ Ticket  ┆ Fare    ┆ Cabin ┆ Embarked │
│ --- ┆ ---         ┆ ---      ┆ ---    ┆   ┆ ---     ┆ ---     ┆ ---   ┆ ---      │
│ u32 ┆ i64         ┆ i64      ┆ i64    ┆   ┆ str     ┆ f64     ┆ str   ┆ str      │
╞═════╪═════════════╪══════════╪════════╪═══╪═════════╪═════════╪═══════╪══════════╡
│ 0   ┆ 892         ┆ 0        ┆ 3      ┆ … ┆ 330911  ┆ 7.8292  ┆ null  ┆ Q        │
│ 1   ┆ 893         ┆ 1        ┆ 3      ┆ … ┆ 363272  ┆ 7.0     ┆ null  ┆ S        │
│ 2   ┆ 894         ┆ 0        ┆ 2      ┆ … ┆ 240276  ┆ 9.6875  ┆ null  ┆ Q        │
│ 3   ┆ 895         ┆ 0        ┆ 3      ┆ … ┆ 315154  ┆ 8.6625  ┆ null  ┆ S        │
│ 4   ┆ 896         ┆ 1        ┆ 3      ┆ … ┆ 3101298 ┆ 12.2875 ┆ null  ┆ S        │
└─────┴─────────────┴──────────┴────────┴───┴─────────┴─────────┴───────┴──────────┘
</code></pre>
<p>In the above example, we renamed the column named ‘PassengerId’ to ‘renamed_col’.</p>
<h2 id="heading-summary">Summary</h2>
<p>Now you know how to work with the Polars Python library to analyze your data more effectively.</p>
<p>In this article, you learned:</p>
<ul>
<li><p>What Polars is and how to install it</p>
</li>
<li><p>How to define series and DataFrames in Polars</p>
</li>
<li><p>Different functions to deal with DataFrames.</p>
</li>
<li><p>How to read and work with CSV files in Polars</p>
</li>
</ul>
<p>Thanks for Reading, and happy data wrangling!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Vibe Coding Effectively as a Dev ]]>
                </title>
                <description>
                    <![CDATA[ It may seem like everyone is a vibe coder these days, and prompting seemed like it would become the new coding. But is this AI-generated code really deployable? Bragging on social media about a clever script is one thing, but pushing a vibe coded app... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-vibe-coding-effectively-as-a-dev/</link>
                <guid isPermaLink="false">6925deb0b459e862808eb04c</guid>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vibe coding ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ankur Tyagi ]]>
                </dc:creator>
                <pubDate>Tue, 25 Nov 2025 16:52:00 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1764089459731/0122c0b7-08e2-434a-b5eb-518025401951.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>It may seem like everyone is a vibe coder these days, and prompting seemed like it would become the new coding. But is this AI-generated code really deployable?</p>
<p>Bragging on social media about a clever script is one thing, but pushing a vibe coded app to prod comes with many security risks.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758881769141/9bedc585-5608-4660-a304-bbb10f10b8f2.png" alt="Vibe-debug, vibe-refactor, and vibe-check" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>With so many AI dev tools out there now, <a target="_blank" href="https://www.freecodecamp.org/news/how-to-perform-code-reviews-in-tech-the-painless-way/">code reviews</a> become more critical than ever.</p>
<p>This article will explore what <strong>vibe coding</strong> means and how code reviews should adapt in the era of AI.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents:</strong></h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-vibe-coding">What is Vibe Coding?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-vibe-coding-in-practice">How to Implement Vibe Coding in Practice</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-isnt-vibe-coded-output-production-ready">Why isn’t Vibe Coded Output Production Ready?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-context-gaps-are-the-first-crack">Context gaps are the first crack.</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-those-gaps-lead-directly-to-integration-blind-spots">Those gaps lead directly to integration blind spots.</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-most-serious-risk-is-security-by-omission">The most serious risk is security by omission.</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-testing-and-correctness-evidence-are-thin">Testing and correctness evidence are thin.</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-operability-lags-behind">Operability lags behind.</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-guidelines-for-ai-code-reviews">Guidelines for AI Code Reviews</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-code-review-process-in-vibe-coding">Code Review Process in Vibe Coding</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-checklist-for-reviewing-ai-generated-code">Checklist for Reviewing AI Generated Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-work-effectively-with-ai-tools">How to Work Effectively with AI Tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-what-is-vibe-coding">What is Vibe Coding?</h2>
<p>In early 2025, AI researcher <a target="_blank" href="https://x.com/karpathy">Andrej Karpathy</a> popularized the term vibe coding to describe a new way of development in which you “fully give in to the vibes” and let AI write code while you focus on high level intent.</p>
<p>A developer expresses their desired functionality in plain language, and an AI system (like an <a target="_blank" href="https://en.wikipedia.org/wiki/Large_language_model">LLM</a>) generates the source code to implement it.</p>
<p>This code-by-prompt approach allows even beginners to produce working code without deep knowledge of programming languages. Karpathy joked that with advanced IDE agents (like <a target="_blank" href="https://www.devtoolsacademy.com/blog/cursor-vs-windsurf/">Cursor’s</a> Composer mode), “I barely even touch the keyboard... I ‘Accept All’ always, I don’t read the diffs anymore... and it mostly works”.</p>
<p>So, vibe coding is coding by vibe and trusting AI to handle the heavy lifting.</p>
<h2 id="heading-how-to-implement-vibe-coding-in-practice">How to Implement Vibe Coding in Practice</h2>
<p>In practice, vibe coding usually involves using AI assistants and adapting your workflow to a more interactive, prompt-driven style.</p>
<p>Here’s an overview of how you can “vibe code” a project:</p>
<h3 id="heading-step-1-choose-an-ai-assistant">Step 1: Choose an AI assistant</h3>
<p>Select a development env that supports AI code generation. Popular choices include <a target="_blank" href="https://cursor.com/">Cursor</a> and <a target="_blank" href="https://github.com/features/copilot">GitHub Copilot</a>.</p>
<h3 id="heading-step-2-define-your-requirements">Step 2: Define your requirements</h3>
<p>Instead of writing boilerplate code, describe what you want to build. Provide AI with a specific prompt detailing functionality. The more <a target="_blank" href="https://www.philschmid.de/context-engineering">context</a> and detail you give, the better AI can fulfill your intent.</p>
<p>For example, when I ran an SEO inspection for my website, DevTools Academy, I used this prompt in Cursor:</p>
<blockquote>
<p>“Now, act as a senior product engineer and UX strategist. Evaluate and improve <a target="_blank" href="https://www.devtoolsacademy.com">https://www.devtoolsacademy.com</a> with a practical, no-fluff lens.</p>
<p>Scope:</p>
<ul>
<li><p>UX</p>
</li>
<li><p>SEO and technical SEO</p>
</li>
<li><p>Positioning and messaging</p>
</li>
<li><p>Copywriting and information architecture</p>
</li>
<li><p>What to add to stand out in the developer tools space.”</p>
</li>
</ul>
</blockquote>
<p>This prompt works well because it gives the AI a clear role, a defined scope, and a specific intent. AI knows it’s not just fixing SEO but also reviewing how the site communicates value to devs. That combination of clarity and context produces actionable insights instead of surface-level suggestions.</p>
<p>Below is a screenshot of that audit in progress and showing how I reviewed code, metadata, and UX recommendations side by side.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761258218099/91e93726-1a7d-4d1a-9839-531355037dfc.png" alt="cursor screenshot showing CodeRabbit reviewing a pull request with comments and summary." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You can checkout the full code on my open source <a target="_blank" href="https://github.com/tyaga001/devtoolsacademy">blog</a> here and check out closed PRs. This will help you learn how I use all these coding agents on a production ready app.</p>
<h3 id="heading-step-3-review-the-code">Step 3: Review the code</h3>
<p>AI will produce initial code based on your prompt. Think of this as a prototype – it’s not perfect. Run the code and see how it behaves.</p>
<p>Let’s look at an example: here, CodeRabbit is reviewing one of my <a target="_blank" href="https://github.com/tyaga001/devtoolsacademy/pull/145">pull requests</a> on GitHub. I had pushed a small fix to sort blog posts correctly and make sure the RSS feed reflects the latest publish date. Within seconds, CodeRabbit analyzed the diff, understood the intent behind my change, and explained exactly what the new code does.</p>
<p>It pointed out that the fix now sorts posts before mapping them, uses the sorted data for both items and the lastBuildDate, and ensures proper chronological order throughout the feed.</p>
<p>It’s like having a senior reviewer who not only checks syntax but also validates logic and confirms that your reasoning holds up.</p>
<p><a target="_blank" href="https://github.com/tyaga001/devtoolsacademy/pull/145"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758879621613/95bee1e7-3953-4416-b48b-e844332be950.png" alt="GitHub pull request showing CodeRabbit review comments on code changes with highlighted fixes." class="image--center mx-auto" width="600" height="400" loading="lazy"></a></p>
<p>This is just a reminder to expect imperfections. Vibe coding embraces a <em>“code first, refine later”</em> mindset. This means you get a working version quickly, then iteratively improve it. You might go through a few cycles of prompt -&gt; code -&gt; test -&gt; tweak.</p>
<h3 id="heading-step-4-validate-debug-polish">Step 4: Validate, debug, polish</h3>
<p>Once AI generated code meets your expectations, do a final review.</p>
<p>Throughout the process, the core idea is that you collaborate with the AI. The AI agent serves as a coding assistant, making real-time suggestions, automating tedious boilerplate, and even generating entire modules on your behalf.</p>
<h2 id="heading-why-isnt-vibe-coded-output-production-ready">Why Isn’t Vibe Coded Output Production Ready?</h2>
<p>Vibe coding moves fast: you describe intent, the AI produces something that runs, and you’re off to the next prompt. What’s missing is the slow, unglamorous work that usually turns a draft into shippable software, like shared context, architectural alignment, verification, and documentation.</p>
<p>AI generates plausible code based on patterns it has seen. But it doesn’t understand your team’s history, your system’s constraints, or the implicit rules that keep everything coherent over time.</p>
<p>That mismatch shows up the moment a “works on my machine” demo meets a real codebase.</p>
<p>Let’s explore the common pitfalls of vibe-coded code, so you’ll know what to watch for. Then, in the checklist section below, I’ll outline practical strategies to address or prevent each issue.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758271815928/5f763a0f-2dda-4318-8c19-0c9e58447abe.png" alt="AI is Limited by Context" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-context-gaps-are-the-first-crack">Context gaps are the first crack.</h3>
<p>AI only sees what you show it, so it’s easy for it to make the right local choice and the wrong global one: duplicating logic that already exists, choosing defaults that conflict with prior decisions, or introducing functions that don’t respect domain boundaries.</p>
<p>The result is code that looks reasonable in isolation but collides with existing assumptions and conventions once integrated.</p>
<h3 id="heading-those-gaps-lead-directly-to-integration-blind-spots">Those gaps lead directly to integration blind spots.</h3>
<p>Drafts often ignore the lived details of your environment – shared utilities, cross-cutting concerns, configuration, deployment hooks, and operational policies. Interfaces may line up at a glance and still fail at runtime because the draft doesn’t fit how your system composes modules, handles errors, or manages state across services.</p>
<h3 id="heading-the-most-serious-risk-is-security-by-omission">The most serious risk is security by omission.</h3>
<p>AI rarely includes robust input validation, clear authentication and authorization paths, or rate limiting unless you spell it out. Secrets handling and logging tend to be superficial or missing. That leaves common exposure points like request handlers, job processors, and webhook endpoints without the checks that prevent injection, SSRF, mass assignment, or data exfiltration.</p>
<p>Even when the surface looks tidy, the absence of explicit security controls means you’re trusting defaults you didn’t choose.</p>
<h3 id="heading-testing-and-correctness-evidence-are-thin">Testing and correctness evidence are thin.</h3>
<p>Quality suffers in quieter ways, too. Beyond “it runs,” there’s little to demonstrate behavior across edge cases or to guard against regressions.</p>
<p>Performance and scalability remain unknowns: extra network calls, N+1 patterns, and quadratic loops sneak in because nobody measured them. Dependencies and environments drift as versions aren’t pinned, infrastructure isn’t declared, and configuration lives only in the author’s head, making behavior differ across machines and CI.</p>
<h3 id="heading-operability-lags-behind">Operability lags behind.</h3>
<p>A lack of metrics, missing health/readiness probes, and no runbook make failures harder to detect and slower to recover from. Add in data quality and compliance concerns (PII handling, encoding assumptions, transitive license obligations), and you have code that demos well but isn’t ready for production’s reliability, security, and audit demands.</p>
<p>In short, vibe-coded output accelerates drafting but skips the shared understanding and evidence that make software safe to ship.</p>
<p>Until those gaps are closed, it’s a prototype, not a release.</p>
<h2 id="heading-guidelines-for-ai-code-reviews">Guidelines for AI Code Reviews</h2>
<p>Your team should keep pre-AI engineering standards as the bar, including security, tests, readability, maintainability, performance, and docs. AI should change how fast you gather the evidence for those standards, not how much evidence you require. In other words, use AI to accelerate the path to your existing bar, never to lower it.</p>
<p>Using AI, you can generate code at speed. But if reviews take the same amount of time (or more time), you lose some of the benefit. The goal isn’t to relax standards, it’s to shorten the time to prove you met them. That means layering in automation (tests, static analysis, secret scans, SCA) and AI-assisted review to catch obvious issues quickly so human reviewers can focus on intent, architecture, and risk.</p>
<p>Well-used assistants can help here. For example, tools like CodeRabbit, GitHub Copilot PR Reviewer, Claude Code, Cursor’s Bugbot, Graphite’s AI Review, and Greptile can highlight potential bugs, security gaps, style deviations, and mismatched intent, and summarize diffs for faster context. Treat these as accelerators for your existing process, not as replacements for judgment.</p>
<h3 id="heading-code-review-process-in-vibe-coding">Code Review Process in Vibe Coding</h3>
<p>The fundamentals of good code reviews haven’t changed – and in fact, they’re more critical now.</p>
<p>Below are some key principles to maintain speed without sacrificing quality.</p>
<h4 id="heading-1-trust-but-verify">1. Trust, but verify.</h4>
<p>A reviewer usually assumes the author understands the system. With vibe-coded output, the “author” may be an AI with limited context. If something looks odd or unnecessary, question it. Run the code, add/execute tests, or ask the developer/AI for clarification on intent and constraints.</p>
<h4 id="heading-2-dont-let-reviews-become-a-bottleneck">2. Don’t let reviews become a bottleneck.</h4>
<p>Vibe coding generates code quickly. If human review takes as long as hand-writing the change, you’ve erased the gain.</p>
<p>Combat this by front-loading automation: run unit/integration tests, static analysis (lint/SAST), secret scans, SCA, and basic perf checks in CI to clear the noise. Then reviewers spend their time on design trade-offs, boundary cases, and risk. The balance is: high standards, faster evidence.</p>
<h4 id="heading-3-use-ai-code-reviews-wisely">3. Use AI code reviews wisely</h4>
<p>AI can help review code just as it helps generate it. Modern “pair reviewer” tools scan a PR and surface likely bugs, security issues, missing tests, or style violations in minutes plus give natural-language summaries of the change.</p>
<p>Tools you can consider include CodeRabbit, GitHub Copilot PR Reviewer, Claude Code, Cursor Bugbot, Graphite, and Greptile. Many integrate with the CLI/IDE and GitHub/GitLab to leave actionable comments.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758272500586/a9cc891f-ab1a-47d8-a607-a772cbaef2e0.png" alt="coderabbit CLI" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Think of them as fast first-pass reviewers that increase coverage and consistency across PRs.</p>
<h4 id="heading-4-human-judgment-is-still-irreplaceable">4. Human judgment is still irreplaceable.</h4>
<p>Even the best AI reviewer is an assistant. Keep humans accountable for correctness, security posture, architectural fit, and user impact. A healthy pattern is AI first-pass &gt; human second-pass that inspects invariants, failure modes, and long-term maintainability.</p>
<h4 id="heading-5-maintain-a-high-bar-for-quality">5. Maintain a high bar for quality.</h4>
<p>It’s tempting to accept “it runs” when an AI wrote it. Don’t. Stakeholders still expect software to be robust, secure, and maintainable. Keep DRY, readability, and testability standards. Insist on input validation, authZ checks where relevant, and sensible logging/metrics. If you can’t provide evidence that you met the bar, you haven’t met it.</p>
<h4 id="heading-6-educate-and-document">6. Educate and document</h4>
<p>When reviewers find bugs or security flaws in AI-generated code, capture the lesson.</p>
<p>Update internal guides with patterns like “When generating handlers, validate and bound inputs, add rate limits, log request IDs, avoid N+1 queries, and sanitize user-visible output.” Over time, bake these into prompts, templates, repo scaffolds, and CI checks so the next AI draft starts closer to done.</p>
<h2 id="heading-checklist-for-reviewing-ai-generated-code">Checklist for Reviewing AI Generated Code</h2>
<p>Before approving any vibe-coded change, make the standards explicit and verifiable. Use this checklist to confirm behavior, security, performance, integration, and documentation so the draft you got from AI becomes code you can safely ship.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762510535966/85ea547a-f955-446b-9e22-965dc18f9e49.png" alt="Checklist for Reviewing AI Generated Code" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Here’s a checklist a human reviewer should go through before approving vibe-coded output:</p>
<h3 id="heading-1-define-the-codes-purpose-scope-amp-non-goals">1. Define the code’s purpose (scope &amp; non-goals).</h3>
<p>Be explicit about what this change does and does not do. Tie it to a user story/ticket and call out non-goals so “helpful” AI changes don’t creep in.</p>
<h3 id="heading-2-verify-x-and-y-behavior-and-edge-cases">2. Verify X and Y (behavior and edge cases).</h3>
<p>Be clear about what you’re verifying. For example, verify input parsing and pagination boundaries, verify that error paths return the correct status and body, and verify that database writes are idempotent. Run existing tests, add missing unit/integration tests, and reproduce edge inputs (empty, null, huge, unicode).</p>
<h3 id="heading-3-perform-code-quality-checks-readability-dry-refactor-needs">3. Perform code-quality checks (readability, DRY, refactor needs).</h3>
<p>AI often produces verbose or duplicated logic. Ensure names are meaningful, side effects are clearly stated, and duplication is removed or minimized. Run linters/formatters, collapse repetition, and extract helpers where they aid clarity.</p>
<h3 id="heading-4-analyze-organization-and-structure-make-sure-it-fits-the-architecture">4. Analyze organization and structure (make sure it fits the architecture).</h3>
<p>AI writes code in isolation. Confirm the change uses existing utilities, layers, and boundaries (domain/services/controllers/jobs). Check imports and module placement, avoid reinventing existing helpers, and align with repository conventions.</p>
<h3 id="heading-5-validate-inputs-and-assumptions-make-the-implicit-explicit">5. Validate inputs and assumptions (make the implicit explicit).</h3>
<p>List the assumptions the AI made (default locale/timezone, allowed ranges, required fields). Add schema validation (DTO/class validators/JSON Schema). Empty, null, over-max, non-ASCII, unexpected enum, malicious strings. And finally, enforce limits/timeouts.</p>
<h3 id="heading-6-perform-security-audits-minimum-pass">6. Perform security audits (minimum pass).</h3>
<ul>
<li><p><strong>AuthN/AuthZ:</strong> Confirm endpoint checks identity and authorization paths; deny-by-default.</p>
</li>
<li><p><strong>Inputs:</strong> Sanitize/validate inputs, prevent injection (SQL/NoSQL/command), and escape user-visible output.</p>
</li>
<li><p><strong>Secrets</strong>: No secrets in code/diff/logs, use env/secret manager, and rotate any test keys.</p>
</li>
<li><p><strong>Abuse controls:</strong> Add rate limits, size limits, and timeouts on network and disk operations. Run SAST/secret scan/SCA, and fix or justify findings.</p>
</li>
</ul>
<h3 id="heading-7-do-a-performance-evaluation-right-now-at-a-small-scale">7. Do a performance evaluation (right now, at a small scale).</h3>
<p>Look for N+1s, needless network calls, unbounded loops, quadratic sorts. Add a micro-benchmark or run a quick load test for hot paths. Set sensible cache/timeout/retry with jitter where applicable.</p>
<h3 id="heading-8-manage-dependencies-pin-justify-minimize">8. Manage dependencies (pin, justify, minimize).</h3>
<p>Review any new libraries. Are they necessary? Maintained? License compatible? Pin versions, add lockfiles, or remove unused transitive adds.</p>
<h3 id="heading-9-review-documentation-what-to-add-and-where">9. Review documentation (what to add and where).</h3>
<p>Ensure the docs are in line with the code. AI often changes some parts or adds code blocks at different places while resolving various issues. These changes might not make it into the docs.</p>
<h3 id="heading-10-observability-see-problems-early">10. Observability (see problems early).</h3>
<p>Use structured logs with request/trace IDs, key counters/timers (success/error/latency), health/readiness probes, and a basic dashboard or alert stub.</p>
<h3 id="heading-11-compliance-and-data-handling-when-applicable">11. Compliance and data handling (when applicable).</h3>
<p>Identify any personally identifiable information (PII), document collection/retention, ensure masking/redaction in logs, verify dependency licenses and data-residency constraints.</p>
<h2 id="heading-how-to-work-effectively-with-ai-tools">How to Work Effectively with AI Tools</h2>
<p>At this point, you can probably see why it’s very important to understand the actual skills involved in AI-assisted development.</p>
<p>There’s a pretty big difference between an experienced developer who uses AI tools to help them get more done, and a newbie who thinks AI can build the next Facebook or Google just with a simple prompt.</p>
<p>An inexperienced dev will ask AI something like "Hey, Build me Twitter and make no mistakes"</p>
<p>But an experienced developer who has a solid fundamentals might say say something like:</p>
<ul>
<li><p>"AI, we're building a Twitter replica. Use $SQL_Database, Use $Language, Avoid $Common_Pitfalls, Follow $Standard_Practices."</p>
</li>
<li><p>"The generated code is prone to X problem, implement this fix."</p>
</li>
<li><p>"Implementation of $X is flawed because of $Y, do $Z instead."</p>
</li>
</ul>
<p>So as you can see, you still need to know the how's and the why's and what depends on what. Often you’ll just need to make the changes manually, because it will be faster. And you don’t want to outsource the critical thinking part, which is the part that AI can't actually do.</p>
<p>LLMs are good at information retrieval. If you know nothing about what you’re looking for, then asking an AI isn’t going to be that helpful (or that reliable). But if you have an idea, some background knowledge/context, and the skills to verify AI’s responses, then it can be really helpful.</p>
<p>Last month, I shared in my <a target="_blank" href="https://bytesizedbets.com/">newsletter</a> how my current coding loop looks in practice.</p>
<p>I draft with Claude Code (or Copilot/Cursor), open a PR, and let an AI reviewer like CodeRabbit (or Copilot PR Reviewer / Cursor Bugbot or Greptile) do the first pass. CI runs tests and scans.</p>
<p>I repeat until everything’s green and the PR is ready to merge. It’s fast, but it’s still disciplined.</p>
<p>If you want to understand why this kind of workflow is becoming essential, read this article: <a target="_blank" href="https://bytesizedbets.com/p/era-of-ai-slop-cleanup-has-begun">Era of AI Slop Cleanup Has Begun</a>. I talk about what’s happening in AI-assisted engineering, where generating code is easy, but keeping it clean and production ready takes experience – and you must have good programming skills.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>AI-generated code can boost productivity – but production value still comes from software that is robust, secure, and maintainable.</p>
<p>Mindless code generation creates technical debt. But when you integrate AI thoughtfully, with guardrails, verification, tests, security checks, and documentation, you can go faster without lowering your standards.</p>
<p>That's it for this article. I hope you learned something new today.</p>
<p>If you have any questions about code reviews, engineering, startups, or business in general, please find me on Twitter: <a target="_blank" href="https://x.com/TheAnkurTyagi">@TheAnkurTyag</a>i. I’d be more than happy to discuss them.</p>
<h3 id="heading-want-to-read-more-interesting-articles-like-this">Want to read more interesting articles like this?</h3>
<p>You can read more about the latest dev tools like this one on my <a target="_blank" href="https://www.devtoolsacademy.com/">website</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The React Handbook for Beginners – JSX, Hooks, and Rendering Explained ]]>
                </title>
                <description>
                    <![CDATA[ React is one of the most powerful and widely used libraries for building user interfaces with JavaScript. From small components to large-scale front-end and full-stack applications, React gives you the flexibility to create interactive, efficient, an... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/react-handbook-for-beginners-learn-jsx-hooks-rendering/</link>
                <guid isPermaLink="false">68f95319417d2ee394355b66</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ coding ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwatobi Sofela ]]>
                </dc:creator>
                <pubDate>Wed, 22 Oct 2025 21:56:41 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761170169453/445fd0f5-54f9-4be5-bacf-2e6c6acd1f21.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>React is one of the most powerful and widely used libraries for building user interfaces with JavaScript. From small components to large-scale front-end and full-stack applications, React gives you the flexibility to create interactive, efficient, and modern features.</p>
<p>But learning React can feel overwhelming. With so many new terms, patterns, and frameworks like Next.js in the mix, it’s easy to feel lost.</p>
<p>That’s why this handbook focuses on React itself without unnecessary distractions. Once you’ve mastered React at its core, you’ll have the confidence to use it with or without frameworks to build anything you can imagine.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-you-should-already-know">What You Should Already Know</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-exactly-is-react">What Exactly Is React?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-why-the-react-name">Why the “React” name?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-is-react-a-framework">Is React a framework?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-is-react-only-for-web-development">Is React only for web development?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-whats-the-primary-goal-of-react">What’s the primary goal of React?</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-a-react-component-to-a-website">How to Add a React Component to a Website</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-create-a-new-project-directory">Create a new project directory</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-create-a-dom-container">Create a DOM container</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-import-react-babel-and-your-component">Import React, Babel, and your component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-create-your-component">Create your component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-configure-a-local-server">Configure a local server</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-jsx">What Is JSX?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-can-react-work-without-jsx">Can React work without JSX?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-1-create-a-react-element-with-jsx">Example 1: Create a React element with JSX</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-2-create-a-react-element-with-regular-javascript">Example 2: Create a React element with regular JavaScript</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-reactcreateelement">What Is React.createElement()?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-jsx">How to Use JSX</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-use-jsx-like-any-javascript-expression">Use JSX like any JavaScript expression</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrap-multi-line-jsx-in-parentheses">Wrap multi-line JSX in parentheses</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrap-expressions-in-curly-braces">Wrap expressions in curly braces</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-camelcase-to-name-attributes">Use camelCase to name attributes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-close-empty-jsx-tags-properly">Close empty JSX tags properly</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-a-react-component-can-return-only-a-single-element">A React component can return only a single element</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-time-to-practice-with-jsx">Time to Practice with JSX 🤸‍♂️🏋️‍♀️🏊‍♀️</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-the-solution">The solution</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-react-component">What Is a React Component?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-syntax-of-a-react-component">Syntax of a React component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-of-a-react-component">Example of a React component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-react-components-best-practices">React components best practices</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-render-lists-of-elements-from-an-array">How to Render Lists of Elements from an Array</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-each-react-element-in-an-array-needs-a-unique-key">Each React element in an array needs a unique key</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-unique-keys-to-each-react-element-in-an-array">How to add unique keys to each React element in an array</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-essential-things-to-know-about-assigning-keys">Essential things to know about assigning keys</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-handle-events-in-react">How to Handle Events in React</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-types-of-event-handlers">Types of event handlers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-inline-event-handler">Example: Inline event handler</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-referenced-event-handler">Example: Referenced event handler</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-react-state">What Is React State?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-syntax-of-react-state">Syntax of React state</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-of-react-state">Example of React state</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-react-trigger-vs-render-vs-commit-vs-paint">React trigger vs render vs commit vs paint</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-does-it-mean-to-trigger-a-render-in-react">What does it mean to trigger a render in React?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-does-it-mean-to-render-react-components">What does it mean to render React components?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-does-it-mean-to-commit-a-react-ui-to-the-browsers-dom">What does it mean to commit a React UI to the browser’s DOM?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-does-it-mean-to-paint-the-dom-nodes-on-the-screen">What does it mean to paint the DOM nodes on the screen?</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-react-ref-hook">What Is the React Ref Hook?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-syntax-of-the-react-ref-hook">Syntax of the React ref Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-of-the-react-ref-hook">Example of the React ref Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-react-ref-hook-best-ractices">React ref Hook best practices</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-variables-vs-refs-vs-states-in-react">Variables vs Refs vs States in React</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-do-variables-work-in-react">How do variables work in React?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-do-refs-work-in-react">How do refs work in React?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-do-states-work-in-react">How do states work in React?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tips-on-using-variables-refs-and-states-in-react">Tips on using variables, refs, and states in React</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-useeffect-hook">What Is the useEffect Hook?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-syntax-of-the-useeffect-hook">Syntax of the useEffect Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-of-the-useeffect-hook">Example of the useEffect Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-useeffect-hooks-best-practices">useEffect Hook’s best practices</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-style-react-components">How to Style React Components</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-use-css-style-sheets-to-style-react-elements">How to use CSS style sheets to style React elements</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-the-inline-style-attribute-to-style-react-elements">How to use the inline style attribute to style React elements</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-css-modules-to-style-react-elements">How to use CSS Modules to style React elements</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-a-css-in-js-library-to-style-react-elements">How to use a CSS-in-JS library to style React elements</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-overview">Overview</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-dive-deeper-into-react">Dive deeper into React</a></li>
</ul>
</li>
</ol>
<h2 id="heading-what-you-should-already-know">What You Should Already Know</h2>
<p>You will get the most value out of this handbook if you are familiar with:</p>
<ul>
<li><p>JavaScript fundamentals (variables, functions, arrays, objects)</p>
</li>
<li><p>Basic CSS for styling</p>
</li>
<li><p>HTML basics for structure</p>
</li>
</ul>
<p>If you’ve ever written a small JavaScript file or built a simple “Hello World” website, you are all set!</p>
<p>Let’s get started with the basics.</p>
<h2 id="heading-what-exactly-is-react">What Exactly Is React?</h2>
<p>React is a component-based JavaScript library for efficiently building user interfaces (UI).</p>
<p>No matter how massive or miniature your project may be, React is well-suited to help you develop any web application efficiently.</p>
<p>Developers primarily use React to build independent, reusable components that can be combined with other isolated user interfaces to create highly scalable applications. For instance, the image below illustrates the individual components of YouTube’s video player page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760577491945/1b0f8c61-b42e-4e3c-afdc-5804fdfa0d42.webp" alt="An Illustration of React Components. The YouTube video player page is illustrated as a combination of independent components." class="image--center mx-auto" width="3403" height="1936" loading="lazy"></p>
<p>In other words, React helps you build complex UIs from small, isolated components that can easily be reused in multiple applications. Each independent component tells React the exact element you want to display on screen.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760577104799/4592a7d2-e75b-4ae6-b1f4-65cfd8e94033.webp" alt="React explained: The super flexible JavaScript library for modern frontend and full-stack app development" class="image--center mx-auto" width="1920" height="1920" loading="lazy"></p>
<p>The image above illustrates React as a highly adaptable library that uses JavaScript functions to build user interfaces for both mobile and web-based applications. Let’s discuss the points highlighted in the image.</p>
<h3 id="heading-why-the-react-name">Why the “React” name?</h3>
<p>The name stems from the idea that React renders your UI and reacts to events in the user interface it has rendered on screen.</p>
<h3 id="heading-is-react-a-framework">Is React a framework?</h3>
<p>No, React is a <a target="_blank" href="https://codesweetly.com/framework-vs-library/">library—not a framework</a>. React serves only as an add-on feature to your application. It’s not designed to be used as an app’s primary support system.</p>
<h3 id="heading-is-react-only-for-web-development">Is React only for web development?</h3>
<p>No, you don’t just use React on the web. For instance, ReactDOM helps build web applications, and React Native helps build mobile applications.</p>
<h3 id="heading-can-react-be-used-for-full-stack-applications">Can React be used for full-stack applications?</h3>
<p>Absolutely. React is super flexible. You can use it in simple HTML projects, integrate it into existing code, or build complex full-stack applications. Its adaptability makes it suitable for a wide variety of development scenarios.</p>
<h3 id="heading-whats-the-primary-goal-of-react">What’s the primary goal of React?</h3>
<p>React’s primary goal is for you to use JavaScript functions to return and manage the UI (HTML element) you want to render (display) on the screen. For instance, consider the following:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DonationUserInterface</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>☕ Buy me a coffee<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
}
</code></pre>
<p>The JavaScript function above is a React component that returns the UI (HTML button element) we want to display on screen and manage with React. In fact, let’s implement the <code>DonationUserInterface</code> component on a live website using only HTML and JavaScript – no frameworks.</p>
<h2 id="heading-how-to-add-a-react-component-to-a-website">How to Add a React Component to a Website</h2>
<p>Follow the steps below to add a donation UI component to a live HTML website.</p>
<h3 id="heading-create-a-new-project-directory">Create a new project directory</h3>
<pre><code class="lang-bash">mkdir codesweetly-donation-ui-001
</code></pre>
<p><strong>Note:</strong> You can use any name you prefer. In this guide, we’ll use <code>codesweetly-donation-ui-001</code> for demonstration.</p>
<p>Afterward, navigate to your project directory using the command line.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> path/to/codesweetly-donation-ui-001
</code></pre>
<h3 id="heading-create-a-dom-container">Create a DOM container</h3>
<p>To add a React component to a webpage, you first need to specify the section of the page where you want to insert the UI. So, create an HTML page:</p>
<pre><code class="lang-bash">touch index.html
</code></pre>
<p>Afterward, open the new file and add the following code:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en-US"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>CodeSweetly Donation UI<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- A div container (the DOM node) created for React to manage --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"donation-ui"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The snippet above created a DOM node (<code>&lt;div&gt;</code> element), inside which we want React to display and manage a donation user interface. In other words, the <code>&lt;div&gt;</code> represents the website’s section you want React to manage.</p>
<p>Some notes:</p>
<ul>
<li><p>The <code>div</code>’s <code>id</code> attribute is the reference we’ll later use in a JavaScript file to find the container and tell React to insert a donation UI.</p>
</li>
<li><p>Although most developers use a <code>&lt;div&gt;</code> tag as the DOM container, you can use other HTML elements like the <code>&lt;main&gt;</code> tag.</p>
</li>
<li><p>You can have multiple DOM containers anywhere inside the <code>&lt;body&gt;</code> element.</p>
</li>
<li><p>A DOM container is usually left empty, as React will overwrite its content.</p>
</li>
</ul>
<h3 id="heading-import-react-babel-and-your-component">Import React, Babel, and your component</h3>
<p>Use script tags to load React, Babel, and your component into your project’s HTML page.</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en-US"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>CodeSweetly Donation UI<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Load the React Library --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react@18/umd/react.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Load the ReactDOM API --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react-dom@18/umd/react-dom.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Load the Babel Compiler --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/@babel/standalone/babel.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"donation-ui"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Load your React component --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/babel"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"DonationUserInterface.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The snippet above uses the first three script tags to load React, ReactDOM, and Babel from unpkg.com.</p>
<p>At the same time, we use the fourth script tag to import our donation component (which we will create in the following section).</p>
<p>Some notes:</p>
<ul>
<li><p>The <code>react</code> package is a library containing React’s core functionality for creating React components.</p>
</li>
<li><p>The ReactDOM API provides the required methods to use React with the DOM.</p>
</li>
<li><p>Babel is a compiler that transforms React code into plain JavaScript, as browsers don’t understand React syntax by default.</p>
</li>
<li><p>The <code>type="text/babel"</code> attribute tells Babel to automatically execute and convert the <code>DonationUserInterface.js</code> script from React code into plain JavaScript.</p>
</li>
<li><p>The setup above is recommended for learning React only. Don’t use it for public projects (production environment). You can learn how to set up React for production in my <a target="_blank" href="https://www.amazon.com/dp/B0FRC4R8T3?tag=codesweetly00-20">Code React Sweetly book</a>.</p>
</li>
<li><p>The scripts will not work if your internet or <code>unpkg.com</code>’s server is down. So, if nothing renders on-screen, enter each script’s <code>src</code> URL in your browser to confirm if the server responds successfully.</p>
</li>
</ul>
<h3 id="heading-create-your-component">Create your component</h3>
<p>Create a <code>DonationUserInterface.js</code> JavaScript file inside the same folder in which your HTML file is located.</p>
<pre><code class="lang-bash">touch DonationUserInterface.js
</code></pre>
<p>Then, paste the following code inside the JavaScript file you’ve just created:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DonationUserInterface</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [donate, setDonate] = React.useState(<span class="hljs-literal">false</span>);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createUserInterface</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (donate) {
      <span class="hljs-keyword">return</span> (
        <span class="xml"><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">"https://www.buymeacoffee.com/codesweetly"</span>&gt;</span>Support page<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>.
          Thank you so much! 🎉
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
      );
    }
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setDonate(true)}&gt;☕ Buy me a coffee<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
  }
  <span class="hljs-keyword">return</span> createUserInterface();
}

<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"donation-ui"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">DonationUserInterface</span> /&gt;</span></span>);
</code></pre>
<p>The snippet above does the following:</p>
<ol>
<li><p>Defines a component named <code>DonationUserInterface</code>.</p>
</li>
<li><p>Initializes the component’s state (built-in object) with the Boolean value <code>false</code>.</p>
</li>
<li><p>Programs the component to return a paragraph element if the state’s <code>donate</code> variable is <code>true</code>. Otherwise, it should return a button element.</p>
</li>
<li><p>Creates a <code>ReactDOMRoot</code> object instance for the <code>donation-ui</code> HTML element you want React to manage. Afterwards, it assigns the newly created instance to the <code>root</code> variable.</p>
</li>
<li><p>Uses the object instance’s <code>render()</code> method to display the <code>DonationUserInterface</code> component inside the root <code>donation-ui</code>.</p>
</li>
</ol>
<h3 id="heading-configure-a-local-server">Configure a local server</h3>
<p>HTML files containing <a target="_blank" href="https://codesweetly.com/javascript-modules-tutorial/">ES modules</a> work only through <code>http://</code> and <code>https://</code> URLs, not locally via a <code>file://</code> URL.</p>
<p>Since we previously used the <code>type="text/babel"</code> attribute to convert the <code>DonationUserInterface.js</code> JavaScript file to an ES module, we need a local server, like “Live Server” or “Servor,” to load the HTML document via an <code>http://</code> scheme. Let’s install Servor so we can use it for this project.</p>
<h4 id="heading-install-the-servor-local-server">Install the Servor local server</h4>
<pre><code class="lang-bash">npm install servor@4.0.2 --save-dev
</code></pre>
<h4 id="heading-run-your-app">Run your app</h4>
<p>After installing Servor, use it to start your app from your terminal:</p>
<pre><code class="lang-bash">npx servor --browse --reload
</code></pre>
<p>Some notes:</p>
<ul>
<li><p>Close the server using <kbd>Ctrl</kbd> + <kbd>C</kbd> on Windows or <kbd>Cmd</kbd> + <kbd>C</kbd> on Mac.</p>
</li>
<li><p><code>--browse</code>: Opens the browser once the server starts.</p>
</li>
<li><p><code>--reload</code>: Reloads the browser whenever you update the project’s files.</p>
</li>
<li><p>You can also add the <code>servor</code> command to the <code>"scripts"</code> field of your project’s <code>package.json</code> file:</p>
</li>
</ul>
<pre><code class="lang-json">{
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"servor --browse --reload"</span>
  },
  <span class="hljs-attr">"devDependencies"</span>: {
    <span class="hljs-attr">"servor"</span>: <span class="hljs-string">"^4.0.2"</span>
  }
}
</code></pre>
<p>By doing so, you can run your app from your terminal like this:</p>
<pre><code class="lang-bash">npm run start
</code></pre>
<p>And that’s it! You’ve successfully added a React component to a live website using a JavaScript function to render a donation UI on screen! 🎉</p>
<p>Are you asking why we’re writing HTML inside JavaScript? Well, that HTML-like code is called JSX. Let’s learn about it.</p>
<h2 id="heading-what-is-jsx">What Is JSX?</h2>
<p>JSX is a JavaScript syntax extension that allows you to build React elements with HTML-like syntax directly inside your JavaScript code.</p>
<p><strong>Tips:</strong></p>
<ul>
<li><p>JSX is sometimes called JavaScript XML or JavaScript Syntax eXtension.</p>
</li>
<li><p>While JSX looks a lot like HTML, it’s not HTML. Instead, it enables you to use HTML-like syntax along with all the strengths of JavaScript.</p>
</li>
</ul>
<h3 id="heading-can-react-work-without-jsx">Can React work without JSX?</h3>
<p>Yes. React can work independently of JSX. But JSX makes it easier to create user interfaces (UI).</p>
<p>In other words, whatever you can do with JSX, you can do the same with plain JavaScript. For instance, consider the two examples below. The first includes JSX syntax, while the second is regular JavaScript syntax.</p>
<h4 id="heading-example-1-create-a-react-element-with-jsx">Example 1: Create a React element with JSX</h4>
<p><code>MyBio.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyBio</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My name is Oluwatobi.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
}
<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">MyBio</span> /&gt;</span></span>);
</code></pre>
<p><code>index.html</code></p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en-US"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>MyBio App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react@18/umd/react.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react-dom@18/umd/react-dom.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/@babel/standalone/babel.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/babel"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"MyBio.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>In the React snippet above, <code>&lt;h1&gt;My name is Oluwatobi.&lt;/h1&gt;</code> and <code>&lt;MyBio /&gt;</code> are JSX.</p>
<p><strong>Tip:</strong> React supports the <code>.jsx</code> file extension for files with JSX code. So, if you prefer to differentiate your JSX files from JavaScript, you can rename <code>MyBio.js</code> to <code>MyBio.jsx</code>. Just note that choosing between using <code>.js</code> vs <code>.jsx</code> for files with JSX is entirely up to you. (Your JSX code is simply a syntactic sugar for the <code>React.createElement()</code> JavaScript call.)</p>
<h4 id="heading-example-2-create-a-react-element-with-regular-javascript">Example 2: Create a React element with regular JavaScript</h4>
<p><code>MyBio.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyBio</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> React.createElement(<span class="hljs-string">"h1"</span>, <span class="hljs-literal">null</span>, <span class="hljs-string">"My name is Oluwatobi."</span>);
}
<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(React.createElement(MyBio));
</code></pre>
<p><code>index.html</code></p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en-US"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>MyBio App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react@18/umd/react.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react-dom@18/umd/react-dom.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/@babel/standalone/babel.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/babel"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"MyBio.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Everything in the React snippet above is plain JavaScript code.</p>
<h2 id="heading-what-is-reactcreateelement">What Is React.createElement()?</h2>
<p><code>React.createElement()</code> is the JavaScript alternative to JSX. It is a method for creating React elements in regular JavaScript.</p>
<p>Browsers can’t read the JSX syntax. This is why we typically use tools like Babel, TypeScript, and Parcel to compile JSX to a <code>React.createElement(component, props, ...children)</code> JavaScript call.</p>
<p>For instance, <code>&lt;button className="support-btn"&gt;Buy me a coffee&lt;/button&gt;</code> will transform to <code>React.createElement("button", { className: "support-btn" }, "Buy me a coffee ")</code> at runtime.</p>
<p>Under the hood, the <code>React.createElement()</code> method creates a JavaScript object conventionally called “React element.”</p>
<p><strong>Tip:</strong> A React element is a JavaScript object that defines the user interface (UI) you want to render on screen.</p>
<p>A simplified version of a React element looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> myBioReactElement = {
  <span class="hljs-attr">type</span>: <span class="hljs-string">"h1"</span>,
  <span class="hljs-attr">props</span>: {
    <span class="hljs-attr">className</span>: <span class="hljs-literal">null</span>,
    <span class="hljs-attr">children</span>: <span class="hljs-string">"My name is Oluwatobi."</span>,
  },
};
</code></pre>
<p><code>React.createElement()</code> is best for projects that want to avoid compiling tools like Babel. Whereas JSX is a syntactic sugar that makes React code easier to read. So, you are free to choose the syntax that works best for you (but most React projects use JSX for its simplicity).</p>
<h2 id="heading-how-to-use-jsx">How to Use JSX</h2>
<p>The following tips will help you get up and running with JSX so you can use it in your React projects.</p>
<h3 id="heading-use-jsx-like-any-javascript-expression">Use JSX like any JavaScript expression</h3>
<p>You can use JSX like any other JavaScript expression because, at <a target="_blank" href="https://codesweetly.com/web-tech-terms-e/#execution-time">execution time</a>, JSX transpiles into regular JavaScript.</p>
<p>In other words, you can store JSX expressions in variables, use them in <code>if</code> statements, or make them the return value of functions.</p>
<p><strong>Example:</strong></p>
<p><code>DisplayMyName.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> firstName = <span class="hljs-literal">false</span>;
<span class="hljs-keyword">const</span> myFirstName = <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My first name is Oluwatobi.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
<span class="hljs-keyword">const</span> mylastName = <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My last name is Sofela.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DisplayMyName</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">if</span> (firstName) {
    <span class="hljs-keyword">return</span> myFirstName;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> mylastName;
  }
}
<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">DisplayMyName</span> /&gt;</span></span>);
</code></pre>
<p><code>index.html</code></p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en-US"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>DisplayMyName App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react@18/umd/react.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react-dom@18/umd/react-dom.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/@babel/standalone/babel.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/babel"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"DisplayMyName.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The React snippet above stores JSX code in variables. We also made it the return value of a function’s <code>if...else</code> statement.</p>
<h3 id="heading-wrap-multi-line-jsx-in-parentheses">Wrap multi-line JSX in parentheses</h3>
<p>Wrapping your JSX code in parentheses is best when it spans across multiple lines. Doing so will make your code readable and avoid the <a target="_blank" href="https://stackoverflow.com/questions/2846283/what-are-the-rules-for-javascripts-automatic-semicolon-insertion-asi">pitfalls of automatic semicolon insertion</a>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> myName = (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My name is Oluwatobi.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);
</code></pre>
<p>The snippet above wraps the <code>div</code> in parentheses because it spans multiple lines.</p>
<h3 id="heading-wrap-expressions-in-curly-braces">Wrap expressions in curly braces</h3>
<p>Suppose you wish to write JavaScript expressions in your JSX code. In that case, wrap the expression in curly braces like so:</p>
<p><code>ExpressionInJSX.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ExpressionInJSX</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>JSX makes it {10 * 3} times faster to build React UIs.<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>;
}
<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ExpressionInJSX</span> /&gt;</span></span>);
</code></pre>
<p><code>index.html</code></p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en-US"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>ExpressionInJSX App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react@18/umd/react.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react-dom@18/umd/react-dom.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/@babel/standalone/babel.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/babel"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"ExpressionInJSX.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p><strong>Tips:</strong></p>
<ul>
<li><p>React reads curly braces (<code>{...}</code>) in JSX code as a JavaScript expression.</p>
</li>
<li><p>Using curly braces to embed a JavaScript expression works only if you use it in either of two ways:</p>
<ol>
<li><p>Directly between the opening and closing JSX tags:</p>
<pre><code class="lang-xml"> <span class="hljs-tag">&lt;<span class="hljs-name">openingTag</span>&gt;</span>I have a {javaScriptExpression} content.<span class="hljs-tag">&lt;/<span class="hljs-name">closingTag</span>&gt;</span>
</code></pre>
</li>
<li><p>As the value of a JSX element’s attribute:</p>
<pre><code class="lang-xml"> <span class="hljs-tag">&lt;<span class="hljs-name">openingTag</span> <span class="hljs-attr">attribute</span>=<span class="hljs-string">{javaScriptExpression}</span>&gt;</span>I have a content<span class="hljs-tag">&lt;/<span class="hljs-name">closingTag</span>&gt;</span>
</code></pre>
</li>
</ol>
</li>
</ul>
<h3 id="heading-use-camelcase-to-name-attributes">Use camelCase to name attributes</h3>
<p>React uses <a target="_blank" href="https://codesweetly.com/naming-convention-explained/#what-is-camelcase">camelCase</a> for JSX attribute keys rather than the lowercase HTML attribute naming convention. This is because, under the hood, JSX compiles into plain JavaScript and, therefore, uses the JavaScript Web APIs.</p>
<p>In other words, instead of writing <code>readonly</code>, use <code>readOnly</code>. Likewise, instead of using <code>maxlength</code>, write <code>maxLength</code>. By doing so, React will gain access to JavaScript’s <code>readOnly</code> and <code>maxLength</code> Web APIs.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> myName = (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"about-me"</span>&gt;</span>My name is Oluwatobi.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);
</code></pre>
<h3 id="heading-close-empty-jsx-tags-properly">Close empty JSX tags properly</h3>
<p>React requires closing all JSX elements explicitly with <code>/&gt;</code>, including empty tags. For instance, you’ll need to write an HTML <code>&lt;img&gt;</code> element as <code>&lt;img /&gt;</code>.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> emptyJSXElement = <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Click me"</span> /&gt;</span></span>;
</code></pre>
<h3 id="heading-a-react-component-can-return-only-a-single-element">A React component can return only a single element</h3>
<p>Creating two or more JSX elements from a component requires wrapping them in a single parent element. Otherwise, React will throw an error. This is because React components return only a single element.</p>
<p><strong>Example:</strong></p>
<p><code>TwoInnerUIs.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TwoInnerUIs</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My name is Oluwatobi.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Buy me a coffee<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TwoInnerUIs</span> /&gt;</span></span>);
</code></pre>
<p><code>index.html</code></p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en-US"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>TwoInnerUIs App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react@18/umd/react.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react-dom@18/umd/react-dom.development.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/@babel/standalone/babel.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/babel"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"TwoInnerUIs.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>In the expression above, the <code>&lt;div&gt;</code> is a parent element containing two (2) inner tags.</p>
<p><strong>Tip:</strong> React allows using a <a target="_blank" href="https://react.dev/reference/react/Fragment">fragment</a> (empty tag) to group elements. Here’s an example:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TwoInnerUIs</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My name is Oluwatobi.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Buy me a coffee<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TwoInnerUIs</span> /&gt;</span></span>);
</code></pre>
<p>Fragments are a great way to return multiple elements without creating unnecessary tags in the HTML DOM.</p>
<h2 id="heading-time-to-practice-with-jsx">Time to Practice with JSX 🤸‍♂️🏋️‍♀️🏊‍♀️</h2>
<p>Here is your moment to practice the JSX concepts you’ve learned.</p>
<p>In this exercise, you will convert the regular JavaScript code below to its JSX equivalent:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SupportCodeSweetly</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> React.createElement(
    <span class="hljs-string">"div"</span>,
    { <span class="hljs-attr">className</span>: <span class="hljs-string">"support-ui"</span> },
    React.createElement(
      <span class="hljs-string">"a"</span>,
      {
        <span class="hljs-attr">id</span>: <span class="hljs-string">"support-link"</span>,
        <span class="hljs-attr">className</span>: <span class="hljs-string">"support-link"</span>,
        <span class="hljs-attr">target</span>: <span class="hljs-string">"_blank"</span>,
        <span class="hljs-attr">href</span>: <span class="hljs-string">"https://www.buymeacoffee.com/codesweetly"</span>,
      },
      <span class="hljs-string">"Buy me a coffee"</span>
    ),
    <span class="hljs-string">". Thank you!"</span>
  );
}

<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(React.createElement(SupportCodeSweetly));
</code></pre>
<p>Take a moment to try it yourself before looking at the solution below. Even if you have to try a couple times, go back and read the above tips, or google a few things, it’ll help you learn the concepts better.</p>
<p>Ok, now that you’ve tried…</p>
<h3 id="heading-the-solution">The solution:</h3>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SupportCodeSweetly</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"support-ui"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"support-link"</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"support-link"</span>
        <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>
        <span class="hljs-attr">href</span>=<span class="hljs-string">"https://www.buymeacoffee.com/codesweetly"</span>
      &gt;</span>
        Buy me a coffee
      <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      . Thank you!
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SupportCodeSweetly</span> /&gt;</span></span>);
</code></pre>
<p>The <code>SupportCodeSweetly</code> component returns the UI we want to display on-screen and manage with React. But what exactly is a React component?</p>
<h2 id="heading-what-is-a-react-component">What Is a React Component?</h2>
<p>A component in React is a class or function that accepts a single argument called <code>props</code> and returns an element (UI).</p>
<h3 id="heading-syntax-of-a-react-component">Syntax of a React component</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760626118056/8fb5818f-b39a-42c7-9399-1acc476604ee.webp" alt="React component syntax" class="image--center mx-auto" width="1920" height="1920" loading="lazy"></p>
<p>The above image illustrates the constituent parts of a React component:</p>
<ol>
<li><p>A JavaScript function with a Pascal case naming convention.</p>
</li>
<li><p>A props parameter, which is the only argument React components accept. (Tip: props is short for properties.)</p>
</li>
<li><p>The component’s body, where you place a sequence of statements like variables, hooks, and conditionals.</p>
</li>
<li><p>A return statement, which is used to output the user interface (UI) you want React to display on-screen. It can be any valid HTML element.</p>
</li>
<li><p>An invocator that executes the component to retrieve its user interface. The invocator can also pass arguments (props) to the component.</p>
</li>
</ol>
<h3 id="heading-example-of-a-react-component">Example of a React component</h3>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyBio</span>(<span class="hljs-params">props</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My name is {props.firstName}.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
}
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/jlj9lg?file=%2Fsrc%2Findex.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The code in the snippet above is a function component that accepts a single argument (props) and returns a React element.</p>
<h3 id="heading-react-components-best-practices">React components best practices</h3>
<p>When you’re working with components in React, there are a few best practices you should follow:</p>
<ul>
<li><p>Capitalize the first letter of your component’s name.</p>
</li>
<li><p>Don’t use bracket notation expressions in React component tags.</p>
</li>
<li><p>React components work best as pure functions.</p>
</li>
<li><p>Create components at the top level of your file.</p>
</li>
<li><p>Split long components into smaller chunks.</p>
</li>
</ul>
<p>As it’s common practice to use components to render a list of elements, let’s now discuss how to implement this optimally.</p>
<h2 id="heading-how-to-render-lists-of-elements-from-an-array">How to Render Lists of Elements from an Array</h2>
<p>Suppose you want to create a list of React elements from an array of data. You can use the JavaScript <a target="_blank" href="https://codesweetly.com/javascript-map-method/"><code>map()</code></a> method.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;

<span class="hljs-comment">// Define the bestColors array:</span>
<span class="hljs-keyword">const</span> bestColors = [<span class="hljs-string">"Blue"</span>, <span class="hljs-string">"White"</span>, <span class="hljs-string">"Pink"</span>];

<span class="hljs-comment">// Use the bestColors array to create a list of React elements:</span>
<span class="hljs-keyword">const</span> bestColorsLiElements = bestColors.map(<span class="hljs-function">(<span class="hljs-params">color</span>) =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>{color}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>);

<span class="hljs-comment">// Render the array of &lt;li&gt; elements to the root DOM:</span>
<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>{bestColorsLiElements}<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>);
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/dcwwqr?file=%2Fsrc%2Findex.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above used <code>map()</code> to create a new list of React elements by converting each of <code>bestColors</code> items to <code>&lt;li&gt;</code> elements.</p>
<p>Notice that we rendered the list of elements directly in the <code>root.render()</code> method. Typically, you would use a component to do such rendering. So, let’s do some refactoring by moving the <code>bestColorsLiElements</code> variable and the <code>&lt;ul&gt;</code> element into a component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BestColor</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Define the bestColors array:</span>
  <span class="hljs-keyword">const</span> bestColors = [<span class="hljs-string">"Blue"</span>, <span class="hljs-string">"White"</span>, <span class="hljs-string">"Pink"</span>];
  <span class="hljs-comment">// Use the bestColors array to create a list of React elements:</span>
  <span class="hljs-keyword">const</span> bestColorsLiElements = bestColors.map(<span class="hljs-function">(<span class="hljs-params">color</span>) =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>{color}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>);
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>{bestColorsLiElements}<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>;
}

<span class="hljs-comment">// Render the array of &lt;li&gt; elements to the root DOM:</span>
<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BestColor</span> /&gt;</span></span>);
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/pj62c3?file=%2Fsrc%2Findex.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>Although the snippet above displays the right content on the screen, it’s not efficient. So, React throws a console error. Let’s discuss the issue.</p>
<h3 id="heading-each-react-element-in-an-array-needs-a-unique-key">Each React element in an array needs a unique key</h3>
<p>If you check your console, you will see a warning message that says: <code>Each child in a list should have a unique "key" prop.</code></p>
<p>The message means that whenever you create an array of elements, React needs you to specify a unique identity for each item in the list.</p>
<p>The unique identity keys help React identify changes to the array.</p>
<p>Let’s refactor the previous snippet so that each element in the <code>bestColorsLiElements</code> has a unique <code>key</code> prop.</p>
<h3 id="heading-how-to-add-unique-keys-to-each-react-element-in-an-array">How to add unique keys to each React element in an array</h3>
<p>There are two common ways to assign unique keys to each element of an array. The first is the unrecommended way. While the second is the best technique, it is worth noting.</p>
<h4 id="heading-not-recommended-way-to-assign-keys-to-an-array-of-react-elements">Not recommended way to assign keys to an array of React elements</h4>
<p>One way to add unique keys is to use each item’s index as its <code>key</code> prop.</p>
<p><strong>Tip:</strong> By default, if you don’t provide a <code>key</code> prop, React uses each element’s index position in the array to identify them (<code>key=0</code>, <code>key=1</code>, and so on).</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BestColor</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> bestColors = [<span class="hljs-string">"Blue"</span>, <span class="hljs-string">"White"</span>, <span class="hljs-string">"Pink"</span>];
  <span class="hljs-comment">// Use each item's index as its key prop:</span>
  <span class="hljs-keyword">const</span> bestColorsLiElements = bestColors.map(<span class="hljs-function">(<span class="hljs-params">color, index</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>{color}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  ));
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>{bestColorsLiElements}<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>;
}

<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BestColor</span> /&gt;</span></span>);
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/yxp4sz?file=%2Fsrc%2Findex.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above specifies a <code>key</code> prop on each <code>&lt;li&gt;</code> element. It then uses each item’s <code>index</code> as the prop’s value.</p>
<p>But note that it’s best to avoid using indexes as a React element’s <code>key</code> prop. You should use it only as a last resort when you don’t have stable IDs.</p>
<p>Whenever you use an index as the <code>key</code> prop, ensure the order of items in the array never changes. Otherwise, you may have severe issues with performance and component state.</p>
<h4 id="heading-best-way-to-assign-keys-to-an-array-of-react-elements">Best way to assign keys to an array of React elements</h4>
<p>The best way to add unique keys to each React element in an array is to use stable IDs from either of the following sources:</p>
<ul>
<li><p><strong>Database:</strong> Use the database-generated IDs as the <code>key</code> props if your data comes from a database, as they are unique by default.</p>
</li>
<li><p><code>crypto.randomUUID()</code> <strong>incrementing counter:</strong> Use the <code>randomUUID()</code> method to generate Universally Unique Identifiers if you are creating and storing your data locally. (Note: This method is a web API. So, it’s available only in supporting browsers’ HTTPS contexts.)</p>
</li>
<li><p><code>uuid</code>: An NPM package for generating Universally Unique Identifiers if you are creating and persisting your data locally. This is a good alternative to the <code>randomUUID()</code> method for cross-platform compatibility.</p>
</li>
</ul>
<p><strong>Example:</strong></p>
<p><code>index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> { bestColors } <span class="hljs-keyword">from</span> <span class="hljs-string">"./bestColors.js"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BestColor</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Use each item's id as its key prop:</span>
  <span class="hljs-keyword">const</span> bestColorsLiElements = bestColors.map(<span class="hljs-function">(<span class="hljs-params">color</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{color.id}</span>&gt;</span>{color.name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  ));
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>{bestColorsLiElements}<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>;
}

<span class="hljs-keyword">const</span> root = createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BestColor</span> /&gt;</span></span>);
</code></pre>
<p><code>bestColors.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> bestColors = [
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"Blue"</span> },
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"White"</span> },
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"Pink"</span> },
];
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/n56z6x?file=%2Fsrc%2Findex.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above specifies a <code>key</code> prop on each <code>&lt;li&gt;</code> element. It then uses each item’s <code>id</code> as the prop’s value.</p>
<p><strong>Note:</strong> Each <code>key</code> prop should be unique among its siblings – not globally. It’s okay to use the same <code>key</code> for an element in a different array.</p>
<h3 id="heading-essential-things-to-know-about-assigning-keys">Essential things to know about assigning keys</h3>
<p>Here are essential facts to remember whenever you assign keys to an array of React elements.</p>
<h4 id="heading-1-set-each-array-elements-key-while-creating-the-array">1. Set each array element’s key while creating the array</h4>
<p>The right place to specify each array element’s unique key is directly inside the <code>map()</code> method <em>while creating the list of elements</em>.</p>
<p>In other words, say you extract your template element into a separate component. Set the <code>key</code> prop on the component’s invocation tag—not on the extracted template element.</p>
<p><strong>Example 1: Incorrect placement of the key prop</strong></p>
<p><code>index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> { bestColors } <span class="hljs-keyword">from</span> <span class="hljs-string">"./bestColors.js"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ColorListElement</span>(<span class="hljs-params">{ color }</span>) </span>{
  <span class="hljs-comment">// WRONG: Don't place the key outside the map() method.</span>
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{color.id}</span>&gt;</span>{color.name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BestColor</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> bestColorsLiElements = bestColors.map(<span class="hljs-function">(<span class="hljs-params">color</span>) =&gt;</span> (
    <span class="hljs-comment">// The key attribute above should have been set here.</span>
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ColorListElement</span> <span class="hljs-attr">color</span>=<span class="hljs-string">{color}</span> /&gt;</span></span>
  ));
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>{bestColorsLiElements}<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>;
}

<span class="hljs-keyword">const</span> root = createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BestColor</span> /&gt;</span></span>);
</code></pre>
<p><code>bestColors.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> bestColors = [
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"Blue"</span> },
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"White"</span> },
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"Pink"</span> },
];
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/frcspn?file=%2Fsrc%2Findex.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above incorrectly sets each item’s key outside the <code>map()</code> method. You should avoid such a mistake!</p>
<p>Always set the <code>key</code> prop <em>while creating the array of elements</em>. So, the snippet above should have set the <code>key</code> on the component invocation tag – in the <code>map()</code> method.</p>
<p><strong>Example 2: Correct placement of the key prop</strong></p>
<p><code>index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> { bestColors } <span class="hljs-keyword">from</span> <span class="hljs-string">"./bestColors.js"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ColorListElement</span>(<span class="hljs-params">{ color }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>{color.name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BestColor</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> bestColorsLiElements = bestColors.map(<span class="hljs-function">(<span class="hljs-params">color</span>) =&gt;</span> (
    <span class="hljs-comment">// CORRECT: Always define the key directly inside the map() method.</span>
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ColorListElement</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{color.id}</span> <span class="hljs-attr">color</span>=<span class="hljs-string">{color}</span> /&gt;</span></span>
  ));
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>{bestColorsLiElements}<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>;
}

<span class="hljs-keyword">const</span> root = createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BestColor</span> /&gt;</span></span>);
</code></pre>
<p><code>bestColors.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> bestColors = [
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"Blue"</span> },
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"White"</span> },
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"Pink"</span> },
];
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/n9m7w2?file=%2Fsrc%2Findex.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above correctly sets each item’s key inside the <code>map()</code> method. This allows React to access the <code>key</code> value for each element in the array returned by the <code>map()</code> method.</p>
<p><strong>Tip:</strong> React’s reconciliation (diffing) algorithm is programmed to access the <code>key</code> of each top-level item of the array. It never looks for the <code>key</code> in the child or descendant elements.</p>
<h4 id="heading-2-react-does-not-pass-keys-to-components">2. React does not pass keys to components</h4>
<p>React neither transfers the <code>key</code> prop to components nor includes it as an attribute of a rendered element.</p>
<p>React uses keys solely to know the state of array items. They help React identify changes to the array.</p>
<p>So if you need to use a specific key’s value in your component or on your DOM element, you should explicitly pass it as the value of a different attribute.</p>
<p><strong>Example:</strong></p>
<p><code>index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> { bestColors } <span class="hljs-keyword">from</span> <span class="hljs-string">"./bestColors.js"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ColorListElement</span>(<span class="hljs-params">props</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
      {props.color.name} (ID: {props.id})
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BestColor</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Use `color.id` as the `key` and `id` props' value.</span>
  <span class="hljs-keyword">const</span> bestColorsLiElements = bestColors.map(<span class="hljs-function">(<span class="hljs-params">color</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ColorListElement</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{color.id}</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{color.id}</span> <span class="hljs-attr">color</span>=<span class="hljs-string">{color}</span> /&gt;</span></span>
  ));
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>{bestColorsLiElements}<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>;
}

<span class="hljs-keyword">const</span> root = createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BestColor</span> /&gt;</span></span>);
</code></pre>
<p><code>bestColors.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> bestColors = [
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"Blue"</span> },
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"White"</span> },
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"Pink"</span> },
];
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/v7yflr?file=%2Fsrc%2Findex.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above initializes each list item’s <code>id</code> attribute with the same value as the <code>key</code> prop. By so doing, the <code>ColorListElement</code> component can access <code>props.id</code> but not <code>props.key</code>.</p>
<h4 id="heading-3-always-generate-the-keys-outside-your-components">3. Always generate the keys outside your components</h4>
<p>Never generate keys on the fly (while <a target="_blank" href="https://codesweetly.com/web-tech-terms-r/#react-render">rendering</a> your components). Instead, create them in your data outside your components. Otherwise, React will recreate the elements on every rendering cycle because the <code>key</code>’s value will always be different.</p>
<p><strong>Example 1: Incorrect place to generate the key prop</strong></p>
<p><code>index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> { bestColors } <span class="hljs-keyword">from</span> <span class="hljs-string">"./bestColors.js"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BestColor</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// WRONG: Never generate keys on the fly.</span>
  <span class="hljs-keyword">const</span> bestColorsLiElements = bestColors.map(<span class="hljs-function">(<span class="hljs-params">color</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{crypto.randomUUID()}</span>&gt;</span>{color}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  ));
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>{bestColorsLiElements}<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>;
}

<span class="hljs-keyword">const</span> root = createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BestColor</span> /&gt;</span></span>);
</code></pre>
<p><code>bestColors.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// The keys' values should have been set here (outside the component while creating your data).</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> bestColors = [<span class="hljs-string">"Blue"</span>, <span class="hljs-string">"White"</span>, <span class="hljs-string">"Pink"</span>];
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/lhwknv?file=%2Fsrc%2Findex.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above incorrectly generated each element’s key while rendering the <code>BestColor</code> component. You should avoid such a mistake to prevent subtle bugs caused by recreating the elements on every render.</p>
<p>Always create each <code>key</code>’s value in your data outside the component.</p>
<p><strong>Example 2: Correct place to generate the key prop</strong></p>
<p><code>index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> { bestColors } <span class="hljs-keyword">from</span> <span class="hljs-string">"./bestColors.js"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BestColor</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> bestColorsLiElements = bestColors.map(<span class="hljs-function">(<span class="hljs-params">color</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{color.id}</span>&gt;</span>{color.name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  ));
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>{bestColorsLiElements}<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>;
}

<span class="hljs-keyword">const</span> root = createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BestColor</span> /&gt;</span></span>);
</code></pre>
<p><code>bestColors.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// CORRECT: Always generate the key in your data outside the component.</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> bestColors = [
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"Blue"</span> },
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"White"</span> },
  { <span class="hljs-attr">id</span>: crypto.randomUUID(), <span class="hljs-attr">name</span>: <span class="hljs-string">"Pink"</span> },
];
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/n56z6x?file=%2Fsrc%2Findex.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above correctly generated each element’s key in the array data outside the component.</p>
<h2 id="heading-how-to-handle-events-in-react">How to Handle Events in React</h2>
<p>Event handling in React involves configuring your JSX elements to respond to user interactions on them (such as mouse clicks, form submission, and element focus).</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">jsxTag</span> <span class="hljs-attr">onEvent</span>=<span class="hljs-string">{handleEvent}</span>&gt;</span>UI Content<span class="hljs-tag">&lt;/<span class="hljs-name">jsxTag</span>&gt;</span>
</code></pre>
<p>Here’s what’s going on:</p>
<ul>
<li><p><code>jsxTag</code>: React elements like <code>&lt;div&gt;</code>, <code>&lt;button&gt;</code>, and <code>&lt;input&gt;</code>.</p>
</li>
<li><p><code>onEvent</code>: The event listener you want to add to the React element. Some examples are <code>onClick</code>, <code>onBlur</code>, and <code>onHover</code>.</p>
</li>
<li><p><code>handleEvent</code>: The event handler function you want to use to handle (respond to) the specified <code>onEvent</code> type.</p>
</li>
</ul>
<p><strong>Tip:</strong> Although you can name the event handler anything you prefer, the typical naming convention is to prefix the event’s name with “handle”. For instance, if the event’s name is <code>focus</code>, the handler’s name will be <code>handleFocus</code>.</p>
<h3 id="heading-types-of-event-handlers">Types of event handlers</h3>
<p>There are two typical ways to define the event handler function in React:</p>
<ul>
<li><p><strong>Inline event handler:</strong> A function defined directly on a JSX element’s opening tag as the value of the event listener prop (<code>onEvent</code>).</p>
</li>
<li><p><strong>Referenced event handler:</strong> A function defined as a separate (independent) logic and linked to an event listener attribute (<code>onEvent</code>) by name referencing.</p>
</li>
</ul>
<h4 id="heading-example-inline-event-handler">Example: Inline event handler</h4>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> alert("You clicked the heading!")}&gt;
      Oluwatobi is my name.
    <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
  );
}
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/7tx7l5?file=%2Fsrc%2Fcomponents%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<h4 id="heading-example-referenced-event-handler">Example: Referenced event handler</h4>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>Oluwatobi is my name.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
}

<span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">() =&gt;</span> alert(<span class="hljs-string">"You clicked the heading!"</span>);
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/msfszz?file=%2Fsrc%2Fcomponents%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>React components have a unique memory that allows them to remember things between renderings. This memory is called “state.”</p>
<h2 id="heading-what-is-react-state">What Is React State?</h2>
<p>React state is a <em>component’s memory</em> for storing data that React should remember during a component’s re-rendering and whose update should trigger a new render.</p>
<h3 id="heading-syntax-of-react-state">Syntax of React state:</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [state, setState] = useState(initialState);

  <span class="hljs-comment">// ...</span>
}
</code></pre>
<ul>
<li><p><code>state</code>: The variable containing the component’s state value.</p>
</li>
<li><p><code>setState</code>: A function for updating the state value.</p>
</li>
<li><p><code>useState</code>: The state Hook for initializing and retrieving the component’s state.</p>
</li>
</ul>
<h3 id="heading-example-of-react-state">Example of React state:</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AboutCompany</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [age, setAge] = useState(<span class="hljs-number">5</span>);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateAge</span>(<span class="hljs-params"></span>) </span>{
    setAge(age + <span class="hljs-number">1</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">h3</span>&gt;</span>CodeSweetly is {age} years old!<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{updateAge}</span>&gt;</span>
        Click to update age
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AboutCompany;
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/9mlsl7?file=%2Fsrc%2FAboutCompany.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>When a user clicks the button UI, the <code>onClick</code> event triggers the <code>updateAge</code> event handler, which uses the <code>setAge</code> setter function to update the component’s <code>age</code> state.</p>
<p><strong>Tip:</strong> React will trigger a re-render of your component every time you use <code>useState</code>’s setter function to update your state. But what exactly do the terms “trigger” and “render” mean?</p>
<h3 id="heading-react-trigger-vs-render-vs-commit-vs-paint">React Trigger vs Render vs Commit vs Paint</h3>
<p>Triggering, rendering, committing, and painting are the steps involved in displaying React UIs on screen. Here are the differences between the four steps:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760637870319/ed8ae7a7-67c1-468a-ba5f-dbbafed8deb0.webp" alt="React Component's Lifecyle" class="image--center mx-auto" width="1920" height="1920" loading="lazy"></p>
<p>The above slide illustrates the four phases in the lifecycle of a component’s UI:</p>
<ul>
<li><p><strong>Trigger:</strong> Specifies the component whose UI you want to display on the screen.</p>
</li>
<li><p><strong>Render:</strong> Calls the component you’ve triggered.</p>
</li>
<li><p><strong>Commit:</strong> Updates the DOM with the UI of the rendered component.</p>
</li>
<li><p><strong>Paint:</strong> Converts the DOM code you’ve committed into user-friendly elements that users can interact with in their browsers.</p>
</li>
</ul>
<p>Let’s discuss these differences in detail.</p>
<h3 id="heading-what-does-it-mean-to-trigger-a-render-in-react">What does it mean to trigger a render in React?</h3>
<p>The trigger event is the first step in displaying a React user interface (UI) on screen. It specifies the component whose UI you want to display on the screen. This event happens on two occasions:</p>
<ol>
<li>When the app starts running. The React application uses the <code>createRoot</code> method to specify the component whose UI you want to render to a DOM node.</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> DonationUI <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/DonationUI.js"</span>;

<span class="hljs-comment">// When the app starts running, you need to use createRoot and its render method to trigger an initial rendering of the app's root component.</span>
<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">DonationUI</span> /&gt;</span></span>);
</code></pre>
<p>The snippet above does the following:</p>
<ul>
<li><p>Uses the <code>ReactDOM.createRoot()</code> method to create a <code>ReactDOMRoot</code> object instance for the <code>root</code> element argument.</p>
</li>
<li><p>Use the object instance’s <code>render()</code> method to trigger an initial rendering of the <code>DonationUI</code> component.</p>
</li>
</ul>
<p>In other words, the <code>createRoot().render()</code> method specifies <code>DonationUI</code> as the component whose UI React should display in the <code>root</code> HTML element.</p>
<ol start="2">
<li>The second reason a trigger event can happen is when a component’s (or its ancestors’) state gets updated with a set function.</li>
</ol>
<p><code>DonationUI.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DonationUI</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [donate, setDonate] = React.useState(<span class="hljs-literal">false</span>);
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createUserInterface</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (donate) {
      <span class="hljs-keyword">return</span> (
        <span class="xml"><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">"https://www.buymeacoffee.com/codesweetly"</span>&gt;</span>Support page<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>.
          Thank you so much!
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
      );
    }
    <span class="hljs-comment">// The setDonate function will trigger a re-rendering of the DonationUI component.</span>
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setDonate(true)}&gt;Buy me a coffee<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
  }
  <span class="hljs-keyword">return</span> createUserInterface();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DonationUI;
</code></pre>
<p>The snippet above does the following:</p>
<ol>
<li><p>Defines a component named <code>DonationUI</code>.</p>
</li>
<li><p>Initializes the component’s state with the Boolean value <code>false</code>.</p>
</li>
<li><p>Programs the component to return a paragraph element if the state’s <code>donate</code> variable is <code>true</code>. Otherwise, it should return a button element.</p>
</li>
</ol>
<p>When users click the button element, the <code>setDonate</code> setter function will trigger a re-rendering of the <code>DonationUI</code> component. Below are the entry script and the HTML code so you can try it yourself locally.</p>
<p><code>index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> DonationUI <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/DonationUI"</span>;

<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
root.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">DonationUI</span> /&gt;</span></span>);
</code></pre>
<p><code>index.html</code></p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en-US"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>CodeSweetly DonationUI<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"index.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/95nvmr?file=%2Fsrc%2Fcomponents%2FDonationUI.js"><strong>Try it on CodeSandbox</strong></a></p>
<h3 id="heading-what-does-it-mean-to-render-react-components">What does it mean to render React components?</h3>
<p>The rendering step is when React <a target="_blank" href="https://codesweetly.com/invoke-vs-call/">invokes (calls)</a> the component you’ve triggered with either the <code>createRoot</code> method or a set function. Rendering causes React to invoke a component to produce the UI you want to display on the screen. The component React will render depends on the moment the trigger event occurred:</p>
<ul>
<li><p><strong>For an initial trigger (at the start of the app),</strong> React will invoke the app’s root component.</p>
</li>
<li><p><strong>For update triggers (whenever a component’s state gets updated),</strong> React will call the function component whose state update initiated the trigger event.</p>
</li>
</ul>
<p><strong>Tip:</strong> Rendering a component means “calling a component” to retrieve its user interface (UI).</p>
<h3 id="heading-what-does-it-mean-to-commit-a-react-ui-to-the-browsers-dom">What does it mean to commit a React UI to the browser’s DOM?</h3>
<p>The committing stage is when React updates the DOM with the UI of the rendered component.</p>
<p>There are some important things to note about this process:</p>
<ul>
<li><p><strong>For an initial render (at the start of the app),</strong> React will initialize the root DOM with the root component’s UI. It will use the <code>appendChild()</code> JavaScript API to append the DOM nodes (UI) retrieved from the component into the app’s root HTML element.</p>
</li>
<li><p><strong>For subsequent re-rendering (after the initial commit),</strong> React will only update the DOM nodes if there’s a difference between the previous rendering output and the latest one. No changes will occur if the component’s latest output is the same as the previously committed one.</p>
</li>
</ul>
<h3 id="heading-what-does-it-mean-to-paint-the-dom-nodes-on-the-screen">What does it mean to paint the DOM nodes on the screen?</h3>
<p>The painting (browser rendering) stage is when the browser repaints the screen to convert the DOM code to user-friendly elements. This is a browser-level process that begins once React has finished updating (committing) the DOM nodes.</p>
<p>Sometimes, components need to store information that shouldn’t trigger a render when updated. In these situations, you can use a ref.</p>
<h2 id="heading-what-is-the-react-ref-hook">What Is the React Ref Hook?</h2>
<p>The React Ref Hook lets you store values that don’t trigger re-renders when changed.</p>
<h3 id="heading-syntax-of-the-react-ref-hook">Syntax of the React ref Hook</h3>
<p>The <code>useRef</code> Hook accepts only one optional argument. Here is the syntax:</p>
<pre><code class="lang-javascript">useRef(initialValue);
</code></pre>
<ul>
<li><p><code>initialValue</code>: The value to store in the component’s ref memory. Any JavaScript data type is allowed.</p>
</li>
<li><p><code>useRef()</code>: Returns an object (<code>{ current: initialValue }</code>).</p>
</li>
</ul>
<h3 id="heading-example-of-the-react-ref-hook">Example of the React ref Hook:</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> myNameRef = useRef(<span class="hljs-string">"Oluwatobi"</span>);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(myNameRef.current); <span class="hljs-comment">// Outputs: "Oluwatobi"</span>
  }

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>Click me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/mgsxyq?file=%2Fsrc%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above used the <code>useRef</code> Hook to store a value (<code>"Oluwatobi"</code>) whose update shouldn’t trigger re-renders.</p>
<h3 id="heading-react-ref-hook-best-practices">React ref Hook best practices</h3>
<p>When you’re working with React’s ref hook, there are some best practices you should follow:</p>
<ul>
<li><p>Use dot syntax to access and update a ref object’s value instead of square bracket notation.</p>
</li>
<li><p>Avoid accessing or updating the <code>current</code> property during rendering to maintain the purity of your components.</p>
</li>
<li><p>Don’t use a function instance as your <code>initialValue</code>. Pass the function itself, not its output.</p>
</li>
<li><p>You can use the React ref Hook to manage your HTML DOM nodes.</p>
</li>
</ul>
<p>But what’s the difference between refs, states, and variables, I hear you ask? Let’s find out below.</p>
<h2 id="heading-variables-vs-refs-vs-states-in-react">Variables vs Refs vs States in React</h2>
<p>In React, variables, refs, and states allow you to store and mutate data. But they work in different ways. Here are the main distinctions between them:</p>
<ol>
<li><p>Does its value persist during re-rendering?</p>
<ul>
<li><p>React Ref: Yes</p>
</li>
<li><p>React State: Yes</p>
</li>
<li><p>JavaScript Variable: No</p>
</li>
</ul>
</li>
<li><p>Would updating its value trigger a re-rendering of the component?</p>
<ul>
<li><p>React Ref: No</p>
</li>
<li><p>React State: Yes</p>
</li>
<li><p>JavaScript Variable: No</p>
</li>
</ul>
</li>
<li><p>Is it plain JavaScript?</p>
<ul>
<li><p>React Ref: Yes</p>
</li>
<li><p>React State: No</p>
</li>
<li><p>JavaScript Variable: Yes</p>
</li>
</ul>
</li>
<li><p>Can you declare it outside a component?</p>
<ul>
<li><p>React Ref: No</p>
</li>
<li><p>React State: No</p>
</li>
<li><p>JavaScript Variable: Yes</p>
</li>
</ul>
</li>
<li><p>Is it usable in conditional statements, loops, or nested functions?</p>
<ul>
<li><p>React Ref: No</p>
</li>
<li><p>React State: No</p>
</li>
<li><p>JavaScript Variable: Yes</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-how-do-variables-work-in-react">How do variables work in React?</h3>
<p>A <a target="_blank" href="https://codesweetly.com/javascript-variable/">variable</a>’s value does not persist during re-rendering. Its value resets at the beginning of a new rendering.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> myVar = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">const</span> [myState, setMyState] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateVar</span>(<span class="hljs-params"></span>) </span>{
    myVar = myVar + <span class="hljs-number">1</span>;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"myVar ="</span>, myVar);
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateState</span>(<span class="hljs-params"></span>) </span>{
    setMyState(myState + <span class="hljs-number">1</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>Variable: {myVar}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>State: {myState}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{updateVar}</span>&gt;</span>Update Variable<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{updateState}</span>&gt;</span>Update State<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/variables-vs-refs-vs-states-in-react/try-it-sdk-vitejs-vite-u6yjihmv"><strong>Try Editing It</strong></a></p>
<p>The snippet above will:</p>
<ul>
<li><p>Increment the variable’s value when you click the “Update Variable” button. This modification doesn’t trigger a re-rendering of the component because React doesn’t track a variable’s changes.</p>
</li>
<li><p>Increment the state’s value when you click the “Update State” button. This modification triggers a re-rendering of the component because React requests a re-render whenever you modify the state.</p>
</li>
<li><p>Reset the variable’s value to zero (0) during each re-rendering of the App component. Therefore, the rendered variable’s value will always be zero (0).</p>
</li>
</ul>
<h3 id="heading-how-do-refs-work-in-react">How do refs work in React?</h3>
<p>A ref’s value persists during re-rendering, but modifying it doesn’t cause React to re-render the component. In other words, a ref is a plain <a target="_blank" href="https://codesweetly.com/javascript-properties-object/">JavaScript object</a> whose value React remembers while re-rendering your component. But React doesn’t track changes to the ref’s value. So, its modifications don’t trigger a new rendering.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> myRef = useRef(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> [myState, setMyState] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateRef</span>(<span class="hljs-params"></span>) </span>{
    myRef.current = myRef.current + <span class="hljs-number">1</span>;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"myRef ="</span>, myRef);
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateState</span>(<span class="hljs-params"></span>) </span>{
    setMyState(myState + <span class="hljs-number">1</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>Ref: {myRef.current}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>State: {myState}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{updateRef}</span>&gt;</span>Update Ref<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{updateState}</span>&gt;</span>Update State<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/variables-vs-refs-vs-states-in-react/try-it-sdk-vitejs-vite-xyjh2fev"><strong>Try Editing It</strong></a></p>
<p>The snippet above will:</p>
<ul>
<li><p>Increment the ref’s value when you click the “Update Ref” button. This modification doesn’t trigger a re-rendering of the component because React doesn’t monitor the ref’s changes.</p>
</li>
<li><p>Increment the state’s value when you click the “Update State” button. This modification triggers a re-rendering of the component because React requests a re-render whenever you modify the state.</p>
</li>
<li><p>Retains the ref and state’s value during each re-rendering of the App component.</p>
</li>
</ul>
<h3 id="heading-how-do-states-work-in-react">How do states work in React?</h3>
<p>A state’s value persists during re-rendering. Modifying it also causes React to re-render the component.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> myVar = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">const</span> myRef = useRef(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> [myState, setMyState] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateVarAndRef</span>(<span class="hljs-params"></span>) </span>{
    myVar = myVar + <span class="hljs-number">1</span>;
    myRef.current = myRef.current + <span class="hljs-number">1</span>;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"myVar ="</span>, myVar);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"myRef ="</span>, myRef);
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateState</span>(<span class="hljs-params"></span>) </span>{
    setMyState(myState + <span class="hljs-number">1</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>Variable: {myVar}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Ref: {myRef.current}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>State: {myState}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{updateVarAndRef}</span>&gt;</span>Update Variable and Ref<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{updateState}</span>&gt;</span>Update State<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/variables-vs-refs-vs-states-in-react/try-it-sdk-vitejs-vite-gklkzfps"><strong>Try Editing It</strong></a></p>
<p>The snippet above will:</p>
<ul>
<li><p>Increment the variable and ref’s value when you click the “Update Variable and Ref” button. This modification doesn’t trigger a re-rendering of the component because React doesn’t monitor changes to the variable or ref.</p>
</li>
<li><p>Increment the state’s value when you click the “Update State” button. This modification triggers a re-rendering of the component because React requests a re-render whenever you modify the state.</p>
</li>
<li><p>Resets the variable’s value during each re-rendering of the App component, while retaining the ref and state’s data.</p>
</li>
</ul>
<h3 id="heading-tips-on-using-variables-refs-and-states-in-react">Tips on using variables, refs, and states in React</h3>
<ul>
<li><p>Use variables for values that should reset on every rendering of the component.</p>
</li>
<li><p>Use the Ref Hook to store values that users do not need to see on screen, as changes to the ref will not trigger a re-rendering of the component.</p>
</li>
<li><p>React state is ideal for storing values that you want to display on the screen, as state changes trigger a re-rendering of the component.</p>
</li>
</ul>
<p>React components sometimes need to fetch data or change the DOM during different lifecycle phases: trigger, render, commit, and paint. The Effect Hook can help with these tasks.</p>
<h2 id="heading-what-is-the-useeffect-hook">What Is the useEffect Hook?</h2>
<p>The <code>useEffect</code> hook lets function components perform side effects outside React.</p>
<h3 id="heading-syntax-of-the-useeffect-hook">Syntax of the useEffect Hook</h3>
<p>The <code>useEffect</code> hook accepts two arguments. Here’s the syntax:</p>
<pre><code class="lang-javascript">useEffect(callback, array);
</code></pre>
<ul>
<li><p><code>callback</code>: The required setup function for the useEffect hook.</p>
</li>
<li><p><code>array</code>: (Optional) The reactive dependencies list that indicates when React runs the callback.</p>
</li>
</ul>
<p><strong>Tip:</strong> React runs the setup function after the component mounts or when dependencies change.</p>
<h3 id="heading-example-of-the-useeffect-hook">Example of the useEffect Hook:</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AboutCompany</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [age, setAge] = useState(<span class="hljs-number">5</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">document</span>.title = <span class="hljs-string">`🥳🎁🎉 It's CodeSweetly's birthday! 🎉🎁🥳`</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">h3</span>&gt;</span>CodeSweetly is {age} years old!<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setAge(age + 1)}&gt;
        Click to update age
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AboutCompany;
</code></pre>
<p>The <code>useEffect</code> code updates the browser’s title after the UI finishes rendering.</p>
<h3 id="heading-useeffect-hooks-best-practices">useEffect Hook’s best practices</h3>
<p>As always, there are some best practices to use this hook most effectively:</p>
<ul>
<li><p>Use <code>useEffect</code> to connect with things outside your React app, such as APIs or timers. If your code has no side effects, you likely don’t need it.</p>
</li>
<li><p>Avoid adding values to the dependency array unless your effect uses them. Include only the state and props needed to prevent unnecessary re-runs.</p>
</li>
<li><p>Declare static objects and functions outside components. Place dynamic ones inside your Effect Hook.</p>
</li>
<li><p>When depending on object props, list each primitive value used in your effect instead of the entire object.</p>
</li>
<li><p>Use <code>StrictMode</code> to help catch common useEffect hook issues during development.</p>
</li>
</ul>
<p>With the basics of React covered, let’s discuss styling.</p>
<h2 id="heading-how-to-style-react-components">How to Style React Components</h2>
<p>The four primary ways to style React elements are:</p>
<ul>
<li><p>CSS style sheets</p>
</li>
<li><p>Inline style attributes</p>
</li>
<li><p>CSS Modules</p>
</li>
<li><p>CSS-in-JS Libraries</p>
</li>
</ul>
<p>Let’s discuss the four styling techniques.</p>
<h3 id="heading-how-to-use-css-style-sheets-to-style-react-elements">How to use CSS style sheets to style React elements</h3>
<p>Below are the steps to style JSX elements with regular CSS style sheets.</p>
<h4 id="heading-1-create-a-css-stylesheet">1. Create a CSS stylesheet</h4>
<p>First, create a CSS stylesheet in your React projects.</p>
<pre><code class="lang-console">touch styles.css
</code></pre>
<p><strong>Tip:</strong> You can create the stylesheet anywhere in your project directory.</p>
<h4 id="heading-2-define-your-ruleset">2. Define your ruleset</h4>
<p>Open the newly created CSS file and declare your styles.</p>
<p><strong>Example:</strong></p>
<p><code>styles.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.text</span> {
  <span class="hljs-attribute">color</span>: seagreen;
  <span class="hljs-attribute">font-weight</span>: bold;
}
</code></pre>
<p>The CSS snippet above instructs browsers to apply a <code>seagreen</code> color and <code>bold</code> font weight on elements with a <code>text</code> class name.</p>
<h4 id="heading-3-apply-the-stylesheets-ruleset-to-your-element">3. Apply the stylesheet’s ruleset to your element</h4>
<p>Import your stylesheet into the component file containing the element you wish to style. Then, apply the stylesheet’s ruleset to it.</p>
<p><strong>Example:</strong></p>
<p><code>App.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import your stylesheet (the path to your stylesheet may be different).</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text"</span>&gt;</span>Oluwatobi is my name.<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> App;
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/mq5xzp?file=%2Fsrc%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above instructs React to apply the <code>"text"</code> ruleset on the element with a <code>className="text"</code> attribute.</p>
<h3 id="heading-how-to-use-the-inline-style-attribute-to-style-react-elements">How to use the inline <code>style</code> attribute to style React elements</h3>
<p>React allows you to apply inline styles to JSX elements in the same way as inline CSS works in HTML. But there are some differences to keep in mind.</p>
<p>First, HTML applies inline styles as a string value:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"color:seagreen; font-weight:bold;"</span>&gt;</span>Oluwatobi is my name.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>But in React, you must define inline styles as objects, not strings:</p>
<pre><code class="lang-javascript">&lt;div style={{ <span class="hljs-attr">color</span>: <span class="hljs-string">"seagreen"</span>, <span class="hljs-attr">fontWeight</span>: <span class="hljs-string">"bold"</span> }}&gt;
  Oluwatobi is my name.
&lt;/div&gt;
</code></pre>
<p>The snippet above uses two sets of curly braces because in JSX (as I mentioned above), you wrap <a target="_blank" href="https://codesweetly.com/javascript-statement/#what-is-a-javascript-expression-statement">JavaScript expressions</a> inside curly braces: for instance, <code>&lt;div&gt;{myNameVariable}&lt;/div&gt;</code>.</p>
<p>So, suppose the expression is a JavaScript object literal. In that case, you will need two sets of curly braces: for instance, <code>&lt;div&gt;{{ name: "Oluwatobi" }}&lt;/div&gt;</code>.</p>
<p>Therefore, in <code>style={{ color: seagreen, fontWeight: bold }}</code>, the first set of curly braces (<code>{...}</code>) tells React that you want to write a JavaScript expression. The second set of curly braces (<code>{ color: seagreen, fontWeight: bold }</code>) is the JavaScript expression (an object) you are assigning as the <code>style</code> attribute’s value.</p>
<p><strong>Example:</strong></p>
<p><code>App.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> "<span class="hljs-attr">seagreen</span>", <span class="hljs-attr">fontWeight:</span> "<span class="hljs-attr">bold</span>" }}&gt;</span>
      Oluwatobi is my name.
    <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> App;
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/84cmjf?file=%2Fsrc%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The React snippet above instructs the computer to apply an inline style to the <code>div</code> element.</p>
<p>You can see that we wrote <code>fontWeight</code> in <a target="_blank" href="https://codesweetly.com/naming-convention-explained/#what-is-camelcase">camelCase</a>. This is because, under the hood, JSX compiles into plain JavaScript. So it uses the JavaScript Web APIs attribute naming convention.</p>
<p>To make your code easier to read, consider storing your inline style object in a separate variable like so:</p>
<p><code>App.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Store your inline style object in a variable:</span>
  <span class="hljs-keyword">const</span> textStyles = { <span class="hljs-attr">color</span>: <span class="hljs-string">"seagreen"</span>, <span class="hljs-attr">fontWeight</span>: <span class="hljs-string">"bold"</span> };
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{textStyles}</span>&gt;</span>Oluwatobi is my name.<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> App;
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/2llmwy?file=%2Fsrc%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<p><strong>Tip:</strong> The Tailwind CSS framework is an inline styling tool that provides utility classes you can apply directly to an element. It offers additional features that are often lacking in regular inline styling. For example, Tailwind allows you to configure media queries and event states (such as <code>hover</code>, <code>focus</code>, and <code>active</code>) in inline styles.</p>
<h3 id="heading-how-to-use-css-modules-to-style-react-elements">How to use CSS modules to style React elements</h3>
<p>As defined on the official <a target="_blank" href="https://github.com/css-modules/css-modules">documentation</a>, a CSS Module is a CSS file in which all class names and animation names are scoped locally by default.</p>
<p>CSS Modules share many similarities with a regular CSS style sheet. But there are some essential differences.</p>
<h4 id="heading-1-filename-convention">1. Filename convention</h4>
<p>The syntax for naming a regular CSS stylesheet is <code>[name].css</code>: for instance, <code>codesweetly-styles.css</code>.</p>
<p>But a CSS module’s file naming convention is <code>[name].module.css</code>: for instance, <code>codesweetly-styles.module.css</code>.</p>
<h4 id="heading-2-styles-scope">2. Styles scope</h4>
<p>Importing a CSS style sheet into your script file makes its rulesets available <em>globally</em> to all components (and child components) of that script.</p>
<p>But importing a CSS module into your script file only makes its rulesets available <em>locally</em> to the component that invokes the module’s rule. Also, that component must be in the script that imports the CSS module.</p>
<p><strong>Example:</strong></p>
<p>Create a regular CSS stylesheet in your React project and add some rules to it:</p>
<p><code>styles.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.imageInfo</span> {
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#442109</span>;
}
</code></pre>
<p>Also, create a CSS module in the same project and add some rules to it:</p>
<p><code>styles.module.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.imageInfo</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">8px</span> ridge <span class="hljs-number">#71380f</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ffe5b4</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span> <span class="hljs-number">0</span> <span class="hljs-number">7px</span>;
}
</code></pre>
<p>Import both the CSS stylesheet and CSS module you’ve just created into your script file:</p>
<p><code>App.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">"../styles.css"</span>;
<span class="hljs-keyword">import</span> codesweetlyStyles <span class="hljs-keyword">from</span> <span class="hljs-string">"../styles.module.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"imageInfo"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Random Image<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://picsum.photos/400/400"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Random Image"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Get a new image each time you refresh your browser.<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> App;
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/3t3nwt?file=%2Fsrc%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>Go ahead and run your app and check its output in your browser.</p>
<p>After running your app, you will notice that React only applied the CSS stylesheet’s ruleset, not the CSS module’s own.</p>
<p>React did so because the stylesheet’s ruleset is globally available to all elements (and child components) of the page where you imported the sheet.</p>
<p>But the ruleset in the module is locally available only to the component that explicitly invokes the rule.</p>
<p>So, to use your CSS module’s style in your component, you must explicitly execute it like so:</p>
<p><code>App.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">"../styles.css"</span>;
<span class="hljs-keyword">import</span> codesweetlyStyles <span class="hljs-keyword">from</span> <span class="hljs-string">"../styles.module.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">imageInfo</span> ${<span class="hljs-attr">codesweetlyStyles.imageInfo</span>}`}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Random Image<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://picsum.photos/400/400"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Random Image"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Get a new image each time you refresh your browser.<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> App;
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/45lkpf?file=%2Fsrc%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above uses the <code>codesweetlyStyles.imageInfo</code> code to instruct React to apply the CSS module’s <code>imageInfo</code> ruleset to the <code>div</code> element.</p>
<h4 id="heading-3-composition">3. Composition</h4>
<p>To compose styles together while using a regular CSS style sheet, you must apply multiple classes to your element.</p>
<p><strong>Example: Compose rulesets with regular CSS style sheets</strong></p>
<p><code>styles.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">4px</span> solid blueviolet;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span> <span class="hljs-number">15px</span>;
}

<span class="hljs-selector-class">.text</span> {
  <span class="hljs-attribute">color</span>: seagreen;
  <span class="hljs-attribute">font-weight</span>: bold;
}
</code></pre>
<p><code>App.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">"../styles.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container text"</span>&gt;</span>Oluwatobi is my name.<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> App;
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/w6h74d?file=%2Fsrc%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>Using multiple classes on an element to implement style composition is not the best practice because CSS will use the order of style definitions in the stylesheet to determine the order of precedence based on the CSS cascading rules.</p>
<p>But CSS modules provide a <code>composes</code> declaration that offers greater flexibility in composing your styles to suit your project’s needs.</p>
<p><strong>Example: Compose rulesets with CSS modules</strong></p>
<p><code>styles.module.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">4px</span> solid blueviolet;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span> <span class="hljs-number">15px</span>;
}

<span class="hljs-selector-class">.text</span> {
  <span class="hljs-attribute">composes</span>: container;
  <span class="hljs-attribute">color</span>: seagreen;
  <span class="hljs-attribute">font-weight</span>: bold;
}
</code></pre>
<p><code>App.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">"../styles.module.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.text}</span>&gt;</span>Oluwatobi is my name.<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> App;
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/j6yl9z?file=%2Fsrc%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>Although you can define multiple <code>composes</code> declarations in a ruleset, they must precede other rules.</p>
<p><strong>Example: All</strong> <code>composes</code> <strong>declarations must come before other rules</strong></p>
<p><code>styles.module.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">4px</span> solid blueviolet;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span> <span class="hljs-number">15px</span>;
}

<span class="hljs-selector-class">.curved</span> {
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.text</span> {
  <span class="hljs-attribute">composes</span>: container;
  <span class="hljs-attribute">composes</span>: curved;
  <span class="hljs-attribute">color</span>: seagreen;
  <span class="hljs-attribute">font-weight</span>: bold;
}
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/3lqshk?file=%2Fsrc%2Fstyles.module.css"><strong>Try it on CodeSandbox</strong></a></p>
<p>You can simplify the <code>.text</code> ruleset by using a single <code>composes</code> declaration for multiple classes.</p>
<p><strong>Example: Compose classes with a single</strong> <code>composes</code> <strong>declaration</strong></p>
<p><code>styles.module.css</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">4px</span> solid blueviolet;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span> <span class="hljs-number">15px</span>;
}

<span class="hljs-selector-class">.curved</span> {
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.text</span> {
  <span class="hljs-attribute">composes</span>: container curved;
  <span class="hljs-attribute">color</span>: seagreen;
  <span class="hljs-attribute">font-weight</span>: bold;
}
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/x4zfyn?file=%2Fsrc%2Fstyles.module.css"><strong>Try it on CodeSandbox</strong></a></p>
<h3 id="heading-how-to-use-a-css-in-js-library-to-style-react-elements">How to use a CSS-in-JS library to style React elements</h3>
<p>A CSS-in-JS library allows you to use the complete features of CSS directly within your JavaScript file.</p>
<p>Some of the popular CSS-in-JS libraries are Linaria, Emotion, Pigment CSS, and Panda CSS.</p>
<p>Feel free to try any CSS-in-JS library you prefer. Here, we’ll use Emotion to illustrate how such a styling technique works in a React application.</p>
<p>So, go ahead and install the library into any of your React projects by running:</p>
<pre><code class="lang-console">npm i @emotion/react@11.14.0
</code></pre>
<p>After you’ve installed Emotion, import it and use it in your component file like so:</p>
<p><code>App.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// The comment below is essential. Emotion will not work without it.</span>
<span class="hljs-comment">/** <span class="hljs-doctag">@jsxImportSource </span><span class="hljs-doctag">@emotion</span>/react */</span>

<span class="hljs-comment">// Define your styles using the JavaScript object syntax.</span>
<span class="hljs-keyword">const</span> codesweetlyStyles = {
  <span class="hljs-attr">border</span>: <span class="hljs-string">"8px ridge #71380f"</span>,
  <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"#ffe5b4"</span>,
  <span class="hljs-attr">padding</span>: <span class="hljs-string">"20px 0 7px"</span>,
  <span class="hljs-attr">textAlign</span>: <span class="hljs-string">"center"</span>,
  <span class="hljs-attr">color</span>: <span class="hljs-string">"maroon"</span>,
  <span class="hljs-string">"@media(min-width: 768px)"</span>: {
    <span class="hljs-attr">color</span>: <span class="hljs-string">"darkslategray"</span>,
  },
};

<span class="hljs-comment">// Apply the styles to your element.</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">css</span>=<span class="hljs-string">{codesweetlyStyles}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Random Image<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://picsum.photos/400/400"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Random Image"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Get a new image each time you refresh your browser.<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> App;
</code></pre>
<p><a target="_blank" href="https://codesandbox.io/p/sandbox/t4ttkx?file=%2Fsrc%2FApp.js"><strong>Try it on CodeSandbox</strong></a></p>
<p>The snippet above does the following:</p>
<ol>
<li><p>Uses the <code>/** @jsxImportSource @emotion/react */</code> comment (JSX Pragma) to tell the Babel JSX plugin to convert the script’s JSX calls to an Emotion function called <code>jsx</code> instead of <code>React.createElement</code>. Make sure you place the pragma directive above your import statements. Otherwise, the Emotion library will not work.</p>
</li>
<li><p>Defines styles in a JavaScript object.</p>
</li>
<li><p>Uses Emotion’s <code>css</code> prop feature to apply the styles to the JSX element.</p>
</li>
</ol>
<p>Notice that the <code>css</code> prop is like the inline <code>style</code> attribute. The main difference is that the <code>css</code> props support more CSS features like nested selectors, auto vendor-prefixing, media queries, and event states (such as <code>hover</code>, <code>focus</code>, and <code>active</code>). So, using CSS-in-JS libraries like Emotion lets you write highly flexible and responsive styles directly in your JavaScript files.</p>
<p><strong>Tip:</strong> The <code>css</code> prop works on any element that supports the <code>className</code> attribute.</p>
<p>Now, go ahead and run your app and check its output in your browser.</p>
<p>And that’s it! You now know how to use the CSS-in-JS library to style your React elements.</p>
<p>I used Emotion in this article because I like how clean its syntax looks. Feel free to test other CSS-in-JS libraries, such as Pigment CSS. You may find one that suits you better.</p>
<h2 id="heading-overview">Overview</h2>
<p>In this handbook, we discussed the core concepts you need to know to start building applications with React. We also used examples to practice creating and styling components.</p>
<p>Whether you’re considering a small personal project or a full-stack app for a larger user base, you now have the foundation to build these projects using React.</p>
<p>Thanks for reading!</p>
<h3 id="heading-dive-deeper-into-react">Dive deeper into React</h3>
<p>This handbook has given you a peek inside my <a target="_blank" href="https://www.amazon.com/dp/B0FRC4R8T3?tag=codesweetly00-20">Code React Sweetly book</a>. Whether you’re just starting or want to sharpen your fundamentals, the book walks you through everything from essential concepts to deploying real apps using JavaScript and TypeScript. It is practical, beginner-friendly, and designed to help you code React sweetly!</p>
<p><a target="_blank" href="https://www.amazon.com/dp/B0FRC4R8T3?tag=codesweetly00-20"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760698961658/f3f297da-1cd2-4777-b440-19b94daaa26f.jpeg" alt="A Beginner’s Guide to React: Learn JSX, Hooks, and Real-World App Development" class="image--center mx-auto" width="970" height="250" loading="lazy"></a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Choose the Best Programming Languages, Libraries, and Patterns ]]>
                </title>
                <description>
                    <![CDATA[ In my first few years learning software development and building applications, I was quite interested in finding the best programming language, platform, libraries, frameworks, patterns, and architectures available. I thought that by finding the best... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-choose-the-best-programming-languages-libraries-and-patterns/</link>
                <guid isPermaLink="false">6898d3414c52a26ffefb1693</guid>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programming languages ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ryan Michael Kay ]]>
                </dc:creator>
                <pubDate>Sun, 10 Aug 2025 17:13:37 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754846007203/c9db729e-ebed-4726-8e3e-5414c8e2714d.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In my first few years learning software development and building applications, I was quite interested in finding the best programming language, platform, libraries, frameworks, patterns, and architectures available. I thought that by finding the <em>best</em> things and focusing on those topics to the exclusion of others, I could avoid wasting precious time.</p>
<p>While I figured out early on that narrowing my focus by using a project-based learning approach (as opposed to the topic-by-topic laundry list approach) was important, finding the best tools for the job was a different matter. </p>
<p>If you happen to be searching for some of those things, then this article is for you. After over a decade of programming products, building client applications, answering thousands of questions from junior and intermediate developers, and wrestling with these questions myself, I will do my best to explain how to find the best <em>things</em>.</p>
<p>This article is intended for junior to intermediate level developers looking to get some practical answers to difficult problems. You will not need extensive programming experience to get through it and you may skip over any technical discussions specifics. Those are meant to be helpful pieces of information, but the core of this article is about how to make these decisions in general using what I call: The Law of Suitability.</p>
<p>The topics I will cover are:</p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-find-the-best-anything">How to Find the Best Anything</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-how-to-find-the-best-water-bottle">How to Find the Best Water Bottle</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-find-the-best-programming-language">How to Find the Best Programming Language</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-navigating-public-and-expert-opinions">Navigating Public and Expert Opinions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-low-level-vs-high-level">Low Level vs High Level</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tightly-structured-static-vs-loosely-structured-dynamic">Tightly Structured (Static) vs Loosely Structured (Dynamic)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-popularity-is-only-one-factor">Popularity Is Only One Factor</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-popularity-is-not-a-guarantee-of-employment">Popularity Is Not A Guarantee Of Employment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-hardware-amp-working-with-what-you-have">Hardware &amp; Working With What You Have</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-if-i-want-the-ai-to-code-for-me">What if I Want the AI to Code For Me?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-avoid-the-sunk-cost-fallacy">Avoid the Sunk-Cost Fallacy</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-find-the-best-libraries-and-frameworks">How to Find the Best Libraries and Frameworks</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-are-libraries-and-frameworks">What Are Libraries and Frameworks?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-choose-libraries-and-frameworks">How to Choose Libraries and Frameworks</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-find-the-best-programming-principles-and-practices">How to Find the Best Programming Principles and Practices</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-dry-dont-repeat-yourself">D.R.Y – Don’t Repeat Yourself</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-about-other-programming-principles">What About Other Programming Principles?</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-a-note-about-patterns-and-architectures">A Note About Patterns and Architectures</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-find-the-best-software-architecture">How to Find the Best Software Architecture</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-design-pattern-trap">The Design Pattern Trap</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-how-to-find-the-best-anything">How to Find the Best Anything</h2>
<p>I invite you to follow along with some basic non-technical examples which lay the groundwork for the rest of this article. The examples may sound silly to some, but I have layered in some conceptual patterns which you can apply to programming languages, tools, and concepts – as well as just about anything where terms like good, bad, best, or worst can apply.</p>
<h3 id="heading-how-to-find-the-best-water-bottle">How to Find the Best Water Bottle</h3>
<p>Suppose that you are looking to solve the problem of staying hydrated and wish to purchase a water bottle. </p>
<p>You consider that figuring out the best water bottle might involve looking into:</p>
<ul>
<li><p>Public opinions and reviews</p>
</li>
<li><p>Expert opinions and reviews</p>
</li>
<li><p>The manufacturer’s descriptions and reputation</p>
</li>
<li><p>Buying and testing water bottles (though preferably not all of them, as that costs too much time and money, generally)</p>
</li>
</ul>
<p>All of those things are fair for consideration. Something which is not well-tested in public presents uncertainty. Expert reviews can help inform your decision, but you have to consider the biases and motivations of such experts. You also should consider if the manufacturer has a history of quality, design, and customer support, or whether they’re simply maximizing profit.</p>
<p>After doing some research, you come up with these options:</p>
<ul>
<li><p>A plastic bottle of water from a vending machine</p>
</li>
<li><p>A high-tech metal bottle which you can even boil stuff in!</p>
</li>
<li><p>A simple but ethically sourced, refillable, BPA-free plastic water bottle</p>
</li>
</ul>
<p>However, you noticed that nobody seemed to universally agree about which option was the best. There were usually some common opinions, but it was never the case that every expert had the same evaluation or recommendation.</p>
<p>After reflecting on this, it became obvious that you need to consider how, when, and where you will be using this water bottle. In other words, you need to <strong>consider the context or situation</strong> of its usage.</p>
<p>Suppose three different contexts within which you have to make this decision:</p>
<ul>
<li><p>You are standing in a rest stop in Death Valley California (often thought to be the hottest place on Earth in summer) and there is a vending machine full of micro-plastic filled, old, generic, and cheap plastic bottles of water in front of you. But you have no other options and are very thirsty</p>
</li>
<li><p>You are in a camping store preparing for a camping trip to New Zealand with lots of hiking and not too much access to filtered water</p>
</li>
<li><p>You are looking on your favorite shopping website for something you can bring to work each day to avoid those dehydration headaches from not drinking enough water</p>
</li>
</ul>
<p>In summary, you shouldn’t ignore second-hand knowledge, expert opinions, popularity, ratings, reviews, testimonials, and even first-hand experience. But you will never find the best water bottle for every situation you find yourself in. The best “anything” depends on the problem you are trying to solve and the context (words like requirements or situation also apply here) of that problem. </p>
<p>In other words, none of these things have an absolute or fixed value – their value is always relative. I call that the <strong>Law of Suitability</strong>.</p>
<p>Let’s now discuss some examples which are directly related to software design and development. </p>
<h2 id="heading-how-to-find-the-best-programming-language">How to Find the Best Programming Language</h2>
<p>The Law of Suitability applies just as much to programming languages as it does to water bottles – even though the details and contexts are different. There is no such thing as the best programming language for every person, team, problem, or feature. </p>
<p>But I do have some specific details and contexts to offer which may help you answer that question for yourself. This section will cover concrete details and some general ideas on how to choose a programming language. These patterns also apply to frameworks, libraries, and most other aspects of programming.</p>
<p>If you are not interested in the topic of finding a programming language, feel free to skip to the next sections on topics like libraries, principles, and patterns.</p>
<h3 id="heading-navigating-public-and-expert-opinions">Navigating Public and Expert Opinions</h3>
<p>Firstly, you need to be skeptical of popularity and the opinions of experts and “influencers” here. </p>
<p>My general tip here is to be extremely cautious about anyone who makes one of these claims:</p>
<ul>
<li><p>“X” language is the best (though saying “X” language is my favourite is perfectly acceptable)</p>
</li>
<li><p>“X” language is the worst, is terrible, is dead, is garbage, is useless, and so on.</p>
</li>
</ul>
<p>There are three groups of people who generally make these sorts of statements:</p>
<ul>
<li><p>Actual experts who are voicing their personal preferences but presenting them as immutable facts (how I wish this was not so common in this industry)</p>
</li>
<li><p>Non-experts parroting opinions of the above group or who have not yet understood the Law of Suitability</p>
</li>
<li><p>Engagement farmers</p>
</li>
</ul>
<p>It’s also worth noting that people can be experts in a subset of problems but that doesn’t guarantee their opinions about all problems are expert level. </p>
<p>This doesn’t mean you should reflexively dismiss expert opinions in general. Consider both the track records of the person and the degree to which they pay attention to the context of their statement. </p>
<p>Let us look at two examples:</p>
<ul>
<li><p><em>Expert A</em> says: “Python has the best tooling, support, and ecosystem for ML development”</p>
</li>
<li><p><em>Expert B</em> says: “Python is the best programming language”</p>
</li>
</ul>
<p>While <em>Expert B</em> is obviously displaying a lack of precision (either deliberately or not) if you have followed me so far, <em>Expert A</em> is a different case. Whether or not the statements made by <em>Expert A</em> are true (for the record, I have written a bit of Python but no ML code), you can tell that they are considering details and context. Look for people like <em>Expert A</em>!</p>
<h3 id="heading-low-level-vs-high-level">Low Level vs High Level</h3>
<p>In simple terms, low level programming languages are difficult for humans to read and write. Also, they tend to be faster and have a lower memory footprint than high level languages. Conversely, high level languages are closer to human language which generally makes them easier for humans to work with.</p>
<p>I must confess, though, that I have seen plenty of examples of people writing unintelligible code in high level languages – please don’t do that.</p>
<p>Someone working on an embedded system might want to do so in a language like C or C++ to optimize performance or work around the limitations of memory and processing power.</p>
<p>But in enterprise systems, which need to run on a variety of platforms and which closely intermingle with business requirements, rules, and real world objects (thing products, users, and so on), lower level languages are not so popular. After all, upper and middle management generally tends to care about low level optimizations only to the extent it affects the user experience. </p>
<p>I love optimization in general, but never forget that everything is fast with small datasets (that is, when <em>n</em> is small) or high processing power. In simpler terms, sometimes human concerns like legibility are significantly more important than insignificant optimizations on efficiency.</p>
<h3 id="heading-tightly-structured-static-vs-loosely-structured-dynamic">Tightly Structured (Static) vs Loosely Structured (Dynamic)</h3>
<p>Ironically, the main downsides and benefits of a language like Java (which is very structured and verbose) versus a language like JavaScript (quite the opposite, depending on how you use it) are the same depending on the context. </p>
<p>Speaking of enterprise systems, using structures, types, interfaces, classes, threading, concurrency primitives, and similar programming constructs can have a variety of benefits. It can insulate you from safety while providing some flexibility via type hierarchies, interfaces, protocols, abstractions and so on.</p>
<p>Further, studying design patterns can teach you repeatable solutions to problems which have been encountered since the dawn of the general purpose computer – or shortly thereafter. </p>
<p>But the Law of Suitability still applies here. Maybe you just need to write a quick script to migrate some data from one SQL database to another. Maybe you know how to approach problems using a more functional approach that doesn’t require or discourages the use of objects, classes, or structs. Maybe you realize one day that trying to apply design patterns, architectures, hierarchies and similar constructs in every situation has actually created as many problems as they were solving. More on that later.</p>
<p>It’s also worth mentioning that most modern language designers and maintainers have understood that we developers like flexibility. Many of us want to avoid premature optimization and unnecessary structure but also don’t want our code to blow up because we accidentally told the program to add together 1.23356 + “Rhinoceros”. </p>
<p>The main point is that structure or a lack of structure is both a blessing and a curse, depending on where it is used.</p>
<h3 id="heading-popularity-is-only-one-factor">Popularity Is Only One Factor</h3>
<p>I’m not going to say that popularity is irrelevant and that you should start with the least popular hipster programming language you can find. No shade intended to hipster programming languages, but unpopularity is not generally a good thing in isolation, either.</p>
<p>The key point is that many people weighing in on programming languages (probably most) don’t have abundant experience working on a variety of platforms, languages, and settings. If someone has only ever written Python and enjoys doing so, they will naturally tend to regard it above others.</p>
<p>We humans have a tendency to find the first thing that works for us and then die on a hill defending it. But to take a more anecdotal approach here, I know a couple dozen intermediate to senior level developers who have extensive experience in Java and other programming languages. Despite Java still being ranked as one of the most popular languages globally, only one of those developers I know actually prefers to write in Java if they have the choice. </p>
<p>Don’t make the mistake of assuming that the first thing that works for many people will be the last thing you need to try out. I have from time to time experimented with languages such as Haskell, which taught me many valuable lessons about the benefits of making my code more functional (and functionally pure) in nature. </p>
<p>But I have zero intention of using Haskell as my go to solution for building GUI applications. </p>
<h3 id="heading-popularity-is-not-a-guarantee-of-employment">Popularity Is Not A Guarantee Of Employment</h3>
<p>One of the most common things you ought to consider is whether or not the language you pick will help you get a job – assuming that’s a concern. Influencers absolutely love to tell people to choose one particular language because it has the most public commits on GitHub, or another because it has the largest number of programmers using it (which is in practice something that’s impossible to say for sure). </p>
<p>Let me flip that on its head: suppose that the most common programming language and platform combination is JavaScript and web. Let’s further suppose that we have pretty concrete data on the number of job postings on the web which confirms that the largest volume of jobs available is for that combination. Let’s finally suppose that for whatever reason, you strongly dislike JavaScript and enjoyed building a website using PHP. </p>
<p>You will find voices who will tell you that PHP is a dead language and a dead end for job searching. </p>
<p>But if you go looking, you may notice that there is a good supply of job postings out there looking for PHP developers who can expand and maintain existing codebases. You might also have a much better chance of getting an interview because <em>the ratio of job postings to applications is significantly better for PHP developers</em> than JavaScript developers. In fact, my team recently hired a PHP developer!</p>
<h3 id="heading-hardware-amp-working-with-what-you-have">Hardware &amp; Working With What You Have</h3>
<p>This section is largely irrelevant to web developers, but may be extremely important for those looking to target specific hardware or operating systems. Simply put, if you don’t have a computer with Mac OS and XCode, you will have a very hard time developing an iOS app, for example. In my case, back in 2014, I chose Android development partly because I had studied a bit of Java – though a big consideration was that I had an Android phone. </p>
<p>There are some ways around this by paying to use a remote device (such as a remote Mac via an online service), but my experience with such services years ago is that they weren’t great.</p>
<p>Think about what resources you have and how that fits into what you want to build or whom you want to work for. If you have not much other than a cheap computer with a web browser, and you still want to build GUI applications, web development can be a great choice.</p>
<h3 id="heading-what-if-i-want-the-ai-to-code-for-me">What if I Want the AI to Code For Me?</h3>
<p>While this topic is worthy of a separate article, I don’t believe this is an unreasonable question to ask. A year ago, I would have told you that at best, the AI can write some basic code and help you learn some things which may or may not be wrong. </p>
<p>How things have changed! Though I would be bad at my job if I copy pasted code I didn’t understand or didn’t test, AI has absolutely become a force multiplier for me as a developer. </p>
<p>Back to the topic in question, how does this relate to choosing a programming language? Well, after telling you that popularity is not always a big deal, by the nature of how LLMs work, popularity is a factor. In terms of general use, languages like Python, JavaScript, and Java are likely to have the largest amount of training data. My experience has been that the languages I typically use, such as Kotlin, TypeScript, and Swift also do fine.</p>
<p>But there is a curious side effect of developing Android or iOS applications that I don’t experience so much in web development. The nature of these constantly changing platforms and SDKs, with tens of thousands of third party libraries, dozens of architectures, and endless opinions about best practices and anti-patterns, means that LLMs can have serious troubles with complexity or specificity. </p>
<p>I expect this issue to be fixed as LLM services improve correctness checking or other methods to reduce hallucinations.</p>
<h3 id="heading-avoid-the-sunk-cost-fallacy">Avoid the Sunk-Cost Fallacy</h3>
<p>Perhaps the most important point I can make in choosing a programming language is to avoid the sunk-cost fallacy. For the first several years of my part-time studies, I didn’t imagine learning a second language based on how difficult it was for me to learn Java.</p>
<p>Roughly 12 years later, I have written non-trivial code in Java, Kotlin, Swift, C++, TypeScript, and SQL. Further, I have dabbled with code in C, Python, JavaScript, Racket, Haskell, Objective C, Visual Basic, and C#. </p>
<p>It was not the case that I sought out to learn all of these things artificially – I don’t tend to learn things outside of the problems in front of me. It’s that these learning opportunities naturally unfolded along with my personal and professional interests. </p>
<p>Learning the fundamentals or approaching mastery of any general purpose programming language will have carry over to others. It’s true that someone learning Python or JavaScript without CS fundamentals is not going to have much of a clue how things work at the OS level or lower. </p>
<p>It’s also true that I have met several people who could probably code circles around me in C/C++/Assembly but never made it past building toy programs in University or College. </p>
<p>Just keep learning and try to find a balance between personal interest and professional goals.</p>
<h2 id="heading-how-to-find-the-best-libraries-and-frameworks">How to Find the Best Libraries and Frameworks</h2>
<p>The next few topics revolve around a question which we’ll revisit a couple of times before the end of this article: “<em>Does it solve more problems than it creates?</em>”</p>
<h3 id="heading-what-are-libraries-and-frameworks">What Are Libraries and Frameworks?</h3>
<p>Before we proceed, here’s a useful but not definitive definition about the relationship between libraries and frameworks. You’ll find other definitions, but there’s remarkably little consensus on topics like this in this industry.</p>
<p>For me, a library is code which you can take from somewhere and use it to build things. It could be anything from a single line to a large and complex sub-system – usually something in between. I could give you a long and pedantic definition, but that’s not appropriate for this context (suitability!). </p>
<p>One example could be Java’s Math (java.lang.Math) library, which provides you with the following: “<em>The class Math contains methods for performing basic numeric operations such as the elementary exponential, logarithm, square root, and trigonometric functions.</em>”</p>
<p>Some people use the term framework interchangeably with library, and I don’t have any problems with that. When I think of a framework, I’m thinking about something which you build stuff around and is not necessarily to do with solving a specific problem domain (such as mathematics). </p>
<p>An example of this would be RxJava, which is a rather complex framework you can use to bind together and manage data flows across an entire application. I’ve used this framework in almost a dozen applications which did very different things in principle.</p>
<p>I do consider a framework to be a library, fundamentally – they just have a different set of goals and often a larger footprint.</p>
<h3 id="heading-how-to-choose-libraries-and-frameworks">How to Choose Libraries and Frameworks</h3>
<p>When I think about choosing libraries and frameworks, I ask myself these questions:</p>
<ul>
<li><p>Does it solve more problems than it creates compared to writing my own solution?</p>
</li>
<li><p>Is it well-maintained (regularly worked on, responsive authors, backed by tech companies)?</p>
</li>
<li><p>Does it have good documentation (less of a problem now that we can leverage AI for this purpose)?</p>
</li>
<li><p>What kind of footprint does it have?</p>
</li>
</ul>
<p>Let’s take two examples. I won’t refer to the specific platform or name of these libraries to avoid offending anyone. But they were/are both used in mobile development (though they are solving common GUI problems on any platform).</p>
<p>Firstly, one of my favorite libraries had one job: It loads images into the UI. </p>
<p>Although devices are more powerful than they used to be, it can still be a problem to load large images on smart phones for display. Mobile operating systems can be aggressive about killing programs (that is, processes) which use up too much of the system’s resources.</p>
<p>This library handles all aspects of loading images that I’m concerned about:</p>
<ul>
<li><p>Loading the image into a particular widget</p>
</li>
<li><p>Displaying an appropriate loading indicator </p>
</li>
<li><p>Displaying an optional error or fallback state that tells the user something went wrong</p>
</li>
<li><p>Handling the complexities of asynchronously loading in (via URL/URI), processing, and compressing potentially large streams of bits (that is, image data)</p>
</li>
<li><p>Doesn’t inflate the packaged application’s size unnecessarily</p>
</li>
<li><p>Doesn’t change its public API frequently (think changing function names which cause people’s implementations to break when updating versions)</p>
</li>
<li><p>It solves problems that I’m not interested in solving</p>
</li>
</ul>
<p>Secondly, one of my least favorite libraries also had one job: Pagination. Pagination, or paging, in this case refers to loading data in <em>chunks</em> into an application. This is an extremely common pattern in shopping cart or social media applications. </p>
<p>The library I am thinking of approaches that problem like so:</p>
<ul>
<li><p>Tightly couples every layer of your client application (from front end to back end) to its dependencies</p>
</li>
<li><p>This tight coupling makes testing difficult without jumping through some hoops</p>
</li>
<li><p>Handles the core problem of pagination well unless you need customization or specialized cases</p>
</li>
<li><p>Frequently changed its public facing API</p>
</li>
<li><p>Solved (in general) a problem which I am quite happy to write my own solution for</p>
</li>
<li><p>Did not play well with other frameworks due to a restrictive set of types and lack of flexibility</p>
</li>
<li><p>Was constantly updated for a couple of years then ditched and marked deprecated</p>
</li>
<li><p>Did not inflate the packaged applications size too much but certainly more than my own solution would</p>
</li>
</ul>
<p>As you can see, even something which solves a core problem reasonably well, can still fail this simple test of: Does it solve more problems than it creates? Having written pagination code by myself on a couple of occasions now, I would have to be pretty strongly convinced not to. </p>
<h2 id="heading-how-to-find-the-best-programming-principles-and-practices">How to Find the Best Programming Principles and Practices</h2>
<p>There are more best practices and principles than I care to describe in detail. What I will do is explain why I treat programming principles as being distinct from immutable/unbreakable laws. Similarly to my goal of finding the best programming language, I wanted to find the best principles in order to write the best code. </p>
<p>The problem is that any programming principle I’ve come across has also been subject to the Law of Suitability. I’ll discuss one example from personal experience and point out that the question we asked above, “does it solve more problems than creates,” also applies here.</p>
<h3 id="heading-dry-dont-repeat-yourself">D.R.Y – Don’t Repeat Yourself</h3>
<p>This principle can be summarized with the idea that if you find duplicated code, you should pull it into a separate module (file, function, class, library, and so on). Without getting into the weeds, the act of pulling the duplicated code into a separate module can be thought of as a process of abstraction. </p>
<p>To be fair to the creators and proponents of this idea, it’s more nuanced than that. But many developers never bother to dig that deep into nuances – nor should they have to. I ran into the nuances simply by applying this idea more than I should have.</p>
<p>There a couple of cases where code duplication is sometimes preferable:</p>
<ul>
<li><p>You have a set of similar modules (say similar widgets or business rules) but they get used in different places for different reasons</p>
</li>
<li><p>You have a set of similar modules which might change for different reasons (for example, rapidly changing demands from product teams and clients with different priorities) </p>
</li>
<li><p>You’re deliberately grouping certain modules that work together in distinct packages, files, or directories to insulate modules/groupings from affecting each other</p>
</li>
<li><p>You find that you need to add details about one particular implementation into your abstraction, but those details don’t apply to other implementations (that is, it’s a bad abstraction)</p>
</li>
</ul>
<p>All of the things I listed above are summaries of things I have run into in the past. The key take away is that I broadly agree with avoiding code duplication. I also know of some cases where I prefer it. Suitability!</p>
<h3 id="heading-what-about-other-programming-principles">What About Other Programming Principles?</h3>
<p>In general, you can think of all programming principles like YAGNI, DRY, SRP (and other aspects of SOLID), and even software development methodologies like AGILE and Waterfall in the same way. Contextually, you can use them as guidelines to help avoid some common problems. But a person of sufficient creativity and experience can come up with a situation where following any of these principles creates more problems than it solves.</p>
<p>In many cases, you need to apply these things too much in order to understand what too much means in practical terms. Just be careful not to swing too far in the other direction when one of these principles really breaks down in front of you. I’ve also made that mistake and had to re-adjust.</p>
<p>To date, I haven’t come across a programming principle which is universally true. There are some which come close to that, but I can always imagine a situation where they’re not the best approach. Take a good one like: Always write the simplest code you can write. In other words, don’t add extra complexity without a reason. </p>
<p>Well, suppose you have a not great value system or incentive structure which encourages inflating your work artificially. Need I say more?</p>
<h2 id="heading-a-note-about-patterns-and-architectures">A Note About Patterns and Architectures</h2>
<p>I’ll now discuss the topic of patterns and architectures in software systems with respect to the Law of Suitability. Software architecture is the only thing I consider myself an expert in, and I have read multiple books on design patterns. I always try to provide some useful info on these topics when I get the chance.</p>
<h3 id="heading-how-to-find-the-best-software-architecture">How to Find the Best Software Architecture</h3>
<p>To summarize entire articles, courses, and public talks I have given on this topic: The best software architecture depends on project and personal requirements. </p>
<p>One way to grasp the main idea is to ask yourself whether the best architecture for a hospital is also a good fit for a 2-bedroom apartment. The obvious answer is that we might expect a few commonalities (doors, windows, bathrooms of some kind, and so on) among these different sets of requirements. But the ideal, or even just a good architecture for a 2 bedroom apartment cannot possibly be the same for a hospital. </p>
<p>In short, you will never find an architecture which works well for all projects and requirements.</p>
<p>Here is a list of architectures I have some familiarity with:</p>
<ul>
<li><p>Model-View-Controller</p>
</li>
<li><p>Model-View-Presenter</p>
</li>
<li><p>Model-View-ViewModel</p>
</li>
<li><p>VIPER</p>
</li>
<li><p>Clean Architecture (Robert C. Martin style)</p>
</li>
<li><p>Model-View-Intent</p>
</li>
</ul>
<p>To make matters more confusing, there are multiple different ways to implement these architectures – almost as many ways as developers implementing them! M-V-VM is one of the more common architectures in mobile development, and I can think of at least five different variations on how to achieve what some people think of as a single architecture.</p>
<p>Here are my general suggestions for working with these architectures:</p>
<ul>
<li><p>Be wary of adding unnecessary complexity with the more complex architectures (particularly Clean Architecture, as many people get this horribly wrong)</p>
</li>
<li><p>Don’t try to make the project requirements fit the architecture – work the other way around (the best indicator for this is noticing that something you’re trying to implement is made unnecessarily difficult because of the architecture you’re using)</p>
</li>
<li><p>Don’t be afraid of applying different approaches in different features of the same application instead of blindly applying the same pattern just for consistency’s sake</p>
</li>
</ul>
<h3 id="heading-the-design-pattern-trap">The Design Pattern Trap</h3>
<p>One of the most common engagement farming tactics I see on social media is to post lists of design patterns “that you must know” in order to get a job or to scare junior programmers into buying your low-quality, copy-pasted content of each pattern.</p>
<p>Don’t get me wrong, I loved studying design patterns and I use a couple key patterns in most GUI applications I build. The Observer (a.k.a. Publisher-Subscriber or Pub-Sub) Pattern really shines when you need to glue together a bunch of asynchronous data sources. I love seeing library developers give me a nice Builder Pattern to work with their APIs. I think understanding the basics of patterns like the Bridge or Facade can teach you how to hide details behind abstractions, which is actually simpler than the big scary words describing these things make it sound.</p>
<p>But I spend very little time in my day to day work thinking about or in design patterns. Instead, I’m always thinking about the kinds of attitudes and principles that give rise to these patterns: </p>
<ul>
<li><p>Promoting loosely coupled code (separating the creation and usage of dependencies and parameters, reasonable usage of abstraction)</p>
</li>
<li><p>Writing classes, interfaces, protocols, and functions which do one thing (though this “one thing” might be a macroscopic goal instead of a microscopic operation)</p>
</li>
<li><p>Avoiding complexity wherever possible (a common source of this complexity is over-use of abstractions)</p>
</li>
<li><p>Not pretending that every complex problem has a simple solution (that is, as simple as it can be but no simpler)</p>
</li>
<li><p>Avoiding pre-mature optimization</p>
</li>
</ul>
<p>Again, I will only apply these principles and attitudes to the extent that I find they solve more problems than they create. Design patterns, when applied too rigorously, can break many of those principles – particularly when it comes to avoiding complexity and pre-mature optimization. </p>
<p>Don’t try to make your project requirements fit your patterns. Instead, think about which patterns might suit your project requirements and deviate as necessary.</p>
<h2 id="heading-summary">Summary</h2>
<p>My goal with this piece was to provide three things:</p>
<ul>
<li><p>A practical overview of choosing a programming language and avoiding the traps the people can fall into when navigating these sorts of topics</p>
</li>
<li><p>A philosophical but pragmatic framework which you can use to evaluate the suitability of anything – with emphasis on learning and developing software</p>
</li>
<li><p>A breakdown of how I approach other topics like tools, architectures, and patterns</p>
</li>
</ul>
<p>While it can be important to consider things like job opportunities and your current hardware, don’t discount personal interest as a driving factor. From what little I remember about studying cognition (learning how to learn), interest is tightly coupled to motivation and memory. We can’t always exclusively do what interests us, but I suggest you look for intersections between personal and practical concerns as often as you can. </p>
<p>In closing, I encourage you to think about other areas where you might be able to explore the principles of suitability and the problems of tribalistic thinking. Change is constant and value is relative.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Embedded Swift: A Modern Approach to Low-Level Programming ]]>
                </title>
                <description>
                    <![CDATA[ Embedded programming has long been dominated by C and C++, powering everything from microcontrollers to real-time systems. While these languages offer unmatched low-level control, they also introduce persistent challenges, manual memory management, u... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/embedded-swift-a-modern-approach-to-low-level-programming/</link>
                <guid isPermaLink="false">688d5fc7d30be1cecdacf767</guid>
                
                    <category>
                        <![CDATA[ embedded systems ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firmware Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C++ ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ memory-management ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programming languages ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Soham Banerjee ]]>
                </dc:creator>
                <pubDate>Sat, 02 Aug 2025 00:45:59 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754090186842/80a42dca-f2c4-49de-b704-2e90134c6397.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Embedded programming has long been dominated by C and C++, powering everything from microcontrollers to real-time systems. While these languages offer unmatched low-level control, they also introduce persistent challenges, manual memory management, unsafe pointer operations, and subtle logic bugs stemming from weak type systems and undefined behavior.</p>
<p>With the release of Swift 6 and its new Embedded Swift compilation mode, developers now have access to a modern, memory-safe, and performant alternative that’s tailored specifically for resource-constrained systems.</p>
<p>While languages like Rust have also emerged to address these issues, Embedded Swift brings the clarity and safety of Swift to microcontroller environments, without giving up on determinism, binary size, or hardware access.</p>
<p>This article introduces Embedded Swift and explores how it compares to traditional C/C++ development. We’ll cover its key features, programming and memory models, how to set up the toolchain for STM32 microcontrollers, and how to link Swift with existing C drivers.</p>
<p>Along the way, we’ll examine performance trade-offs, growing ecosystem support, and the broader industry movement toward memory-safe languages. As I hope you’ll see, Swift is a serious contender in the future of embedded development.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To get the most out of this article, you should have a basic understanding of programming in Swift and C. Familiarity with embedded hardware platforms and firmware development concepts will also be helpful.</p>
<p>If you're new to embedded systems, consider reviewing this <a target="_blank" href="https://www.freecodecamp.org/news/learn-embedded-systems-firmware-basics-handbook-for-devs/">introductory guide to embedded firmware</a> to build foundational knowledge before diving into Embedded Swift.</p>
<h2 id="heading-scope">Scope</h2>
<p>This article is intended as a practical introduction to Embedded Swift. It covers:</p>
<ul>
<li><p>An overview of Embedded Swift and its key language features</p>
</li>
<li><p>Swift’s programming and memory model in an embedded context</p>
</li>
<li><p>Setting up the Embedded Swift toolchain on macOS for STM32 microcontrollers</p>
</li>
<li><p>Interoperability with C code and linking to existing low-level drivers</p>
</li>
<li><p>A look at memory and instruction-level performance</p>
</li>
<li><p>Future directions and use cases for Embedded Swift</p>
</li>
</ul>
<p>Note that this article does not provide a full tutorial on the Swift language itself. While the primary focus is on STM32, similar principles apply to other supported platforms such as ESP32, Raspberry Pi Pico, and nRF52.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-swift-what-is-embedded-swift">What is Swift? What is Embedded Swift?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-swift-programming-model">Swift Programming Model</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-swift-memory-management">Swift Memory Management</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-memory-and-instruction-cycle-comparison">Memory and Instruction Cycle Comparison</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-setup-embedded-swift">How to Setup Embedded Swift</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-c-swift-linkages">C-Swift Linkages:</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-future-work">Future Work</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-swift-what-is-embedded-swift">What is Swift? What is Embedded Swift?</h2>
<p>Swift is a modern programming language developed by Apple that combines the performance of compiled languages with the expressiveness and safety of modern language design. While Swift was originally created for iOS and macOS development, it has evolved into a powerful general-purpose language used in server-side development, systems programming, and increasingly, embedded systems.</p>
<p>Embedded Swift is a special compilation mode introduced in Swift 6 that brings the benefits of Swift to resource-constrained platforms like microcontrollers. It lets developers use a safe, high-level language while still producing compact, deterministic, and performant binaries suitable for embedded applications.</p>
<h3 id="heading-key-features-of-swift">Key Features of Swift</h3>
<p>Embedded Swift retains many of the powerful language features that make Swift an attractive alternative to C/C++ in embedded development:</p>
<p><strong>Type Safety</strong>: Swift uses a strong static type system, which prevents many programming errors at compile time. Unlike C, where type mismatches can result in undefined behavior, Swift ensures all types are used correctly before code even runs.</p>
<p><strong>Strict Type Checking</strong>: Swift doesn't allow implicit type conversions that could lose data or cause unexpected behavior. For example:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// This won't compile in Swift</span>
<span class="hljs-keyword">let</span> integer: <span class="hljs-type">Int</span> = <span class="hljs-number">42</span>
<span class="hljs-keyword">let</span> decimal: <span class="hljs-type">Double</span> = <span class="hljs-number">3.14</span>
<span class="hljs-keyword">let</span> result = integer + decimal  <span class="hljs-comment">// Error: Cannot convert value of type 'Int' to expected argument type 'Double'</span>

<span class="hljs-comment">// You must be explicit about conversions</span>
<span class="hljs-keyword">let</span> result = <span class="hljs-type">Double</span>(integer) + decimal  <span class="hljs-comment">// Correct</span>
</code></pre>
<p><strong>Non-nullable Types by Default</strong>: In C, pointers can be null by default, which introduces risk. In Swift, variables cannot be nil unless explicitly marked as optionals:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">var</span> name: <span class="hljs-type">String</span> = <span class="hljs-string">"John"</span>
name = <span class="hljs-literal">nil</span>  <span class="hljs-comment">// Compile error - String cannot be nil</span>

<span class="hljs-keyword">var</span> optionalName: <span class="hljs-type">String?</span> = <span class="hljs-string">"John"</span>
optionalName = <span class="hljs-literal">nil</span>  <span class="hljs-comment">// This is allowed</span>
</code></pre>
<h4 id="heading-memory-safety-via-arc-covered-in-detail-later">Memory Safety via ARC (Covered in detail later):</h4>
<p>Swift manages memory automatically using Automatic Reference Counting (ARC). Unlike manual memory management in C/C++, ARC handles object lifecycles efficiently without unpredictable garbage collection pauses. We'll cover ARC and its impact in embedded contexts in a dedicated section later.</p>
<p><strong>Modern Syntax</strong>:<br>Swift's syntax is clean, consistent, and designed for readability. It supports modern paradigms including:</p>
<ul>
<li><p>Functional programming (map, filter, reduce)</p>
</li>
<li><p>Generics (type-safe abstractions)</p>
</li>
<li><p>Protocol-Oriented Programming (discussed in the next section)</p>
</li>
</ul>
<p>These features allow you to write more expressive and maintainable code compared to procedural C or inheritance-heavy C++.</p>
<p><strong>Performance</strong>:<br>Swift is designed to perform on par with C++ in many scenarios. Optimizations such as inlining, dead code elimination, and static dispatch help ensure that high-level abstractions don’t compromise performance. In embedded mode, Swift disables features like runtime reflection and dynamic dispatch to further reduce overhead.</p>
<p>To fully leverage Swift for embedded development, it's important to understand its programming model. Unlike C’s procedural approach or C++’s class-heavy design, Swift promotes protocol-oriented programming and composition, which offers both flexibility and safety in embedded system design.</p>
<h2 id="heading-swift-programming-model">Swift Programming Model</h2>
<p>Swift embraces a multi-paradigm programming model that blends object-oriented, functional, and protocol-oriented programming, all underpinned by strong type safety and memory safety.</p>
<p>For embedded developers coming from C or C++, this model may feel different at first. But it provides a more modular and testable way to build complex systems, something especially valuable in embedded applications where hardware abstraction and strict reliability are critical.</p>
<h3 id="heading-protocol-oriented-programming-pop">Protocol-Oriented Programming (POP)</h3>
<p>Swift emphasizes protocols over inheritance, encouraging developers to define behaviors through protocols and implement them using value types like <code>struct</code> and <code>enum</code>, rather than relying heavily on classes.</p>
<p>This philosophy favors composition over inheritance, allowing you to build complex functionality by combining smaller, well-defined components.</p>
<p>Key Concepts<strong>:</strong></p>
<ul>
<li><p><code>protocol</code> defines required behavior.</p>
</li>
<li><p>Protocol extensions provide default behavior.</p>
</li>
<li><p>Prefer value semantics using <code>struct</code>.</p>
</li>
</ul>
<p>Example<strong>:</strong></p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">Speakable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">speak</span><span class="hljs-params">()</span></span>
}

<span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">Speakable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">speak</span><span class="hljs-params">()</span></span> {
        <span class="hljs-built_in">print</span>(<span class="hljs-string">"Default sound"</span>)
    }
}

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Dog</span>: <span class="hljs-title">Speakable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">speak</span><span class="hljs-params">()</span></span> {
        <span class="hljs-built_in">print</span>(<span class="hljs-string">"Woof!"</span>)
    }
}
</code></pre>
<p>Embedded Swift uses protocols with static dispatch. With static dispatch, the compiler knows the exact memory address of the function to call and can generate a direct jump instruction. There's no runtime lookup, no indirection, and no uncertainty.</p>
<h4 id="heading-why-pop-matters-for-embedded-systems">Why POP Matters for Embedded Systems</h4>
<p>First, you get flexible hardware extraction. Protocols make it easy to define interfaces for hardware components, allowing for mock implementations during testing or platform-specific variations.</p>
<p>Second, you have nice low overhead. Embedded Swift uses static dispatch for protocols, meaning there’s no runtime lookup, and calls are resolved at compile time for maximum performance.</p>
<p>Also, <code>struct</code> and <code>enum</code> types avoid heap allocations, making code more efficient and predictable in low-memory environments.</p>
<p>Now that we’ve explored how Swift’s programming model enables safer and more modular embedded code, let’s turn to another critical piece of the puzzle: memory management. Swift’s use of Automatic Reference Counting (ARC) replaces manual memory handling and offers important benefits, and tradeoffs, for embedded systems.</p>
<h2 id="heading-swift-memory-management">Swift Memory Management</h2>
<p>One of Swift’s most impactful features, especially in the context of embedded systems, is its use of Automatic Reference Counting (ARC) for memory management. Unlike C/C++, where memory must be manually allocated and freed using <code>malloc</code> and <code>free</code>, Swift automates this process while maintaining deterministic performance.</p>
<p>This automation significantly reduces the risk of common memory-related bugs like leaks, dangling pointers, or use-after-free errors, all of which are notorious in low-level C code.</p>
<h3 id="heading-how-arc-works">How ARC works</h3>
<p>Swift supports ARC not only for the Cocoa Touch API's but for all APIs, providing a streamlined approach to memory management. Unlike garbage collection systems that can cause unpredictable pauses, ARC works deterministically at compile time and runtime to manage memory.</p>
<p>ARC automatically tracks and manages the lifetime of objects in memory based on how many references point to them.</p>
<ul>
<li><p>Reference Counting: Every object has a counter that tracks how many strong references point to it.</p>
</li>
<li><p>Retain / Release: The compiler inserts <code>retain</code> and <code>release</code> calls automatically during assignment and deinitialization.</p>
</li>
<li><p>Immediate Deallocation: When the reference count reaches zero, the object is deallocated immediately.</p>
</li>
<li><p>Deterministic: Unlike garbage collectors, ARC doesn’t introduce unpredictable pauses or runtime scanning.</p>
</li>
</ul>
<p>Swift offers multiple reference types to give you precise control over memory behavior and prevent cycles:</p>
<p><strong>Strong References</strong> (default)</p>
<ul>
<li><p>Keeps the referenced object alive.</p>
</li>
<li><p>Used in most cases.</p>
</li>
</ul>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MotorController</span> </span>{
    <span class="hljs-keyword">var</span> sensor: <span class="hljs-type">SensorData?</span>  <span class="hljs-comment">// Strong reference</span>

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateReading</span><span class="hljs-params">(newData: SensorData)</span></span> {
        <span class="hljs-keyword">self</span>.sensor = newData  <span class="hljs-comment">// Previous sensor data automatically deallocated</span>
    }
}
</code></pre>
<p><strong>Weak References</strong></p>
<ul>
<li><p>Used to break reference cycles (especially in two-way object relationships).</p>
</li>
<li><p>Automatically becomes <code>nil</code> when the referenced object is deallocated.</p>
</li>
</ul>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Device</span> </span>{
    <span class="hljs-keyword">var</span> controller: <span class="hljs-type">MotorController?</span>

    <span class="hljs-keyword">deinit</span> {
        <span class="hljs-built_in">print</span>(<span class="hljs-string">"Device deallocated"</span>)
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MotorController</span> </span>{
    <span class="hljs-keyword">weak</span> <span class="hljs-keyword">var</span> device: <span class="hljs-type">Device?</span>  <span class="hljs-comment">// ← Weak reference breaks the cycle</span>

    <span class="hljs-keyword">deinit</span> {
        <span class="hljs-built_in">print</span>(<span class="hljs-string">"MotorController deallocated"</span>)
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">breakCycle</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">let</span> device = <span class="hljs-type">Device</span>()
    <span class="hljs-keyword">let</span> controller = <span class="hljs-type">MotorController</span>()

    device.controller = controller
    controller.device = device  <span class="hljs-comment">// ← This is now a weak reference</span>

    <span class="hljs-comment">// When this function ends, both objects are properly deallocated</span>
}

breakCycle()
<span class="hljs-comment">// Output:</span>
<span class="hljs-comment">// Device deallocated</span>
<span class="hljs-comment">// MotorController deallocated</span>
</code></pre>
<p><strong>Unowned References</strong></p>
<ul>
<li><p>Non-optional version of <code>weak</code>.</p>
</li>
<li><p>Assumes the object will never be deallocated while still in use.</p>
</li>
<li><p>More lightweight than <code>weak</code>, but unsafe if misused.</p>
</li>
</ul>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SensorSystem</span> </span>{
    <span class="hljs-keyword">unowned</span> <span class="hljs-keyword">let</span> controller: <span class="hljs-type">MotorController</span>  <span class="hljs-comment">// unowned reference</span>

    <span class="hljs-keyword">init</span>(controller: <span class="hljs-type">MotorController</span>) {
        <span class="hljs-keyword">self</span>.controller = controller
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MotorController</span> </span>{
    <span class="hljs-keyword">var</span> sensorSystem: <span class="hljs-type">SensorSystem?</span>

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">setupSensors</span><span class="hljs-params">()</span></span> {
        sensorSystem = <span class="hljs-type">SensorSystem</span>(controller: <span class="hljs-keyword">self</span>)
    }

    <span class="hljs-keyword">deinit</span> {
        <span class="hljs-built_in">print</span>(<span class="hljs-string">"MotorController deallocated"</span>)
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">testUnowned</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">let</span> controller = <span class="hljs-type">MotorController</span>()
    controller.setupSensors()
    <span class="hljs-comment">// sensorSystem deallocates before controller ends</span>
}

testUnowned()
<span class="hljs-comment">// Output: MotorController deallocated</span>
</code></pre>
<h3 id="heading-arc-overhead-in-embedded-systems">ARC Overhead in Embedded Systems</h3>
<p>While ARC provides safety benefits, it does introduce some overhead compared to manual memory management:</p>
<h4 id="heading-memory-overhead">Memory Overhead:</h4>
<p>ARC-managed class instances in Swift typically include an additional 4 or 8 bytes to store reference count metadata, depending on the system architecture, 4 bytes on 32-bit systems and 8 bytes on 64-bit systems. This metadata allows the runtime to track how many active references exist to a given object and deallocate it when no references remain. When developers use weak or unowned references, the memory footprint increases further. These references require additional data structures, such as side tables or tracking mechanisms, to manage object liveness and cleanup. In the case of weak references specifically, Swift maintains zeroing weak reference tables that automatically null out pointers once the referenced object is deallocated, ensuring memory safety.</p>
<h4 id="heading-cpu-overhead">CPU Overhead:</h4>
<p>ARC introduces some runtime overhead due to retain and release operations, which are inserted automatically during reference assignments. These operations involve incrementing or decrementing the reference count and are especially common in code that passes objects between functions or stores them in collections. To ensure thread safety, these updates are typically implemented using atomic operations, which add further instruction cycles. In complex object graphs, ARC may also engage in cycle detection and cleanup through the use of weak references to prevent memory leaks caused by strong reference cycles. While Swift's ARC provides deterministic and efficient memory management, it does so with both memory and CPU costs that developers should consider carefully, especially in performance-critical embedded systems.</p>
<h3 id="heading-type-safety-and-error-prevention">Type Safety and Error Prevention</h3>
<p>Swift's type system prevents many common errors that plague C/C++ programs:</p>
<ul>
<li><p><strong>Buffer Overflows</strong>: Swift arrays are bounds-checked, preventing buffer overflow vulnerabilities that are common in C.</p>
</li>
<li><p><strong>Null Pointer Dereferences</strong>: Swift's optional types make null pointer dereferences impossible at compile time.</p>
</li>
<li><p><strong>Use After Free</strong>: Swift's ownership model prevents use-after-free errors that can cause crashes or security vulnerabilities.</p>
</li>
</ul>
<p>Now that we’ve covered Swift's memory model and ARC behavior, let’s explore how it compares to C in terms of memory usage and instruction cycles, a crucial aspect when evaluating Embedded Swift for real-world deployment.</p>
<h2 id="heading-memory-and-instruction-cycle-comparison">Memory and Instruction Cycle Comparison</h2>
<p>Understanding the performance characteristics of Swift versus C is essential for embedded systems, where every instruction cycle and byte of memory matters. While Swift brings advantages like safety and expressiveness, these benefits come with certain trade-offs in terms of memory usage and runtime behavior that embedded developers must evaluate carefully.</p>
<h3 id="heading-memory-management">Memory Management:</h3>
<p>Swift uses Automatic Reference Counting (ARC) to manage memory. ARC tracks the number of references to each object and deallocates it when no references remain. This eliminates the need for explicit <code>free()</code> calls but introduces overhead.</p>
<p>C, in contrast, uses manual memory management. Developers allocate memory using <code>malloc</code> and release it using <code>free</code>, or rely on the stack for most short-lived data.</p>
<p>The table below provides the memory management comparison between Swift and C:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Feature</strong></td><td><strong>Swift (ARC)</strong></td><td><strong>C (Manual)</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Memory strategy</td><td>Automatic reference counting</td><td>Manual with <code>malloc</code>/<code>free</code></td></tr>
<tr>
<td>Overhead per object</td><td>4–8 bytes (for ref count)</td><td>None for stack; variable for heap</td></tr>
<tr>
<td>Deallocation</td><td>Deterministic, triggered by ARC</td><td>Developer-controlled</td></tr>
<tr>
<td>Weak reference support</td><td>Requires additional metadata</td><td>Not built-in</td></tr>
<tr>
<td>Thread safety</td><td>Atomic operations in ARC</td><td>Not guaranteed</td></tr>
<tr>
<td>Layout control</td><td>Limited, compiler-managed</td><td>Full control (via structs/pointers)</td></tr>
</tbody>
</table>
</div><p>Swift ensures safety through deterministic cleanup and predictable memory usage. But this comes at the cost of added memory and CPU overhead.</p>
<p>C’s approach offers complete control over memory layout and minimal runtime cost, but increases the risk of memory leaks and fragmentation without disciplined practices.</p>
<h3 id="heading-instruction-cycle-analysis">Instruction Cycle Analysis</h3>
<p>The safety features in Swift, such as bounds checking, optional unwrapping, and ARC updates, translate into additional CPU instructions. While this can impact performance, the Swift compiler is aggressive about optimization in release builds. For example, inlining and ARC elision can remove much of the overhead in performance-critical paths.</p>
<p>C has no built-in safety checks, allowing it to generate highly efficient, predictable code. Developers can even use inline assembly for tight control over performance.</p>
<p>The table below provides the instruction cycle comparison between Swift and C:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Instruction-Level Feature</strong></td><td><strong>Swift</strong></td><td><strong>C</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Reference count updates</td><td>2–4 instructions per assignment</td><td>N/A</td></tr>
<tr>
<td>Bounds checking</td><td>1–3 instructions per array access</td><td>None</td></tr>
<tr>
<td>Optional unwrapping</td><td>1–2 instructions per check</td><td>N/A</td></tr>
<tr>
<td>Method dispatch</td><td>Protocols introduce indirection</td><td>Direct calls or function pointers</td></tr>
<tr>
<td>Optimization potential</td><td>ARC elision, inlining, dead code removal</td><td>Full manual control, inline assembly</td></tr>
<tr>
<td>Predictability</td><td>High in optimized builds, with some abstraction overhead</td><td>Very high, minimal abstraction</td></tr>
</tbody>
</table>
</div><p>Although Swift inserts extra instructions for safety, much of this cost can be mitigated through compiler optimization.</p>
<p>C has no such features by default, making it ideal for applications where performance must be tightly controlled and the developer is willing to take full responsibility for safety.</p>
<h3 id="heading-instruction-count-comparison-swift-vs-c-loop-performance">Instruction Count Comparison: Swift vs C Loop Performance</h3>
<p>When evaluating Swift and C for embedded use, it's helpful to analyze instruction-level performance on basic operations, such as a loop that processes an array of floating-point numbers. This gives us a concrete sense of the computational cost of each language's safety and abstraction features.</p>
<p>Let’s consider a simple example: summing an array of <code>Float</code> values and returning the average. In Swift, the code uses a high-level <code>for-in</code> loop over an array:</p>
<p>Simple loop performance:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// Swift loop with safety checks</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">processData</span><span class="hljs-params">(<span class="hljs-number">_</span> data: [Float])</span></span> -&gt; <span class="hljs-type">Float</span> {
    <span class="hljs-keyword">var</span> sum: <span class="hljs-type">Float</span> = <span class="hljs-number">0.0</span>
    <span class="hljs-keyword">for</span> value <span class="hljs-keyword">in</span> data {  <span class="hljs-comment">// Iterator with bounds checking</span>
        sum += value     <span class="hljs-comment">// Safe arithmetic</span>
    }
    <span class="hljs-keyword">return</span> sum / <span class="hljs-type">Float</span>(data.<span class="hljs-built_in">count</span>)  <span class="hljs-comment">// Safe division</span>
}
<span class="hljs-comment">// Estimated: ~8-10 instructions per iteration</span>
</code></pre>
<p>Although elegant and safe, this loop includes several safety mechanisms:</p>
<ol>
<li><p>Bounds checking on every array access</p>
</li>
<li><p>Reference counting if <code>data</code> is passed as a reference type</p>
</li>
<li><p>Overflow protection in debug mode</p>
</li>
<li><p>Optional handling or runtime checks if <code>data</code> might be empty</p>
</li>
</ol>
<p>These checks introduce runtime overhead, resulting in an estimated 8–10 instructions per iteration on most platforms (depending on optimization level and target architecture). In release builds, Swift aggressively inlines and strips redundant checks, but some level of abstraction cost remains, especially compared to raw memory access in C.</p>
<p>Now, compare that to its equivalent in C:</p>
<pre><code class="lang-c"><span class="hljs-comment">// C loop without safety checks</span>
<span class="hljs-function"><span class="hljs-keyword">float</span> <span class="hljs-title">process_data</span><span class="hljs-params">(<span class="hljs-keyword">float</span>* data, <span class="hljs-keyword">int</span> count)</span> </span>{
    <span class="hljs-keyword">float</span> sum = <span class="hljs-number">0.0f</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; count; i++) {  <span class="hljs-comment">// Direct pointer arithmetic</span>
        sum += data[i];                <span class="hljs-comment">// Direct memory access</span>
    }
    <span class="hljs-keyword">return</span> sum / count;  <span class="hljs-comment">// Direct division (no safety check)</span>
}
<span class="hljs-comment">// Estimated: ~4-5 instructions per iteration</span>
</code></pre>
<p>This version performs direct memory access with pointer arithmetic, no bounds checks, and no type safety. The C code is lower-level, with fewer runtime checks, and compiles down to just 4–5 instructions per iteration, depending on the target CPU and compiler flags. It is lean and fast, ideal for cycles-per-instruction-critical scenarios.</p>
<p>The table below shows the comparison of single loop performance between Swift and C:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Aspect</td><td>Swift</td><td>C</td></tr>
</thead>
<tbody>
<tr>
<td>Array access</td><td>Bounds-checked</td><td>Direct pointer access</td></tr>
<tr>
<td>Loop iteration</td><td>High-level iterator abstraction</td><td>Raw loop with pointer increment</td></tr>
<tr>
<td>Instruction count (per loop)</td><td>~8–10 (in debug), ~6–8 (in release)</td><td>~4–5</td></tr>
<tr>
<td>Division</td><td>Safe (avoids divide-by-zero in dev)</td><td>Direct</td></tr>
<tr>
<td>Overflow behavior</td><td>Checked in debug, unchecked in release</td><td>Unchecked</td></tr>
<tr>
<td>Readability and safety</td><td>High</td><td>Low</td></tr>
<tr>
<td>Performance</td><td>Lower (but optimizable)</td><td>Higher (manual)</td></tr>
</tbody>
</table>
</div><p>Now that we’ve compared Swift and C in terms of memory and cycle costs, let’s move into the practical side: how to set up Embedded Swift on an STM32 platform and get started with real-world development.</p>
<h2 id="heading-how-to-setup-embedded-swift">How to Setup Embedded Swift</h2>
<p>In this section, we'll walk through how to configure and use Embedded Swift for development on STM32 microcontrollers. STM32 is a popular family of ARM Cortex-M–based microcontrollers, commonly used in industrial, consumer, and IoT applications.</p>
<h3 id="heading-prerequisites-1">Prerequisites</h3>
<p><strong>Required Software:</strong></p>
<ul>
<li><p>Swift Development Snapshot (includes the Embedded Swift toolchain)</p>
</li>
<li><p>Swiftly - Easiest way to manage and install swift toolchains</p>
</li>
<li><p>Swiftc - Swift Compiler command-line tool</p>
</li>
<li><p>Python3 - Required to run scripts to convert Mach-O to binary files</p>
</li>
<li><p>Git (to clone sample repositories) like <a target="_blank" href="https://github.com/swiftlang/swift-embedded-examples">https://github.com/swiftlang/swift-embedded-examples</a></p>
</li>
<li><p>A Unix-like development environment (macOS is currently best supported)</p>
</li>
</ul>
<p><strong>Target Hardware:</strong> This guide focuses on STM32 microcontrollers, which are widely used in embedded applications and have excellent community support.</p>
<p>This guide walks you through the full setup process, from installing the required Swift toolchain to flashing the final binary onto your board. We’ll begin by installing the Swift Development Snapshot using Swiftly, a simple command-line utility for managing Swift toolchains. From there, we’ll configure the build system, set up the correct board variant, customize the build script, and compile the Swift and C source code into a binary. Finally, we’ll flash the firmware onto the STM32 using standard tools</p>
<h3 id="heading-install-swift-development-snapshot">Install Swift Development Snapshot</h3>
<p>The easiest way to install and manage Embedded Swift toolchains is by using the swiftly tool, which simplifies downloading and using Swift snapshots.</p>
<h4 id="heading-macos-installation">macOS Installation:</h4>
<p>The below steps will help install the Swift embedded toolchain:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Using Swiftly (Recommended)</span>
curl -O https://download.swift.org/swiftly/darwin/swiftly.pkg
installer -pkg swiftly.pkg -target CurrentUserHomeDirectory
~/.swiftly/bin/swiftly init --quiet-shell-followup
<span class="hljs-built_in">source</span> <span class="hljs-string">"<span class="hljs-variable">${SWIFTLY_HOME_DIR:-<span class="hljs-variable">$HOME</span>/.swiftly}</span>/env.sh"</span>

<span class="hljs-comment"># Install and use development snapshot</span>
swiftly install main-snapshot
swiftly use main-snapshot

<span class="hljs-comment"># Verify installation</span>
swift --version
</code></pre>
<p>You can clone this Github example repository:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/swiftlang/swift-embedded-examples.git 
<span class="hljs-built_in">cd</span> swift-embedded-examples/projects/stm32-blink
</code></pre>
<p>The stm32-blink contains:</p>
<ul>
<li><p>Swift code that toggles GPIOs</p>
</li>
<li><p>A C startup file with vector table</p>
</li>
<li><p>A build.sh script that uses swiftc, clang, and a custom linker setup</p>
</li>
</ul>
<h3 id="heading-setup-the-stm32-board">Setup the STM32 Board</h3>
<p>Tell the build script which STM32 board is being used:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">export</span> STM_BOARD=STM32F746G_DISCOVERY
</code></pre>
<p>You can add your own board variant by defining the appropriate memory map and compiler flags in the script.</p>
<h3 id="heading-modify-buildsh-optional">Modify build.sh (Optional)</h3>
<p>Ensure the script correctly locates the following:</p>
<ul>
<li><p>swiftc: should point to the toolchain you installed with Swiftly</p>
</li>
<li><p>clang: can be macOS’s default Clang</p>
</li>
<li><p>libBuiltin.a, crt0.s, and macho2bin.py: used to provide minimal runtime support and convert output to flashable binaries</p>
</li>
</ul>
<p>If needed, update these paths:</p>
<pre><code class="lang-bash">SWIFT_EXEC=<span class="hljs-variable">${SWIFT_EXEC:-$(swiftly which swiftc)}</span>
CLANG_EXEC=<span class="hljs-variable">${CLANG_EXEC:-$(xcrun -f clang)}</span>
PYTHON_EXEC=<span class="hljs-variable">${PYTHON_EXEC:-$(which python3)}</span>
</code></pre>
<p>Ensure the linker flags match your target’s flash and RAM sizes.</p>
<h3 id="heading-build-and-flash-the-project">Build and Flash the Project:</h3>
<p>Run:</p>
<pre><code class="lang-bash">./build.sh
</code></pre>
<p>This compiles Swift and C code, links them, and produces a blink.bin file.</p>
<p>If successful, you’ll see:</p>
<pre><code class="lang-bash">.build/blink.bin  <span class="hljs-comment"># ready to flash Step 6: Flash the Firmware to STM32</span>
</code></pre>
<p>Use ST-Link tools or openocd to flash your board. Example using st-flash:</p>
<pre><code class="lang-bash">brew install stlink
st-flash write .build/blink.bin 0x8000000
</code></pre>
<p>You should now see an LED blinking.</p>
<p><a target="_blank" href="https://docs.swift.org/embedded/documentation/embedded/stm32baremetalguide">Here’s</a> a more detailed step by step approach to writing a bare metal code on STM32. For comprehensive installation guides covering other platforms (Raspberry Pi Pico, ESP32, nRF52), detailed IDE configuration, troubleshooting, and advanced examples, you can check out the official documentation:</p>
<ul>
<li><p>Complete Setup Guide: <a target="_blank" href="https://docs.swift.org/embedded/documentation/embedded/installembeddedswift/">Install Embedded Swift</a></p>
</li>
<li><p>Platform Examples: <a target="_blank" href="https://github.com/apple/swift-embedded-examples">Swift Embedded Examples Repository</a></p>
</li>
<li><p>Getting Started Tutorial: <a target="_blank" href="https://docs.swift.org/embedded/documentation/embedded">Embedded Swift on Microcontrollers</a></p>
</li>
</ul>
<p>Now that we’ve set up Embedded Swift and explored how to build and run an example project, let’s look at a critical real-world scenario: interfacing Swift with low-level C drivers.</p>
<h2 id="heading-c-swift-linkages">C-Swift Linkages</h2>
<p>In many embedded projects, low-level hardware drivers are written in C because of its close-to-metal control and widespread ecosystem support. Embedded Swift supports seamless interoperability with C, which lets you reuse existing C libraries and drivers, write hardware control logic in C, and implement higher-level application logic in Swift.</p>
<p>This hybrid model lets you combine Swift’s safety and productivity with C’s hardware-level control, with no runtime overhead or object translation.</p>
<p>Let’s walk through an example where a low-level sensor driver is implemented in C and the application logic is written in Swift.</p>
<h3 id="heading-c-header-file-sensordriverh">C Header File (sensor_driver.h):</h3>
<p>This C header file defines the public interface for a low-level sensor driver. It includes standard fixed-width integer types and declares four functions:</p>
<ul>
<li><p>sensor_init(): Initializes the hardware sensor</p>
</li>
<li><p>sensor_read_temperature() and sensor_read_humidity(): Read raw sensor values</p>
</li>
<li><p>sensor_delay_ms(): Delays execution for a given number of milliseconds</p>
</li>
</ul>
<p>This interface acts as a bridge between Swift and C. Swift will link to these functions by name, no wrappers or bindings required.</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">ifndef</span> SENSOR_DRIVER_H</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> SENSOR_DRIVER_H</span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdint.h&gt;</span></span>

<span class="hljs-comment">// Low-level sensor driver functions</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sensor_init</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">uint32_t</span> <span class="hljs-title">sensor_read_temperature</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">uint32_t</span> <span class="hljs-title">sensor_read_humidity</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sensor_delay_ms</span><span class="hljs-params">(<span class="hljs-keyword">uint32_t</span> milliseconds)</span></span>;

<span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span>
</code></pre>
<h3 id="heading-c-implementation-sensordriverc">C Implementation (sensor_driver.c):</h3>
<p>This implementation assumes the sensor is memory-mapped at a fixed address (<code>0x40001000</code>). Each register, temperature, humidity, and control, is accessed by offset from that base address.</p>
<p>The <code>sensor_init</code>() function writes <code>0x01</code> to the control register, presumably enabling or starting the sensor hardware.</p>
<p>The <code>sensor_read_temperature()</code> method and <code>sensor_read_humidity()</code> method reads from memory-mapped registers and return the raw ADC values from the sensor.</p>
<p>The <code>sensor_delay_ms()</code> method performs a simple busy-wait loop using nop (no-operation) instructions to approximate a delay. This is suitable for short, coarse-grained delays in bare-metal contexts.</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"sensor_driver.h"</span></span>

<span class="hljs-comment">// Hardware register addresses</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> SENSOR_BASE_ADDR    0x40001000</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> TEMP_REG_OFFSET     0x00</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> HUMIDITY_REG_OFFSET 0x04</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> CONTROL_REG_OFFSET  0x08</span>

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sensor_init</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
    <span class="hljs-comment">// Initialize sensor hardware</span>
    <span class="hljs-keyword">volatile</span> <span class="hljs-keyword">uint32_t</span>* control_reg = (<span class="hljs-keyword">volatile</span> <span class="hljs-keyword">uint32_t</span>*)(SENSOR_BASE_ADDR + CONTROL_REG_OFFSET);
    *control_reg = <span class="hljs-number">0x01</span>; <span class="hljs-comment">// Enable sensor</span>
}

<span class="hljs-function"><span class="hljs-keyword">uint32_t</span> <span class="hljs-title">sensor_read_temperature</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
    <span class="hljs-keyword">volatile</span> <span class="hljs-keyword">uint32_t</span>* temp_reg = (<span class="hljs-keyword">volatile</span> <span class="hljs-keyword">uint32_t</span>*)(SENSOR_BASE_ADDR + TEMP_REG_OFFSET);
    <span class="hljs-keyword">return</span> *temp_reg;
}

<span class="hljs-function"><span class="hljs-keyword">uint32_t</span> <span class="hljs-title">sensor_read_humidity</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
    <span class="hljs-keyword">volatile</span> <span class="hljs-keyword">uint32_t</span>* humidity_reg = (<span class="hljs-keyword">volatile</span> <span class="hljs-keyword">uint32_t</span>*)(SENSOR_BASE_ADDR + HUMIDITY_REG_OFFSET);
    <span class="hljs-keyword">return</span> *humidity_reg;
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sensor_delay_ms</span><span class="hljs-params">(<span class="hljs-keyword">uint32_t</span> milliseconds)</span> </span>{
    <span class="hljs-comment">// Simple delay implementation</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">uint32_t</span> i = <span class="hljs-number">0</span>; i &lt; milliseconds * <span class="hljs-number">1000</span>; i++) {
        __asm__(<span class="hljs-string">"nop"</span>);
    }
}
</code></pre>
<h3 id="heading-swift-code-using-c-driver">Swift Code Using C Driver:</h3>
<p>To use these C functions from Swift, you declare them using <code>@_silgen_name</code>, which tells the Swift compiler to link directly to these symbol names at runtime.</p>
<p>The <code>SensorController</code> class encapsulates sensor-related logic. In its <code>init()</code> method, it calls the <code>sensor_init()</code> function defined in C to initialize the sensor hardware.</p>
<p>The <code>readSensors()</code> method reads the raw values from the C driver, converts them into human-readable units using helper functions, stores them internally, and returns the processed values.</p>
<p>The <code>convertTemperature()</code> and <code>convertHumidity()</code> conversion methods apply a basic linear formula to turn raw ADC values into temperature in Celsius and humidity in percentage, respectively. These formulas would be based on the specific sensor’s datasheet.</p>
<p>The <code>checkThresholds()</code> method applies simple threshold logic, a good example of where Swift’s readability and type safety shine. You could easily expand this logic to include error bounds, state machines, or alerts.</p>
<pre><code class="lang-swift"><span class="hljs-comment">// Import C driver functions</span>

<span class="hljs-comment">/*
These declarations match the C function signatures exactly. 
They allow Swift to invoke the C functions as if they were native Swift functions 
— with zero overhead.
*/</span>
@_silgen_name(<span class="hljs-string">"sensor_init"</span>)
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">sensor_init</span><span class="hljs-params">()</span></span>

@_silgen_name(<span class="hljs-string">"sensor_read_temperature"</span>)
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">sensor_read_temperature</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">UInt32</span>

@_silgen_name(<span class="hljs-string">"sensor_read_humidity"</span>)
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">sensor_read_humidity</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">UInt32</span>

@_silgen_name(<span class="hljs-string">"sensor_delay_ms"</span>)
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">sensor_delay_ms</span><span class="hljs-params">(<span class="hljs-number">_</span> ms: UInt32)</span></span>

<span class="hljs-comment">// Swift sensor controller using C driver</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SensorController</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> lastTemperature: <span class="hljs-type">Float</span> = <span class="hljs-number">0.0</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> lastHumidity: <span class="hljs-type">Float</span> = <span class="hljs-number">0.0</span>

    <span class="hljs-keyword">init</span>() {
        <span class="hljs-comment">// Initialize the C driver</span>
        sensor_init()
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">readSensors</span><span class="hljs-params">()</span></span> -&gt; (temperature: <span class="hljs-type">Float</span>, humidity: <span class="hljs-type">Float</span>) {
        <span class="hljs-comment">// Read raw values from C driver</span>
        <span class="hljs-keyword">let</span> rawTemp = sensor_read_temperature()
        <span class="hljs-keyword">let</span> rawHumidity = sensor_read_humidity()

        <span class="hljs-comment">// Convert raw values to meaningful units in Swift</span>
        <span class="hljs-keyword">let</span> temperature = convertTemperature(rawValue: rawTemp)
        <span class="hljs-keyword">let</span> humidity = convertHumidity(rawValue: rawHumidity)

        <span class="hljs-comment">// Store for comparison</span>
        lastTemperature = temperature
        lastHumidity = humidity

        <span class="hljs-keyword">return</span> (temperature: temperature, humidity: humidity)
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">convertTemperature</span><span class="hljs-params">(rawValue: UInt32)</span></span> -&gt; <span class="hljs-type">Float</span> {
        <span class="hljs-comment">// Convert raw ADC value to Celsius</span>
        <span class="hljs-keyword">return</span> (<span class="hljs-type">Float</span>(rawValue) * <span class="hljs-number">3.3</span> / <span class="hljs-number">4095.0</span> - <span class="hljs-number">0.5</span>) * <span class="hljs-number">100.0</span>
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">convertHumidity</span><span class="hljs-params">(rawValue: UInt32)</span></span> -&gt; <span class="hljs-type">Float</span> {
        <span class="hljs-comment">// Convert raw ADC value to percentage</span>
        <span class="hljs-keyword">return</span> <span class="hljs-type">Float</span>(rawValue) * <span class="hljs-number">100.0</span> / <span class="hljs-number">4095.0</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">checkThresholds</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-comment">// Swift logic for threshold checking</span>
        <span class="hljs-keyword">let</span> tempThreshold: <span class="hljs-type">Float</span> = <span class="hljs-number">25.0</span>
        <span class="hljs-keyword">let</span> humidityThreshold: <span class="hljs-type">Float</span> = <span class="hljs-number">60.0</span>

        <span class="hljs-keyword">return</span> lastTemperature &gt; tempThreshold || lastHumidity &gt; humidityThreshold
    }
}

<span class="hljs-comment">// Main application loop</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">Never</span> {
    <span class="hljs-keyword">let</span> sensorController = <span class="hljs-type">SensorController</span>()

    <span class="hljs-keyword">while</span> <span class="hljs-literal">true</span> {
        <span class="hljs-comment">// Read sensors using Swift controller with C driver</span>
        <span class="hljs-keyword">let</span> readings = sensorController.readSensors()

        <span class="hljs-comment">// Process data with Swift's type safety and expressiveness</span>
        <span class="hljs-keyword">if</span> sensorController.checkThresholds() {
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"Warning: Temperature: \(readings.temperature)°C, Humidity: \(readings.humidity)%"</span>)
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"Normal: Temperature: \(readings.temperature)°C, Humidity: \(readings.humidity)%"</span>)
        }

        <span class="hljs-comment">// Delay using C driver function</span>
        sensor_delay_ms(<span class="hljs-number">1000</span>) <span class="hljs-comment">// 1 second delay</span>
    }
}
</code></pre>
<p>The <code>func main()</code> is the main event loop standard for embedded systems. It creates the sensor controller, reads sensor data in a loop, checks thresholds, and prints results accordingly. The loop includes a delay (via the C driver) to avoid hammering the sensor continuously.</p>
<p>In an actual embedded context, instead of using <code>print()</code>, you might blink an LED, send UART messages, or log data to memory.</p>
<p>With Embedded Swift and C now working together, let’s explore what lies ahead. The next section outlines ongoing improvements, emerging use cases, and research directions that are shaping the future of Embedded Swift.</p>
<h2 id="heading-future-work">Future Work</h2>
<p>Embedded Swift is still a young but rapidly evolving technology. Its modern language features, type safety, and performance make it an attractive option for embedded development, and ongoing work is expanding its capabilities, reach, and ecosystem.</p>
<h3 id="heading-ongoing-improvements">Ongoing Improvements</h3>
<p><strong>Compiler Optimizations</strong>: The Swift compiler team is actively improving code generation for embedded targets, including:</p>
<ul>
<li><p>Reducing binary size</p>
</li>
<li><p>Minimizing ARC overhead</p>
</li>
<li><p>Improving static dispatch performance</p>
</li>
</ul>
<p><strong>Hardware Support</strong>: Embedded Swift can target a wide variety of ARM and RISC-V microcontrollers, which are popular for building industrial applications. Support for additional architectures is being developed.</p>
<p><strong>Tooling Enhancements</strong>: Tooling support for Embedded Swift is still evolving, but several community-driven and open-source efforts are making development more accessible:</p>
<ul>
<li><p><strong>Build Systems</strong>: The Swift Embedded Working Group provides example projects that adapt Swift Package Manager (SwiftPM) for cross-compilation. Custom linker scripts and build helpers are available for platforms like STM32 and nRF52.</p>
</li>
<li><p><strong>Debugging Support</strong>: Developers can debug Embedded Swift programs using existing tools like GDB or OpenOCD, provided the build includes appropriate debug symbols. While not yet officially streamlined, this approach enables step-through debugging on real hardware.</p>
</li>
<li><p><strong>IDE Integration</strong>: There is no official IDE support yet, but some developers use VSCode with Swift syntax highlighting and external build tasks. These setups are still manual but serve as early prototypes for embedded workflows.</p>
</li>
</ul>
<h3 id="heading-emerging-use-cases">Emerging Use Cases</h3>
<p>There are a number of emerging use cases for embedded Swift. For example, Swift’s memory safety, type guarantees, and protocol-oriented design make it ideal for secure and scalable IoT devices, especially where firmware bugs could affect user safety or privacy.</p>
<p>The automotive sector is also exploring Swift for infotainment systems, driver assistance features, and safety-critical logic (where deterministic execution and safety matter).</p>
<p>Swift’s expressive syntax and compile-time safety make it suitable for industrial automation – think real-time control loops, sensor fusion systems, and edge devices in smart manufacturing.</p>
<p>It’s also useful for medical devices, as it aligns well with strict medical regulations around memory safety, type guarantees, and predictable resource usage.</p>
<h3 id="heading-community-and-ecosystem">Community and Ecosystem</h3>
<h4 id="heading-open-source-projects">Open Source Projects</h4>
<p>The Swift Embedded working group maintains <a target="_blank" href="https://github.com/swiftlang/swift-embedded-examples">example repositories</a> showcasing how to use Embedded Swift on microcontrollers such as STM32, nRF52, and ESP32. Early-stage libraries for UART, GPIO, and basic peripherals are emerging, though the ecosystem is still young compared to C or Rust.</p>
<h4 id="heading-learning-resources">Learning Resources</h4>
<p>While <a target="_blank" href="https://docs.swift.org/embedded/documentation/embedded">Embedded Swift</a> is not yet widely taught in formal curricula, community tutorials and exploratory projects (for example, Swift for Arduino) are lowering the barrier for hobbyists and independent learners. As tooling matures, educational adoption is likely to follow.</p>
<h4 id="heading-industry-interest">Industry Interest</h4>
<p>Embedded Swift is beginning to draw attention from developers and companies looking for safer, more maintainable alternatives to C. Although large-scale adoption remains limited, use cases like rapid prototyping, IoT development, and internal experimentation are gaining traction.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Embedded Swift represents a major step forward in embedded programming. By combining the power and safety of Swift with the low-level control needed for microcontrollers, it offers an exciting alternative to traditional C and C++ development.</p>
<p>While C will remain essential for hardware-level programming and performance-critical paths, Swift brings compelling advantages to many embedded scenarios:</p>
<ul>
<li><p><strong>Memory safety</strong>: Swift eliminates entire categories of bugs such as buffer overflows, use-after-free, and null pointer dereferencing.</p>
</li>
<li><p><strong>Type safety</strong>: Many logic errors are caught at compile time, long before they can cause runtime failures.</p>
</li>
<li><p><strong>Modern language features</strong>: Developers can use functional paradigms, generics, and protocol-oriented design even in embedded code.</p>
</li>
<li><p><strong>C interoperability</strong>: Swift works seamlessly with existing C libraries, allowing gradual adoption without rewriting low-level drivers.</p>
</li>
<li><p><strong>Developer productivity</strong>: Clear syntax, automatic memory management, and strong tooling lead to faster development and easier maintenance.</p>
</li>
</ul>
<p>Government and regulatory bodies are increasingly encouraging or mandating the use of memory-safe programming languages to reduce vulnerabilities in critical software systems. For example:</p>
<ul>
<li><p>In 2022, the <a target="_blank" href="https://media.defense.gov/2025/Jun/23/2003742198/-1/-1/0/CSI_MEMORY_SAFE_LANGUAGES_REDUCING_VULNERABILITIES_IN_MODERN_SOFTWARE_DEVELOPMENT.PDF"><strong>U.S. National Security Agency (NSA)</strong></a> recommended moving away from unsafe languages like C/C++ for new software projects, promoting memory-safe alternatives.</p>
</li>
<li><p>In June 2025, the NSA and CISA released a joint Cybersecurity Information Sheet titled “<a target="_blank" href="https://www.nsa.gov/Press-Room/Press-Releases-Statements/Press-Release-View/Article/4223298/nsa-and-cisa-release-csi-highlighting-importance-of-memory-safe-languages-in-so/">Memory Safe Languages: Reducing Vulnerabilities in Modern Software Development</a>”, which emphasized that memory safety flaws remain a persistent risk, and organizations should develop strategies to adopt memory-safe programming languages in new systems.</p>
</li>
<li><p>The <a target="_blank" href="https://www.trust-in-soft.com/resources/blogs/memory-safety-is-key-the-shift-in-u.s.-cyber-standards"><strong>U.S. Cybersecurity and Infrastructure Security Agency (CISA)</strong></a> and <a target="_blank" href="https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-218.pdf"><strong>NIST</strong></a> have echoed similar guidance in the context of national cybersecurity.</p>
</li>
</ul>
<p>While these documents do not mention Swift explicitly, Swift's strong type system, ARC-based memory model, and compile-time safety guarantees align closely with the goals outlined in these recommendations. As such, it offers a practical, developer-friendly path toward safer embedded development.</p>
<p>Swift may not be the right fit for every embedded system. In applications where every byte of memory or instruction cycle is critical, real-time guarantees are hard requirements, or toolchain maturity is essential (for example, RTOS integration, static analyzers), C or Rust may still be preferred.</p>
<p>But in many modern embedded applications, especially those involving rapid prototyping, fast product iteration, safety-critical or maintainable firmware, and interoperability with existing C codebases, Swift offers a highly productive and safe development experience.</p>
<p>Embedded Swift is still maturing, but its momentum is undeniable. With ongoing compiler work, community-driven examples, and growing interest from developers, it’s poised to play a major role in the future of embedded systems.</p>
<p>Whether you're building an IoT device, a piece of industrial equipment, or a proof-of-concept wearable, Swift can help you write safer, more expressive firmware, without giving up performance or control.</p>
<p>Swift can be especially powerful during the prototyping phase, when the primary goal is to validate functionality quickly and safely. And with its increasing support for multiple hardware platforms, it offers a strong foundation for bringing modern software development practices to the embedded world.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use a Resistive Soil Moisture Sensor ]]>
                </title>
                <description>
                    <![CDATA[ A resistive soil moisture sensor is a widely used, simple, and affordable way of estimating the amount of water in the soil. In this tutorial, you will learn how to interface a resistive soil moisture sensor with an Arduino UNO microcontroller. You w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-a-resistive-soil-moisture-sensor/</link>
                <guid isPermaLink="false">686f06fb2134825dffc4a228</guid>
                
                    <category>
                        <![CDATA[ arduino ]]>
                    </category>
                
                    <category>
                        <![CDATA[ embedded systems ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Michael Ikoko ]]>
                </dc:creator>
                <pubDate>Thu, 10 Jul 2025 00:19:07 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752106699262/6ae871df-e1fb-4019-a446-9bd8cca1cab0.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A resistive soil moisture sensor is a widely used, simple, and affordable way of estimating the amount of water in the soil.</p>
<p>In this tutorial, you will learn how to interface a resistive soil moisture sensor with an Arduino UNO microcontroller. You will learn about the parts and components of the sensor, how to calibrate the sensor for your soil type, and how to read both analog and digital output data from the sensor.</p>
<p>You will implement two practical examples in this tutorial:</p>
<ol>
<li><p>The first example illustrates how you can read the analog output data from the sensor and convert the analog reading to a percentage value.</p>
</li>
<li><p>The second example illustrates how you can use the digital output from the sensor to determine if the soil is wet or dry, and indicate the result using a red and green LED.</p>
</li>
</ol>
<p>At the end of the tutorial, you will have a solid understanding of how a resistive soil moisture sensor works and how to integrate the sensor into your microcontroller-based projects.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To effectively follow along with this tutorial, you should have the following components:</p>
<ul>
<li><p>Arduino UNO</p>
</li>
<li><p>Resistive Soil Moisture Sensor</p>
</li>
<li><p>Breadboard</p>
</li>
<li><p>5 LEDs (any color for the analog example)</p>
</li>
<li><p>1 red LED and 1 green LED (for the digital example)</p>
</li>
<li><p>220-ohm resistors (one per LED)</p>
</li>
<li><p>Jumper wires</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-a-soil-moisture-sensor">What is a Soil Moisture Sensor?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-types-of-soil-moisture-sensors">Types of Soil Moisture Sensors</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-parts-of-a-resistive-soil-moisture-sensor">Parts of a Resistive Soil Moisture Sensor</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-calibrate-the-sensor-for-your-soil">How to Calibrate the Sensor for Your Soil</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-1-how-to-determine-soil-moisture-level-in-percentage-from-analog-output">Example 1: How to Determine Soil Moisture Level in Percentage from Analog Output</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-example-2-how-to-determine-soil-moisture-state-from-digital-output">Example 2: How to Determine Soil Moisture State from Digital Output</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-a-soil-moisture-sensor">What is a Soil Moisture Sensor?</h2>
<p>A soil moisture sensor is a device that estimates the moisture content in the soil. Soil moisture sensors typically operate by measuring the soil's electrical properties, such as dielectric and resistance. Some soil moisture sensors also use time domain methods to determine the propagation speed of electromagnetic waves through the soil.</p>
<p>Soil moisture sensors have various applications in different fields. These applications include, but are not limited to:</p>
<ul>
<li><p>Climate and environmental research</p>
</li>
<li><p>Automated/smart irrigation system</p>
</li>
<li><p>Greenhouse monitoring systems</p>
</li>
<li><p>Urban planning</p>
</li>
</ul>
<h2 id="heading-types-of-soil-moisture-sensors">Types of Soil Moisture Sensors</h2>
<p>Soil moisture sensors are categorized based on the property of the soil that they measure as an indicator of the moisture content. The most common soil moisture sensors for small-scale projects are:</p>
<ul>
<li><p>Resistive soil moisture sensors</p>
</li>
<li><p>Capacitive soil moisture sensors</p>
</li>
</ul>
<h3 id="heading-resistive-soil-moisture-sensor">Resistive Soil Moisture Sensor</h3>
<p>A resistive soil moisture sensor estimates the moisture content based on the relationship between water content and soil resistivity. The electrical resistivity of the soil reduces exponentially as the water content increases.</p>
<p>The resistive soil moisture sensor has two probes inserted into the soil. It measures the electrical resistance of the soil between the two probes.</p>
<h3 id="heading-capacitive-soil-moisture-sensor">Capacitive Soil Moisture Sensor</h3>
<p>A capacitive soil moisture sensor determines the moisture content of the soil based on the relationship between water content and the dielectric properties of the soil. The dielectric constant of a soil increases as the water content increases.</p>
<p>A capacitive soil moisture sensor typically has a positive plate and a negative plate with space between them. When inserted into the soil, the soil becomes the dielectric medium between both plates. The sensor measures the change in the soil's dielectric property.</p>
<h3 id="heading-how-to-choose-between-resistive-and-capacitive-sensors">How to Choose Between Resistive and Capacitive Sensors</h3>
<p>The choice between a resistive and capacitive soil moisture sensor depends on a couple of factors:</p>
<ul>
<li><p><strong>Cost</strong>: A resistive soil moisture sensor is typically less expensive than a capacitive sensor.</p>
</li>
<li><p><strong>Accuracy</strong>: Capacitive soil moisture sensors are more accurate than their resistive counterparts. Factors like soil type and application of fertilizers have a lesser effect on the sensitivity of the capacitive soil moisture sensor.</p>
</li>
<li><p><strong>Long-term use</strong>: Resistive soil moisture sensors are prone to corrosion with frequent use. This happens because the current flowing through the probes in contact with the soil causes electrolysis of the metal electrodes in the probes. On the other hand, capacitive soil moisture sensors are resistant to corrosion. This is because the contact plates are embedded in corrosion-resistant materials and don't need to be in direct contact with the soil.</p>
</li>
</ul>
<h2 id="heading-parts-of-a-resistive-soil-moisture-sensor">Parts of a Resistive Soil Moisture Sensor</h2>
<p>The resistor soil moisture sensor module is usually made of two parts: the sensor probes and the voltage comparator module.</p>
<h3 id="heading-the-sensor-probes">The Sensor Probes</h3>
<p>The probes are the part of the sensor that is placed in the soil. The probes are used to detect the electrical resistance across two points in the soil.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751909048810/7c2367b5-872c-4e98-acf8-d8b2f0851f6c.jpeg" alt="Sensor probes labelled diagram" class="image--center mx-auto" width="2048" height="1152" loading="lazy"></p>
<p>As shown in the diagram above, the sensor probes have the following components:</p>
<ul>
<li><p><strong>Electrodes</strong>: The metal electrodes conduct current through the soil. When the sensor is powered, current flows from one electrode through the soil to the other electrode and back to the comparator module. The sensor then measures the soil's resistance to the electrical signal flowing through the soil across the electrodes to determine the moisture level.</p>
</li>
<li><p><strong>Non-polarized connector pins</strong>: The two connector pins are used to connect the probes to the voltage comparator module. The pins have no polarity and can be connected in any order to the respective connector pins on the voltage comparator module. The probe is connected to the comparator module using female-to-female jumper wires.</p>
</li>
</ul>
<h3 id="heading-the-voltage-comparator-module">The Voltage Comparator Module</h3>
<p>The voltage comparator module interprets the electrical signal from the probes, processes the signals, and provides both analog and digital outputs that can be read by the microcontroller.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751909173338/454ae6bf-2d34-4131-af88-c990eb988cbd.jpeg" alt="Sensor voltage comparator module labelled diagram" class="image--center mx-auto" width="2048" height="1152" loading="lazy"></p>
<p>The voltage comparator module has the following components:</p>
<ul>
<li><p><strong>LM393 Comparator Chip</strong>: The LM393 comparator is a dual comparator that compares the electrical signal from the probes to a reference set by the potentiometer and produces a digital output. The reference signal corresponds to a certain soil moisture level (threshold) and is set using the potentiometer.</p>
<ul>
<li><p>The comparator outputs a <code>HIGH</code> when the analog signal read from the probes is above the reference, this means the soil has less moisture than the threshold moisture level.</p>
</li>
<li><p>The comparator outputs a <code>LOW</code> when the analog signal read from the probes is less than the reference; this means the soil has more moisture than the threshold moisture level.</p>
</li>
</ul>
</li>
<li><p><strong>Potentiometer</strong>: The potentiometer is used to set the reference electrical signal that is used by the LM393 comparator chip. The potentiometer raises or lowers the threshold moisture level. It consists of a knob that can be turned either clockwise or counterclockwise.</p>
</li>
<li><p><strong>Power Indicator (PWR-LED)</strong>: The power indicator is an LED that turns on when the module is powered on.</p>
</li>
<li><p><strong>Digital Output Indicator (DO-LED)</strong>: The digital output indicator is an LED that turns on when the sensor detects wet soil. That is, the current moisture level read from the sensor is above the threshold, and the comparator outputs a <code>LOW</code>.</p>
</li>
<li><p><strong>Power Supply Pin (VCC)</strong>: This pin is used to supply power to the sensor. The sensor module can be powered by a 5V or 3.3V voltage source. You should note that changing the voltage source also changes the analog output from the sensor. In this tutorial, you will be using one of the digital pins to power the sensor. The digital pins of the Arduino output 5V. The sensor typically has an operating current of 15mA, and the Arduino digital output pin can provide a maximum current of 40mA, so it can safely power the sensor.</p>
</li>
<li><p><strong>Ground Pin (GND)</strong>: This pin is used to provide a ground reference for the sensor. It is usually connected to any ground pin in your microcontroller.</p>
</li>
<li><p><strong>Digital Output Pin (DO)</strong>: The digital output pin outputs a <code>HIGH</code> or a <code>LOW</code> based on the value obtained from the LM393 comparator. This pin is usually used by a microcontroller to read the digital output of the LM393 comparator.</p>
</li>
<li><p><strong>Analog Output Pin (AO)</strong>: The analog output pin provides a 10-bit analog voltage value. The values range from 0 to 1023, and they indicate the moisture level of the soil. Typically, in most sensors, higher analog values indicate drier soil and lower analog values indicate wetter soil.</p>
</li>
<li><p><strong>Sensor Probe Connector Pins</strong>: These two pins are used to connect the sensor probes to the voltage comparator module.</p>
</li>
</ul>
<h2 id="heading-how-to-calibrate-the-sensor-for-your-soil">How to Calibrate the Sensor for Your Soil</h2>
<p>As explained earlier in the article, the resistive soil moisture sensor is sensitive to soil type. This means that it’s important that you calibrate the sensor to the soil type you intend to use it on. You do this to improve the accuracy of your readings on a particular soil.</p>
<p>One way of calibrating the sensor is to determine the possible range of values for the soil type. That means you measure the sensor's output when the soil is totally dry and when the soil is totally wet. You can then use this range of values to map the sensor's reading to a new scale, like a percentage. The following steps describe how you can calibrate the sensor:</p>
<h3 id="heading-step-1-connect-the-sensor-to-the-arduino">Step 1: Connect the Sensor to the Arduino</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751909238974/d84a8df3-52d0-4f5e-90a4-9a4fa6c198fb.jpeg" alt="Schematic diagram for soil calibration" class="image--center mx-auto" width="1393" height="1553" loading="lazy"></p>
<p>Using the image above as a reference, connect the sensor to the Arduino microcontroller as follows:</p>
<ol>
<li><p>Connect the <strong>VCC</strong> or <strong>Power</strong> pin of the sensor's module to digital pin <strong>7</strong> of the Arduino. This allows you to control the supply voltage to the sensor in the Arduino sketch, ensuring that the sensor is only powered when you want to take a reading. Doing this can help improve the durability of the sensor.</p>
</li>
<li><p>Connect the <strong>GND</strong> pin of the sensor's module to a ground pin in the microcontroller.</p>
</li>
<li><p>Connect the analog output pin <strong>AO</strong> of the sensor's module to the analog pin <strong>A0</strong> of the Arduino. This is the pin where you will read the analog data from the sensor.</p>
</li>
<li><p>Connect the two pins on the probes to the two connector pins on the sensor's module. The connector pins have no polarity.</p>
</li>
</ol>
<h3 id="heading-step-2-upload-calibration-sketch-to-microcontroller">Step 2: Upload Calibration Sketch to Microcontroller</h3>
<p>Upload the following sketch into the Arduino:</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> sensorPin = A0; <span class="hljs-comment">// Analog input pin for sensor</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> powerPin = <span class="hljs-number">7</span>; <span class="hljs-comment">// Digital pin to power the sensor</span>

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">getAverageReading</span><span class="hljs-params">(<span class="hljs-keyword">int</span> analogPin, <span class="hljs-keyword">int</span> powerPin, <span class="hljs-keyword">int</span> samples = <span class="hljs-number">10</span>)</span> </span>{
  <span class="hljs-keyword">long</span> total = <span class="hljs-number">0</span>;

  digitalWrite(powerPin, HIGH); <span class="hljs-comment">// Power ON sensor</span>
  delay(<span class="hljs-number">500</span>); <span class="hljs-comment">// Wait for sensor to stabilize</span>

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; samples; i++) {                    
 total += analogRead(analogPin);
    delay(<span class="hljs-number">10</span>); <span class="hljs-comment">// Short gap between cycles</span>
 }

  digitalWrite(powerPin, LOW); <span class="hljs-comment">// Power OFF sensor</span>
  <span class="hljs-keyword">return</span> total / samples;
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span> </span>{
  Serial.begin(<span class="hljs-number">9600</span>);

  pinMode(powerPin, OUTPUT);
  digitalWrite(powerPin, LOW); <span class="hljs-comment">// Ensure sensor is off at start</span>

  Serial.println(<span class="hljs-string">"Calibration mode: Insert into DRY or WET soil and observe values."</span>);
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">loop</span><span class="hljs-params">()</span> </span>{
  <span class="hljs-keyword">int</span> avgReading = getAverageReading(sensorPin, powerPin, <span class="hljs-number">20</span>); <span class="hljs-comment">// Take 20 averaged samples</span>
  Serial.print(<span class="hljs-string">"Average analog reading: "</span>);
  Serial.println(avgReading);
  delay(<span class="hljs-number">2000</span>); <span class="hljs-comment">// Update every 2 seconds</span>
}
</code></pre>
<p>In the sketch, you begin by defining the pins for powering the sensor and reading the analog data from the sensor. The digital pin <code>7</code> powers the sensor, and the analog pin <code>A0</code> reads data from the sensor.</p>
<p>The <code>getAverageReading</code> function powers on the sensor, takes multiple readings from the sensor, powers off the sensor, and returns the average of the readings taken. The function has three parameters:</p>
<ul>
<li><p><code>analogPin</code> – The analog input pin, which reads data from the sensor to the microcontroller.</p>
</li>
<li><p><code>powerPin</code> – The pin used to power the sensor. The sensor is powered only when you want to take a reading.</p>
</li>
<li><p><code>samples</code> – The number of readings taken from the sensor. This defaults to <code>10</code>. You take multiple readings as a way of filtering out noise in the sensor data.</p>
</li>
</ul>
<p>In the <code>setup</code> function, you begin by setting the baud rate, which is <code>9600</code> for Arduino UNO and differs across different microcontrollers. Then you set the digital pin <code>7</code> used to power the sensor as an output pin, and write a <code>LOW</code> to the sensor to ensure it is off at the start.</p>
<p>Lastly, in the <code>loop</code> function, you get the average analog reading from the <code>getAverageReading</code> function and print it to the Serial Monitor. You should note that in the sketch, the readings are taken every 2 seconds – this delay should be longer in a practical application in order to improve the durability of the sensor.</p>
<h3 id="heading-step-3-record-the-value-for-dry-soil">Step 3: Record the Value for Dry Soil</h3>
<p>Insert the sensor's probe into a completely dry soil sample, and record the average analog reading. You can dry the soil by baking it in an oven to remove moisture. Note that you must allow the soil to cool before inserting the sensor's probe. Hot soil may damage the sensor. The analog readings from the sensor differ according to soil type but are typically very high for dry soil. This is what I obtained for a dry soil sample:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751909305339/35d99200-d169-4419-9292-e54a9c544d77.png" alt="Serial monitor showing analog reading for dry soil" class="image--center mx-auto" width="1368" height="738" loading="lazy"></p>
<h3 id="heading-step-4-record-the-value-for-wet-soil">Step 4: Record the Value for Wet Soil</h3>
<p>Insert the sensor's probe into a completely wet soil sample, and record the average analog reading. The value is typically low when the soil is saturated. This is what I obtained for a wet soil sample:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751909623291/5478b034-ce56-4f9b-a6d7-758508eb0c1a.png" alt="Serial monitor showing analog reading for wet soil" class="image--center mx-auto" width="1370" height="738" loading="lazy"></p>
<p>You will use these recorded analog values for wet and dry soil in the subsequent section as reference points to map future readings onto a percent scale. In the example provided later in this tutorial, the moisture level is expressed as a percentage, between 0%(dry) and 100%(wet). Using the calibration values ensures that the percentage output accurately reflects the conditions of your soil type.</p>
<h2 id="heading-example-1-how-to-determine-soil-moisture-level-in-percentage-from-analog-output">Example 1 – How to Determine Soil Moisture Level in Percentage from Analog Output</h2>
<p>In this example, you will learn how to read the analog data from the soil moisture sensor, convert the analog reading to a percentage value, and visually represent the moisture level using five LEDs.</p>
<p>The analog reading from the sensor is inversely proportional to the soil moisture level. This means that higher analog readings indicate drier soil and lower readings indicate wetter soil.</p>
<p>The LEDs act as a visual indicator of the moisture percentage. The LEDs are lit based on a range of soil moisture levels:</p>
<ul>
<li><p>1 LED: 0-20% (very dry)</p>
</li>
<li><p>2 LEDs: 20-40%</p>
</li>
<li><p>3 LEDs: 40-60%</p>
</li>
<li><p>4 LEDs: 60-80%</p>
</li>
<li><p>5 LEDs: 80-100% (very wet)</p>
</li>
</ul>
<h3 id="heading-circuit-diagram">Circuit Diagram</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751909722810/0aff204d-2ddd-44d5-80b5-5765b9cf5fe9.jpeg" alt="Circuit diagram for Example 1" class="image--center mx-auto" width="1797" height="1893" loading="lazy"></p>
<p>Using the schematic above as a reference, design the circuit as follows:</p>
<ol>
<li><p>Connect the sensor to the Arduino in the same way as described in the calibration section. That is, connect the sensor's power pin (VCC) to digital pin 7, analog output pin <strong>AO</strong> to analog pin <strong>A0</strong>, and ground pin to any ground pin of the microcontroller.</p>
</li>
<li><p>Connect each of the LEDs in series with a 220-ohm resistor.</p>
</li>
<li><p>Connect the anode of the five LEDs to digital pins 3, 4, 5, 6, and 8 of the microcontroller.</p>
</li>
</ol>
<p>This is how my setup looked:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751909770251/226bd848-2a58-4e2f-9bf4-796a54983d47.jpeg" alt="Physical setup for Project 1" class="image--center mx-auto" width="1561" height="1688" loading="lazy"></p>
<h3 id="heading-arduino-code">Arduino Code</h3>
<p>Upload the following sketch to your Arduino:</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> sensorPin = A0; <span class="hljs-comment">// Analog input from soil moisture sensor</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> powerPin = <span class="hljs-number">7</span>; <span class="hljs-comment">// Digital pin to power the sensor</span>

<span class="hljs-comment">// LED bar pins (from lowest to highest)</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> ledPins[<span class="hljs-number">5</span>] = {<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">8</span>};

<span class="hljs-comment">// Calibrated analog values - replace with your values</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> dryValue = <span class="hljs-number">1005</span>;
<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> wetValue = <span class="hljs-number">254</span>;

<span class="hljs-comment">// Global to hold the last analog value</span>
<span class="hljs-keyword">int</span> lastAnalogReading = <span class="hljs-number">0</span>;

<span class="hljs-comment">// Read and calculate soil moisture percentage</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">getMoisturePercent</span><span class="hljs-params">(<span class="hljs-keyword">int</span> analogPin, <span class="hljs-keyword">int</span> powerPin, <span class="hljs-keyword">int</span> samples = <span class="hljs-number">10</span>)</span> </span>{
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> total = <span class="hljs-number">0</span>;

  digitalWrite(powerPin, HIGH);
  delay(<span class="hljs-number">10</span>); <span class="hljs-comment">// Allow sensor to stabilize</span>

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; samples; i++) {
 total += analogRead(analogPin);
    delay(<span class="hljs-number">10</span>);
 }

  digitalWrite(powerPin, LOW);

  <span class="hljs-keyword">int</span> avgReading = total / samples;
 lastAnalogReading = avgReading;

  <span class="hljs-keyword">int</span> percent = <span class="hljs-built_in">map</span>(avgReading, dryValue, wetValue, <span class="hljs-number">0</span>, <span class="hljs-number">100</span>);
  <span class="hljs-keyword">return</span> constrain(percent, <span class="hljs-number">0</span>, <span class="hljs-number">100</span>);
}

<span class="hljs-comment">// Update LED states using boolean array</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">updateLEDBar</span><span class="hljs-params">(<span class="hljs-keyword">int</span> percent)</span> </span>{
  <span class="hljs-keyword">bool</span> ledStates[<span class="hljs-number">5</span>] = {<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>}; <span class="hljs-comment">// Default all OFF</span>

  <span class="hljs-keyword">if</span> (percent &lt;= <span class="hljs-number">20</span>) {
    ledStates[<span class="hljs-number">0</span>] = <span class="hljs-literal">true</span>;
 } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (percent &lt;= <span class="hljs-number">40</span>) {
    ledStates[<span class="hljs-number">0</span>] = ledStates[<span class="hljs-number">1</span>] = <span class="hljs-literal">true</span>;
 } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (percent &lt;= <span class="hljs-number">60</span>) {
    ledStates[<span class="hljs-number">0</span>] = ledStates[<span class="hljs-number">1</span>] = ledStates[<span class="hljs-number">2</span>] = <span class="hljs-literal">true</span>;
 } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (percent &lt;= <span class="hljs-number">80</span>) {
    ledStates[<span class="hljs-number">0</span>] = ledStates[<span class="hljs-number">1</span>] = ledStates[<span class="hljs-number">2</span>] = ledStates[<span class="hljs-number">3</span>] = <span class="hljs-literal">true</span>;
 } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</span>; i++) ledStates[i] = <span class="hljs-literal">true</span>;
 }

 <span class="hljs-comment">// Write LED states to pins</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</span>; i++) {
    digitalWrite(ledPins[i], ledStates[i] ? HIGH : LOW);
 }
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span> </span>{
  Serial.begin(<span class="hljs-number">9600</span>);
  pinMode(sensorPin, INPUT);
  pinMode(powerPin, OUTPUT);
  digitalWrite(powerPin, LOW); <span class="hljs-comment">// Start with sensor powered off</span>

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</span>; i++) {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], LOW); <span class="hljs-comment">// Ensure all LEDs start OFF</span>
 }

  Serial.println(<span class="hljs-string">"Soil Moisture Monitor with 5-LED Bar (Boolean Array)"</span>);
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">loop</span><span class="hljs-params">()</span> </span>{
  <span class="hljs-keyword">int</span> moisturePercent = getMoisturePercent(sensorPin, powerPin, <span class="hljs-number">20</span>);

 <span class="hljs-comment">// Print both analog reading and percent</span>
  Serial.print(<span class="hljs-string">"Analog Reading: "</span>);
  Serial.print(lastAnalogReading);
  Serial.print(<span class="hljs-string">"  |  Moisture: "</span>);
  Serial.print(moisturePercent);
  Serial.println(<span class="hljs-string">" %"</span>);

  updateLEDBar(moisturePercent);

  delay(<span class="hljs-number">2000</span>); <span class="hljs-comment">// Update every 2 seconds</span>
}
</code></pre>
<p>In the sketch, you start by defining the analog pin for reading data from the sensor and the digital pin for powering the sensor. You also define the following variables, which will be used in the code:</p>
<ul>
<li><p><code>ledPins[5]</code> – An array that stores the digital pins used to power each LED. The pins are arranged from the first LED to the last one. That is the visual display order from left to right.</p>
</li>
<li><p><code>dryValue</code> – This variable stores the analog value recorded for dry soil during the calibration section.</p>
</li>
<li><p><code>wetValue</code> – This variable stores the analog value recorded for wet soil during the calibration section.</p>
</li>
<li><p><code>lastAnalogReading</code> – This variable stores the last reading taken by the sensor. You use this variable to log the actual analog reading to the Serial Monitor.</p>
</li>
</ul>
<p>The <code>getMoisturePercent</code> function powers on the sensor, takes multiple readings, powers off the sensor, calculates the average analog reading, represents the analog reading in percent, and returns the percent value. The function also saves the average analog reading to the <code>lastAnalogReading</code> variable. You can print it directly here, but this sketch saves it in a separate variable so that you can print it later in the <code>loop</code> function for readability.</p>
<p>You can express the average analog reading in percentage with the <code>map(avgReading, dryValue, wetValue, 0, 100)</code> function. The function remaps the average reading stored in <code>avgReading</code> from the range of your calibration values <code>dryValue</code> and <code>wetValue</code> to a new range between <code>0</code> and <code>100</code> (where <code>0</code> is the driest and <code>100</code> is the wettest). You then use the <code>constrain</code> function to keep values within the <code>0</code> and <code>100</code> range.</p>
<p>The <code>updateLEDBar</code> function displays the percent value using the LEDs. The <code>ledStates</code> array in the function stores the logic state of each LED. You begin by setting all LEDs off – that is, having a state <code>0</code>. The next bit of logic is a simple <code>if</code> statement where you turn on the required LEDs corresponding to a particular percent range by setting the elements in the array to <code>true</code> (equivalent to <code>1</code>). You end the function by writing the states in the <code>ledStates</code> to the pins in <code>ledPins</code>.</p>
<p>The <code>setup</code> function is pretty routine: you set the baud rate for serial communication, define input and output digital pins, and write a <code>LOW</code> to the digital output pins to ensure they are all turned off at the start.</p>
<p>In the <code>loop</code> function, you call the <code>getMoisturePercent</code> function to get the percent moisture value. You then print the percent value and the average analog reading to the Serial Monitor for clarity. Lastly, you call the <code>updateLEDBar</code> function with the percent value as a parameter to turn on the respective LEDs to indicate the moisture level.</p>
<h3 id="heading-test-the-system">Test the System</h3>
<p>You can proceed to test the example with different moisture levels. For example:</p>
<ul>
<li>At around a 37% moisture level, two LEDs are lit.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751909854736/5312e441-d9fd-498f-bd87-b902231b27f4.jpeg" alt="Test example 1 with 37% moisture level" width="2106" height="738" loading="lazy"></p>
<ul>
<li>At about a 76% moisture level, four LEDs are lit.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751909910096/eabf2f8d-7499-4c6a-be49-74d4c8a3da30.jpeg" alt="Test example 1 with 76% moisture level" width="2108" height="738" loading="lazy"></p>
<p>You can also simulate the example on Tinkercad here: <a target="_blank" href="https://www.tinkercad.com/embed/6s47ZvIrNOP">https://www.tinkercad.com/embed/6s47ZvIrNOP</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752100775640/12f92988-7697-4069-9068-86f663b20794.png" alt="Example 1 Tinkercad simulation image" class="image--center mx-auto" width="1366" height="615" loading="lazy"></p>
<h2 id="heading-example-2-how-to-determine-soil-moisture-state-from-digital-output">Example 2 – How to Determine Soil Moisture State from Digital Output</h2>
<p>In the previous project, you learned how to read the analog data from the sensor and convert the value into a percentage. If your application requires a binary output, you can use the digital output pin. In this section, you'll learn how to use the digital output pin of the sensor.</p>
<p>The digital output pin has only two states:</p>
<ul>
<li><p><code>LOW</code> – This state corresponds to 0V and is the output when the soil is wet, that is, the moisture level is above the set threshold.</p>
</li>
<li><p><code>HIGH</code> – This state corresponds to 5V and is the output when the soil is dry, that is, the moisture level is below the threshold moisture level.</p>
</li>
</ul>
<h3 id="heading-circuit-diagram-1">Circuit Diagram</h3>
<p>The example built in this section is very simple. It consists of a red and green LED. When the sensor outputs a <code>LOW</code> from the digital output pin, which means the soil is wet, the green LED turns on. When the sensor outputs a <code>HIGH</code> from the digital output pin, which means the soil is dry, the red LED turns on.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751909967743/761e3422-ad95-4f8e-9b4d-4963970c926e.jpeg" alt="Circuit diagram for example 2" width="1987" height="1826" loading="lazy"></p>
<p>Using the circuit diagram above as a reference, design the circuit as follows:</p>
<ol>
<li><p>Place the sensor module on the breadboard.</p>
</li>
<li><p>As in the previous project, connect the power (VCC) pin of the sensor module to digital pin 7 of the microcontroller, and the ground (GND) pin to a ground pin on the microcontroller.</p>
</li>
<li><p>Connect the digital output (DO) pin of the sensor to digital pin 2 of the microcontroller. This pin is where you will read the data from the sensor.</p>
</li>
<li><p>Connect the red and green LEDs each to a 220-ohm resistor in series.</p>
</li>
<li><p>Connect the anode of the red and green LEDs to digital pins 12 and 13 of the microcontroller, respectively.</p>
</li>
</ol>
<p>This is how my physical connection looked:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751910000801/55382b8f-cdd4-4f85-9b6a-342af252329b.jpeg" alt="Physical setup for example 2" width="1400" height="1100" loading="lazy"></p>
<h3 id="heading-how-to-set-the-threshold-moisture-level">How to Set the Threshold Moisture Level</h3>
<p>Before using the digital output pin of the soil sensor module, you first have to set a threshold moisture level.</p>
<p>The sensor's module has a built-in potentiometer that allows you to adjust the moisture level, which will be used as a threshold. The sensor also has a built-in LM393 comparator, which continuously compares the actual reading from the sensor to the threshold set by the potentiometer and outputs the appropriate state.</p>
<p>You can set the threshold moisture level by rotating the knob on the potentiometer. Rotating the potentiometer clockwise lowers the threshold. Rotating the potentiometer counterclockwise raises the threshold. The sensor module also has a built-in LED labeled <strong>DO-LED</strong> that turns on when the sensor output is <code>LOW</code>. Set the threshold as follows:</p>
<ol>
<li><p>Place the sensor's probe in soil just dry enough that it requires irrigation. That is the soil whose moisture level you want to use as a threshold. Note that the DO-LED should be off.</p>
</li>
<li><p>Use a small screwdriver to rotate the potentiometer clockwise until the DO-LED comes on. Turning clockwise reduces the threshold level until it is slightly lower than the current moisture level, thereby triggering the digital output indicator (DO-LED) to turn on.</p>
</li>
<li><p>Turn the screw slightly counterclockwise just enough to turn the built-in digital LED off. Given that the current moisture level of the soil is dry enough that it needs to be watered, you still want the sensor to read this level as dry. So turning counterclockwise reduces the threshold to a level just above the current moisture level of the soil, which triggers the DO-LED to turn off.</p>
</li>
</ol>
<h3 id="heading-arduino-code-1">Arduino Code</h3>
<p>Upload the following sketch to the Arduino:</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> sensorPower = <span class="hljs-number">7</span>; <span class="hljs-comment">// Digital pin to power the sensor</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> sensorPin = <span class="hljs-number">2</span>; <span class="hljs-comment">// Digital input from the sensor</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> greenLED = <span class="hljs-number">13</span>; <span class="hljs-comment">// Green LED pin</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> redLED = <span class="hljs-number">12</span>; <span class="hljs-comment">// Red LED pin</span>

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">getSensorReading</span><span class="hljs-params">(<span class="hljs-keyword">int</span> digitalPin, <span class="hljs-keyword">int</span> powerPin)</span> </span>{  
  digitalWrite(powerPin, HIGH); <span class="hljs-comment">// Power ON sensor</span>
  delay(<span class="hljs-number">500</span>); <span class="hljs-comment">// Wait for sensor to stabilize</span>

  <span class="hljs-keyword">int</span> reading = digitalRead(digitalPin);

  digitalWrite(powerPin, LOW); <span class="hljs-comment">// Power OFF sensor</span>
  <span class="hljs-keyword">return</span> reading;
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span> </span>{
  Serial.begin(<span class="hljs-number">9600</span>);

  pinMode(sensorPower, OUTPUT);
  pinMode(sensorPin, INPUT);
  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);

 <span class="hljs-comment">// Ensure everything starts OFF</span>
  digitalWrite(sensorPower, LOW);
  digitalWrite(greenLED, LOW);
  digitalWrite(redLED, LOW);
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">loop</span><span class="hljs-params">()</span> </span>{
  <span class="hljs-keyword">int</span> sensorReading = getSensorReading(sensorPin, sensorPower);

  Serial.println(<span class="hljs-string">"==================================="</span>);
  Serial.print(<span class="hljs-string">"Digital Reading: "</span>);
  Serial.println(sensorReading);

  <span class="hljs-keyword">if</span> (sensorReading == HIGH) {
    Serial.println(<span class="hljs-string">"Status: Soil moisture is LOW (dry)"</span>);
    Serial.println(<span class="hljs-string">"Action: Water the soil"</span>);
    digitalWrite(redLED, HIGH);
    digitalWrite(greenLED, LOW);
 } <span class="hljs-keyword">else</span> {
    Serial.println(<span class="hljs-string">"Status: Soil moisture is GOOD (wet)"</span>);
    Serial.println(<span class="hljs-string">"Action: No watering needed"</span>);
    digitalWrite(greenLED, HIGH);
    digitalWrite(redLED, LOW);
 }

  Serial.println(<span class="hljs-string">"==================================="</span>);
  Serial.println(); 
  delay(<span class="hljs-number">2000</span>); <span class="hljs-comment">// Update every 2 seconds</span>
}
</code></pre>
<p>In the sketch, you define the digital pin used to read data from the sensor, the digital pins to power the sensor, and the green and red LEDs.</p>
<p>The <code>getSensorReading</code> function powers on the sensor, takes the digital reading from the sensor, powers off the sensor, and returns the digital reading taken from the sensor.</p>
<p>The <code>setup</code> function is routine: you set the baud rate, define the digital pins as input or output, and write a <code>LOW</code> to the output pins to ensure they are off at the start.</p>
<p>In the <code>loop</code> function, you call the <code>getSensorReading</code> to get the digital reading from the sensor. If the sensor outputs a <code>HIGH</code>, you turn on the red LED and print a message that the soil is dry. If the sensor outputs a <code>LOW</code>, you turn on the green LED and print a message that the soil is wet.</p>
<h3 id="heading-test-the-system-1">Test the System</h3>
<p>You can proceed to test the project using different moisture levels. For example:</p>
<ul>
<li>For wet soil, that is, if the moisture level is above the threshold, you should have the following output:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751910035826/19edc7e0-09a2-404a-8ce4-fb978c5b9f6b.jpeg" alt="Test example 2 with wet soil" width="2293" height="724" loading="lazy"></p>
<ul>
<li>For dry soil, that is, if the moisture level is below the threshold, you should have the following output:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751910068607/33881bb3-ba7b-41fd-a637-001016298312.jpeg" alt="Test example 2 with dry soil" width="2293" height="724" loading="lazy"></p>
<p>You can also simulate the example on Tinkercad here: <a target="_blank" href="https://www.tinkercad.com/embed/2wHwfKherNz">https://www.tinkercad.com/embed/2wHwfKherNz</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752100906816/cd1b3de4-f5e6-4760-ab03-8f46443ba270.png" alt="Example 2 Tinkercad simulation" class="image--center mx-auto" width="1366" height="611" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned what a resistive soil moisture sensor is, how to calibrate the sensor for your soil type, and how to use the sensor's analog and digital data to determine the moisture level of the soil.</p>
<p>The examples provided a solid foundation for working with the sensor. You can extend these examples into more complex projects, such as an automated irrigation system or remote monitoring of soil moisture.</p>
<p>For projects that require greater accuracy and frequent or sustained sensor operation, you should explore the capacitive sensor.</p>
<p>You can access all the code on <a target="_blank" href="https://github.com/michaelikoko/resistive-soil-moisture-sensor">GitHub</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Work with React Forms So They Don't Break Your Brain ]]>
                </title>
                <description>
                    <![CDATA[ If you’ve ever built a form in React and felt like the input fields had a mind of their own, you’re not alone. One minute your form is working fine, the next you’re staring at a blank input that won’t update. Or React throws a warning like “A compone... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-work-with-react-forms/</link>
                <guid isPermaLink="false">686bd09bed71f7a85eba0f6f</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Forms and input elements ]]>
                    </category>
                
                    <category>
                        <![CDATA[ controlled and uncontrolled components ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwadamisi Samuel ]]>
                </dc:creator>
                <pubDate>Mon, 07 Jul 2025 13:50:19 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751502730489/90e30388-3517-457a-8ca0-630f589da914.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you’ve ever built a form in React and felt like the input fields had a mind of their own, you’re not alone. One minute your form is working fine, the next you’re staring at a blank input that won’t update. Or React throws a warning like <code>“A component is changing an uncontrolled input of type text to be controlled.”</code> and you’re not even sure what that means.</p>
<p>I didn’t really get it either until I realized that React doesn’t just read form inputs – it can <code>own</code> them. And whether you let React control your inputs or let the <code>DOM</code> handle them makes a real difference in how your form behaves.</p>
<p>In this article, I’ll break down:</p>
<ul>
<li><p>What controlled and uncontrolled components are</p>
</li>
<li><p>Why the difference matters</p>
</li>
<li><p>When to use each one</p>
</li>
<li><p>And how to avoid common beginner mistakes</p>
</li>
</ul>
<p>You’ll get real code, clear examples, and a no-nonsense guide to making React forms behave exactly how you want.</p>
<h3 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-a-controlled-component">What Is a Controlled Component?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-an-uncontrolled-component">What Is an Uncontrolled Component?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-controlled-vs-uncontrolled-whats-the-difference">Controlled vs Uncontrolled: What's the Difference?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-controlled-vs-uncontrolled-components">When to Use Controlled vs Uncontrolled Components</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-use-controlled-components-when">Use Controlled Components When:</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-uncontrolled-components-when">Use Uncontrolled Components When:</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-a-controlled-component">What Is a Controlled Component?</h2>
<p>A <code>controlled component</code> in React is an input (like a text box or dropdown) where React keeps track of the value.</p>
<p>Instead of the browser handling the input on its own, you use React state to tell the input what to show, and update that state when the user types. Basically, for every keystroke the state updates and the component re-renders. </p>
<p>Here’s a basic example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">NameForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span> //<span class="hljs-attr">Whatever</span> <span class="hljs-attr">the</span> <span class="hljs-attr">state</span> <span class="hljs-attr">is</span>, <span class="hljs-attr">that</span> <span class="hljs-attr">is</span> <span class="hljs-attr">what</span> <span class="hljs-attr">the</span> <span class="hljs-attr">value</span> <span class="hljs-attr">of</span> <span class="hljs-attr">the</span> <span class="hljs-attr">input</span> <span class="hljs-attr">field</span> <span class="hljs-attr">will</span> <span class="hljs-attr">be</span>
      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setName(e.target.value)} //When you type, this function runs and updates the state
    /&gt;</span>
  );
}
</code></pre>
<p>React re-renders with the new value, keeping the UI and the data in sync. You're always in control of what’s in that field.</p>
<p><strong>Why use this approach?</strong></p>
<ul>
<li><p>You always know the current value.</p>
</li>
<li><p>It’s easy to validate, reset, or change the input from code.</p>
</li>
<li><p>It’s the standard approach in most React apps.</p>
</li>
</ul>
<h2 id="heading-what-is-an-uncontrolled-component">What Is an Uncontrolled Component?</h2>
<p>An <code>uncontrolled component</code> is the opposite of what we just looked at. Instead of using React state to manage the input, you let the browser handle it on its own, like a regular HTML form.</p>
<p>To get the value, you use something called a <code>ref</code> (short for “reference”) to reach into the DOM and grab it when you need it.</p>
<p>In React, <code>refs</code> are created using a built-in hook called <code>useRef</code>. This hook lets you create a reference to a DOM element (like an <code>&lt;input&gt;</code> ), so you can directly access its current value whenever you need it (for example, when a form is submitted).</p>
<p>Unlike <code>useState</code>, which tracks changes and causes re-renders, <code>useRef</code> simply gives you a way to "point to" or "reach into" an element in the DOM without triggering re-renders. It’s useful when you don’t want React to manage the input’s state, but you still need to read its value later.</p>
<p>Here’s what that looks like:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">NameForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> inputRef = useRef();

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">() =&gt;</span> {
    alert(inputRef.current.value); <span class="hljs-comment">//displays the value of the input element</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{inputRef}</span> /&gt;</span>; //gives you direct access to the input element
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> //
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>React isn’t involved in tracking every keystroke. It only checks the value when you ask for it and the input keeps track of it’s value on it’s own.</p>
<p><strong>Why use this?</strong></p>
<ul>
<li><p>It’s simpler for quick forms where you only need the value at the end (like on submit).</p>
</li>
<li><p>It avoids re-renders while typing, which can be useful in performance-sensitive apps.</p>
</li>
</ul>
<p>But: it’s harder to do things like validation, real-time updates, or syncing with other parts of your app.</p>
<h2 id="heading-controlled-vs-uncontrolled-whats-the-difference">Controlled vs Uncontrolled: What's the Difference?</h2>
<p>Now that you’ve seen both, let’s make the differences crystal clear.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Controlled Components</strong></td><td><strong>Uncontrolled Components</strong></td></tr>
</thead>
<tbody>
<tr>
<td>React is in charge.</td><td>The browser is in charge.</td></tr>
<tr>
<td>You use useState to store the value.</td><td>You use useRef to access the value.</td></tr>
<tr>
<td>You update the value with onChange.</td><td>The input keeps its own value.</td></tr>
<tr>
<td>React re-renders the input every time the value changes.</td><td>You access it using a ref only when you need it.</td></tr>
</tbody>
</table>
</div><p>Think of a controlled component like a parent carefully tracking what their kid is writing in a notebook, checking every word as it's written.</p>
<p>An uncontrolled component is more like letting the kid write freely and just reading what they wrote at the end.</p>
<h2 id="heading-when-to-use-controlled-vs-uncontrolled-components">When to Use Controlled vs Uncontrolled Components</h2>
<p>Both controlled and uncontrolled components have their place. The key is knowing when each one makes sense for your project and what you want to achieve.</p>
<h3 id="heading-use-controlled-components-when">Use Controlled Components When:</h3>
<ul>
<li><p>You need to validate input while the user types.<br>  <strong>Example</strong>: Show an error if the user leaves a field empty.</p>
</li>
<li><p>You want to enable/disable buttons based on input.<br>  <strong>Example</strong>: Disable the “Submit” button until all fields are filled.</p>
</li>
<li><p>You’re building dynamic forms.<br>  <strong>Example</strong>: Show or hide fields based on what the user selects.</p>
</li>
<li><p>You need to sync input values with other state.<br>  <strong>Example</strong>: Update a live preview as the user types.</p>
</li>
</ul>
<h3 id="heading-use-uncontrolled-components-when">Use Uncontrolled Components When:</h3>
<ul>
<li><p>You just need the value when the form is submitted.<br>  <strong>Example</strong>: A basic contact form that sends data once.</p>
</li>
<li><p>You don’t need to update the UI based on input.</p>
</li>
<li><p>You want better performance in large forms.<br>  <strong>Example</strong>: Dozens of inputs that don’t need to trigger re-renders on every change.</p>
</li>
</ul>
<p><strong>In short:</strong></p>
<ul>
<li><p>If you need to watch, validate, or react to what the user types(interact with your app’s state or UI), go with controlled.</p>
</li>
<li><p>If you just need to grab the value later, uncontrolled can work fine.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Controlled vs. Uncontrolled Components might seem like a small technical distinction at first but understanding the difference gives you much more control over how your forms behave in React.</p>
<p>Controlled components put you in the driver’s seat. React manages the form state for you, so you always know what’s in your inputs. This makes it easy to validate user input in real-time, sync form data with other parts of your app, and build more interactive, dynamic experiences.</p>
<p>Uncontrolled components, on the other hand, keep things minimal. The browser handles the input’s state, and you only reach in to get the value when you need it, usually using a ref.</p>
<p>There’s no one-size-fits-all answer for which is better. It depends entirely on your needs. If your form needs to react to user input as it changes or connect tightly with app logic, go controlled. If you just need to collect some values and move on, uncontrolled might be simpler.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write a PHP Script to Calculate the Area of a Triangle ]]>
                </title>
                <description>
                    <![CDATA[ In programming, being able to find the area of a triangle is useful for many reasons. It can help you understand logic-building and syntax, and it’s a common programming problem used in school assignments. There are also many real-world applications,... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/use-php-to-calculate-the-area-of-a-triangle/</link>
                <guid isPermaLink="false">68542db2cefef90e768ba1fe</guid>
                
                    <category>
                        <![CDATA[ PHP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mathematics ]]>
                    </category>
                
                    <category>
                        <![CDATA[ triangle ]]>
                    </category>
                
                    <category>
                        <![CDATA[ DSA ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MathJax ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ AYUSH MISHRA ]]>
                </dc:creator>
                <pubDate>Thu, 19 Jun 2025 15:33:06 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750346934679/2e46bebb-9614-4f1a-afb5-9bbe27906b4e.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In programming, being able to find the area of a triangle is useful for many reasons. It can help you understand logic-building and syntax, and it’s a common programming problem used in school assignments. There are also many real-world applications, such as computer graphics, geometry-based simulations, or construction-related calculations.</p>
<p>In this article, we’ll look at a common problem: we are given the dimensions of a triangle, and our task is to calculate its area. You can calculate the area of a triangle using different formulas, depending on the information you have about the triangle. Here, you’re going to learn how to do it using PHP.</p>
<h3 id="heading-after-reading-this-tutorial">After reading this tutorial:</h3>
<ul>
<li><p>You will understand the basic logic behind calculating the area of a triangle.</p>
</li>
<li><p>You will know how to write PHP code that calculates the triangle’s area using pre-defined and user-entered values.</p>
</li>
<li><p>You will know how to apply this logic in small projects and assignments.</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-find-the-area-of-a-triangle-using-direct-formulas">Find the Area of a Triangle Using Direct Formulas</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-find-the-area-of-a-triangle-using-the-base-and-height-approach">Find the Area of a Triangle Using the Base and Height Approach</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-find-the-area-of-a-triangle-using-herons-formula">Find the Area of a Triangle Using Heron's Formula</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-find-the-area-of-a-triangle-using-two-sides-and-included-angle-trigonometric-formula">Find the Area of a Triangle Using Two Sides and Included Angle (Trigonometric Formula)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>You’ll understand this guide more easily if you have some knowledge about a few things:</p>
<h3 id="heading-basic-php">Basic PHP</h3>
<p>You’ll need to know basic PHP syntax to fully understand the problem. If you know how to write a simple echo statement or create a variable in PHP, then you should be good to go.</p>
<h3 id="heading-local-php-environment">Local PHP Environment</h3>
<p>To run the PHP code successfully, you should have local PHP development, such as XAMPP or WAMP, on your machine. You can also use online PHP editors like PHP Fiddle or OnlineGDB to run a PHP script without any installation.</p>
<p>In this tutorial we are going to explore three approaches to determine the area of the triangle in PHP based on the amount of information available about the triangle.</p>
<ul>
<li><p><strong>Base and Height Formula Approach:</strong> This approach is applicable when you have the perpendicular height from the base and length of the base in the problem.</p>
</li>
<li><p><strong>Heron’s Formula:</strong> This approach is used to calculate the area of triangle when you have the lengths of all three sides of the triangle.</p>
</li>
<li><p><strong>Trigonometric Formula Approach:</strong> This approach is applied on the problem when you have the length of two sides and the included angle between them.</p>
</li>
</ul>
<p>First, let’s go back to math class and use some direct formulas to find the area.</p>
<h2 id="heading-find-the-area-of-a-triangle-using-direct-formulas">Find the Area of a Triangle Using Direct Formulas</h2>
<h3 id="heading-example-1">Example 1:</h3>
<p>In this first example, you’re given the input base and height of a triangle. You have to return the area of the triangle. For this example, you’ll use a direct formula to calculate the area of the triangle.</p>
<p><strong>Input:</strong></p>
<p>Base = 5,</p>
<p>Height = 10</p>
<p>You can calculate the area of the triangle using the formula:</p>
<p>$$Area = (Base * Height) / 2$$</p><p>So, if you plug in the values you have, you get: (5* 10) / 2 = 25.</p>
<p><strong>Output:</strong></p>
<p>Area = 25</p>
<h3 id="heading-example-2">Example 2:</h3>
<p>In this second example, you’re given the length of two sides of a triangle and one angle between them. You have to return the area of the triangle. In this example, you’ll use another direct formula to calculate the area of the triangle.</p>
<p><strong>Input:</strong></p>
<p>Side A = 7, Side B = 9, Angle between them = 60°</p>
<p>In this case, you’ll use the formula:</p>
<p>$$Area = (1/2) A B * sin(Angle).$$</p><p>Then just substitute in the values you’ve been given to find the area.</p>
<p><strong>Output:</strong></p>
<p>Area = 27.33 (approximately)</p>
<p>Now let’s look at some different approaches to finding the area of a triangle using PHP.</p>
<h2 id="heading-find-the-area-of-a-triangle-using-the-base-and-height-approach">Find the Area of a Triangle Using the Base and Height Approach</h2>
<p>This is the simplest and most direct approach for calculating the area of a triangle when you know the base and height. In this approach, you’ll directly put values in the formula and find the area of the triangle – but you’ll do it with PHP code.</p>
<p>First, define the base and height of the triangle. Then apply the formula for the area of the triangle. As we saw above, the formula for the area of a triangle is:</p>
<p>$$Area = (Base * Height) / 2$$</p><p>After calculating the area of the triangle, output the answer.</p>
<p>Alright, so here’s how we can implement that in PHP:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-comment">// Define the base and height</span>
$base = <span class="hljs-number">5</span>;
$height = <span class="hljs-number">10</span>;

<span class="hljs-comment">// Calculate the area</span>
$area = ($base * $height) / <span class="hljs-number">2</span>;

<span class="hljs-comment">// Output the result</span>
<span class="hljs-keyword">echo</span> <span class="hljs-string">"The area of the triangle is: "</span> . $area . <span class="hljs-string">" square units."</span>;
<span class="hljs-meta">?&gt;</span>
</code></pre>
<p>Output:</p>
<p>The area of the triangle is 25 square units.</p>
<p>In the above code, first we initialize the base and height of triangle in two variables. Then we plug those values into the area formula. PHP calculates the area of the triangle and displays the answer.</p>
<p><strong>Time Complexity</strong>: In the above approach, we are using the direct formula to calculate and return the area of the triangle, so the time complexity will be constant at O(1). The constant time complexity is efficient as it will remain constant, regardless of the size or values of the base and height.</p>
<p><strong>Space Complexity</strong>: The Space Complexity will be O(1). The space used by the above program is constant, which ensures minimal use of memory. This space complexity is ideal in environments where memory efficiency is a priority.</p>
<p>We use the above approach when we have the length of the base and height of the triangle (whether directly given or easily measurable in a right angle triangle). This method works best for right-angled triangles.</p>
<h2 id="heading-find-the-area-of-a-triangle-using-herons-formula">Find the Area of a Triangle Using Heron's Formula</h2>
<p>Heron’s formula is named after a Greek mathematician named Heron of Alexandria. Heron’s formula is useful when you know the lengths of all three sides of the triangle and you want to calculate the area without needing the height. This formula works for any type of triangle, including scalene triangles (triangles with sides of all different lengths).</p>
<p>Here’s Heron’s formula to calculate the area of a triangle:</p>
<p>$$√s(s−a)(s−b)(s−c) ​$$</p><p>Where:</p>
<ul>
<li><p>s = semi-perimeter = (a+b+c)/2 is the semi-perimeter of the triangle.</p>
</li>
<li><p>a, b, and c are the lengths of the sides.</p>
</li>
</ul>
<p>First, we define the three sides of the triangle. Then, we check all three conditions of the <a target="_blank" href="https://en.wikipedia.org/wiki/Triangle_inequality">Triangle Inequality Theorem</a> which states that if the sum of two sides is greater than the third side, then it is a valid triangle, and the given sides can form a triangle.</p>
<p>We can calculate the semi-perimeter of the triangle using the formula s = a+b+c/2. Then we can apply Heron's formula to calculate the area. After calculating the area, then output the answer.</p>
<p>Here’s how you can implement this in PHP:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-comment">// Define the sides of the triangle</span>
$a = <span class="hljs-number">7</span>;
$b = <span class="hljs-number">9</span>;
$c = <span class="hljs-number">10</span>;

<span class="hljs-comment">// Check if the sides form a valid triangle using the Triangle Inequality Theorem</span>
<span class="hljs-keyword">if</span> (($a + $b &gt; $c) &amp;&amp; ($a + $c &gt; $b) &amp;&amp; ($b + $c &gt; $a)) {

    <span class="hljs-comment">// Calculate the semi-perimeter</span>
    $s = ($a + $b + $c) / <span class="hljs-number">2</span>;

    <span class="hljs-comment">// Calculate the area using Heron's formula</span>
    $area = sqrt($s * ($s - $a) * ($s - $b) * ($s - $c));

    <span class="hljs-comment">// Output the result</span>
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"The area of the triangle is: "</span> . $area . <span class="hljs-string">" square units."</span>;

} <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// If the sides can't form a valid triangle</span>
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"The given sides do not form a valid triangle."</span>;
}
<span class="hljs-meta">?&gt;</span>
</code></pre>
<p>Output:</p>
<p>The area of the triangle is: 27.321 square units.</p>
<p>In the above code, we first create three variables to store the lengths of the triangle’s sides, and check if the given sides form a valid triangle or not using the Triangle Inequality Theorem. Then we calculate the semi-perimeter using the formula: s = a + b + c / 2. We put the value of the semi-perimeter and lengths of all sides in Heron’s formula to calculate the area. The area of triangle is returned after calculating using the formula.</p>
<p><strong>Time Complexity</strong>: There is a total fixed number of operations such as addition, subtraction, multiplication, and square root. These operations don’t depend on input size as they are performed only a fixed number of times. This means that the time complexity is constant O(1).</p>
<p><strong>Space Complexity</strong>: We have used a fixed number of variables to calculate the area of the triangle. We have not used any additional data structures such as arrays or objects. The memory usage in the program is constant, which is better for low-memory environments. The space complexity is constant O(1).</p>
<p>This approach works best when the lengths of all sides are given. This approach is used mainly for scalene or isosceles triangles where height is directly not given. This approach can work for any type of triangle, however – scalene, isosceles, or equilateral.</p>
<h2 id="heading-find-the-area-of-a-triangle-using-two-sides-and-included-angle-trigonometric-formula">Find the Area of a Triangle Using Two Sides and Included Angle (Trigonometric Formula)</h2>
<p>In this approach, we will see a different variation of the problem. When you know two sides of a triangle and the included angle between them, you can calculate the area using this formula:</p>
<p>$$Area = 1/2 × a × b × sin(θ)$$</p><p>Where:</p>
<ul>
<li><p>a and b are the lengths of the two sides.</p>
</li>
<li><p>θ is the included angle between the two sides, measured in degrees or radians.</p>
</li>
</ul>
<p>Using the above formula, you can calculate the area of a triangle without needing its height. First, you define the two sides of the triangle and the angle between them. Then you convert the angle from degrees to radians if needed (in PHP, you can use deg2rad() to convert degrees to radians). Then you apply the formula.</p>
<p>After calculating the area of the triangle, output the result.</p>
<p>Here’s how to implement this in PHP:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-comment">// Define the two sides and the included angle</span>
$a = <span class="hljs-number">7</span>;
$b = <span class="hljs-number">9</span>;
$angle = <span class="hljs-number">60</span>; <span class="hljs-comment">// Angle in degrees</span>

<span class="hljs-comment">// Convert the angle from degrees to radians</span>
$angle_in_radians = deg2rad($angle);

<span class="hljs-comment">// Calculate the area using the formula</span>
$area = <span class="hljs-number">0.5</span> * $a * $b * sin($angle_in_radians);

<span class="hljs-comment">// Output the result</span>
<span class="hljs-keyword">echo</span> <span class="hljs-string">"The area of the triangle is: "</span> . $area . <span class="hljs-string">" square units."</span>;
<span class="hljs-meta">?&gt;</span>
</code></pre>
<p>Output:</p>
<p>The area of the triangle is: 27.321 square units.</p>
<p>Explanation:</p>
<p>In the above case, we’re using the formula:</p>
<p>Area of Triangle = 1/2 × a × b × sin(θ)</p>
<p>And we’re substituting the following values into the formula:</p>
<p>Area= 1/2 × 7 × 9 × sin(60 ∘) ≈ 27.321</p>
<p>In the code, we declared two variables to store the length of the two sides of the triangle, and the variable <code>$angle</code> hold the included angle in degrees. We used <code>deg2rad()</code>, a PHP built-in function which converts an angle from degrees to radians. Then, we applied the actual formula: Area = 1/2 × 7 × 9 × sin(60 ∘). PHP stores the final answer in the <code>$area</code> variable.</p>
<p><strong>Time Complexity</strong>: We are using the direct formula to calculate the area of a triangle when the length of two sides and the angle between them are given. The constant time complexity is O(1).</p>
<p><strong>Space Complexity</strong>: Similarly, it does not take any extra space or use any data structures. It uses a single variable to store the result, which is why the space complexity is constant O(1).</p>
<p>This approach is perfect for the problem in which two sides and the included angle (angle between those sides) are known. You can use it when you cannot easily calculate the height of the triangle. This problem has real-life applications in geometry problems, CAD applications, or physics simulations. This method is very accurate and doesn’t require the length of all sides.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you’ve learned how you can calculate the area of a triangle, both manually and using PHP. You have seen different approaches and learned about which one is best given the information you have. First, we discussed the base and height approach, then looked at Heron’s formula, and finally examined how to handle things when two sides and the included angle are given.</p>
<p>Understanding the logic behind each of these approaches helps you choose the right one based on the given data.</p>
<p>And if you'd like to support me and my work directly so I can keep creating these tutorials, <a target="_blank" href="https://paypal.me/ayushM010">you can do so here</a>. Thank you!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
