<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sean Coughlin's Blog]]></title><description><![CDATA[I am a Software Engineer interested in Web Development, App Development, and Machine Learning.]]></description><link>https://blog.seancoughlin.me</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 17:56:58 GMT</lastBuildDate><atom:link href="https://blog.seancoughlin.me/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The Art and Science of URI Design: A Practical Guide]]></title><description><![CDATA[In my years of web architecture work, I've found that few elements are as foundational yet frequently underappreciated as URI design. Like street addresses in a city, URIs form the navigational backbone of our digital landscape—deceptively simple, ye...]]></description><link>https://blog.seancoughlin.me/the-art-and-science-of-uri-design-a-practical-guide</link><guid isPermaLink="true">https://blog.seancoughlin.me/the-art-and-science-of-uri-design-a-practical-guide</guid><category><![CDATA[APIs]]></category><category><![CDATA[REST API]]></category><category><![CDATA[architecture]]></category><category><![CDATA[Design]]></category><category><![CDATA[design patterns]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Thu, 10 Apr 2025 00:19:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744244192772/e1e40b30-206f-4d4e-9b75-69790358662b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my years of web architecture work, I've found that few elements are as foundational yet frequently underappreciated as URI design. Like street addresses in a city, URIs form the navigational backbone of our digital landscape—deceptively simple, yet profoundly impactful when thoughtfully constructed.</p>
<h2 id="heading-why-uri-design-matters">Why URI Design Matters</h2>
<p>Good URI design creates what I call "cognitive ergonomics" for your digital interfaces. When developers can correctly guess a URI before reading your documentation, you've achieved something special. This isn't merely aesthetic satisfaction—it translates to reduced onboarding time, fewer integration errors, and more intuitive exploration of your API.</p>
<p>It's worth noting that no single URI design approach has emerged as the definitive standard. Different industries and platforms prioritize different aspects—semantic clarity, brevity, security, or backend alignment. What matters most is thoughtful consideration followed by consistent application of whatever approach you choose.</p>
<h2 id="heading-uri-design-cheat-sheet">URI Design Cheat Sheet</h2>
<p>Here's my distilled wisdom on practical URI construction—a cheat sheet that balances pragmatism with principle:</p>
<h3 id="heading-core-principles">Core Principles</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Principle</td><td>Do ✅</td><td>Don't ❌</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Persistence</strong></td><td>Keep URIs stable indefinitely</td><td>Change URIs without redirection</td></tr>
<tr>
<td><strong>HTTP Methods</strong></td><td><code>GET /users/123</code></td><td><code>/getUser/123</code></td></tr>
<tr>
<td><strong>Descriptiveness</strong></td><td><code>/products/headphones</code></td><td><code>/p/12345</code></td></tr>
<tr>
<td><strong>Consistency</strong></td><td>Follow one pattern throughout</td><td>Mix different naming conventions</td></tr>
</tbody>
</table>
</div><h3 id="heading-resource-naming-approaches">Resource Naming Approaches</h3>
<pre><code class="lang-plaintext"># Common patterns - choose one and be consistent:
/users                # Collection (plural)
/users/123            # Specific resource (plural collection)
/user/123             # Specific resource (singular)
</code></pre>
<h3 id="heading-structural-guidelines">Structural Guidelines</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Aspect</td><td>Options</td><td>Examples</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Case</strong></td><td>Lowercase (recommended)</td><td><code>/blog-posts</code></td></tr>
<tr>
<td></td><td>camelCase</td><td><code>/blogPosts</code></td></tr>
<tr>
<td><strong>Word Separators</strong></td><td>Hyphens (recommended)</td><td><code>/first-post</code></td></tr>
<tr>
<td></td><td>Underscores</td><td><code>/first_post</code></td></tr>
<tr>
<td></td><td>No separator</td><td><code>/firstpost</code></td></tr>
<tr>
<td><strong>File Extensions</strong></td><td>Avoid when possible</td><td><code>/users</code> not <code>/users.json</code></td></tr>
<tr>
<td><strong>Query Parameters</strong></td><td>For filtering/sorting</td><td><code>/products?category=audio&amp;sort=price</code></td></tr>
<tr>
<td><strong>Trailing Slash</strong></td><td>Be consistent (preferably avoid)</td><td><code>/about</code> (not <code>/about/</code>)</td></tr>
</tbody>
</table>
</div><h3 id="heading-versioning-strategies">Versioning Strategies</h3>
<pre><code class="lang-plaintext"># In URI path (most common)
/api/v1/users

# In header
Accept: application/vnd.example.v1+json

# In query parameter
/api/users?version=1
</code></pre>
<h3 id="heading-relationship-representation">Relationship Representation</h3>
<pre><code class="lang-plaintext"># Nested resources (shows ownership)
/users/123/posts/456

# Flat structure with references
/posts/456?user=123
</code></pre>
<h3 id="heading-managing-change">Managing Change</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Scenario</td><td>Solution</td></tr>
</thead>
<tbody>
<tr>
<td>URI must change</td><td>Use 301 (permanent) redirect</td></tr>
<tr>
<td>Temporary change</td><td>Use 302 (temporary) redirect</td></tr>
<tr>
<td>Content moved</td><td>Use 307/308 redirects</td></tr>
</tbody>
</table>
</div><h3 id="heading-security-considerations">Security Considerations</h3>
<ul>
<li><p>Never include sensitive data in URIs (<a target="_blank" href="https://https.cio.gov/faq/">but you do get some protection from HTTPS</a>)</p>
</li>
<li><p>Be cautious with revealing database IDs</p>
</li>
<li><p>Consider obfuscating sequential IDs for private resources</p>
</li>
</ul>
<h3 id="heading-industry-differences">Industry Differences</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Industry</td><td>Common Practice</td><td>Example</td></tr>
</thead>
<tbody>
<tr>
<td><strong>E-commerce</strong></td><td>Product hierarchy</td><td><code>/products/category/item</code></td></tr>
<tr>
<td><strong>Finance</strong></td><td>Security-focused, opaque</td><td><code>/accounts/A123B456</code></td></tr>
<tr>
<td><strong>Government</strong></td><td>Formal, descriptive</td><td><code>/services/tax-filing/form-1040</code></td></tr>
</tbody>
</table>
</div><h3 id="heading-remember">Remember</h3>
<ul>
<li><p>No perfect standard exists - context matters</p>
</li>
<li><p>Consistency within your API is most important</p>
</li>
<li><p>Document your conventions for developers</p>
</li>
</ul>
<h2 id="heading-closing-thoughts">Closing Thoughts</h2>
<p>The best URI designs are often invisible—they work so intuitively that users and developers navigate your digital spaces without conscious effort. It's only when URIs are inconsistent, opaque, or unstable that their importance becomes painfully apparent.</p>
<p>As you implement these principles, remember that you're not just arranging technical identifiers—you're crafting the fundamental navigational psychology of your system. Choose wisely, implement consistently, and document clearly.</p>
<hr />
<p><em>As Tim Berners-Lee wisely noted: "</em><a target="_blank" href="https://www.w3.org/Provider/Style/URI"><em>Cool URIs don't change.</em></a><em>"</em></p>
]]></content:encoded></item><item><title><![CDATA[Visualizing the Invisible: My Journey Building an Algorithm Visualizer]]></title><description><![CDATA[Ever tried explaining how a sorting algorithm works to someone who doesn't code? I have—and watching their eyes glaze over faster than a quicksort partitioning an array is quite the humbling experience.
This challenge inspired me to build an interact...]]></description><link>https://blog.seancoughlin.me/visualizing-the-invisible-my-journey-building-an-algorithm-visualizer</link><guid isPermaLink="true">https://blog.seancoughlin.me/visualizing-the-invisible-my-journey-building-an-algorithm-visualizer</guid><category><![CDATA[Next.js]]></category><category><![CDATA[side project]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[visualization]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Thu, 10 Apr 2025 00:03:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744243380271/edd57e31-8211-466d-9eab-cd00f8b19e12.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ever tried explaining how a sorting algorithm works to someone who doesn't code? I have—and watching their eyes glaze over faster than a quicksort partitioning an array is quite the humbling experience.</p>
<p>This challenge inspired me to build an interactive <a target="_blank" href="https://algorithm-visualizer.seancoughlin.me">Algorithm Visualizer—a simple web app</a> that shows how algorithms actually work, step by step. It's like having x-ray vision into code that's normally hidden behind the scenes, making it easier to understand what these algorithms are really doing.</p>
<h2 id="heading-the-architecture-building-a-cognitive-bridge">The Architecture: Building a Cognitive Bridge</h2>
<p>Algorithm Visualizer is built on a modern web application stack that prioritizes both developer experience and end-user performance:</p>
<ul>
<li><p><strong>Next.js</strong>: Provides the foundational architecture, leveraging its App Router for intuitive, hierarchical navigation between algorithm categories and individual visualizations</p>
</li>
<li><p><strong>React</strong>: Powers the component-based UI architecture, with hooks managing the complex state transitions during algorithm execution</p>
</li>
<li><p><strong>TypeScript</strong>: Offers type safety that proved invaluable when modeling algorithm steps and state transitions</p>
</li>
<li><p><strong>Tailwind CSS</strong>: Enables rapid styling with consistency across the application's visual language</p>
</li>
</ul>
<p>What makes this project noteworthy is that it's entirely client-side—there's no authentication flow, no database, no server-side processing. This architectural choice prioritizes simplicity and accessibility: anyone with a browser can instantly explore algorithm concepts without setup friction.</p>
<p>The project is deployed using Vercel, which provides seamless hosting and automatic previews for each commit. A GitHub Actions CI/CD pipeline handles automated testing, linting, and deployment, ensuring code quality and a smooth development workflow with minimal manual intervention.</p>
<h2 id="heading-the-core-visualization-mechanism-algorithmic-cinematography">The Core Visualization Mechanism: Algorithmic Cinematography</h2>
<p>The visualization engine functions on a simple yet powerful principle: algorithms are instrumented to generate "snapshots" at each significant step of their execution. These snapshots are then rendered as frames in an interactive animation sequence.</p>
<p>Consider the bubble sort algorithm—rather than simply rearranging values and returning a sorted array, my implementation:</p>
<ol>
<li><p>Creates a deep copy of the input array at each comparison or swap</p>
</li>
<li><p>Tracks which elements are being compared, swapped, or marked as completed</p>
</li>
<li><p>Captures these states in a sequence of steps</p>
</li>
<li><p>Enables users to navigate forward, backward, or automatically play through the sequence</p>
</li>
</ol>
<p>This approach effectively turns algorithms inside-out, exposing their internal decision-making rather than just their inputs and outputs. It's the difference between watching a chess match move-by-move versus simply seeing the final board state.</p>
<h2 id="heading-the-algorithm-portfolio-computational-diversity">The Algorithm Portfolio: Computational Diversity</h2>
<p>The platform currently visualizes three categories of algorithms:</p>
<h3 id="heading-sorting-algorithms">Sorting Algorithms</h3>
<ul>
<li><p><strong>Bubble Sort</strong>: The computational equivalent of bubbles rising in water—simple to understand yet inefficient for large datasets</p>
</li>
<li><p><strong>Selection Sort</strong>: Methodically finding the smallest element repeatedly</p>
</li>
<li><p><strong>Insertion Sort</strong>: Mimicking how you might sort playing cards in your hand</p>
</li>
<li><p><strong>Merge Sort</strong>: Divide and conquer applied to sorting with guaranteed O(n log n) performance</p>
</li>
<li><p><strong>Quick Sort</strong>: The speed demon of sorting with excellent average performance</p>
</li>
<li><p><strong>Heap Sort</strong>: Leveraging a binary heap structure for consistent performance</p>
</li>
</ul>
<h3 id="heading-searching-algorithms">Searching Algorithms</h3>
<ul>
<li><p><strong>Linear Search</strong>: The computational equivalent of checking each drawer for your lost keys</p>
</li>
<li><p><strong>Binary Search</strong>: The clever approach of eliminating half the possibilities at each step</p>
</li>
</ul>
<h3 id="heading-graph-algorithms">Graph Algorithms</h3>
<ul>
<li><p><strong>Depth-First Search (DFS)</strong>: Exploring as deeply as possible along branches before backtracking</p>
</li>
<li><p><strong>Breadth-First Search (BFS)</strong>: Exploring all neighbors at the current depth before moving deeper</p>
</li>
<li><p><strong>Dijkstra's Algorithm</strong>: Finding shortest paths with weighted edges</p>
</li>
<li><p><strong>Topological Sort</strong>: Ordering vertices such that for every directed edge, the source comes before the target</p>
</li>
</ul>
<h2 id="heading-educational-infrastructure-beyond-simple-visualization">Educational Infrastructure: Beyond Simple Visualization</h2>
<p>Beyond the core visualizations, I've built several features that transform this from a simple animation tool to a practical learning platform:</p>
<h3 id="heading-interactive-controls">Interactive Controls</h3>
<p>Users can play, pause, step forward/backward, adjust animation speed, and generate new datasets—offering control comparable to a video player but for algorithm execution.</p>
<h3 id="heading-chromatic-understanding">Chromatic Understanding</h3>
<p>Color-coding provides instant visual cues for different algorithm states:</p>
<ul>
<li><p>Blue elements represent unsorted/unvisited items</p>
</li>
<li><p>Yellow highlights current comparisons/examinations</p>
</li>
<li><p>Red indicates swapping operations</p>
</li>
<li><p>Green marks completed elements or found targets</p>
</li>
</ul>
<h3 id="heading-algorithm-context">Algorithm Context</h3>
<p>Each algorithm is presented with:</p>
<ul>
<li><p>Plain-language descriptions of how it works</p>
</li>
<li><p>Pseudocode representation for conceptual understanding</p>
</li>
<li><p>Time and space complexity information</p>
</li>
<li><p>Difficulty classification for progressive learning</p>
</li>
</ul>
<h3 id="heading-comprehensive-glossary">Comprehensive Glossary</h3>
<p>A dedicated glossary section functions as a computational lexicon, defining key terms from "Algorithm" to "Time Complexity" with illustrative examples and cross-references.</p>
<h2 id="heading-the-engineering-challenges-thinking-about-thinking">The Engineering Challenges: Thinking About Thinking</h2>
<p>Building this platform required solutions to several interesting problems:</p>
<h3 id="heading-the-context-step-management-pattern">The Context-Step Management Pattern</h3>
<p>The core state management pattern revolves around an <code>AlgorithmContext</code> that maintains:</p>
<ul>
<li><p>Current algorithm selection</p>
</li>
<li><p>Dataset being manipulated</p>
</li>
<li><p>Visualization steps generated from algorithm execution</p>
</li>
<li><p>Current step index within the visualization</p>
</li>
<li><p>Playback control state (playing/paused, speed)</p>
</li>
</ul>
<p>This is implemented using React's Context API and a reducer pattern to handle actions like:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Actions that can be dispatched to the reducer</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> VisualizationAction =
  | { <span class="hljs-keyword">type</span>: <span class="hljs-string">"SET_CURRENT_STEP"</span>; payload: <span class="hljs-built_in">number</span> }
  | { <span class="hljs-keyword">type</span>: <span class="hljs-string">"SET_IS_PLAYING"</span>; payload: <span class="hljs-built_in">boolean</span> }
  | { <span class="hljs-keyword">type</span>: <span class="hljs-string">"SET_SPEED"</span>; payload: <span class="hljs-built_in">number</span> }
  | { <span class="hljs-keyword">type</span>: <span class="hljs-string">"SET_ALGORITHM"</span>; payload: <span class="hljs-built_in">string</span> }
  <span class="hljs-comment">// ... other actions</span>
</code></pre>
<h3 id="heading-algorithm-visualization-generation">Algorithm Visualization Generation</h3>
<p>Each algorithm implementation follows a pattern that distinguishes between:</p>
<ol>
<li><p>The algorithm's actual sorting/searching logic</p>
</li>
<li><p>The step recording logic that captures state transitions</p>
</li>
</ol>
<p>For example, in the bubble sort implementation:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bubbleSort</span>(<span class="hljs-params">array: <span class="hljs-built_in">number</span>[]</span>): <span class="hljs-title">AlgorithmVisualization</span> </span>{
  <span class="hljs-keyword">const</span> steps: SortingStep[] = [];
  <span class="hljs-keyword">const</span> arr = [...array];
  <span class="hljs-comment">// ... sorting logic interleaved with step recording ...</span>
  steps.push({
    array: [...arr],
    comparing: [j, j + <span class="hljs-number">1</span>],
    swapped: <span class="hljs-literal">true</span>,
    completed: [...completed],
  });
  <span class="hljs-comment">// ... more sorting and step recording ...</span>
  <span class="hljs-keyword">return</span> createVisualization(<span class="hljs-string">"bubbleSort"</span>, steps, {
    timeComplexity: <span class="hljs-string">"O(n²)"</span>,
    spaceComplexity: <span class="hljs-string">"O(1)"</span>,
    <span class="hljs-comment">// ... other metadata ...</span>
  });
}
</code></pre>
<p>This separation of concerns ensures the visualizations accurately represent algorithm execution while maintaining clean, understandable code.</p>
<h3 id="heading-rendering-different-algorithm-types">Rendering Different Algorithm Types</h3>
<p>Different algorithm categories require substantially different visualization approaches:</p>
<ul>
<li><p>Sorting algorithms are represented as bars with varying heights</p>
</li>
<li><p>Searching algorithms display the elements being searched with positional indicators</p>
</li>
<li><p>Graph algorithms use a node-edge representation with traversal indicators</p>
</li>
</ul>
<p>The component architecture handles this diversity through polymorphism:</p>
<pre><code class="lang-tsx">{category === "sorting" &amp;&amp; (
  &lt;SortingVisualization
    step={visualizationData.steps[currentStep] as SortingStep}
    maxValue={maxValue}
  /&gt;
)}
{category === "searching" &amp;&amp; (
  &lt;SearchVisualization
    step={visualizationData.steps[currentStep] as SearchStep}
    maxValue={maxValue}
  /&gt;
)}
{category === "graph" &amp;&amp; (
  &lt;GraphVisualization
    step={visualizationData.steps[currentStep] as GraphStep}
  /&gt;
)}
</code></pre>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Building this Algorithm Visualizer was honestly a fun challenge. I wanted to see algorithms in action rather than just read about them, and I figured others might feel the same way.</p>
<p>What I enjoyed most was seeing how these abstract concepts became clearer once I could actually watch them run step by step. There's something satisfying about watching a sorting algorithm gradually organize a jumbled array or seeing how a search algorithm hunts down a value.</p>
<p>The project turned out to be educational for me too. As I built each visualization, I found myself understanding these algorithms at a deeper level. It's one thing to read about bubble sort in a textbook; it's another to code it up and watch it bubble those values to the top.</p>
<p>I hope this tool helps others who are learning about algorithms or just curious about how they work. Sometimes seeing is understanding!</p>
<hr />
<p><em>The Algorithm Visualizer is available at</em> <a target="_blank" href="https://algorithm-visualizer.seancoughlin.me/"><em>algorithm-visualizer.seancoughlin.me</em></a> <em>and the source code can be found on</em> <a target="_blank" href="https://github.com/Scc33/algorithm-visualizer"><em>GitHub</em></a><em>.</em></p>
]]></content:encoded></item><item><title><![CDATA[Managing Concurrency with Spring Bean Scopes: A Complete Guide]]></title><description><![CDATA["Why is user data leaking between accounts in our production app?" The developer's message hit our Slack channel at 2 AM. The culprit? A seemingly innocent Spring bean storing user information in an instance variable.
You might be wondering: if Sprin...]]></description><link>https://blog.seancoughlin.me/managing-concurrency-with-spring-bean-scopes-a-complete-guide</link><guid isPermaLink="true">https://blog.seancoughlin.me/managing-concurrency-with-spring-bean-scopes-a-complete-guide</guid><category><![CDATA[Springboot]]></category><category><![CDATA[Spring framework]]></category><category><![CDATA[Spring]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[asynchronous]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Fri, 04 Apr 2025 13:16:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743772469432/ee6cda19-6dbf-403a-aa97-ba8954099eec.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>"Why is user data leaking between accounts in our production app?" The developer's message hit our Slack channel at 2 AM. The culprit? A seemingly innocent Spring bean storing user information in an instance variable.</p>
<p>You might be wondering: if <a target="_blank" href="https://docs.spring.io/spring-framework/reference/core/beans/factory-scopes.html">Spring beans are singletons by default</a>, how do they handle thousands of concurrent requests without catastrophic data contamination? It's a paradox that confuses even experienced developers—and getting it wrong can lead to security breaches, data corruption, and those dreaded middle-of-the-night emergencies.</p>
<p>This guide will demystify Spring's bean scoping system, revealing how the framework elegantly manages concurrent requests despite its singleton-first approach. We'll explore when to break away from the default scope, how to match bean lifecycles to your state management needs, and how to test for the subtle bugs that scope-related issues can create.</p>
<h2 id="heading-the-singleton-paradox-how-spring-handles-concurrent-requests">The Singleton Paradox: How Spring Handles Concurrent Requests</h2>
<p>If you're new to Spring, you might wonder: if beans are singletons by default, how can the framework possibly handle multiple concurrent requests without users seeing each other's data?</p>
<p>The answer lies in stateless design. Spring's architecture encourages developers to create stateless services, where beans don't store request-specific data as instance variables. Instead, data flows through method parameters and return values.</p>
<p>Consider this example of a well-designed stateless service:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaxCalculatorService</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">calculateTax</span><span class="hljs-params">(<span class="hljs-keyword">double</span> income, String state)</span> </span>{
        <span class="hljs-keyword">double</span> taxRate = getTaxRateForState(state);
        <span class="hljs-keyword">return</span> income * taxRate;
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> <span class="hljs-title">getTaxRateForState</span><span class="hljs-params">(String state)</span> </span>{
        <span class="hljs-keyword">return</span> state.equals(<span class="hljs-string">"IL"</span>) ? <span class="hljs-number">0.0495</span> : <span class="hljs-number">0.05</span>;
    }
}
</code></pre>
<p>This service can safely handle concurrent requests because each thread maintains its own execution stack with local variables that don't interfere with other threads.</p>
<h2 id="heading-when-singletons-go-wrong-the-perils-of-mutable-state">When Singletons Go Wrong: The Perils of Mutable State</h2>
<p>To understand why stateless design matters, consider this problematic implementation:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ShoppingCartService</span> </span>{
    <span class="hljs-keyword">private</span> List&lt;String&gt; items = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();
    <span class="hljs-keyword">private</span> String username;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setUsername</span><span class="hljs-params">(String username)</span> </span>{
        <span class="hljs-keyword">this</span>.username = username;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addItem</span><span class="hljs-params">(String item)</span> </span>{
        items.add(item);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;String&gt; <span class="hljs-title">getItems</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> items;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">checkout</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Processing order for: "</span> + username);
        System.out.println(<span class="hljs-string">"Items: "</span> + items);
        items.clear();
    }
}
</code></pre>
<p>This service stores user-specific data as instance variables. Since it's a singleton, all users share the same instance, leading to these problems:</p>
<ol>
<li><p>User A could see User B's items or username</p>
</li>
<li><p>One user's checkout could clear another user's cart</p>
</li>
<li><p>Race conditions could corrupt data as concurrent requests modify the same lists</p>
</li>
</ol>
<h2 id="heading-understanding-spring-bean-scopes">Understanding Spring Bean Scopes</h2>
<p>Spring offers several scopes to address different state management needs:</p>
<h3 id="heading-singleton-scope-default">Singleton Scope (Default)</h3>
<p>One instance per Spring container, shared across all requests.</p>
<p><strong>Best for:</strong> Stateless services, immutable data, thread-safe utilities</p>
<p><strong>Example use case:</strong> Tax calculators, email formatters, validation services</p>
<h3 id="heading-request-scope">Request Scope</h3>
<p>Creates a new instance for each HTTP request.</p>
<ul>
<li><p><strong>Best for:</strong> Request-specific context, tracking request metadata</p>
</li>
<li><p><strong>Example use case:</strong> Request loggers, audit contexts, request validators</p>
</li>
</ul>
<h3 id="heading-session-scope">Session Scope</h3>
<p>Creates a new instance for each user session.</p>
<ul>
<li><p><strong>Best for:</strong> User-specific data that persists across multiple requests</p>
</li>
<li><p><strong>Example use case:</strong> Shopping carts, user preferences, multi-step wizards</p>
</li>
</ul>
<h3 id="heading-prototype-scope">Prototype Scope</h3>
<p>Creates a new instance each time requested.</p>
<ul>
<li><p><strong>Best for:</strong> Stateful components that must be unique</p>
</li>
<li><p><strong>Example use case:</strong> Complex object builders, non-shared resources</p>
</li>
</ul>
<h2 id="heading-configuring-bean-scopes-in-spring">Configuring Bean Scopes in Spring</h2>
<p>Configuring a bean's scope is straightforward:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Component</span>
<span class="hljs-meta">@RequestScope</span>  <span class="hljs-comment">// or @SessionScope, or @Scope("prototype")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserContext</span> </span>{
    <span class="hljs-keyword">private</span> String userId;
    <span class="hljs-keyword">private</span> Instant loginTime;

    <span class="hljs-comment">// Getters and setters</span>
}
</code></pre>
<h2 id="heading-real-world-example-building-a-spring-backend-for-react">Real-World Example: Building a Spring Backend for React</h2>
<p>When developing a Spring backend for a React frontend, managing state becomes especially important. Let's look at a practical example that uses different scopes appropriately:</p>
<pre><code class="lang-java"><span class="hljs-comment">// Singleton - Stateless service</span>
<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductService</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ProductRepository repository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ProductService</span><span class="hljs-params">(ProductRepository repository)</span> </span>{
        <span class="hljs-keyword">this</span>.repository = repository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Product&gt; <span class="hljs-title">findProducts</span><span class="hljs-params">(String category)</span> </span>{
        <span class="hljs-keyword">return</span> repository.findByCategory(category);
    }
}

<span class="hljs-comment">// Request-scoped - Tracks request-specific data</span>
<span class="hljs-meta">@Component</span>
<span class="hljs-meta">@RequestScope</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RequestAuditContext</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String requestId = UUID.randomUUID().toString();
    <span class="hljs-keyword">private</span> Instant startTime = Instant.now();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">logRequest</span><span class="hljs-params">(String endpoint)</span> </span>{
        <span class="hljs-keyword">long</span> duration = Duration.between(startTime, Instant.now()).toMillis();
        System.out.println(<span class="hljs-string">"Request "</span> + requestId + <span class="hljs-string">" to "</span> + endpoint + <span class="hljs-string">" took "</span> + duration + <span class="hljs-string">"ms"</span>);
    }
}

<span class="hljs-comment">// Session-scoped - Maintains user state across requests</span>
<span class="hljs-meta">@Component</span>
<span class="hljs-meta">@SessionScope</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ShoppingCart</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> List&lt;CartItem&gt; items = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addItem</span><span class="hljs-params">(CartItem item)</span> </span>{
        items.add(item);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;CartItem&gt; <span class="hljs-title">getItems</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> Collections.unmodifiableList(items);
    }
}
</code></pre>
<h2 id="heading-integration-with-react-frontend">Integration with React Frontend</h2>
<p>Spring's session management works well with React frontends, but requires some configuration:</p>
<h3 id="heading-cookie-based-sessions">Cookie-Based Sessions</h3>
<p>For traditional cookie-based sessions:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Configuration</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SessionConfig</span> </span>{
    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> CookieSerializer <span class="hljs-title">cookieSerializer</span><span class="hljs-params">()</span> </span>{
        DefaultCookieSerializer serializer = <span class="hljs-keyword">new</span> DefaultCookieSerializer();
        serializer.setSameSite(<span class="hljs-string">"Lax"</span>);
        serializer.setCookiePath(<span class="hljs-string">"/"</span>);
        serializer.setUseSecureCookie(<span class="hljs-keyword">true</span>);
        <span class="hljs-keyword">return</span> serializer;
    }
}
</code></pre>
<p>React needs to include credentials with requests:</p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">'https://api.example.com/api/user/profile'</span>, {
  <span class="hljs-attr">credentials</span>: <span class="hljs-string">'include'</span> <span class="hljs-comment">// Important for sending cookies</span>
})
</code></pre>
<h3 id="heading-jwt-based-authentication">JWT-Based Authentication</h3>
<p>For token-based approaches:</p>
<pre><code class="lang-java"><span class="hljs-meta">@RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthController</span> </span>{
    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> JwtTokenProvider tokenProvider;

    <span class="hljs-meta">@PostMapping("/login")</span>
    <span class="hljs-keyword">public</span> ResponseEntity&lt;?&gt; login(<span class="hljs-meta">@RequestBody</span> LoginRequest loginRequest) {
        <span class="hljs-comment">// Authenticate user</span>
        String token = tokenProvider.generateToken(username);
        <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-keyword">new</span> JwtResponse(token));
    }
}
</code></pre>
<p>React would store and send the token:</p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">'https://api.example.com/user/cart'</span>, {
  <span class="hljs-attr">headers</span>: {
    <span class="hljs-string">'Authorization'</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${token}</span>`</span>
  }
})
</code></pre>
<h2 id="heading-performance-implications-of-bean-scopes">Performance Implications of Bean Scopes</h2>
<p>Bean scope selection impacts application performance in several ways:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Scope</td><td>Memory Usage</td><td>Creation Cost</td><td>Relative Performance</td></tr>
</thead>
<tbody>
<tr>
<td>Singleton</td><td>Lowest</td><td>Once at startup</td><td>Fastest (100%)</td></tr>
<tr>
<td>Request</td><td>Medium</td><td>Once per request</td><td>Medium (70-90%)</td></tr>
<tr>
<td>Session</td><td>Potentially high</td><td>Once per session</td><td>Medium-Fast (80-95%)</td></tr>
<tr>
<td>Prototype</td><td>Varies</td><td>On each retrieval</td><td>Slowest (50-80%)</td></tr>
</tbody>
</table>
</div><p>For most applications, these performance differences are negligible compared to database access and external API calls. Still, high-throughput applications should minimize the use of request-scoped beans on critical paths.</p>
<h2 id="heading-testing-for-scope-related-issues">Testing for Scope-Related Issues</h2>
<p>Detecting scope-related problems requires specific testing approaches:</p>
<h3 id="heading-concurrent-request-testing">Concurrent Request Testing</h3>
<pre><code class="lang-java"><span class="hljs-meta">@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ConcurrentRequestTests</span> </span>{
    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> TestRestTemplate restTemplate;

    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testConcurrentRequests</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> InterruptedException </span>{
        <span class="hljs-keyword">int</span> threadCount = <span class="hljs-number">10</span>;
        CountDownLatch latch = <span class="hljs-keyword">new</span> CountDownLatch(threadCount);
        AtomicInteger successCount = <span class="hljs-keyword">new</span> AtomicInteger(<span class="hljs-number">0</span>);

        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; threadCount; i++) {
            <span class="hljs-keyword">final</span> String userId = <span class="hljs-string">"user"</span> + i;
            <span class="hljs-keyword">new</span> Thread(() -&gt; {
                <span class="hljs-keyword">try</span> {
                    ResponseEntity&lt;String&gt; response = restTemplate.postForEntity(
                        <span class="hljs-string">"/api/profile"</span>, 
                        Map.of(<span class="hljs-string">"userId"</span>, userId, <span class="hljs-string">"action"</span>, <span class="hljs-string">"update"</span>),
                        String.class
                    );

                    <span class="hljs-keyword">if</span> (response.getBody().contains(userId)) {
                        successCount.incrementAndGet();
                    }
                } <span class="hljs-keyword">finally</span> {
                    latch.countDown();
                }
            }).start();
        }

        latch.await(<span class="hljs-number">10</span>, TimeUnit.SECONDS);
        assertEquals(threadCount, successCount.get());
    }
}
</code></pre>
<h3 id="heading-session-contamination-testing">Session Contamination Testing</h3>
<p>Create tests that verify user A never sees user B's data:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Test</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testNoSessionContamination</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-comment">// Create two separate sessions</span>
    TestRestTemplate userA = <span class="hljs-keyword">new</span> TestRestTemplate();
    TestRestTemplate userB = <span class="hljs-keyword">new</span> TestRestTemplate();

    <span class="hljs-comment">// Add different items to each cart</span>
    userA.postForEntity(<span class="hljs-string">"/api/cart/add"</span>, <span class="hljs-keyword">new</span> CartItem(<span class="hljs-string">"item-A"</span>), Void.class);
    userB.postForEntity("/api/cart/add", <span class="hljs-keyword">new</span> CartItem(<span class="hljs-string">"item-B"</span>), Void.class);

    <span class="hljs-comment">// Verify each user sees only their own items</span>
    ResponseEntity&lt;Cart&gt; userACart = userA.getForEntity(<span class="hljs-string">"/api/cart"</span>, Cart.class);
    ResponseEntity&lt;Cart&gt; userBCart = userB.getForEntity(<span class="hljs-string">"/api/cart"</span>, Cart.class);

    assertTrue(userACart.getBody().containsItem(<span class="hljs-string">"item-A"</span>));
    assertFalse(userACart.getBody().containsItem(<span class="hljs-string">"item-B"</span>));

    assertTrue(userBCart.getBody().containsItem(<span class="hljs-string">"item-B"</span>));
    assertFalse(userBCart.getBody().containsItem(<span class="hljs-string">"item-A"</span>));
}
</code></pre>
<h2 id="heading-best-practices-for-bean-scope-management">Best Practices for Bean Scope Management</h2>
<ol>
<li><p><strong>Default to Stateless Singletons</strong>: Design services to be stateless when possible</p>
</li>
<li><p><strong>Match Scope to State Requirements</strong>:</p>
<ul>
<li><p>Application-wide state → Singleton with thread-safe collections</p>
</li>
<li><p>User-specific state → Session scope</p>
</li>
<li><p>Request-specific state → Request scope</p>
</li>
</ul>
</li>
<li><p><strong>Prefer Method Parameters</strong>: Pass data through method parameters rather than storing in instance variables</p>
</li>
<li><p><strong>Use ThreadLocal Carefully</strong>: For framework code that needs request context without dependency injection</p>
</li>
<li><p><strong>Document Scope Decisions</strong>: Add comments or documentation explaining scope choices for non-standard cases</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Understanding Spring bean scopes is crucial for building robust, scalable applications that handle concurrent requests correctly. By matching the right scope to your state management needs, you can create applications that are both thread-safe and efficient.</p>
<p>The next time you create a Spring bean, ask yourself: "What is the right scope for this component's state?" By making this a conscious decision rather than accepting the default, you'll build more reliable applications and avoid the subtle bugs that come from improper state management.</p>
<p>Remember, in most cases, following Spring's push toward stateless design with singleton beans is the right approach. Only reach for other scopes when you have a specific state management requirement that demands it.</p>
]]></content:encoded></item><item><title><![CDATA[Building an Interactive SQL Learning Platform with React, Next.js, and SQL.js]]></title><description><![CDATA[Have you ever tried teaching someone SQL only to spend the first hour fighting with database installations? Or maybe you've been that frustrated beginner, wondering why you need to configure a server just to learn a query language. This exact pain po...]]></description><link>https://blog.seancoughlin.me/building-an-interactive-sql-learning-platform-with-react-nextjs-and-sqljs</link><guid isPermaLink="true">https://blog.seancoughlin.me/building-an-interactive-sql-learning-platform-with-react-nextjs-and-sqljs</guid><category><![CDATA[SQL]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[education]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[WebAssembly]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Thu, 03 Apr 2025 21:30:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743715757003/582c3d3d-0d57-48a8-bf1e-21aa0171a851.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever tried teaching someone <a target="_blank" href="https://en.wikipedia.org/wiki/SQL">SQL</a> only to spend the first hour fighting with database installations? Or maybe you've been that frustrated beginner, wondering why you need to configure a server just to learn a query language. This exact pain point inspired me to build <a target="_blank" href="https://buddysql.seancoughlin.me">SQL Playground</a> - a side project that lets anyone learn SQL directly in their browser, no setup required.</p>
<blockquote>
<p><strong>Note:</strong> While researching after development, I discovered there was once a PHP-based tool called "<a target="_blank" href="https://en.wikipedia.org/wiki/SQLBuddy">SQL Buddy</a>" (last updated in 2011), which was a database administration tool for MySQL and SQLite. My project, despite the similar educational focus on SQL, is entirely unrelated and takes a completely different approach as a modern, client-side learning platform rather than a database administration tool. Coincidentally, I deployed my project to <a target="_blank" href="http://buddysql.seancoughlin.me">buddysql.seancoughlin.me</a> before learning about the old SQL Buddy tool - the URL similarity is purely accidental!</p>
</blockquote>
<h2 id="heading-the-vision-sql-without-the-setup-ceremony">The Vision: SQL Without the Setup Ceremony</h2>
<p>Anyone who's taught SQL knows the first obstacle isn't the language itself—it's getting everyone to successfully install and configure a database system. This "setup tax" creates a significant barrier to entry, especially for beginners. My side project, <strong>SQL Playground</strong>, eliminates this friction entirely.</p>
<p>By leveraging SQL.js (SQLite compiled to WebAssembly) and the modern capabilities of client-side web applications, I've created an environment where learners can:</p>
<ul>
<li><p>Write SQL queries directly in their browser</p>
</li>
<li><p>See results immediately with proper feedback</p>
</li>
<li><p>Progress through structured lessons that build upon each other</p>
</li>
<li><p>Practice on a realistic sample database</p>
</li>
<li><p>Save their progress locally without requiring accounts</p>
</li>
</ul>
<h2 id="heading-the-technology-stack-modern-typed-and-component-driven">The Technology Stack: Modern, Typed, and Component-Driven</h2>
<p>My implementation rests on a carefully selected technology foundation that prioritizes developer experience, maintainability, and performance:</p>
<h3 id="heading-core-stack">Core Stack</h3>
<ul>
<li><p><strong>Next.js 15</strong> - For its robust React framework capabilities and excellent developer experience</p>
</li>
<li><p><strong>React 19</strong> - Providing the component-based UI architecture</p>
</li>
<li><p><strong>TypeScript</strong> - Adding type safety throughout the codebase</p>
</li>
<li><p><strong>Tailwind CSS</strong> - For utility-first styling that scales elegantly</p>
</li>
<li><p><a target="_blank" href="https://sql.js.org/#/"><strong>SQL.js</strong></a> - The magic ingredient that brings SQLite to the browser via WebAssembly</p>
</li>
</ul>
<h3 id="heading-key-implementation-details">Key Implementation Details</h3>
<p>The architecture follows a clean separation of concerns:</p>
<ol>
<li><p><strong>Data Layer</strong>:</p>
<ul>
<li><p>SQL.js provides a complete SQLite database engine in the browser</p>
</li>
<li><p>Custom hooks manage database initialization and query execution</p>
</li>
<li><p>Local storage persists user progress between sessions</p>
</li>
</ul>
</li>
<li><p><strong>UI Layer</strong>:</p>
<ul>
<li><p>React components for lesson content, SQL editor, and results display</p>
</li>
<li><p>Tailwind CSS for responsive, maintainable styling</p>
</li>
<li><p>Split-view interface that keeps lessons and code editor visible simultaneously</p>
</li>
</ul>
</li>
<li><p><strong>Learning Content</strong>:</p>
<ul>
<li><p>Structured curriculum from SQL basics to joins and aggregations</p>
</li>
<li><p>Interactive challenges with intelligent feedback</p>
</li>
<li><p>Pre-populated e-commerce database with realistic relationships</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-the-development-journey-from-concept-to-implementation">The Development Journey: From Concept to Implementation</h2>
<p>My development process followed an iterative approach, starting with the core functionality of executing SQL in the browser and gradually building up the educational framework around it.</p>
<h3 id="heading-step-1-setting-up-the-sqljs-environment">Step 1: Setting Up the SQL.js Environment</h3>
<p>The first technical challenge was properly integrating SQL.js. This required:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Initializing SQL.js with WebAssembly</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initializeSql</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> SQL = <span class="hljs-keyword">await</span> initSqlJs({
    <span class="hljs-attr">locateFile</span>: <span class="hljs-function"><span class="hljs-params">file</span> =&gt;</span> <span class="hljs-string">`https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.8.0/<span class="hljs-subst">${file}</span>`</span>
  });
  <span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> SQL.Database();
  <span class="hljs-keyword">return</span> { SQL, db };
}
</code></pre>
<p>The SQL.js initialization was straightforward once I understood the right approach to load it as a client-side module:</p>
<h3 id="heading-step-2-creating-the-interactive-sql-editor">Step 2: Creating the Interactive SQL Editor</h3>
<p>The SQL editor component became the heart of the application. It needed to:</p>
<ul>
<li><p>Allow users to write and edit SQL</p>
</li>
<li><p>Execute queries against the in-memory database</p>
</li>
<li><p>Display results in a readable format</p>
</li>
<li><p>Provide helpful feedback on errors</p>
</li>
</ul>
<p>The editor implementation uses React state to track the current query and results:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [query, setQuery] = useState(initialQuery || <span class="hljs-string">""</span>);
<span class="hljs-keyword">const</span> [queryResult, setQueryResult] = useState({
  <span class="hljs-attr">results</span>: <span class="hljs-literal">null</span>,
  <span class="hljs-attr">error</span>: <span class="hljs-literal">null</span>
});

<span class="hljs-keyword">const</span> executeQuery = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> result = onExecuteQuery(query);
    setQueryResult(result);
    <span class="hljs-comment">// ... additional processing for grading/feedback</span>
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error executing query:"</span>, err);
  }
};
</code></pre>
<h3 id="heading-step-3-building-the-learning-framework">Step 3: Building the Learning Framework</h3>
<p>With the technical foundation in place, we focused on crafting an effective learning experience. This meant:</p>
<ol>
<li><p><strong>Designing a curriculum</strong> that progresses logically from basic SELECT statements to complex joins</p>
</li>
<li><p><strong>Creating a sample database</strong> with realistic relationships between customers, products, orders, etc.</p>
</li>
<li><p><strong>Implementing a grading system</strong> that can evaluate SQL queries beyond simple string matching:</p>
</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-comment">// Grading logic excerpt</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">gradeQuery</span>(<span class="hljs-params">
  userQuery: <span class="hljs-built_in">string</span>,
  queryResults: SqlResult[] | <span class="hljs-literal">null</span>,
  hasError: <span class="hljs-built_in">boolean</span>,
  options: GradeOptions
</span>): <span class="hljs-title">GradeResult</span> </span>{
  <span class="hljs-comment">// Various checks for correctness...</span>
  <span class="hljs-keyword">if</span> (options.mustContain &amp;&amp; options.mustContain.length &gt; <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">const</span> normalizedUserQuery = normalizeQuery(userQuery, options.caseSensitive);
    <span class="hljs-keyword">const</span> missingTerms = options.mustContain.filter(<span class="hljs-function">(<span class="hljs-params">term</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> normalizedTerm = options.caseSensitive ? term : term.toLowerCase();
      <span class="hljs-keyword">return</span> !normalizedUserQuery.includes(normalizedTerm);
    });

    <span class="hljs-keyword">if</span> (missingTerms.length &gt; <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">return</span> {
        isCorrect: <span class="hljs-literal">false</span>,
        score: <span class="hljs-number">40</span>,
        feedback: <span class="hljs-string">`Your query is missing some important elements.`</span>,
        hints: [<span class="hljs-string">`Make sure your query includes: <span class="hljs-subst">${missingTerms.join(<span class="hljs-string">", "</span>)}</span>`</span>],
        <span class="hljs-keyword">type</span>: <span class="hljs-string">"warning"</span>,
      };
    }
  }
  <span class="hljs-comment">// Additional validation logic...</span>
}
</code></pre>
<ol start="4">
<li><strong>Storing progress</strong> using browser local storage:</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useLocalStorage</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">
  key: <span class="hljs-built_in">string</span>,
  initialValue: T
</span>): [<span class="hljs-title">T</span>, (<span class="hljs-params">value: T | ((val: T) =&gt; T)</span>) =&gt; <span class="hljs-title">void</span>, (<span class="hljs-params"></span>) =&gt; <span class="hljs-title">void</span>] </span>{
  <span class="hljs-keyword">const</span> [storedValue, setStoredValue] = useState&lt;T&gt;(initialValue);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> item = <span class="hljs-built_in">window</span>.localStorage.getItem(key);
      setStoredValue(item ? <span class="hljs-built_in">JSON</span>.parse(item) : initialValue);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
      setStoredValue(initialValue);
    }
  }, [key, initialValue]);

  <span class="hljs-comment">// ... setter and removal functions</span>

  <span class="hljs-keyword">return</span> [storedValue, setValue, removeValue];
}
</code></pre>
<h2 id="heading-technical-challenges-and-solutions">Technical Challenges and Solutions</h2>
<p>No project is without its hurdles. Here are some of the more interesting challenges I encountered:</p>
<h3 id="heading-challenge-1-sqljs-webassembly-loading">Challenge 1: SQL.js WebAssembly Loading</h3>
<p><strong>Problem</strong>: SQL.js requires WebAssembly, which has specific loading requirements in modern browsers.</p>
<p><strong>Solution</strong>: I implemented a custom <code>useSqlJs</code> hook that handles script loading, WebAssembly initialization, and database setup. After exploring different approaches, I found it much simpler to load SQL.js from a CDN rather than trying to manually compile it into the application. This approach simplified dependency management and ensured the WebAssembly files were properly served:</p>
<h3 id="heading-challenge-2-query-evaluation">Challenge 2: Query Evaluation</h3>
<p><strong>Problem</strong>: Determining if a user's SQL query is "correct" is not straightforward - there are often multiple valid approaches to the same problem.</p>
<p><strong>Solution</strong>: We developed a flexible grading system that can:</p>
<ul>
<li><p>Check for required SQL elements (SELECT, FROM, specific table names)</p>
</li>
<li><p>Validate result structure (column names, row counts)</p>
</li>
<li><p>Provide specific feedback based on different types of errors</p>
</li>
</ul>
<h3 id="heading-challenge-3-react-hydration">Challenge 3: React Hydration</h3>
<p><strong>Problem</strong>: Next.js server-side rendering doesn't play well with browser-only libraries like SQL.js.</p>
<p><strong>Solution</strong>: We made specific components "client-only" using the "use client" directive, ensuring that SQL.js initialization only happens in the browser environment.</p>
<pre><code class="lang-typescript"><span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { useState, useEffect, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-comment">// SQL.js related code...</span>
</code></pre>
<h2 id="heading-the-database-architecture-an-e-commerce-playground">The Database Architecture: An E-commerce Playground</h2>
<p>To provide a realistic learning environment, I created a sample e-commerce database with four key tables:</p>
<ol>
<li><p><strong>Customers</strong>: customer_id, first_name, last_name, email, join_date</p>
</li>
<li><p><strong>Products</strong>: product_id, name, description, price, category</p>
</li>
<li><p><strong>Orders</strong>: order_id, customer_id, order_date, total_amount</p>
</li>
<li><p><strong>Order_Items</strong>: item_id, order_id, product_id, quantity, price_each</p>
</li>
</ol>
<p>This schema allows for meaningful queries that demonstrate real-world SQL concepts:</p>
<ul>
<li><p>Basic SELECTs for product or customer information</p>
</li>
<li><p>Filtering with WHERE to find products in specific categories</p>
</li>
<li><p>Aggregations to calculate total sales or average prices</p>
</li>
<li><p>JOINs to connect orders with customer information</p>
</li>
</ul>
<h2 id="heading-lessons-learned-and-future-directions">Lessons Learned and Future Directions</h2>
<p>Building SQL Playground taught me several valuable lessons:</p>
<ol>
<li><p><strong>WebAssembly is powerful but quirky</strong> - The ability to run SQLite in the browser is remarkable, but WASM has its own set of challenges around loading and memory management.</p>
</li>
<li><p><strong>Client-side state management requires careful thinking</strong> - Without a backend, all progress tracking had to be managed through local storage with appropriate fallbacks.</p>
</li>
<li><p><strong>Feedback is crucial for learning</strong> - Simply executing queries isn't enough; meaningful feedback dramatically improves the learning experience.</p>
</li>
</ol>
<p>For future enhancements, I'm considering:</p>
<ul>
<li><p><strong>More advanced SQL lessons</strong> - Covering subqueries, window functions, and common table expressions</p>
</li>
<li><p><strong>Custom database import</strong> - Allowing users to upload their own schemas</p>
</li>
<li><p><strong>Query visualization</strong> - Displaying query execution plans visually</p>
</li>
<li><p><strong>Performance optimizations</strong> for larger datasets</p>
</li>
</ul>
<h2 id="heading-conclusion-the-browser-as-a-learning-environment">Conclusion: The Browser as a Learning Environment</h2>
<p><a target="_blank" href="https://buddysql.seancoughlin.me">SQL Playground</a> demonstrates how modern web technologies can assist technical education. By eliminating setup friction and providing immediate feedback, I've created an environment where learning SQL becomes about the language itself, not the surrounding infrastructure.</p>
<p>This project showcases the power of WebAssembly to bring traditionally server-side technologies to the client, opening new possibilities for interactive learning experiences. Whether you're a SQL novice or looking to sharpen your skills, I hope this tool makes your journey more enjoyable and effective.</p>
<p>The code is open-source and <a target="_blank" href="https://github.com/Scc33/BuddySQL">available on GitHub</a>, and I welcome contributions from the community to enhance this learning resource further.</p>
<hr />
<p><em>This side project was built with React, Next.js, TypeScript, Tailwind CSS, and SQL.js, demonstrating how modern web technologies can create powerful, serverless applications for technical education.</em></p>
]]></content:encoded></item><item><title><![CDATA[Building an Accessible Web: Key Features Every Developer Should Implement]]></title><description><![CDATA[Making websites accessible ensures that individuals of all abilities can easily navigate, understand, and interact with your content, enhancing the overall user experience for everyone.
This blog post will guide you through eleven key accessibility f...]]></description><link>https://blog.seancoughlin.me/building-an-accessible-web-key-features-every-developer-should-implement</link><guid isPermaLink="true">https://blog.seancoughlin.me/building-an-accessible-web-key-features-every-developer-should-implement</guid><category><![CDATA[HTML5]]></category><category><![CDATA[React]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[HTML]]></category><category><![CDATA[Accessibility]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Wed, 09 Oct 2024 15:30:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728487601529/6ec7c957-58af-41df-ab78-a188756bcf91.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Making websites accessible ensures that individuals of all abilities can easily navigate, understand, and interact with your content, enhancing the overall user experience for everyone.</p>
<p>This blog post will guide you through eleven key accessibility features, providing actionable advice and code snippets to make your web development more inclusive.</p>
<p>Let's dive in.</p>
<h3 id="heading-semantic-html">Semantic HTML</h3>
<p>Using <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Semantics">semantic HTML</a> helps assistive technologies (like screen readers) understand the structure of your web page, providing users with a clear, consistent experience.</p>
<h4 id="heading-code-example">Code Example:</h4>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Main Navigation"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#home"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#services"</span>&gt;</span>Services<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#contact"</span>&gt;</span>Contact<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">header</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">article</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Accessibility in Web Development<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Making the web accessible to everyone.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<p>Using elements like <code>&lt;header&gt;</code>, <code>&lt;nav&gt;</code>, and <code>&lt;article&gt;</code> helps convey meaning and makes the structure understandable for assistive devices.</p>
<h3 id="heading-keyboard-navigation">Keyboard Navigation</h3>
<p>Many users rely solely on their keyboard for navigation, so it's essential that interactive elements are accessible using keys like "Tab," "Enter," and "Space."</p>
<h4 id="heading-code-example-1">Code Example:</h4>
<pre><code class="lang-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> alert('Button clicked!')}
  onKeyDown={(e) =&gt; {
    if (e.key === 'Enter' || e.key === ' ') {
      alert('Button clicked!');
    }
  }}
&gt;
  Click Me
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>This allows users to activate the button with the "Enter" or "Space" keys, ensuring it works for both mouse and keyboard users.</p>
<h3 id="heading-aria-attributes">ARIA Attributes</h3>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA">ARIA (Accessible Rich Internet Applications)</a> attributes help define roles and states for non-standard elements, making them accessible to users with disabilities.</p>
<h4 id="heading-code-example-2">Code Example:</h4>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
  <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span>
  <span class="hljs-attr">tabIndex</span>=<span class="hljs-string">{0}</span>
  <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">"false"</span>
  <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"content"</span>
  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> toggleContent()}
  onKeyDown={(e) =&gt; {
    if (e.key === 'Enter' || e.key === ' ') toggleContent();
  }}
&gt;
  Toggle Content
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span>Here is the expandable content.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>ARIA roles like <code>aria-expanded</code> and <code>aria-controls</code> help communicate an element's current state and functionality to assistive technologies.</p>
<h3 id="heading-alternative-text-for-images">Alternative Text for Images</h3>
<p>Adding <code>alt</code> text to images ensures users relying on screen readers understand the purpose of an image.</p>
<h4 id="heading-code-example-3">Code Example:</h4>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"logo.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Company Logo"</span> /&gt;</span>

<span class="hljs-comment">&lt;!-- Decorative Image --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"decorative-line.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
</code></pre>
<p>Provide descriptive <code>alt</code> text for informative images, and use an empty <code>alt</code> attribute (<code>alt=""</code>) for decorative images so they’re skipped by screen readers.</p>
<h3 id="heading-color-contrast-and-text-size">Color Contrast and Text Size</h3>
<p>Sufficient contrast between text and background is crucial for readability, particularly for visually impaired users.</p>
<h4 id="heading-code-example-4">Code Example:</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#000</span>; <span class="hljs-comment">/* Dark text */</span>
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>; <span class="hljs-comment">/* Light background */</span>
}

<span class="hljs-selector-class">.large-text</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5em</span>; <span class="hljs-comment">/* Ensures readability */</span>
}
</code></pre>
<p>Always ensure good contrast ratios (at least 4.5:1) between text and background, and provide resizable text for better readability.</p>
<h3 id="heading-descriptive-link-text">Descriptive Link Text</h3>
<p>Link text should be descriptive enough to make sense out of context, helping users understand where the link will take them.</p>
<h4 id="heading-code-example-5">Code Example:</h4>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/accessibility-resources"</span>&gt;</span>Learn more about accessibility<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>Avoid using generic phrases like "Click here," which can be confusing when read out of context by screen readers.</p>
<h3 id="heading-form-labels-and-instructions">Form Labels and Instructions</h3>
<p>Clear labels are essential for users relying on assistive technology to fill out forms accurately.</p>
<h4 id="heading-code-example-6">Code Example:</h4>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">aria-required</span>=<span class="hljs-string">"true"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"password"</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">aria-required</span>=<span class="hljs-string">"true"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>Use <code>aria-required</code> and appropriate <code>&lt;label&gt;</code> elements to make forms easier to navigate and understand.</p>
<h3 id="heading-captioning-and-transcripts-for-media">Captioning and Transcripts for Media</h3>
<p>To accommodate users who are deaf or hard of hearing, provide captions for videos and transcripts for audio content.</p>
<h4 id="heading-code-example-7">Code Example:</h4>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">video</span> <span class="hljs-attr">controls</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Company Overview"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"overview.mp4"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"video/mp4"</span>&gt;</span>
  Your browser does not support the video tag.
<span class="hljs-tag">&lt;/<span class="hljs-name">video</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Link to transcript --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/overview-transcript"</span>&gt;</span>Read the transcript<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>Adding captions or transcripts makes multimedia content accessible for users who might not be able to hear or see the media.</p>
<h3 id="heading-skip-to-main-content-links">Skip to Main Content Links</h3>
<p>A "Skip to Main Content" link helps users with assistive technologies bypass repetitive content like navigation menus.</p>
<h4 id="heading-code-example-8">Code Example:</h4>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#main-content"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"skip-link"</span>&gt;</span>Skip to Main Content<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"main-content"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Main Content<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Here is the primary content of the page.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<p>Place skip links at the top of the page and make them visible when focused, improving the navigation experience.</p>
<h3 id="heading-responsive-design">Responsive Design</h3>
<p>Accessible web design should adapt to various screen sizes and devices, especially for users relying on magnification or different input devices.</p>
<h4 id="heading-code-example-9">Code Example:</h4>
<pre><code class="lang-css"><span class="hljs-comment">/* CSS */</span>
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">600px</span>) {
  <span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.2em</span>;
  }
  <span class="hljs-selector-class">.content</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  }
}
</code></pre>
<p>Ensuring text and layout adjust for different screen sizes helps users who rely on screen magnification or mobile devices.</p>
<h3 id="heading-alerts-and-notifications">Alerts and Notifications</h3>
<p>Make dynamic content changes perceivable to users by notifying assistive technologies of updates.</p>
<h4 id="heading-code-example-10">Code Example:</h4>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span> <span class="hljs-attr">aria-live</span>=<span class="hljs-string">"assertive"</span>&gt;</span>
  Form submission successful!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Use <code>role="alert"</code> and <code>aria-live</code> attributes to notify users about dynamic changes, like form submission success messages.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Incorporating these eleven accessibility features into your web development workflow ensures your website is more inclusive and usable for everyone, including individuals with disabilities.</p>
<p>Accessibility is an ongoing effort, but even small changes can have a huge impact on the user experience.</p>
<h4 id="heading-additional-resources">Additional Resources</h4>
<ul>
<li><p><a target="_blank" href="https://www.w3.org/WAI/fundamentals/accessibility-intro/">Introduction to Web Accessibility</a></p>
</li>
<li><p><a target="_blank" href="https://www.w3.org/WAI/WCAG21/quickref/">Web Content Accessibility Guidelines (WCAG)</a></p>
</li>
<li><p><a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/">ARIA Authoring Practices</a></p>
</li>
<li><p><a target="_blank" href="https://webaim.org/resources/contrastchecker/">Color Contrast Checker</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Supercharge Your Java App: Performance Testing with Gatling]]></title><description><![CDATA[Introduction
In modern software development, performance is as crucial as functionality. It’s no longer enough for an application to simply "work"; it needs to work well under pressure. Imagine launching a new app that starts slowing down or crashing...]]></description><link>https://blog.seancoughlin.me/supercharge-your-java-app-performance-testing-with-gatling</link><guid isPermaLink="true">https://blog.seancoughlin.me/supercharge-your-java-app-performance-testing-with-gatling</guid><category><![CDATA[Gatling]]></category><category><![CDATA[performance]]></category><category><![CDATA[Performance Optimization]]></category><category><![CDATA[Java]]></category><category><![CDATA[optimization]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Thu, 03 Oct 2024 15:57:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727970510465/05039b4c-1b30-4796-8838-0a86b0878488.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In modern software development, performance is as crucial as functionality. It’s no longer enough for an application to simply "work"; it needs to work <strong>well</strong> under pressure. Imagine launching a new app that starts slowing down or crashing when too many users log in at once. That’s a fast-track way to lose users and damage a brand.</p>
<p>This is where <strong>performance testing</strong> comes in. It’s a method to ensure your application can handle the real-world demands of its users. Performance testing helps you uncover weak points before your users do, giving you the insights you need to make sure your app is fast, stable, and scalable. In this post, we’ll dive into how you can use Gatling to test the performance of your Java applications, from getting started to writing effective tests.</p>
<p>But first, let’s talk about what performance testing actually is and why it matters.</p>
<h2 id="heading-understanding-performance-testing">Understanding Performance Testing</h2>
<h3 id="heading-what-is-performance-testing">What is Performance Testing?</h3>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Software_performance_testing">Performance testing</a> is a way to evaluate how an application behaves when it's under different kinds of load. The goal isn't just to see if the application works, but to see <em>how well</em> it works under various conditions. Does it slow down when a certain number of users hit it at once? Does the response time stay within acceptable limits? Does it crash if pushed too hard? These are all questions performance testing aims to answer.</p>
<p>Different types of performance testing focus on different aspects of this behavior:</p>
<ul>
<li><p><strong>Load Testing</strong>: This simulates a typical number of users accessing the application at the same time. The goal here is to see if the system can handle its expected everyday usage without slowing down or failing.</p>
</li>
<li><p><strong>Stress Testing</strong>: Stress testing takes things a step further by pushing the application beyond its normal capacity. It’s all about finding the breaking point—how many users or requests it takes before things start falling apart. The purpose here isn’t to simulate normal use but to understand how the application behaves under extreme conditions, like a spike in traffic.</p>
</li>
</ul>
<p>Both of these are crucial for understanding the limitations and resilience of your system.</p>
<h3 id="heading-why-performance-testing-matters">Why Performance Testing Matters</h3>
<p>The reason performance testing is so important is simple: user experience. No matter how good your app’s features are, if it’s slow or unreliable, people won’t stick around. Performance problems often don’t show up until users actually start using the system, which can make them tricky to catch if you don’t test properly.</p>
<p>By running performance tests early and often, you can:</p>
<ul>
<li><p><strong>Spot bottlenecks before they hit production</strong>: It’s much easier to fix performance issues during development than it is once they’re live.</p>
</li>
<li><p><strong>Ensure your system scales</strong>: As your user base grows, you want to be sure your app grows with it, without losing speed or reliability.</p>
</li>
<li><p><strong>Improve stability</strong>: By stress-testing your system, you’ll learn how it behaves under extreme load and be able to prepare for real-world scenarios, whether it's a product launch or a sudden influx of users.</p>
</li>
</ul>
<p>Ultimately, performance testing helps ensure that when your users hit the system hard, it holds up—and that’s key to building reliable software.</p>
<h2 id="heading-introducing-gatling-for-java-applications">Introducing Gatling for Java Applications</h2>
<h3 id="heading-what-is-gatling">What is Gatling?</h3>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Gatling_\(software\)">Gatling</a> is an <a target="_blank" href="https://gatling.io">open-source tool</a> specifically designed for load and performance testing. It's often used to test how applications respond under heavy traffic. What sets Gatling apart is its ability to simulate a large number of users with minimal resource usage. This makes it an excellent tool for testing web applications, especially those built in Java.</p>
<p>While Gatling was originally written in <a target="_blank" href="https://en.wikipedia.org/wiki/Scala_\(programming_language\)">Scala</a>, it now provides a Java DSL, which is what we’ll focus on in this guide. The <a target="_blank" href="https://docs.gatling.io">Java DSL</a> allows you to write Gatling simulations in a way that feels natural to Java developers. The idea is to write performance tests just like you’d write any other Java code, without needing to dive into a new language.</p>
<h3 id="heading-why-use-gatling-for-java">Why Use Gatling for Java?</h3>
<p>There are several reasons why Gatling stands out for testing Java applications:</p>
<ul>
<li><p><strong>Java DSL</strong>: You can write Gatling tests in Java, meaning you don't have to learn Scala if you don’t want to. This reduces the learning curve and lets you get started quickly.</p>
</li>
<li><p><strong>Efficient and Lightweight</strong>: Gatling uses an asynchronous, non-blocking model, which allows it to simulate thousands of users with low memory usage.</p>
</li>
<li><p><strong>Modular and Reusable</strong>: Gatling scenarios are easy to write and can be reused and extended, making it suitable for long-term projects with evolving performance testing needs.</p>
</li>
</ul>
<p>Now, let’s move on to how you can set up Gatling in a Java project.</p>
<h2 id="heading-setting-up-gatling-in-a-java-project-with-gradle">Setting Up Gatling in a Java Project with Gradle</h2>
<p>Since we’re focusing on Java, we’ll use <a target="_blank" href="https://gradle.org"><strong>Gradle</strong></a> to manage dependencies and run the tests. Gatling works well with Gradle, and integrating it into your Java project is simple.</p>
<h4 id="heading-adding-gatling-dependencies">Adding Gatling Dependencies</h4>
<p>First, you need to add the necessary dependencies to your <code>build.gradle</code> file. Here’s how you do that:</p>
<pre><code class="lang-plaintext">plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'io.gatling.highcharts:gatling-charts-highcharts:3.9.5'
    testImplementation 'io.gatling:gatling-app:3.9.5'
}
</code></pre>
<p>This pulls in Gatling along with the Highcharts plugin for better visual reporting (even though we won’t focus on HTML reports here). The <code>gatling-app</code> dependency allows us to run the simulations.</p>
<h4 id="heading-project-structure">Project Structure</h4>
<p>The structure of your project will be similar to any other Java application. Here's what a basic setup might look like:</p>
<pre><code class="lang-plaintext">src
└── test
    └── java
        └── simulations
            └── BasicSimulation.java
</code></pre>
<p>Place your Gatling test files inside the <code>src/test/java/simulations</code> directory. This ensures they are properly picked up when you run your tests using Gradle.</p>
<h2 id="heading-writing-your-first-gatling-test-in-java">Writing Your First Gatling Test in Java</h2>
<p>Now that Gatling is set up in your project, let’s write a simple test to see how it works.</p>
<h4 id="heading-creating-a-basic-simulation">Creating a Basic Simulation</h4>
<p>Here's a basic Gatling test written in Java that simulates a user making a GET request to a web page:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> simulations;

<span class="hljs-keyword">import</span> io.gatling.javaapi.core.*;
<span class="hljs-keyword">import</span> io.gatling.javaapi.http.*;

<span class="hljs-keyword">import</span> <span class="hljs-keyword">static</span> io.gatling.javaapi.core.CoreDsl.*;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">static</span> io.gatling.javaapi.http.HttpDsl.*;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BasicSimulation</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Simulation</span> </span>{
    HttpProtocolBuilder httpProtocol = http
        .baseUrl(<span class="hljs-string">"http://example.com"</span>)  <span class="hljs-comment">// Set the base URL</span>
        .acceptHeader(<span class="hljs-string">"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"</span>)
        .acceptLanguageHeader(<span class="hljs-string">"en-US,en;q=0.5"</span>)
        .userAgentHeader(<span class="hljs-string">"Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0"</span>);

    ScenarioBuilder scn = scenario(<span class="hljs-string">"BasicSimulation"</span>)  <span class="hljs-comment">// Define the scenario</span>
        .exec(http(<span class="hljs-string">"request_1"</span>)  <span class="hljs-comment">// Name the request</span>
        .get(<span class="hljs-string">"/"</span>))  <span class="hljs-comment">// Send a GET request to the root of the URL</span>
        .pause(<span class="hljs-number">1</span>);  <span class="hljs-comment">// Simulate a 1-second pause (user "think" time)</span>

    {
        setUp(scn.injectOpen(atOnceUsers(<span class="hljs-number">10</span>)))  <span class="hljs-comment">// Simulate 10 users accessing the site at once</span>
            .protocols(httpProtocol);  <span class="hljs-comment">// Apply the HTTP protocol settings to this scenario</span>
    }
}
</code></pre>
<ul>
<li><p><a target="_blank" href="https://docs.gatling.io/reference/script/protocols/http/protocol/"><code>HttpProtocolBuilder</code></a>: This is where you configure your HTTP protocol settings. In this example, we’re setting the base URL to "<a target="_blank" href="http://example.com">http://example.com</a>" and defining headers that are sent with every request.</p>
</li>
<li><p><a target="_blank" href="https://docs.gatling.io/reference/script/core/scenario/"><code>ScenarioBuilder</code></a>: The scenario is the "user journey." In this case, the user sends a simple GET request to the root ("/") of the website. After that, there’s a 1-second pause to simulate real user behavior.</p>
</li>
<li><p><code>setUp</code>: This sets up the scenario and specifies how many users should be simulated. In this example, we're simulating 10 users hitting the website simultaneously using the <code>atOnceUsers(10)</code> injection profile.</p>
</li>
</ul>
<h4 id="heading-running-the-test">Running the Test</h4>
<p>To run the Gatling test using Gradle, use the following command:</p>
<pre><code class="lang-bash">./gradlew gatlingRun -Dgatling.simulationClass=simulations.BasicSimulation
</code></pre>
<p>This tells Gradle to execute the <code>BasicSimulation</code> class. If everything is set up correctly, the test will run, and you’ll see the results printed in the terminal.</p>
<h2 id="heading-enhancing-your-gatling-tests">Enhancing Your Gatling Tests</h2>
<p>Once you’ve successfully run a basic simulation, you’ll want to start adding complexity to your tests. Real-world user behavior is rarely as simple as sending a single request, so let’s look at how you can simulate more realistic scenarios and add performance validation checks.</p>
<h4 id="heading-simulating-realistic-user-behavior">Simulating Realistic User Behavior</h4>
<p>In this section, we’ll expand on the simple test by chaining together multiple requests to simulate a more realistic user journey.</p>
<p>Here’s an example of a scenario where a user visits a homepage, searches for a product, and then views a product detail page:</p>
<pre><code class="lang-java">ScenarioBuilder scn = scenario(<span class="hljs-string">"UserJourney"</span>)
    .exec(http(<span class="hljs-string">"Home Page"</span>)
        .get(<span class="hljs-string">"/"</span>))  <span class="hljs-comment">// Visit the home page</span>
    .pause(<span class="hljs-number">2</span>)  <span class="hljs-comment">// Pause for 2 seconds</span>
    .exec(http(<span class="hljs-string">"Search Page"</span>)
        .get(<span class="hljs-string">"/search?q=gatling"</span>))  <span class="hljs-comment">// Perform a search</span>
    .pause(<span class="hljs-number">1</span>)  <span class="hljs-comment">// Pause for 1 second</span>
    .exec(http(<span class="hljs-string">"Product Page"</span>)
        .get(<span class="hljs-string">"/products/1"</span>));  <span class="hljs-comment">// View a product detail page</span>
</code></pre>
<ul>
<li><p>We simulate a user visiting three different pages of the site, with pauses in between to mimic the natural "think time" of a real user.</p>
</li>
<li><p>Each HTTP request has a name (<code>Home Page</code>, <code>Search Page</code>, <code>Product Page</code>), making it easy to identify in the logs or results.</p>
</li>
</ul>
<p>You can also add more complexity with <strong>POST</strong> requests, form submissions, and cookies to mimic user sessions. The idea here is to mirror actual user behavior as closely as possible.</p>
<h4 id="heading-adding-assertions">Adding Assertions</h4>
<p>Assertions are a powerful feature that allows you to define the performance criteria that your application should meet. For example, you can assert that the maximum response time should be under 2 seconds or that at least 99% of requests should succeed.</p>
<p>Here’s how you can add assertions to the simulation:</p>
<pre><code class="lang-java">{
    setUp(scn.injectOpen(atOnceUsers(<span class="hljs-number">10</span>)).protocols(httpProtocol))
        .assertions(
            global().responseTime().max().lt(<span class="hljs-number">2000</span>),  <span class="hljs-comment">// Assert that the max response time is less than 2 seconds</span>
            global().successfulRequests().percent().gt(<span class="hljs-number">99.0</span>)  <span class="hljs-comment">// Assert that at least 99% of requests succeed</span>
        );
}
</code></pre>
<ul>
<li><p><code>global().responseTime().max().lt(2000)</code>: This ensures that no request takes longer than 2 seconds.</p>
</li>
<li><p><code>global().successfulRequests().percent().gt(99.0)</code>: This checks that 99% or more of the requests are successful.</p>
</li>
</ul>
<p>By including assertions, you can automatically validate that your system is meeting its performance goals.</p>
<h2 id="heading-best-practices-for-performance-testing-with-gatling">Best Practices for Performance Testing with Gatling</h2>
<p>Now that you’re familiar with writing Gatling tests, let’s talk about best practices to ensure your performance tests provide the most value.</p>
<h4 id="heading-clear-objectives">Clear Objectives</h4>
<p>Before writing any tests, it’s important to know <em>what</em> you’re testing and <em>why</em>. Define clear objectives for each test:</p>
<ul>
<li><p>Are you checking for acceptable response times?</p>
</li>
<li><p>Do you want to know the maximum load your system can handle?</p>
</li>
<li><p>Are you simulating real-world usage patterns?</p>
</li>
</ul>
<p>By setting specific goals, you can create focused tests that provide actionable insights.</p>
<h4 id="heading-simulating-realistic-scenarios">Simulating Realistic Scenarios</h4>
<p>It’s essential that the scenarios you test resemble actual user behavior. Here are a few tips:</p>
<ul>
<li><p><strong>Use real-world data</strong>: If possible, base your test data on actual usage patterns or production logs. This ensures your tests reflect how users interact with your app.</p>
</li>
<li><p><strong>Think time</strong>: Adding realistic pauses between requests (like in the <code>pause()</code> method) helps simulate the delay users naturally take between actions.</p>
</li>
</ul>
<h4 id="heading-monitor-system-resources">Monitor System Resources</h4>
<p>While running performance tests, it’s not just the response times that matter. You should also keep an eye on system resources like CPU, memory, and network usage to see how your infrastructure handles the load.</p>
<p>Here’s where external monitoring tools (like Grafana, Prometheus, or JVisualVM) can come in handy. Monitoring helps ensure that performance issues are caught at the system level, not just from the perspective of response times.</p>
<h4 id="heading-automating-performance-tests-in-cicd-pipelines">Automating Performance Tests in CI/CD Pipelines</h4>
<p>Performance testing shouldn’t be a one-off event. By integrating your Gatling tests into a CI/CD pipeline, you can run them automatically with every release. This way, performance regressions are caught early, before they hit production.</p>
<p>While we won’t go into detail here, many CI/CD tools (like Jenkins or GitLab CI) support running Gatling tests as part of your deployment process, ensuring that your app’s performance remains consistent over time.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We’ve covered the essentials of performance testing with Gatling for Java applications—from setting up the environment to writing and enhancing tests. Performance testing is a crucial step in delivering reliable, scalable applications that provide a smooth user experience under real-world conditions. Gatling’s Java DSL makes it easy for developers to integrate performance testing into their workflow without having to switch languages.</p>
<h3 id="heading-faqs">FAQs</h3>
<p><strong>Can Gatling test non-HTTP protocols?</strong></p>
<p>Yes, while Gatling is primarily used for HTTP, it also supports protocols like WebSockets, JMS, and even custom protocols with some extra configuration.</p>
<p><strong>How do I handle authentication in Gatling tests?</strong></p>
<p>Gatling can handle various types of authentication, including basic authentication, OAuth, and even cookies or tokens. For basic authentication, you can add credentials like this:</p>
<pre><code class="lang-java">httpProtocol.auth().basic(<span class="hljs-string">"username"</span>, <span class="hljs-string">"password"</span>);
</code></pre>
<p>For token-based authentication, you can include the token in the headers of your request.</p>
<p><strong>What’s the</strong> <a target="_blank" href="https://stackoverflow.com/questions/9750509/load-vs-stress-testing"><strong>difference between load and stress testing</strong></a><strong>?</strong></p>
<ul>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Software_performance_testing#Load_testing"><strong>Load Testing</strong></a> simulates the normal or expected number of users to see how the system performs under typical conditions.</p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Software_performance_testing#Stress_testing"><strong>Stress Testing</strong></a> pushes the system beyond its limits to find its breaking point. The goal is to see how the application behaves under extreme load and when it fails.</p>
</li>
</ul>
<h3 id="heading-resources">Resources</h3>
<p>For further reading and to deepen your understanding of performance testing with Gatling, check out the following resources:</p>
<ul>
<li><p><a target="_blank" href="https://gatling.io/docs/current/">Gatling Official Documentation</a>: The go-to guide for all things Gatling.</p>
</li>
<li><p><a target="_blank" href="https://github.com/gatling/gatling">Gatling GitHub Repository</a>: Explore the source code and community examples.</p>
</li>
<li><p><a target="_blank" href="https://gradle.org/">Gradle for Gatling</a>: Learn more about using Gradle to manage your Gatling tests.</p>
</li>
<li><p><a target="_blank" href="https://blog.seancoughlin.me/gradle-java-build-tools-tasks-dependencies-and-multi-project-builds">Gradle: Java Build Tools, Tasks, Dependencies, and Multi-Project Builds</a>: Learn what Gradle is and how to use it in your Java applications.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Using ChatGPT as a Study Partner]]></title><description><![CDATA[Personal Tutor
I recently stumbled upon a super effective way to prep for my AWS certification using ChatGPT, and I’m honestly excited to share it. Whether you're grinding through certification prep (like I am) or studying for any exam, this might ju...]]></description><link>https://blog.seancoughlin.me/using-chatgpt-as-a-study-partner</link><guid isPermaLink="true">https://blog.seancoughlin.me/using-chatgpt-as-a-study-partner</guid><category><![CDATA[Study ]]></category><category><![CDATA[learning]]></category><category><![CDATA[Learning Journey]]></category><category><![CDATA[chatgpt]]></category><category><![CDATA[AWS certification]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Thu, 03 Oct 2024 15:09:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727968017526/4029a79a-acd0-4d83-8113-1b2ed12e317e.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-personal-tutor">Personal Tutor</h2>
<p>I recently stumbled upon a super effective way to prep for my AWS certification using ChatGPT, and I’m honestly excited to share it. Whether you're grinding through certification prep (like I am) or studying for any exam, this might just be the secret weapon you didn’t know you needed.</p>
<p>Here’s what I’ve been doing with ChatGPT Plus (though this totally works on the free tier too!):</p>
<ol>
<li><p><strong>Instant Quizzes on the Fly</strong>: Whenever I want to test myself, I just ask ChatGPT to fire off some multiple-choice questions or quick quizzes. The best part? It feels like a custom quiz tailored exactly to what I need to focus on.</p>
</li>
<li><p><strong>Clear Explanations in Real-Time</strong>: Stuck on a tricky concept? ChatGPT breaks it down for me in simple terms and takes me through the logic step-by-step. No more Googling for hours hoping to find the right explanation.</p>
</li>
<li><p><strong>Creating Extra Practice Material</strong>: When I feel like I need more than just notes, I ask ChatGPT to whip up additional practice problems. I’ve even had it generate examples on AWS architecture for my Solutions Architect exam prep—it’s like having an endless source of study material.</p>
</li>
<li><p><strong>Voice Mode for a True Tutor Experience</strong>: Here’s the kicker—I’ve been using ChatGPT in voice mode. It’s like having a real conversation with a tutor, and it makes reviewing topics feel way more engaging. You can literally quiz yourself while going for a walk, no books required!</p>
</li>
</ol>
<h2 id="heading-quizzing-example">Quizzing Example</h2>
<p>Below is an example of how our interaction went—quizzing me on topics, providing feedback, and guiding me through key concepts.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">🧑‍💻</div>
<div data-node-type="callout-text">“So I have been studying for AWS certifications. It's been helpful for my work, and I was wondering if you could act as a tutor for me, maybe help quiz me, teach me, correct me when I'm wrong, that sort of thing.”</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">🤖</div>
<div data-node-type="callout-text">Absolutely, I'd be glad to help you with your AWS studies! Which certification are you focusing on, and are there specific topics or services you'd like to start with? We can go through questions, concepts, or any areas you want to focus on.</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">👨‍💻</div>
<div data-node-type="callout-text">“What are the largest topic areas on the test? Let's start there and then we can decide what we want to delve into.”</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">🤖</div>
<div data-node-type="callout-text">The AWS Solutions Architect exam covers a broad range of topics. The major areas include: 1. <strong>Design Resilient Architectures</strong>: This focuses on designing multi-tier architecture solutions, decoupling mechanisms using AWS services, and designing highly available and fault-tolerant architectures. 2. <strong>Design High-Performing Architectures</strong>: This area involves identifying elastic and scalable compute solutions, selecting high-performing and scalable storage solutions, and designing high-performing networking solutions. 3. <strong>Specify Secure Applications and Architectures</strong>: This includes securing application tiers, selecting appropriate data security options, and designing secure access to AWS resources. 4. <strong>Design Cost-Optimized Architectures</strong>: This focuses on identifying cost-effective storage, compute, and database services based on requirements, as well as designing optimizations for cost in architectures. Would you like to start with one of these areas, or is there another topic you're more interested in?</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">👨‍💻</div>
<div data-node-type="callout-text">“I think right now the most helpful thing for me would be to start with quizzing so I can get an understanding of where I'm at. So why don't you pick one of those topics, generate up a quiz question, ask me about it, and then we can go from there.”</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">🤖</div>
<div data-node-type="callout-text">Sounds like a plan! Let's start with "Design Resilient Architectures." Here's a question for you: <strong>Question</strong>: You're designing a multi-tier web application in AWS. The application needs to be highly available and fault-tolerant. Which combination of AWS services would you use to achieve this? Choose the best answer: A) Amazon EC2 with Auto Scaling, Amazon RDS with Multi-AZ deployments, and Elastic Load Balancing. B) Amazon EC2 with instance store, Amazon S3 for storage, and Amazon CloudFront for content delivery. C) Amazon RDS with Read Replicas, Amazon DynamoDB, and Amazon SNS for messaging. D) Amazon EC2 Spot Instances, Amazon Glacier for backups, and Amazon Elastic File System (EFS). What's your answer and reasoning?</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">👨‍💻</div>
<div data-node-type="callout-text">“OK, I would go with A. So EC2 will be your compute platform, since that's the infrastructure as a service. The autoscaling group will allow you to scale to whatever traffic needs the web application needs. On the back end, RDS will be your database and data store. Multi-AZ will allow you to be fault tolerant, since you're running on multiple availability zones. And I think that hits all of the requirements to the question.”</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">🤖</div>
<div data-node-type="callout-text">Excellent reasoning, and you're absolutely right! Option A is the best choice. Amazon EC2 with Auto Scaling ensures that you have the right number of instances to handle varying traffic, and Elastic Load Balancing distributes incoming traffic across those instances. Amazon RDS with Multi-AZ deployments provides high availability and failover support for…</div>
</div>

<p>With this kind of back-and-forth, ChatGPT has become an essential part of my study routine, making exam prep feel more interactive and engaging.</p>
<p>Whether you're studying for tech certifications, academic exams, or just expanding your skills, ChatGPT can be a flexible, interactive study partner. From quizzing yourself to getting clear explanations, it’s been incredibly helpful for my AWS exam prep. And the best part? You don’t need the paid version for most of these features—the free tier works just fine for these kinds of interactions.</p>
]]></content:encoded></item><item><title><![CDATA[Multithreading in Java and Spring Boot]]></title><description><![CDATA[Introduction
In today's world of high-performance applications, responsiveness, and scalability are critical. Whether you're building a web application, processing large datasets, or handling multiple tasks simultaneously, having a solid understandin...]]></description><link>https://blog.seancoughlin.me/multithreading-in-java-and-spring-boot</link><guid isPermaLink="true">https://blog.seancoughlin.me/multithreading-in-java-and-spring-boot</guid><category><![CDATA[Java]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Spring]]></category><category><![CDATA[Threads]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Wed, 02 Oct 2024 16:21:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727885248978/745b304a-46fb-4dce-a430-31dcefcf51ea.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In today's world of high-performance applications, responsiveness, and scalability are critical. Whether you're building a web application, processing large datasets, or handling multiple tasks simultaneously, having a solid understanding of <a target="_blank" href="https://en.wikipedia.org/wiki/Multithreading_\(computer_architecture\)">multithreading</a> can dramatically improve the efficiency and performance of your code.</p>
<p>Multithreading is a key tool in a developer's arsenal, and while Java has long supported multithreading, Spring Boot takes it further by simplifying asynchronous processing. In this guide, we’ll explore how to implement multithreading in Java and dive into Spring Boot's built-in features for managing concurrency, helping you streamline your application development.</p>
<h2 id="heading-what-is-multithreading">What is Multithreading?</h2>
<p>At its core, multithreading allows a program to run multiple parts of its code simultaneously. A <a target="_blank" href="https://en.wikipedia.org/wiki/Thread_\(computing\)"><strong>thread</strong> is the smallest unit of a process</a>, and multithreading involves running multiple threads at the same time, enabling the parallel execution of tasks. This can lead to better performance and responsiveness, especially in resource-intensive applications or those that need to handle many simultaneous operations.</p>
<p><strong>Benefits of Multithreading:</strong></p>
<ul>
<li><p><strong>Improved Performance</strong>: By dividing a task across multiple threads, work can be done faster than running it in a single thread.</p>
</li>
<li><p><strong>Enhanced Responsiveness</strong>: Applications, especially GUIs or web servers, can remain responsive while handling long-running operations in the background.</p>
</li>
<li><p><strong>Better Utilization of Resources</strong>: Modern CPUs have multiple cores, and multithreading ensures that they are all used efficiently.</p>
</li>
</ul>
<p>However, multithreading is not without its challenges. Threads need to coordinate when accessing shared resources, and improper handling can lead to issues like deadlocks or race conditions. That’s why understanding the underlying mechanisms and using the right tools is essential for successful multithreaded programming.</p>
<h2 id="heading-overview-of-multithreading-in-java">Overview of Multithreading in Java</h2>
<p>Java has been built with multithreading at its core, and it provides multiple ways to create and manage threads. Whether you're handling simple tasks or complex concurrent operations, Java offers flexibility through various APIs. In this section, we'll cover some of the most common methods for implementing multithreading in Java.</p>
<h3 id="heading-1-creating-threads-in-java">1. Creating Threads in Java</h3>
<p>There are two primary ways to create threads in Java: <a target="_blank" href="https://www.geeksforgeeks.org/multithreading-in-java/">by extending the <code>Thread</code> class</a> or by implementing the <code>Runnable</code> interface.</p>
<p><strong>1.1 Extending the</strong> <code>Thread</code> Class</p>
<p>One of the simplest ways to create a thread is to extend the <code>Thread</code> class and override its <code>run()</code> method, which defines the code that the thread will execute.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyThread</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Thread</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// Code to be executed in the new thread</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++) {
            System.out.println(<span class="hljs-string">"Thread "</span> + Thread.currentThread().getId() + <span class="hljs-string">": "</span> + i);
        }
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        MyThread thread1 = <span class="hljs-keyword">new</span> MyThread();
        MyThread thread2 = <span class="hljs-keyword">new</span> MyThread();
        thread1.start(); <span class="hljs-comment">// Starts a new thread</span>
        thread2.start(); <span class="hljs-comment">// Starts another thread</span>
    }
}
</code></pre>
<p>In this example, two threads (<code>thread1</code> and <code>thread2</code>) are created, and both execute the code inside the <code>run()</code> method concurrently. The <code>start()</code> method is used to begin execution in a new thread.</p>
<p><strong>1.2 Implementing the</strong> <code>Runnable</code> Interface</p>
<p>Another more flexible way to create a thread is by implementing the <a target="_blank" href="https://docs.oracle.com/javase/8/docs/api/?java/lang/Runnable.html"><code>Runnable</code> interface</a>. This allows your class to extend other classes while still being used in a thread. You pass the <code>Runnable</code> object to a <code>Thread</code> object, which runs the code in the <code>run()</code> method.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyRunnable</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Runnable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// Code to be executed in the new thread</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++) {
            System.out.println(<span class="hljs-string">"Thread "</span> + Thread.currentThread().getId() + <span class="hljs-string">": "</span> + i);
        }
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        Thread thread1 = <span class="hljs-keyword">new</span> Thread(<span class="hljs-keyword">new</span> MyRunnable());
        Thread thread2 = <span class="hljs-keyword">new</span> Thread(<span class="hljs-keyword">new</span> MyRunnable());
        thread1.start(); <span class="hljs-comment">// Starts a new thread</span>
        thread2.start(); <span class="hljs-comment">// Starts another thread</span>
    }
}
</code></pre>
<p>By using <code>Runnable</code>, we decouple the thread behavior from the actual thread creation, making the code more modular and flexible.</p>
<p><strong>1.3 Using Lambda Expressions (Java 8+)</strong></p>
<p><a target="_blank" href="https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html">With the introduction of Java 8</a>, <a target="_blank" href="https://stackoverflow.com/questions/66611118/what-is-best-way-of-implementing-multithreading-in-java">you can use lambda expressions</a> to simplify the implementation of the <code>Runnable</code> interface. This results in more concise and readable code.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        Runnable task = () -&gt; {
            <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++) {
                System.out.println(<span class="hljs-string">"Thread "</span> + Thread.currentThread().getId() + <span class="hljs-string">": "</span> + i);
            }
        };

        Thread thread1 = <span class="hljs-keyword">new</span> Thread(task);
        Thread thread2 = <span class="hljs-keyword">new</span> Thread(task);
        thread1.start();
        thread2.start();
    }
}
</code></pre>
<p>This approach significantly reduces the amount of boilerplate code, making multithreading easier and faster to implement.</p>
<h3 id="heading-2-managing-threads-with-executorservice"><strong>2. Managing Threads with ExecutorService</strong></h3>
<p>When working with multiple threads, manually managing thread creation can become cumbersome. Java provides the <a target="_blank" href="https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/ExecutorService.html"><code>ExecutorService</code> interface</a>, which offers a flexible and efficient way to manage thread pools.</p>
<p><a target="_blank" href="https://www.baeldung.com/java-executor-service-tutorial"><strong>ExecutorService</strong> manages a pool of threads</a> that can be reused to execute multiple tasks, instead of creating a new thread for each task. This reduces the overhead of thread creation and improves performance.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.util.concurrent.ExecutorService;
<span class="hljs-keyword">import</span> java.util.concurrent.Executors;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExecutorExample</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        <span class="hljs-comment">// Create a thread pool with 2 threads</span>
        ExecutorService executor = Executors.newFixedThreadPool(<span class="hljs-number">2</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++) {
            executor.submit(() -&gt; {
                System.out.println(<span class="hljs-string">"Thread "</span> + Thread.currentThread().getId() + <span class="hljs-string">" is running"</span>);
            });
        }

        <span class="hljs-comment">// Shutdown the executor service</span>
        executor.shutdown();
    }
}
</code></pre>
<p>In this example, an <code>ExecutorService</code> is created with a fixed pool of 2 threads. The <code>submit()</code> method is used to assign tasks to the thread pool, and the executor manages the thread lifecycle for you. Once all tasks are completed, the <code>shutdown()</code> method is called to stop the executor.</p>
<h3 id="heading-3-synchronization-and-thread-safety"><strong>3. Synchronization and Thread Safety</strong></h3>
<p>Multithreading introduces the need for synchronization when multiple threads access shared resources. Without proper synchronization, data corruption or inconsistent states can occur. Java provides the <a target="_blank" href="https://stackoverflow.com/questions/1085709/what-does-synchronized-mean"><code>synchronized</code> keyword</a> to ensure that only one thread at a time can access critical sections of code.</p>
<p><strong>Example of Synchronization:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> count = <span class="hljs-number">0</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">increment</span><span class="hljs-params">()</span> </span>{
        count++;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getCount</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> count;
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> InterruptedException </span>{
        Counter counter = <span class="hljs-keyword">new</span> Counter();

        Thread thread1 = <span class="hljs-keyword">new</span> Thread(() -&gt; {
            <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">1000</span>; i++) {
                counter.increment();
            }
        });

        Thread thread2 = <span class="hljs-keyword">new</span> Thread(() -&gt; {
            <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">1000</span>; i++) {
                counter.increment();
            }
        });

        thread1.start();
        thread2.start();

        thread1.join(); <span class="hljs-comment">// Wait for thread1 to finish</span>
        thread2.join(); <span class="hljs-comment">// Wait for thread2 to finish</span>

        System.out.println(<span class="hljs-string">"Final count: "</span> + counter.getCount());
    }
}
</code></pre>
<p>In this example, the <code>increment()</code> method is synchronized to ensure that only one thread can modify the <code>count</code> variable at a time, preventing race conditions.</p>
<h2 id="heading-multithreading-in-spring-and-spring-boot">Multithreading in Spring and Spring Boot</h2>
<p>Spring Framework provides powerful tools for handling multithreading and asynchronous tasks. By abstracting much of the complexity around thread management, Spring simplifies the process of running tasks concurrently and provides <a target="_blank" href="https://spring.io/guides/gs/async-method">built-in mechanisms to handle asynchronous</a> operations with minimal boilerplate.</p>
<h3 id="heading-1-introduction-to-springs-asynchronous-features">1. Introduction to Spring's Asynchronous Features</h3>
<p>Spring allows you to create and manage asynchronous tasks with a variety of abstractions. The most common approach is using the <code>@Async</code> annotation, but Spring also provides support for more complex scenarios, such as scheduled tasks, task executors, and even reactive programming for non-blocking I/O.</p>
<p>Spring Boot, in particular, makes it easy to configure and use these features without needing complex setup. Let's dive into how to implement multithreading using Spring Boot.</p>
<h3 id="heading-2-implementing-asynchronous-methods-with-async">2. Implementing Asynchronous Methods with <code>@Async</code></h3>
<p>Spring's <a target="_blank" href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Async.html"><code>@Async</code> annotation</a> is a simple yet powerful way to run methods asynchronously. When applied to a method, it allows the method to execute in a separate thread, freeing up the main thread to continue executing other tasks. This is particularly useful for long-running operations that you don't want to block the main flow of your application.</p>
<p><strong>Enabling Asynchronous Execution:</strong> To use the <code>@Async</code> annotation, you must first <a target="_blank" href="https://www.baeldung.com/spring-async">enable async support in your Spring Boot application by adding the <code>@EnableAsync</code> annotation to a configuration class</a>.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-keyword">import</span> org.springframework.scheduling.annotation.EnableAsync;

<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@EnableAsync</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AsyncConfig</span> </span>{
}
</code></pre>
<p>Once you've enabled asynchronous support, you can apply the <code>@Async</code> annotation to any method in a Spring-managed bean.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.scheduling.annotation.Async;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;
<span class="hljs-keyword">import</span> java.util.concurrent.CompletableFuture;

<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AsyncService</span> </span>{

    <span class="hljs-meta">@Async</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> CompletableFuture&lt;String&gt; <span class="hljs-title">performAsyncTask</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">try</span> {
            <span class="hljs-comment">// Simulate a long-running task</span>
            Thread.sleep(<span class="hljs-number">1000</span>);
        } <span class="hljs-keyword">catch</span> (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        <span class="hljs-keyword">return</span> CompletableFuture.completedFuture(<span class="hljs-string">"Task completed"</span>);
    }
}
</code></pre>
<p>In the example above, the <code>performAsyncTask()</code> method is marked with <code>@Async</code>, meaning that when this method is called, Spring will automatically execute it in a separate thread from the thread pool, allowing the main thread to continue without waiting for the task to complete.</p>
<h3 id="heading-3-customizing-async-behavior-with-threadpooltaskexecutor">3. Customizing Async Behavior with <code>ThreadPoolTaskExecutor</code></h3>
<p>By default, Spring Boot uses a simple thread pool when executing asynchronous tasks. However, in a production environment, you may want to customize the thread pool to suit your application's needs. <a target="_blank" href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.html">Spring Boot provides the <code>ThreadPoolTaskExecutor</code></a> for this purpose, which allows you to configure thread pool parameters such as core pool size, max pool size, and queue capacity.</p>
<p><strong>Example: Custom Thread Pool Configuration</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-keyword">import</span> org.springframework.core.task.TaskExecutor;
<span class="hljs-keyword">import</span> org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
<span class="hljs-keyword">import</span> org.springframework.scheduling.annotation.EnableAsync;

<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@EnableAsync</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AsyncConfig</span> </span>{

    <span class="hljs-meta">@Bean(name = "taskExecutor")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> TaskExecutor <span class="hljs-title">taskExecutor</span><span class="hljs-params">()</span> </span>{
        ThreadPoolTaskExecutor executor = <span class="hljs-keyword">new</span> ThreadPoolTaskExecutor();
        executor.setCorePoolSize(<span class="hljs-number">2</span>);
        executor.setMaxPoolSize(<span class="hljs-number">5</span>);
        executor.setQueueCapacity(<span class="hljs-number">500</span>);
        executor.setThreadNamePrefix(<span class="hljs-string">"MyExecutor-"</span>);
        executor.initialize();
        <span class="hljs-keyword">return</span> executor;
    }
}
</code></pre>
<p>In this example, the <code>ThreadPoolTaskExecutor</code> is configured with:</p>
<ul>
<li><p><strong>Core pool size</strong>: Minimum number of threads that will always be available.</p>
</li>
<li><p><strong>Max pool size</strong>: Maximum number of threads that can be created.</p>
</li>
<li><p><strong>Queue capacity</strong>: How many tasks can be queued before new threads are created.</p>
</li>
<li><p><strong>Thread name prefix</strong>: Custom naming pattern for threads in this executor.</p>
</li>
</ul>
<p>To use this custom thread pool, the method annotated with <code>@Async</code> will automatically utilize the <code>taskExecutor</code> defined in the configuration.</p>
<p>Here’s a quick table summarizing good choices for <code>TaskExecutor</code> configuration parameters based on different use cases:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Use Case</strong></td><td><strong>Core Pool Size</strong></td><td><strong>Max Pool Size</strong></td><td><strong>Queue Capacity</strong></td><td><strong>Description</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Short, Non-blocking Tasks (e.g., logging, simple notifications)</strong></td><td>2</td><td>5</td><td>50</td><td>Small pool size is sufficient since tasks are short-lived and non-blocking. A moderate queue allows efficient task handling without overloading the system.</td></tr>
<tr>
<td><strong>I/O Bound Tasks (e.g., file reading, database queries)</strong></td><td>4</td><td>10</td><td>100</td><td>For I/O-bound tasks, increase pool size to handle more tasks concurrently. A larger queue ensures tasks can be queued efficiently during I/O waits.</td></tr>
<tr>
<td><strong>CPU-Intensive Tasks (e.g., complex calculations, image processing)</strong></td><td># of CPU cores</td><td># of CPU cores</td><td>0 or very small (1-10)</td><td>Set core pool size and max pool size to the number of CPU cores, ensuring optimal CPU utilization. Avoid large queues to prevent task delays and bottlenecks.</td></tr>
<tr>
<td><strong>Long-running Blocking Tasks (e.g., external API calls, large data processing)</strong></td><td>5</td><td>20</td><td>200</td><td>Higher pool and queue sizes help handle blocking tasks efficiently, ensuring the system can handle spikes in tasks without being overwhelmed.</td></tr>
<tr>
<td><strong>High Concurrency (e.g., web applications handling thousands of requests)</strong></td><td>10</td><td>50</td><td>500+</td><td>In high-concurrency environments, a larger pool and queue size ensure that the system can handle many requests concurrently without running out of resources.</td></tr>
</tbody>
</table>
</div><p><strong>General Guidelines:</strong></p>
<ul>
<li><p><strong>Core Pool Size</strong>: The number of threads that are always available (even if idle). A good default is equal to the number of CPU cores for CPU-bound tasks.</p>
</li>
<li><p><strong>Max Pool Size</strong>: The maximum number of threads the pool can create. Increase this if tasks are often blocked or waiting on external resources.</p>
</li>
<li><p><strong>Queue Capacity</strong>: The number of tasks that can be queued before new threads are created. For short tasks, a larger queue is efficient. For long tasks, consider a smaller queue to avoid long delays.</p>
</li>
</ul>
<h3 id="heading-4-scheduling-tasks-with-scheduled">4. Scheduling Tasks with <code>@Scheduled</code></h3>
<p>Another powerful feature in Spring Boot is the ability to schedule tasks to run at specific intervals or times using the <a target="_blank" href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html"><code>@Scheduled</code> annotation</a>. This is useful for running background jobs, such as database cleanup, report generation, or sending periodic notifications.</p>
<p><strong>Enabling Scheduling:</strong> To use the <code>@Scheduled</code> annotation, you must enable scheduling by adding <code>@EnableScheduling</code> to a configuration class.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-keyword">import</span> org.springframework.scheduling.annotation.EnableScheduling;

<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@EnableScheduling</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SchedulerConfig</span> </span>{
}
</code></pre>
<p>Now, you can create methods that are scheduled to run at fixed intervals, using cron expressions, or after a specific delay.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.scheduling.annotation.Scheduled;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Component;

<span class="hljs-meta">@Component</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ScheduledTask</span> </span>{

    <span class="hljs-meta">@Scheduled(fixedRate = 5000)</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">performTask</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Task executed every 5 seconds"</span>);
    }

    <span class="hljs-meta">@Scheduled(cron = "0 0 12 * * ?")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">performTaskAtNoon</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Task executed at 12 PM every day"</span>);
    }
}
</code></pre>
<p>In this example, the <code>performTask()</code> method runs every 5 seconds, while <code>performTaskAtNoon()</code> runs every day at 12 PM. Spring handles the scheduling internally, ensuring that the tasks are executed on time without blocking the main application thread.</p>
<h3 id="heading-5-taskexecutor-for-higher-level-abstraction">5. TaskExecutor for Higher-Level Abstraction</h3>
<p><a target="_blank" href="https://docs.spring.io/spring-framework/reference/integration/scheduling.html">Spring provides the <code>TaskExecutor</code> interface as a higher-level abstraction for managing asynchronous tasks</a>. This allows you to execute <code>Runnable</code> tasks without dealing with the lower-level details of thread management.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.core.task.TaskExecutor;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaskExecutorService</span> </span>{

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> TaskExecutor taskExecutor;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">executeAsyncTask</span><span class="hljs-params">()</span> </span>{
        taskExecutor.execute(() -&gt; {
            System.out.println(<span class="hljs-string">"Task executed asynchronously using TaskExecutor"</span>);
        });
    }
}
</code></pre>
<p>Here, the <code>TaskExecutor</code> interface is injected, and the <code>executeAsyncTask()</code> method uses it to execute a task asynchronously. This provides a simple and clean way to run background tasks without needing to create new threads manually.</p>
<h3 id="heading-6-reactive-programming-with-webflux">6. Reactive Programming with WebFlux</h3>
<p>For more advanced use cases, Spring Boot also supports <a target="_blank" href="https://docs.spring.io/spring-framework/reference/web/webflux.html"><strong>reactive programming</strong> with <strong>Spring WebFlux</strong></a>. This is particularly useful for non-blocking, event-driven applications that need to handle a large number of concurrent requests without consuming excessive system resources.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.GetMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RestController;
<span class="hljs-keyword">import</span> reactor.core.publisher.Flux;
<span class="hljs-keyword">import</span> java.time.Duration;

<span class="hljs-meta">@RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ReactiveController</span> </span>{

    <span class="hljs-meta">@GetMapping("/reactive")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Flux&lt;String&gt; <span class="hljs-title">getReactiveStream</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> Flux.just(<span class="hljs-string">"Message 1"</span>, <span class="hljs-string">"Message 2"</span>, <span class="hljs-string">"Message 3"</span>)
                   .delayElements(Duration.ofSeconds(<span class="hljs-number">1</span>));
    }
}
</code></pre>
<p>In this example, a <code>Flux</code> (a reactive stream) is returned, which emits a series of messages with a delay of 1 second between each. This non-blocking model ensures that the server can handle other requests while the stream is being processed.</p>
<h2 id="heading-thread-safety-in-spring-boot">Thread Safety in Spring Boot</h2>
<p>When dealing with multithreading in Spring Boot, thread safety is a critical consideration, especially since Spring beans are typically singleton by default. This means that multiple threads could access the same instance of a bean simultaneously, potentially leading to data corruption or inconsistent states if shared resources are not handled correctly.</p>
<h4 id="heading-common-thread-safety-issues"><strong>Common Thread Safety Issues:</strong></h4>
<ol>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Race_condition"><strong>Race Conditions</strong></a>: Occurs when two or more threads access shared data and try to change it at the same time.</p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Deadlock_\(computer_science\)"><strong>Deadlocks</strong></a>: Happen when two or more threads are blocked forever, waiting for each other to release resources.</p>
</li>
<li><p><strong>Memory Consistency Errors</strong>: Result when multiple threads access shared variables without proper synchronization.</p>
</li>
</ol>
<h4 id="heading-handling-thread-safety-in-spring-boot"><strong>Handling Thread Safety in Spring Boot:</strong></h4>
<ol>
<li><p><strong>Use of</strong> <code>synchronized</code> Keyword: You can synchronize methods or code blocks to ensure that only one thread can execute them at a time, preventing race conditions.</p>
<p> <strong>Example:</strong></p>
<pre><code class="lang-java"> <span class="hljs-meta">@Service</span>
 <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterService</span> </span>{
     <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> count = <span class="hljs-number">0</span>;

     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">increment</span><span class="hljs-params">()</span> </span>{
         count++;
     }

     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getCount</span><span class="hljs-params">()</span> </span>{
         <span class="hljs-keyword">return</span> count;
     }
 }
</code></pre>
<p> In this example, both <code>increment()</code> and <code>getCount()</code> are synchronized to ensure that the counter is safely updated and retrieved, preventing multiple threads from corrupting the shared variable.</p>
</li>
<li><p><strong>Atomic Variables</strong>: For lightweight thread-safe operations, you can use Java's <code>Atomic</code> classes (e.g., <code>AtomicInteger</code>, <code>AtomicBoolean</code>), which <a target="_blank" href="https://stackoverflow.com/questions/16729364/atomic-operations-and-multithreading">provide methods for thread-safe manipulation of variables without the overhead of synchronization</a>.</p>
<p> <strong>Example:</strong></p>
<pre><code class="lang-java"> <span class="hljs-keyword">import</span> java.util.concurrent.atomic.AtomicInteger;

 <span class="hljs-meta">@Service</span>
 <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AtomicCounterService</span> </span>{
     <span class="hljs-keyword">private</span> AtomicInteger count = <span class="hljs-keyword">new</span> AtomicInteger(<span class="hljs-number">0</span>);

     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">increment</span><span class="hljs-params">()</span> </span>{
         count.incrementAndGet();
     }

     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getCount</span><span class="hljs-params">()</span> </span>{
         <span class="hljs-keyword">return</span> count.get();
     }
 }
</code></pre>
</li>
<li><p><strong>ThreadLocal Variables</strong>: <a target="_blank" href="https://www.baeldung.com/java-threadlocal"><code>ThreadLocal</code> variables</a> allow you to store data that is specific to the current thread, ensuring that each thread has its own copy of the variable. This is useful for managing thread-specific data like request contexts.</p>
<p> <strong>Example:</strong></p>
<pre><code class="lang-java"> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserContext</span> </span>{
     <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> ThreadLocal&lt;String&gt; userContext = <span class="hljs-keyword">new</span> ThreadLocal&lt;&gt;();

     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setUser</span><span class="hljs-params">(String user)</span> </span>{
         userContext.set(user);
     }

     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">getUser</span><span class="hljs-params">()</span> </span>{
         <span class="hljs-keyword">return</span> userContext.get();
     }

     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">clear</span><span class="hljs-params">()</span> </span>{
         userContext.remove();
     }
 }
</code></pre>
</li>
</ol>
<p>By carefully managing shared resources and considering thread safety in your Spring Boot applications, you can avoid common pitfalls like race conditions and data inconsistency.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Multithreading is an essential tool for building high-performance, responsive applications, both in Java and Spring Boot. Starting with core Java concepts like extending <code>Thread</code>, implementing <code>Runnable</code>, and using <code>ExecutorService</code>, you can efficiently handle concurrent tasks. Spring Boot makes multithreading even easier by abstracting much of the complexity, offering tools like the <code>@Async</code> annotation, custom thread pools via <code>ThreadPoolTaskExecutor</code>, and scheduling tasks with <code>@Scheduled</code>.</p>
<p>Whether you're managing simple asynchronous tasks or building large, scalable systems that need to handle thousands of concurrent requests, the right use of multithreading can significantly improve your application's performance and scalability. Understanding thread safety and using the appropriate tools (such as synchronization, atomic variables, or <code>ThreadLocal</code>) ensures that your application functions reliably under concurrent loads.</p>
<p>With the knowledge gained from this guide, you're well-equipped to implement multithreading in your Java and Spring Boot applications efficiently and safely.</p>
<h3 id="heading-further-reading">Further Reading</h3>
<ul>
<li><p><a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/concurrency/index.html">Java Concurrency</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Java_memory_model">Java Memory Model</a></p>
</li>
<li><p><a target="_blank" href="https://blog.seancoughlin.me/understanding-concurrency-vs-parallelization">Understanding Concurrency vs. Parallelization</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Understanding Concurrency vs. Parallelization]]></title><description><![CDATA[Introduction
Imagine you're in a busy kitchen during dinner rush hour. As the head chef, you're managing multiple dishes at once—checking the oven, chopping vegetables, and stirring a sauce. You aren't doing these tasks simultaneously, but you're swi...]]></description><link>https://blog.seancoughlin.me/understanding-concurrency-vs-parallelization</link><guid isPermaLink="true">https://blog.seancoughlin.me/understanding-concurrency-vs-parallelization</guid><category><![CDATA[concurrency]]></category><category><![CDATA[Parallel Programming]]></category><category><![CDATA[parallelism]]></category><category><![CDATA[Computer Science]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Tue, 01 Oct 2024 19:57:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727811010986/619a0dd6-8d99-40ba-835a-89397d4b2b36.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Imagine you're in a busy kitchen during dinner rush hour. As the head chef, you're managing multiple dishes at once—checking the oven, chopping vegetables, and stirring a sauce. You aren't doing these tasks simultaneously, but you're switching between them quickly to keep everything moving. This is <strong>concurrency</strong>—handling many tasks by switching between them, making sure nothing burns while you're multitasking.</p>
<p>Now picture that same kitchen, but this time you're not alone. You have a team of chefs, each working on a different dish at the same time. One chef chops the vegetables, another stirs the sauce, and someone else checks the oven. Together, you're speeding up the entire process by working simultaneously. This is <strong>parallelization</strong>—dividing tasks across multiple workers to get things done faster.</p>
<p>In software development, <a target="_blank" href="https://www.merriam-webster.com/dictionary/concurrency">concurrency</a> and <a target="_blank" href="https://www.merriam-webster.com/dictionary/parallel">parallelization</a> are two key concepts that define how tasks are handled and executed. Both are vital to improving efficiency and performance, but they work in different ways. Whether you're writing code for a responsive web server or speeding up computations in scientific applications, understanding the differences between these two approaches can help you optimize your projects.</p>
<h2 id="heading-defining-the-concepts">Defining the Concepts</h2>
<h3 id="heading-what-is-concurrency">What is Concurrency?</h3>
<p>Concurrency is about managing multiple tasks at the same time but not necessarily executing them simultaneously. Think of it as time-sharing or task-switching—each task gets a slice of time to make progress, and the system switches between them efficiently. The main goal of concurrency is to ensure that a system can handle multiple operations without slowing down, maintaining responsiveness even when handling many tasks.</p>
<ul>
<li><p><strong>Key characteristics of concurrency</strong>:</p>
<ul>
<li><p><strong>Task interleaving</strong>: Tasks appear to run in parallel, but they’re actually being processed one after another in short bursts.</p>
</li>
<li><p><strong>Responsiveness</strong>: Concurrency helps systems remain responsive to new inputs, even when they’re already busy with other tasks.</p>
</li>
<li><p><strong>Single or multiple cores</strong>: Concurrency can work on a single processor core by switching between tasks, but it can also leverage multiple cores to improve efficiency.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-what-is-parallelization">What is Parallelization?</h3>
<p>Parallelization, on the other hand, involves breaking down a task into smaller parts that can be executed simultaneously on multiple processors or cores. The primary goal of parallelization is to increase speed and performance by doing more in less time. This approach is common in tasks that require heavy computation, such as processing large datasets, rendering graphics, or training machine learning models.</p>
<ul>
<li><p><strong>Key characteristics of parallelization</strong>:</p>
<ul>
<li><p><strong>Simultaneous execution</strong>: Tasks are divided and executed at the same time, utilizing multiple cores or processors.</p>
</li>
<li><p><strong>Performance boost</strong>: Parallelization is used to reduce execution time by distributing the workload across multiple workers.</p>
</li>
<li><p><strong>Requires multiple cores</strong>: Unlike concurrency, parallelization requires more than one core or processor to truly execute tasks simultaneously.</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-core-differences-between-concurrency-and-parallelization">Core Differences Between Concurrency and Parallelization</h2>
<p>While concurrency and parallelization are often discussed together, they operate in fundamentally different ways. Here's a side-by-side comparison of their key characteristics:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Aspect</strong></td><td><strong>Concurrency</strong></td><td><strong>Parallelization</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Execution Model</strong></td><td>Task switching and interleaving, not simultaneous</td><td>Simultaneous execution of multiple tasks across multiple processors/cores</td></tr>
<tr>
<td><strong>Objective</strong></td><td>Efficient task management and maintaining responsiveness</td><td>Speeding up execution by performing tasks at the same time</td></tr>
<tr>
<td><strong>Resource Utilization</strong></td><td>Can operate on a single core or processor</td><td>Requires multiple cores or processors</td></tr>
<tr>
<td><strong>Speedup Potential</strong></td><td>May not always result in faster execution, focuses on responsiveness</td><td>Designed to reduce execution time and improve performance</td></tr>
<tr>
<td><strong>Use Case Focus</strong></td><td>Ideal for handling many tasks without requiring simultaneous execution</td><td>Best for heavy computation tasks needing faster completion times</td></tr>
</tbody>
</table>
</div><h2 id="heading-real-world-use-cases">Real-World Use Cases</h2>
<p>Concurrency and parallelization are applied in different scenarios depending on the goals of the system—whether it’s managing multiple tasks or speeding up performance. Here are some practical examples of both in action:</p>
<h3 id="heading-concurrency-use-cases">Concurrency Use Cases:</h3>
<ul>
<li><p><strong>Web Servers</strong>: Modern web servers handle multiple client requests concurrently. Even if a single server has only one core, it can still manage thousands of connections by quickly switching between them, ensuring no request is left unattended.</p>
</li>
<li><p><strong>User Interface (UI) Applications</strong>: In apps like video editors or web browsers, concurrency ensures the interface remains responsive. While a file is being loaded or an image is being processed in the background, the user can still scroll, click, and interact with the UI.</p>
</li>
<li><p><strong>Operating Systems</strong>: Operating systems manage multiple processes at the same time, allocating CPU time to each one in quick bursts. This makes it possible to run multiple applications simultaneously without noticeable slowdowns.</p>
</li>
</ul>
<h3 id="heading-parallelization-use-cases">Parallelization Use Cases:</h3>
<ul>
<li><p><strong>Scientific Computing</strong>: Tasks like weather forecasting, protein folding simulations, or astrophysics modeling involve enormous amounts of data. Parallelization divides these computations across multiple cores or machines, drastically speeding up the time required to get results.</p>
</li>
<li><p><strong>Video and Image Processing</strong>: Rendering a 3D scene or encoding large videos can be computationally intensive. Parallelization allows different parts of the rendering or encoding process to be handled at the same time, shortening the time required for the task.</p>
</li>
<li><p><strong>Machine Learning</strong>: Training deep learning models on massive datasets can take days or even weeks. Parallelizing the computation across GPUs or clusters of machines reduces training time by processing multiple parts of the dataset simultaneously.</p>
</li>
</ul>
<h3 id="heading-hybrid-use-cases">Hybrid Use Cases:</h3>
<ul>
<li><strong>Database Systems</strong>: Databases use concurrency to handle multiple queries at once, ensuring responsiveness, but they also parallelize large, complex queries to speed up the data retrieval and processing.</li>
</ul>
<h2 id="heading-mnemonics-to-remember-the-differences">Mnemonics to Remember the Differences</h2>
<p>To make the concepts of concurrency and parallelization easier to remember, here are some clever mnemonics:</p>
<ul>
<li><p><strong>Concurrency: "One Chef, Many Dishes"</strong></p>
<ul>
<li>Imagine a single chef managing several dishes. They chop vegetables, stir a sauce, and check the oven, but they only work on one task at a time, constantly switching between them to keep everything on track. This is concurrency—managing multiple tasks by switching between them efficiently, without doing them all at once.</li>
</ul>
</li>
<li><p><strong>Parallelization: "A Team of Chefs"</strong></p>
<ul>
<li>Now, imagine a kitchen with multiple chefs. Each chef is working on a different dish simultaneously—one chops vegetables, another stirs the sauce, and someone else handles the oven. This is parallelization—dividing the work across multiple workers (or processors) so tasks get done at the same time, speeding up the entire process.</li>
</ul>
</li>
</ul>
<p>These mnemonics should help you remember that <strong>concurrency</strong> is about juggling tasks, while <strong>parallelization</strong> is about doing tasks simultaneously.</p>
<h2 id="heading-visualizations-of-concurrency-and-parallelization">Visualizations of Concurrency and Parallelization</h2>
<h3 id="heading-concurrency-on-a-single-core-cpu">Concurrency on a Single-Core CPU</h3>
<pre><code class="lang-plaintext">Time
 │
 v
 ___        ___        ___        ___  
|th1| ---&gt; |th2| ---&gt; |th3| ---&gt; |th4| ---&gt; (Single-core CPU switching between threads)
|   |      |   |      |   |      |   |
|___|      |___|      |___|      |___|
</code></pre>
<ul>
<li><strong>Explanation</strong>: In concurrency, a single-core CPU manages multiple tasks (threads), but only one task is running at any given moment. It switches between tasks rapidly, making progress on all tasks, but never executing them at the same time.</li>
</ul>
<h3 id="heading-parallelization-on-a-multi-core-cpu">Parallelization on a Multi-Core CPU</h3>
<pre><code class="lang-plaintext">    Time
    │
    v
  ___ ___    ___ ___    ___ ___    ___ ___  
 |th1|th2|  |th3|th4|  |th5|th6|  |th7|th8| ---&gt; (Multi-core CPU executing threads in parallel)
 |   |   |  |   |   |  |   |   |  |   |   |
 |___|___|  |___|___|  |___|___|  |___|___|
</code></pre>
<ul>
<li><strong>Explanation</strong>: In parallelization, multiple cores execute different tasks at the same time. Each thread (task) runs on its own core, allowing the system to perform multiple operations simultaneously, thus improving performance and reducing execution time.</li>
</ul>
<p>You’re welcome! Let's complete the rest of the article, keeping the quality and clarity high. Here’s the final portion:</p>
<h2 id="heading-practical-implications-for-developers">Practical Implications for Developers</h2>
<p>Understanding when to apply concurrency versus parallelization can help developers build more efficient and responsive applications. Here are some guidelines on when and how to use these techniques:</p>
<h4 id="heading-when-to-use-concurrency"><strong>When to Use Concurrency</strong>:</h4>
<ul>
<li><p><strong>Responsive Applications</strong>: If you’re building a web server or a user interface that must handle multiple tasks or requests simultaneously, concurrency helps manage those tasks efficiently without overwhelming the system.</p>
</li>
<li><p><strong>I/O Bound Tasks</strong>: For tasks that spend a lot of time waiting on external resources (e.g., network requests, file reading), concurrency is beneficial. Instead of idly waiting for one task to finish, the system can switch to another task, improving overall responsiveness.</p>
</li>
</ul>
<h4 id="heading-when-to-use-parallelization"><strong>When to Use Parallelization</strong>:</h4>
<ul>
<li><p><strong>Performance-Intensive Applications</strong>: If your application requires a lot of computation—such as processing large datasets, performing heavy calculations, or rendering graphics—parallelization will improve performance by splitting the workload across multiple cores or processors.</p>
</li>
<li><p><strong>CPU Bound Tasks</strong>: When tasks are constrained by the CPU’s processing power (e.g., machine learning model training, simulations), parallelization will help by utilizing the full capacity of the hardware.</p>
</li>
</ul>
<h4 id="heading-best-practices"><strong>Best Practices</strong>:</h4>
<ul>
<li><p><strong>Concurrency</strong>: Make use of asynchronous programming models (like async/await) to handle I/O-bound tasks. Ensure that you manage resources (such as threads or file handles) efficiently to avoid bottlenecks.</p>
</li>
<li><p><strong>Parallelization</strong>: Use tools like <strong>OpenMP</strong> for parallel processing in C/C++ or <a target="_blank" href="https://joblib.readthedocs.io/en/stable/"><strong>joblib</strong></a> and <strong>multiprocessing</strong> in Python to take advantage of multi-core systems. Be mindful of synchronization to avoid race conditions.</p>
</li>
</ul>
<h2 id="heading-common-pitfalls-and-challenges">Common Pitfalls and Challenges</h2>
<p>Both concurrency and parallelization come with their own set of challenges. Understanding these pitfalls can help you avoid performance bottlenecks and bugs in your applications.</p>
<h4 id="heading-concurrency-challenges"><strong>Concurrency Challenges</strong>:</h4>
<ul>
<li><p><strong>Race Conditions</strong>: When two or more tasks access shared resources simultaneously, without proper synchronization, it can lead to inconsistent results.</p>
</li>
<li><p><strong>Deadlocks</strong>: Occurs when two tasks are waiting for each other to release resources, causing both tasks to stall indefinitely.</p>
</li>
<li><p><strong>Task Management Complexity</strong>: Managing multiple concurrent tasks can become complex as the number of tasks grows, leading to bugs that are difficult to reproduce and debug.</p>
</li>
</ul>
<h4 id="heading-parallelization-challenges"><strong>Parallelization Challenges</strong>:</h4>
<ul>
<li><p><strong>Diminishing Returns</strong>: According to <a target="_blank" href="https://en.wikipedia.org/wiki/Amdahl%27s_law"><strong>Amdahl’s Law</strong></a>, as you increase the number of parallel tasks, the time spent on the sequential portion of the task becomes the bottleneck, limiting the potential speedup.</p>
</li>
<li><p><strong>Synchronization Overhead</strong>: Parallel tasks often need to synchronize to share data or complete a collective operation, and this can introduce delays, negating the performance benefits.</p>
</li>
<li><p><strong>Hardware Limitations</strong>: Adding more cores or processors does not always guarantee better performance, especially if tasks require frequent communication or memory access, which can become the bottleneck.</p>
</li>
</ul>
<h4 id="heading-solutions"><strong>Solutions</strong>:</h4>
<ul>
<li><p><strong>Concurrency</strong>: Use proper locking mechanisms (mutexes, semaphores) to manage access to shared resources. Design your application to avoid circular dependencies, which can lead to deadlocks.</p>
</li>
<li><p><strong>Parallelization</strong>: Break down tasks into as many independent sub-tasks as possible, minimizing the need for synchronization. Profile your application to understand where bottlenecks occur before adding more threads or cores.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Concurrency and parallelization are fundamental concepts that can drastically improve the performance and responsiveness of software applications, but they are not interchangeable. Concurrency helps manage multiple tasks by switching between them, making systems more responsive, while parallelization boosts performance by executing tasks simultaneously.</p>
<p>As a developer, it’s important to understand the nature of the tasks you are working with. Are you managing a lot of I/O-bound tasks? Concurrency is your friend. Are you trying to reduce the time spent on CPU-heavy computations? Parallelization will provide the speedup you need.</p>
<p>By understanding the differences, real-world applications, and potential pitfalls of concurrency and parallelization, you can make informed decisions that lead to better-designed systems.</p>
<hr />
<h2 id="heading-further-reading-and-resources">Further Reading and Resources</h2>
<p>For readers interested in diving deeper into these topics, here are some great resources:</p>
<ul>
<li><p><strong>Online Articles</strong>:</p>
<ul>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/1050222/what-is-the-difference-between-concurrency-and-parallelism">What is the difference between concurrency and parallelism?</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/1050222/what-is-the-difference-between-concurrency-and-parallelism">Concurrency (computer science)</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/1050222/what-is-the-difference-between-concurrency-and-parallelism">Parallel computing</a></p>
</li>
<li><p><a target="_blank" href="https://realpython.com/python-multiprocessing/">Parallel Programming in Python with multiprocessing</a></p>
</li>
<li><p><a target="_blank" href="https://docs.python.org/3/library/asyncio.html">Managing Concurrency with Asyncio in Python</a></p>
</li>
</ul>
</li>
<li><p><strong>Tools and Libraries</strong>:</p>
<ul>
<li><p><strong>Python</strong>: <code>asyncio</code>, <a target="_blank" href="https://docs.python.org/3/library/multiprocessing.html"><code>multiprocessing</code></a>, <a target="_blank" href="https://docs.python.org/3/library/concurrent.futures.html"><code>concurrent.futures</code></a></p>
</li>
<li><p><strong>Java</strong>: <a target="_blank" href="https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html"><code>java.util.concurrent</code></a> package</p>
</li>
<li><p><strong>C/C++</strong>: <a target="_blank" href="https://en.wikipedia.org/wiki/OpenMP">OpenMP</a>, <a target="_blank" href="https://en.wikipedia.org/wiki/Pthreads">POSIX threads</a></p>
</li>
</ul>
</li>
</ul>
<hr />
<h2 id="heading-frequently-asked-questions-faqs">Frequently Asked Questions (FAQs)</h2>
<p><strong>Q: Is concurrency always faster than sequential execution?</strong><br />A: Not necessarily. Concurrency focuses on responsiveness and task management, not speed. It allows multiple tasks to make progress without waiting, but it doesn’t always lead to faster execution times, especially for CPU-bound tasks.</p>
<p><strong>Q: Can I use concurrency and parallelization together?</strong><br />A: Yes! Many systems use concurrency to handle multiple tasks and parallelization to speed up specific subtasks. For example, a web server might use concurrency to manage requests and parallelization to perform computations on those requests.</p>
<p><strong>Q: What’s the main advantage of parallelization?</strong><br />A: Parallelization shines when you need to improve performance by reducing the time it takes to complete a task. By dividing a task into smaller parts and running them simultaneously across multiple cores, you can significantly shorten execution time.</p>
<p><strong>Q: How do I avoid deadlocks in concurrent programming?</strong><br />A: Deadlocks occur when tasks are waiting on each other to release resources. To avoid deadlocks, ensure that tasks acquire resources in a consistent order, and try to use <a target="_blank" href="https://en.wikipedia.org/wiki/Synchronization_\(computer_science\)">non-blocking synchronization mechanisms</a> like <strong>locks with timeouts</strong>.</p>
<p><strong>Q: Can concurrency and parallelization be used in everyday applications?</strong><br />A: Absolutely. Many everyday applications, like web browsers and media players, use concurrency to manage multiple tasks (e.g., playing a video while loading a webpage) and parallelization to improve performance (e.g., decoding a video using multiple cores).</p>
]]></content:encoded></item><item><title><![CDATA[Gradle: Java Build Tools, Tasks, Dependencies, and Multi-Project Builds]]></title><description><![CDATA[Introduction
In Java development, build tools are a crucial part of the workflow. They automate tasks such as compiling code, managing dependencies, packaging applications, and even running tests. As projects grow in size and complexity, manually han...]]></description><link>https://blog.seancoughlin.me/gradle-java-build-tools-tasks-dependencies-and-multi-project-builds</link><guid isPermaLink="true">https://blog.seancoughlin.me/gradle-java-build-tools-tasks-dependencies-and-multi-project-builds</guid><category><![CDATA[Java]]></category><category><![CDATA[gradle]]></category><category><![CDATA[Build tool]]></category><category><![CDATA[backend]]></category><category><![CDATA[automation]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Mon, 30 Sep 2024 20:47:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727729240252/9a737cc0-1bee-4dc8-b722-a23cf317f7e0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In Java development, build tools are a crucial part of the workflow. They automate tasks such as compiling code, managing dependencies, packaging applications, and even running tests. As projects grow in size and complexity, manually handling these tasks becomes impractical, which is where build tools like <a target="_blank" href="https://gradle.org">Gradle come in</a>. Gradle is a flexible, powerful build tool that can be customized to suit your project's needs, from simple apps to multi-module enterprise systems.</p>
<p>Before diving into Gradle, it's important to understand where it fits in the landscape of Java build tools. Java developers typically have several options when it comes to automating the build process, and each tool offers different strengths depending on the project and team requirements.</p>
<hr />
<h2 id="heading-java-build-tools">Java Build Tools</h2>
<p><a target="_blank" href="https://www.java.com/en/">Java</a> build tools have evolved over time, from simple automation systems to complex, highly configurable tools. Each tool has its own strengths and use cases. Here’s a quick overview of the three most common tools: <a target="_blank" href="https://ant.apache.org"><strong>Ant</strong></a>, <a target="_blank" href="https://maven.apache.org"><strong>Maven</strong></a>, and <a target="_blank" href="https://en.wikipedia.org/wiki/Gradle"><strong>Gradle</strong></a>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Build Tool</td><td>Description</td><td>Strengths</td><td>Weaknesses</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Ant</strong></td><td>An older, task-based build system using XML configuration. It offers flexibility but requires manual setup.</td><td>Highly customizable and simple to start. Developers can control every step in the build process.</td><td>XML configurations are verbose and require manual management of dependencies and build steps.</td></tr>
<tr>
<td><strong>Maven</strong></td><td>A convention-over-configuration build system that uses XML and focuses heavily on dependency management and a standard project structure.</td><td>Automatic dependency management and a standardized project structure that simplifies configuration.</td><td>Less flexible than Ant. Projects need to fit into Maven’s conventions, which can be limiting.</td></tr>
<tr>
<td><strong>Gradle</strong></td><td>A flexible, script-based build tool that supports both Groovy and Kotlin for configuration. It combines the flexibility of Ant with the dependency management of Maven.</td><td>Fast, flexible, and highly customizable with incremental builds. Supports both Groovy and Kotlin.</td><td>More complex to learn initially due to its flexibility, especially when working with large projects.</td></tr>
</tbody>
</table>
</div><ul>
<li><p><strong>Ant</strong> is the oldest of the three and is entirely task-based. It provides great control over every step in the build process but requires manual configuration of each task, making it verbose and less automated.</p>
</li>
<li><p><strong>Maven</strong>, on the other hand, introduced the idea of "convention over configuration." It relies on a predefined project structure, making it easier to use, but less flexible. Maven’s strength lies in dependency management, allowing developers to easily manage libraries and external resources.</p>
</li>
<li><p><strong>Gradle</strong> is the most recent build tool and is designed to combine the best of both worlds. It provides flexibility through scripting (either Groovy or Kotlin) and offers automated dependency management. Gradle’s incremental build capabilities make it faster, especially for large projects.</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">While tools like Ant, Maven, and Gradle manage the entire build lifecycle—including dependency management, testing, and packaging—<code>javac</code> is only responsible for <strong>compiling</strong> Java source files into <a target="_blank" href="https://en.wikipedia.org/wiki/Java_bytecode">bytecode</a>. <code>javac</code> requires manual handling of dependencies and additional tasks, making it less suited for complex projects compared to comprehensive build tools like Gradle.</div>
</div>

<p>In the next section, we will focus on getting started with Gradle, exploring its task system and how it handles dependencies.</p>
<hr />
<h2 id="heading-getting-started-with-gradle">Getting Started with Gradle</h2>
<p>Gradle is highly flexible and can be used in a variety of project setups, from simple command-line apps to complex, multi-module systems. It uses a <a target="_blank" href="https://en.wikipedia.org/wiki/Domain-specific_language">domain-specific language (DSL)</a> for configuration, allowing you to define tasks and manage dependencies in a streamlined way. You can choose to use either <strong>Groovy</strong> or <strong>Kotlin</strong> as the DSL for your build scripts, depending on your preference.</p>
<h4 id="heading-installing-gradle"><strong>Installing Gradle</strong></h4>
<p>To get started, you’ll first need to install Gradle. Here’s a quick guide on how to set it up:</p>
<ol>
<li><p><strong>Install Gradle</strong>: You can download Gradle directly from the <a target="_blank" href="https://gradle.org/install/">official site</a>, or install it using a package manager like Homebrew on macOS:</p>
<pre><code class="lang-bash"> brew install gradle
</code></pre>
</li>
<li><p><strong>Verify Installation</strong>:</p>
<pre><code class="lang-bash"> gradle -v
</code></pre>
</li>
<li><p><strong>Gradle Wrapper</strong>: The Gradle Wrapper allows you to run Gradle builds without needing to install Gradle on every machine. It ensures that the correct version of Gradle is used consistently across all environments.</p>
<ul>
<li><p>To set up the wrapper, run:</p>
<pre><code class="lang-bash">  gradle wrapper
</code></pre>
</li>
<li><p>This generates scripts (<code>gradlew</code> and <code>gradlew.bat</code>) that can be used to execute Gradle commands:</p>
<pre><code class="lang-bash">  ./gradlew build
</code></pre>
</li>
</ul>
</li>
</ol>
<h4 id="heading-creating-a-basic-gradle-project"><strong>Creating a Basic Gradle Project</strong></h4>
<p>Once Gradle is installed, you can create a new project using the <code>gradle init</code> command. This sets up a basic project structure.</p>
<pre><code class="lang-bash">gradle init --<span class="hljs-built_in">type</span> java-application
</code></pre>
<p>This will generate the following files:</p>
<pre><code class="lang-xml">├── build.gradle
├── settings.gradle
├── src
│   └── main
│       └── java
│           └── App.java
│   └── test
│       └── java
│           └── AppTest.java
</code></pre>
<ul>
<li><p><strong>build.gradle</strong>: This is the main build script where you define tasks, dependencies, and configurations.</p>
</li>
<li><p><strong>settings.gradle</strong>: Defines the project name and includes subprojects for multi-project builds.</p>
</li>
</ul>
<h4 id="heading-basic-project-structure-in-gradle"><strong>Basic Project Structure in Gradle</strong></h4>
<p>Here’s a minimal example of what a <code>build.gradle</code> file might look like for a Java application:</p>
<p><strong>Groovy (</strong><code>build.gradle</code>):</p>
<pre><code class="lang-xml">plugins {
    id 'application'
}

group = 'com.example'
version = '1.0.0'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.google.guava:guava:31.0.1-jre'
    testImplementation 'junit:junit:4.13.2'
}

application {
    mainClass = 'com.example.App'
}
</code></pre>
<p><strong>Kotlin (</strong><code>build.gradle.kts</code>):</p>
<pre><code class="lang-kotlin">plugins {
    application
}

group = <span class="hljs-string">"com.example"</span>
version = <span class="hljs-string">"1.0.0"</span>

repositories {
    mavenCentral()
}

dependencies {
    implementation(<span class="hljs-string">"com.google.guava:guava:31.0.1-jre"</span>)
    testImplementation(<span class="hljs-string">"junit:junit:4.13.2"</span>)
}

application {
    mainClass.<span class="hljs-keyword">set</span>(<span class="hljs-string">"com.example.App"</span>)
}
</code></pre>
<p>Here’s what’s happening in this <code>build.gradle</code> file:</p>
<ul>
<li><p><strong>Plugins</strong>: The <code>application</code> plugin is applied, which makes it easy to run the app.</p>
</li>
<li><p><strong>Group/Version</strong>: Defines the group and version of the project, which is useful when packaging the app.</p>
</li>
<li><p><strong>Repositories</strong>: Specifies where to look for dependencies. In this case, it’s using <strong>Maven Central</strong>.</p>
</li>
<li><p><strong>Dependencies</strong>: Adds dependencies required by the project, including a library (<code>guava</code>) for the main code and a testing library (<code>junit</code>) for the test code.</p>
</li>
<li><p><strong>Application</strong>: Specifies the main class that Gradle will use to run the application.</p>
</li>
</ul>
<h4 id="heading-running-gradle-tasks"><strong>Running Gradle Tasks</strong></h4>
<p><a target="_blank" href="https://docs.gradle.org/current/userguide/tutorial_using_tasks.html">Gradle projects are driven by tasks</a>. You can use built-in tasks or define your own custom tasks. Some common built-in tasks include:</p>
<ul>
<li><p><code>gradle build</code>: Compiles and packages your project.</p>
</li>
<li><p><code>gradle run</code>: Runs the application (if the <code>application</code> plugin is applied).</p>
</li>
<li><p><code>gradle clean</code>: Deletes previous build outputs.</p>
</li>
<li><p><code>gradle test</code>: Runs the tests in your project.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-bash">./gradlew build
./gradlew run
</code></pre>
<p>These commands will build and run your application based on the configuration defined in the <code>build.gradle</code> file. In the next section, we’ll look deeper into tasks and dependencies, which are central to Gradle's functionality.</p>
<hr />
<h2 id="heading-understanding-gradle-tasks">Understanding Gradle Tasks</h2>
<p>In Gradle, a <strong>task</strong> is a single unit of work, such as compiling code, running tests, packaging a JAR file, or deploying an application. Tasks are the building blocks of any Gradle project, and the entire build process is a series of tasks executed in a particular order. Gradle allows you to create your own custom tasks or use the many pre-built tasks that come with Gradle plugins.</p>
<h4 id="heading-defining-and-running-tasks"><strong>Defining and Running Tasks</strong></h4>
<p>At its simplest, a task in Gradle can be defined in the <code>build.gradle</code> file using the following syntax:</p>
<p><strong>Groovy (</strong><code>build.gradle</code>):</p>
<pre><code class="lang-xml">task hello {
    doLast {
        println 'Hello, Gradle!'
    }
}
</code></pre>
<p><strong>Kotlin (</strong><code>build.gradle.kts</code>):</p>
<pre><code class="lang-kotlin">tasks.register(<span class="hljs-string">"hello"</span>) {
    doLast {
        println(<span class="hljs-string">"Hello, Gradle!"</span>)
    }
}
</code></pre>
<p>In this example, the task <code>hello</code> prints the message "Hello, Gradle!" when executed. You can run this task by invoking it from the command line:</p>
<pre><code class="lang-bash">./gradlew hello
</code></pre>
<h4 id="heading-task-actions-dofirst-and-dolast"><strong>Task Actions:</strong> <code>doFirst</code> and <code>doLast</code></h4>
<p>Tasks can have multiple actions. You can define actions that run at the beginning or the end of the task using <code>doFirst</code> and <code>doLast</code> blocks. These blocks allow you to insert actions before or after the main task action.</p>
<p><strong>Example: Using</strong> <code>doFirst</code> and <code>doLast</code></p>
<p><strong>Groovy</strong>:</p>
<pre><code class="lang-xml">task setup {
    doFirst {
        println 'Setting up the environment...'
    }
    doLast {
        println 'Environment setup complete.'
    }
}
</code></pre>
<p><strong>Kotlin</strong>:</p>
<pre><code class="lang-kotlin">tasks.register(<span class="hljs-string">"setup"</span>) {
    doFirst {
        println(<span class="hljs-string">"Setting up the environment..."</span>)
    }
    doLast {
        println(<span class="hljs-string">"Environment setup complete."</span>)
    }
}
</code></pre>
<p>This task will first print "Setting up the environment..." before executing the main task logic, and then print "Environment setup complete." after the task completes.</p>
<h4 id="heading-task-dependencies"><strong>Task Dependencies</strong></h4>
<p>In many cases, tasks need to run in a specific order. For instance, you may want to clean the build directory before compiling the code. Gradle allows you to define <a target="_blank" href="https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:task_dependencies"><strong>task dependencies</strong></a> so that tasks are executed in a particular sequence.</p>
<p><strong>Example: Defining Task Dependencies</strong></p>
<p><strong>Groovy</strong>:</p>
<pre><code class="lang-xml">task clean {
    doLast {
        println 'Cleaning build directory...'
    }
}

task build(dependsOn: clean) {
    doLast {
        println 'Building the project...'
    }
}
</code></pre>
<p><strong>Kotlin</strong>:</p>
<pre><code class="lang-kotlin">tasks.register(<span class="hljs-string">"clean"</span>) {
    doLast {
        println(<span class="hljs-string">"Cleaning build directory..."</span>)
    }
}

tasks.register(<span class="hljs-string">"build"</span>) {
    dependsOn(<span class="hljs-string">"clean"</span>)
    doLast {
        println(<span class="hljs-string">"Building the project..."</span>)
    }
}
</code></pre>
<p>In this example, the <code>build</code> task depends on the <code>clean</code> task. When you run <code>./gradlew build</code>, Gradle will first execute the <code>clean</code> task before running the <code>build</code> task.</p>
<h4 id="heading-built-in-tasks"><strong>Built-in Tasks</strong></h4>
<p>Gradle comes with several built-in tasks that you’ll frequently use. Some of the most common include:</p>
<ul>
<li><p><code>clean</code>: Deletes previous build outputs.</p>
</li>
<li><p><code>build</code>: Compiles the code and assembles the outputs (like JAR files).</p>
</li>
<li><p><code>test</code>: Runs unit tests.</p>
</li>
<li><p><code>assemble</code>: Packages your project into a deliverable format (such as a JAR or WAR file).</p>
</li>
</ul>
<p>You can list all available tasks in your project by running:</p>
<pre><code class="lang-bash">./gradlew tasks
</code></pre>
<p>This command will display a list of all available tasks, including those provided by plugins and any custom tasks you've defined.</p>
<h4 id="heading-custom-tasks-use-cases"><strong>Custom Tasks: Use Cases</strong></h4>
<p>Tasks are highly flexible and can be customized to handle any kind of work. Here are a few common use cases for custom tasks:</p>
<ol>
<li><p><strong>Running Shell Commands</strong>: You can use Gradle tasks to run external commands, such as shell scripts or command-line tools.</p>
<pre><code class="lang-xml"> task runScript(type: Exec) {
     commandLine 'bash', '-c', './my-script.sh'
 }
</code></pre>
</li>
<li><p><strong>Automating File Operations</strong>: Gradle tasks can manipulate files, like copying or moving files between directories.</p>
<pre><code class="lang-xml"> task copyFiles(type: Copy) {
     from 'src/files'
     into 'build/files'
 }
</code></pre>
</li>
<li><p><strong>Custom Build Steps</strong>: If your project requires additional steps in the build process, like generating documentation or compiling assets, you can create tasks for those actions.</p>
<pre><code class="lang-xml"> task generateDocs {
     doLast {
         println 'Generating project documentation...'
     }
 }
</code></pre>
</li>
<li><p><strong>Combining Multiple Tasks</strong>: You can create a task that aggregates several other tasks, allowing you to run multiple tasks in a single command.</p>
<pre><code class="lang-xml"> task fullBuild {
     dependsOn 'clean', 'build', 'test'
 }
</code></pre>
</li>
</ol>
<p>By customizing tasks, you can automate a wide range of workflows and integrate them into your overall build process.</p>
<hr />
<h2 id="heading-multi-project-builds-in-gradle">Multi-Project Builds in Gradle</h2>
<p>When working on large-scale applications, it's common to break the project into multiple smaller, reusable modules. This is where <strong>multi-project builds</strong> in Gradle come in handy. They allow you to manage several subprojects within a single build while still keeping the overall structure modular and maintainable.</p>
<p>Think of it like a toolbox with separate compartments, each serving a unique purpose but all working together for the same project.</p>
<h4 id="heading-why-use-multi-project-builds"><strong>Why Use Multi-Project Builds?</strong></h4>
<p>Multi-project builds make sense when:</p>
<ul>
<li><p>You have multiple modules that share common dependencies or functionality.</p>
</li>
<li><p>You want to separate concerns by having distinct components (like libraries, services, or UI) in their own modules.</p>
</li>
<li><p>You’re working in a team where different developers focus on different parts of the system.</p>
</li>
</ul>
<p>For example, if you're building an e-commerce application, you might split it into modules like <code>frontend</code>, <code>backend</code>, and <code>database</code>, each with its own configuration and dependencies.</p>
<h4 id="heading-setting-up-a-multi-project-build"><strong>Setting Up a Multi-Project Build</strong></h4>
<p>In Gradle, you start by defining your project structure. Here’s what a simple multi-project setup might look like:</p>
<pre><code class="lang-xml">rootProject/
    ├── build.gradle
    ├── settings.gradle
    ├── app/
    │   └── build.gradle
    └── lib/
        └── build.gradle
</code></pre>
<ul>
<li><p>The <strong>root project</strong> contains a <code>settings.gradle</code> file, which includes references to the subprojects.</p>
</li>
<li><p>Each subproject (e.g., <code>app</code> and <code>lib</code>) has its own <code>build.gradle</code> file.</p>
</li>
</ul>
<p>In the <code>settings.gradle</code> file, you specify the included subprojects like this:</p>
<pre><code class="lang-xml">// settings.gradle
rootProject.name = 'MyMultiProject'
include 'app', 'lib'
</code></pre>
<p>Each subproject can have its own configuration, but they can also share common settings or dependencies through the root <code>build.gradle</code> file. For example, you might want both the <code>app</code> and <code>lib</code> modules to use the same version of a dependency:</p>
<pre><code class="lang-xml">// root build.gradle
subprojects {
    apply plugin: 'java'

    repositories {
        mavenCentral()
    }

    dependencies {
        testImplementation 'junit:junit:4.13.2'
    }
}
</code></pre>
<h4 id="heading-managing-dependencies-between-projects"><strong>Managing Dependencies Between Projects</strong></h4>
<p>One of the major advantages of multi-project builds is the ability to define dependencies between subprojects. For example, the <code>app</code> project might rely on the <code>lib</code> project:</p>
<pre><code class="lang-xml">// app/build.gradle
dependencies {
    implementation project(':lib')
}
</code></pre>
<p>This way, you can share functionality between modules without duplicating code. Running a Gradle build will automatically compile the <code>lib</code> project before compiling the <code>app</code> project, ensuring that everything works smoothly together.</p>
<p>Multi-project builds help keep large projects organized and scalable. As your application grows, Gradle makes it easy to manage multiple modules while maintaining clear separation between them.</p>
<hr />
<h2 id="heading-the-gradle-wrapper">The Gradle Wrapper</h2>
<p>The <a target="_blank" href="https://docs.gradle.org/current/userguide/gradle_wrapper.html"><strong>Gradle Wrapper</strong></a> is one of those features you might not fully appreciate until you’ve worked on a project with multiple developers—or worse, multiple machines with different environments. The wrapper solves a simple but significant problem: ensuring that everyone on your team, and every build system, uses the exact same version of Gradle, without requiring them to install it globally.</p>
<h4 id="heading-what-is-the-gradle-wrapper"><strong>What Is the Gradle Wrapper?</strong></h4>
<p>The Gradle Wrapper is essentially a set of scripts and configuration files included in your project that automatically downloads and runs the correct version of Gradle. This means you don’t have to worry about whether your CI server or a colleague has Gradle installed—everything is self-contained.</p>
<p>Here’s how it works:</p>
<ul>
<li><p>The wrapper consists of a few files: <code>gradlew</code>, <code>gradlew.bat</code>, and the <code>gradle-wrapper.properties</code> file, which specifies the Gradle version to use.</p>
</li>
<li><p>When you run <code>./gradlew build</code> (on Unix-based systems) or <code>gradlew.bat build</code> (on Windows), the wrapper checks whether the specified version of Gradle is installed. If it’s not, it downloads that version automatically.</p>
</li>
</ul>
<h4 id="heading-why-use-the-gradle-wrapper"><strong>Why Use the Gradle Wrapper?</strong></h4>
<p>The main advantage of the wrapper is consistency. Imagine you’re working on a project with three developers. Developer A is using Gradle 7.0, Developer B is on Gradle 7.2, and Developer C hasn’t installed Gradle yet. Without the wrapper, this could lead to unpredictable behavior or errors if different Gradle versions handle certain tasks differently. The wrapper ensures that everyone uses the same version, avoiding these kinds of problems.</p>
<p>Another benefit is in <strong>Continuous Integration (CI)</strong> environments. CI servers can run Gradle builds without needing to install Gradle globally, which simplifies the setup. The Gradle Wrapper ensures the build runs in the correct environment every time.</p>
<h4 id="heading-setting-up-the-gradle-wrapper"><strong>Setting Up the Gradle Wrapper</strong></h4>
<p>You can add the wrapper to any project by running this command:</p>
<pre><code class="lang-bash">gradle wrapper
</code></pre>
<p>This will generate the necessary files (<code>gradlew</code>, <code>gradlew.bat</code>, and the <code>gradle/wrapper</code> directory). Once the wrapper is in place, all developers and systems can use <code>./gradlew</code> or <code>gradlew.bat</code> instead of <code>gradle</code>.</p>
<p>If you need to upgrade the version of Gradle that the wrapper uses, simply modify the <code>gradle-wrapper.properties</code> file:</p>
<pre><code class="lang-xml"># gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
</code></pre>
<p>After updating the <code>distributionUrl</code>, running the wrapper will download and use the new version.</p>
<p>It may seem like a small detail, but the Gradle Wrapper is a key feature for maintaining consistency and simplicity across development environments. By eliminating the need to install Gradle manually, it removes a common source of friction, especially in teams and automated build systems. It ensures that no matter where your project is built—locally, on a server, or in the cloud—it will always use the correct version of Gradle.</p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Gradle is a versatile and powerful build tool that provides a comprehensive way to manage your Java projects, from simple applications to complex, multi-module systems. We've covered the basics of Gradle tasks, how to manage dependencies, and explored the flexibility of multi-project builds.</p>
<p>Whether you're automating simple build tasks or coordinating multiple modules in a large-scale project, Gradle’s flexibility and speed make it a valuable tool for Java developers. By mastering its core concepts, you’ll streamline your workflow and improve the maintainability of your projects.</p>
]]></content:encoded></item><item><title><![CDATA[Mastering Snapshot Testing with Vite, Vitest, or Jest in TypeScript]]></title><description><![CDATA[Snapshot testing is a powerful and efficient way to ensure the UI of your application remains consistent over time. By capturing the rendered output of a component and comparing it to a previously stored snapshot, any unintended changes can be quickl...]]></description><link>https://blog.seancoughlin.me/mastering-snapshot-testing-with-vite-vitest-or-jest-in-typescript</link><guid isPermaLink="true">https://blog.seancoughlin.me/mastering-snapshot-testing-with-vite-vitest-or-jest-in-typescript</guid><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[vite]]></category><category><![CDATA[snapshot testing]]></category><category><![CDATA[Jest]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Wed, 10 Jul 2024 22:26:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720650255517/a29d7413-b973-4c1e-9fc6-ae05e07bbdca.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Snapshot testing is a powerful and efficient way to ensure the UI of your application remains consistent over time. By capturing the rendered output of a component and comparing it to a previously stored snapshot, any unintended changes can be quickly identified.</p>
<p>This article will guide you through the process of setting up snapshot testing in a TypeScript project using Vite as the build tool, with both Vitest and Jest as the testing frameworks.</p>
<h2 id="heading-what-are-snapshot-tests">What are Snapshot Tests?</h2>
<p>Snapshot tests are a type of automated test that helps you verify the UI of your application. They work by rendering a component, taking a snapshot of its output, and comparing it to a previously stored snapshot. If the output has changed, the test will fail, alerting you to a potential unintended change in your UI.</p>
<p>Snapshot tests are particularly useful for large components and complex UIs, as they allow you to quickly identify when something has changed, ensuring your UI remains consistent.</p>
<h3 id="heading-why-are-snapshot-tests-important">Why are Snapshot Tests Important?</h3>
<ol>
<li><p><strong>Consistency</strong>: They ensure that your UI remains consistent over time, catching any unexpected changes.</p>
</li>
<li><p><strong>Efficiency</strong>: They automate the process of checking the UI, saving time compared to manual testing.</p>
</li>
<li><p><strong>Confidence</strong>: They give you confidence that your changes have not unintentionally affected the UI.</p>
</li>
</ol>
<hr />
<h2 id="heading-introduction-to-vite">Introduction to Vite</h2>
<p>Vite is a fast and modern build tool for JavaScript projects. It provides a smooth development experience with features like hot module replacement (HMR), lightning-fast cold starts, and a highly optimized build process. Using Vite, you can create and develop your applications efficiently, making it a popular choice for modern web development.</p>
<h2 id="heading-setting-up-a-new-vite-application">Setting Up a New Vite Application</h2>
<p>To get started, create a new Vite application with <a target="_blank" href="https://www.npmjs.com/package/create-vite">the following command</a>:</p>
<pre><code class="lang-bash">npm create vite@latest
</code></pre>
<p>Follow the prompts to set up your project. Once the setup is complete, navigate to your project directory.</p>
<h2 id="heading-installing-vitest-and-required-packages">Installing Vitest and Required Packages</h2>
<p>Next, install Vitest along with the necessary packages for testing:</p>
<pre><code class="lang-bash">npm install vitest@latest --save-dev
npm install --save-dev @testing-library/react @testing-library/dom jsdom
</code></pre>
<h2 id="heading-configuring-vite-for-testing">Configuring Vite for Testing</h2>
<p>To configure Vite for testing with Vitest, modify your <code>vite.config.ts</code> file as follows:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vite'</span>
<span class="hljs-keyword">import</span> react <span class="hljs-keyword">from</span> <span class="hljs-string">'@vitejs/plugin-react'</span>

<span class="hljs-comment">// https://vitejs.dev/config/</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  plugins: [react()],
  test: {
    environment: <span class="hljs-string">'jsdom'</span>,
    include: [<span class="hljs-string">'**/*.test.tsx'</span>],
  }
});
</code></pre>
<p>This configuration sets up the testing environment to use <code>jsdom</code> and includes all files with a <code>.test.tsx</code> extension.</p>
<h2 id="heading-writing-a-snapshot-test-with-vitest">Writing a Snapshot Test with Vitest</h2>
<p>Create a test file named <code>App.test.tsx</code> and add the following code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { render } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;
<span class="hljs-keyword">import</span> { expect, it } <span class="hljs-keyword">from</span> <span class="hljs-string">"vitest"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App"</span>;

it(<span class="hljs-string">"toUpperCase"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { asFragment } = render(&lt;App /&gt;);
  expect(asFragment()).toMatchSnapshot();
});
</code></pre>
<p>This test renders the <code>App</code> component and captures a snapshot of its output. When you run the test for the first time, <a target="_blank" href="https://vitest.dev/guide/snapshot">Vitest will generate a snapshot file</a> containing the rendered output.</p>
<p>To run your tests, use the following command:</p>
<pre><code class="lang-bash">npx vitest run
</code></pre>
<h2 id="heading-vitest-snapshot-output">Vitest Snapshot Output</h2>
<p>The output of the snapshot test will look something like this:</p>
<pre><code class="lang-xml">// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`toUpperCase 1`] = `
<span class="hljs-tag">&lt;<span class="hljs-name">DocumentFragment</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">a</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://vitejs.dev"</span>
      <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
        <span class="hljs-attr">alt</span>=<span class="hljs-string">"Vite logo"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"logo"</span>
        <span class="hljs-attr">src</span>=<span class="hljs-string">"/vite.svg"</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://react.dev"</span>
      <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
        <span class="hljs-attr">alt</span>=<span class="hljs-string">"React logo"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"logo react"</span>
        <span class="hljs-attr">src</span>=<span class="hljs-string">"/src/assets/react.svg"</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>
    Vite + React
  <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
    <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>
  &gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
      count is 0
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
      Edit 
      <span class="hljs-tag">&lt;<span class="hljs-name">code</span>&gt;</span>
        src/App.tsx
      <span class="hljs-tag">&lt;/<span class="hljs-name">code</span>&gt;</span>
       and save to test HMR
    <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 class="hljs-tag">&lt;<span class="hljs-name">p</span>
    <span class="hljs-attr">class</span>=<span class="hljs-string">"read-the-docs"</span>
  &gt;</span>
    Click on the Vite and React logos to learn more
  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">DocumentFragment</span>&gt;</span>
`;
</code></pre>
<hr />
<h2 id="heading-setting-up-jest-for-snapshot-testing">Setting Up Jest for Snapshot Testing</h2>
<p>Jest is another popular testing framework that was originally built with CommonJS modules in mind. Setting up Jest in a Vite project involves a bit more configuration.</p>
<p>First, install the required packages:</p>
<pre><code class="lang-bash">npm install --save-dev jest ts-jest @types/jest
npm install --save-dev jest-environment-jsdom jest-transform-stub
</code></pre>
<p>Initialize the Jest configuration:</p>
<pre><code class="lang-bash">npx ts-jest config:init
</code></pre>
<p>Modify the generated <code>jest.config.js</code> file to include the following settings:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('ts-jest').JestConfigWithTsJest}</span> </span>**/</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">testEnvironment</span>: <span class="hljs-string">"jsdom"</span>,
  <span class="hljs-attr">transform</span>: {
    <span class="hljs-string">"^.+.tsx?$"</span>: [<span class="hljs-string">"ts-jest"</span>, { <span class="hljs-attr">tsconfig</span>: <span class="hljs-string">"tsconfig.app.json"</span> }],
  },
  <span class="hljs-attr">testMatch</span>: [<span class="hljs-string">"**/*.spec.tsx"</span>],
  <span class="hljs-attr">moduleNameMapper</span>: { <span class="hljs-string">"\\.(css|less|scss|sass|svg)$"</span>: <span class="hljs-string">"jest-transform-stub"</span> },
};
</code></pre>
<h2 id="heading-writing-a-snapshot-test-with-jest">Writing a Snapshot Test with Jest</h2>
<p>Create a test file named <code>App.spec.tsx</code> and add the following code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { render } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App"</span>;

it(<span class="hljs-string">"toUpperCase"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { asFragment } = render(&lt;App /&gt;);
  expect(asFragment()).toMatchSnapshot();
});
</code></pre>
<p>Notice that the test syntax is nearly identical to that of Vitest, as Vitest implements the Jest API.</p>
<p>To run your Jest tests, use the following command:</p>
<pre><code class="lang-bash">npx jest
</code></pre>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Snapshot testing is a valuable technique for maintaining UI consistency in your applications. In this article, we explored how to set up snapshot testing in a TypeScript project using Vite as the build tool, with both Vitest and Jest as the testing frameworks.</p>
<p>While Vitest offers a more streamlined setup with Vite, Jest remains a powerful option with extensive community support and plugins. By following these steps, you can ensure your UI remains consistent and catch any unintended changes early in the development process.</p>
<h2 id="heading-faq">FAQ</h2>
<h3 id="heading-what-is-snapshot-testing">What is snapshot testing?</h3>
<p>Snapshot testing is an automated testing technique that captures the rendered output of a component and compares it to a previously stored snapshot to identify any changes.</p>
<h3 id="heading-why-use-vite-for-building-applications">Why use Vite for building applications?</h3>
<p>Vite offers a fast and modern development experience with features like hot module replacement and optimized builds, making it a popular choice for modern web development.</p>
<h3 id="heading-how-does-vitest-compare-to-jest">How does Vitest compare to Jest?</h3>
<p>Vitest implements the Jest API, making it a more streamlined choice for Vite projects. However, Jest offers extensive community support and plugins, making it a versatile option for many projects.</p>
<h3 id="heading-can-i-use-snapshot-testing-with-typescript">Can I use snapshot testing with TypeScript?</h3>
<p>Yes, both Vitest and Jest support TypeScript, allowing you to use snapshot testing in your TypeScript projects.</p>
<h3 id="heading-how-do-i-update-a-snapshot">How do I update a snapshot?</h3>
<p>To update a snapshot, you can run the tests with the <code>-u</code> flag (e.g., <code>npx vitest run -u</code> or <code>npx jest -u</code>), which will update the stored snapshots with the current output.</p>
<p>By implementing snapshot testing in your Vite projects using Vitest or Jest, you can enhance the reliability and consistency of your UI, ensuring a smoother and more efficient development process.</p>
<h2 id="heading-github-example">GitHub Example</h2>
<p>To see the complete code in action, visit the following GitHub repository.</p>
<ul>
<li><a target="_blank" href="https://github.com/Scc33/snapshot-example"><strong>snapshot-example</strong></a></li>
</ul>
<h2 id="heading-related-articles">Related Articles</h2>
<p>I have a passion for frontend development and testing! Be sure to check out my other articles on the subject for more insights and tips.</p>
<ul>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/jsdom-vs-happy-dom-navigating-the-nuances-of-javascript-testing">jsdom vs happy-dom: Navigating the Nuances of JavaScript Testing</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/maximizing-web-development-efficiency-a-comprehensive-guide-to-vite">Maximizing Web Development Efficiency: A Comprehensive Guide to Vite</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/vitest-vs-jest-the-new-javascript-testing-framework">Vitest vs. Jest: The New JavaScript Testing Framework</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/testing-react-applications-built-with-vite-using-vitest">Testing React Applications Built with Vite Using Vitest</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/testing-a-react-app-built-with-vite-using-jest-and-babel">Testing a React App Built with Vite Using Jest and Babel</a>"</p>
</li>
</ul>
<h2 id="heading-documentation">Documentation</h2>
<p>Nothing is complete without documentation, visit the following resources for more information.</p>
<ul>
<li><p><a target="_blank" href="https://vitejs.dev">Vite documentation</a></p>
</li>
<li><p><a target="_blank" href="https://vitest.dev">Vitest documentation</a></p>
</li>
<li><p><a target="_blank" href="https://jestjs.io/docs/getting-started">Jest documentation</a></p>
</li>
<li><p><a target="_blank" href="https://kulshekhar.github.io/ts-jest/docs/">ts-jest documentation</a></p>
</li>
<li><p><a target="_blank" href="https://jestjs.io/docs/snapshot-testing">Jest snapshot testing</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/jsdom/jsdom">jsdom GitHub</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[HTTPS and TLS Explained]]></title><description><![CDATA[Introduction
Transport Layer Security (TLS) is an essential cryptographic protocol that ensures the security and integrity of data transmitted over the internet. When combined with the Hypertext Transfer Protocol (HTTP), it forms HTTPS, providing a s...]]></description><link>https://blog.seancoughlin.me/https-and-tls-explained</link><guid isPermaLink="true">https://blog.seancoughlin.me/https-and-tls-explained</guid><category><![CDATA[http]]></category><category><![CDATA[https]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Security]]></category><category><![CDATA[internet]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Wed, 10 Jul 2024 02:23:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720577948995/667423e7-6254-4001-ae55-c08ce70c38b0.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Transport_Layer_Security">Transport Layer Security (TLS)</a> is an essential cryptographic protocol that ensures the security and integrity of data transmitted over the internet. When combined with the <a target="_blank" href="https://en.wikipedia.org/wiki/HTTP">Hypertext Transfer Protocol (HTTP)</a>, it forms <a target="_blank" href="https://en.wikipedia.org/wiki/HTTPS">HTTPS</a>, providing a secure channel for web communications. This article delves into how TLS encrypts the critical components of HTTPS requests, ensuring data confidentiality and integrity.</p>
<h2 id="heading-understanding-https-and-tls">Understanding HTTPS and TLS</h2>
<h3 id="heading-https">HTTPS</h3>
<p>Hypertext Transfer Protocol Secure (HTTPS) is the secure version of HTTP, the primary protocol used to send data between a web browser and a website. <a target="_blank" href="https://web.dev/articles/why-https-matters">HTTPS ensures that communications between a user's browser and a website are encrypted and secure, protecting the data from eavesdropping and tampering.</a></p>
<p><strong>Key Features of HTTPS:</strong></p>
<ul>
<li><p><strong>Encryption:</strong> HTTPS encrypts the data exchanged between the browser and the server, making it unreadable to anyone who intercepts it. This is crucial for protecting sensitive information like login credentials, credit card numbers, and personal data.</p>
</li>
<li><p><strong>Authentication:</strong> HTTPS uses digital certificates to authenticate the identity of the website, ensuring that users are communicating with the legitimate site and not an imposter.</p>
</li>
<li><p><strong>Data Integrity:</strong> HTTPS ensures that the data sent and received is not altered during transmission, protecting against data tampering.</p>
</li>
</ul>
<p><a target="_blank" href="https://www.geeksforgeeks.org/explain-working-of-https/"><strong>How HTTPS Works</strong></a><strong>:</strong></p>
<ol>
<li><p><strong>Connection Initiation:</strong> When a user navigates to an HTTPS-secured website, the browser and server initiate a connection.</p>
</li>
<li><p><strong>Certificate Exchange:</strong> The server sends its SSL/TLS certificate to the browser. This certificate contains the server's public key and is issued by a trusted Certificate Authority (CA).</p>
</li>
<li><p><strong>TLS Handshake:</strong> The browser and server perform a TLS handshake, establishing a secure session by agreeing on encryption methods and generating session keys.</p>
</li>
<li><p><strong>Secure Communication:</strong> Once the handshake is complete, all data exchanged between the browser and the server is encrypted using the session keys.</p>
</li>
</ol>
<h3 id="heading-tls">TLS</h3>
<p><a target="_blank" href="https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/">Transport Layer Security (TLS) is a cryptographic protocol</a> that provides end-to-end security for data transmitted over the internet. TLS evolved from the Secure Sockets Layer (SSL) protocol and is widely used to secure web communications, as well as other types of data transfers.</p>
<p><strong>Key Features of TLS:</strong></p>
<ul>
<li><p><strong>Encryption:</strong> TLS encrypts data to prevent unauthorized access and ensure privacy.</p>
</li>
<li><p><strong>Authentication:</strong> TLS uses certificates to verify the identities of the communicating parties.</p>
</li>
<li><p><strong>Integrity:</strong> TLS ensures that data is not tampered with during transmission.</p>
</li>
</ul>
<p><strong>How TLS Works:</strong></p>
<ol>
<li><p><strong>TLS Handshake:</strong> When a secure connection is initiated, the client and server perform a TLS handshake. This involves:</p>
<ul>
<li><p><strong>Negotiating Cipher Suites:</strong> Agreeing on the encryption algorithms to be used.</p>
</li>
<li><p><strong>Exchanging Keys:</strong> Using public key cryptography to securely exchange session keys.</p>
</li>
<li><p><strong>Authentication:</strong> The server proves its identity to the client using its certificate.</p>
</li>
</ul>
</li>
<li><p><strong>Session Encryption:</strong> Once the handshake is complete, the session keys are used to encrypt and decrypt data, ensuring secure communication.</p>
</li>
</ol>
<h2 id="heading-encryption-of-https-requests-using-tls">Encryption of HTTPS Requests Using TLS</h2>
<p>Once the TLS handshake is completed, the secure channel is established, and HTTPS requests can be sent securely. Here are the crucial parts of an HTTPS request that TLS encrypts:</p>
<h3 id="heading-request-line">Request Line</h3>
<p>The request line of an HTTP request (e.g., <code>GET /index.html HTTP/1.1</code>) is encrypted by TLS. This ensures that the specific resource being requested cannot be intercepted or manipulated by attackers.</p>
<h3 id="heading-headers">Headers</h3>
<p>HTTP headers contain essential metadata about the request or response, such as content type, user agent, cookies, and authentication tokens. TLS encrypts these headers to prevent leakage of sensitive information.</p>
<h3 id="heading-message-body">Message Body</h3>
<p>The message body of an HTTP request or response can contain sensitive data, such as user credentials, personal information, or financial transactions. TLS encrypts the message body, ensuring that this data remains confidential and secure from eavesdroppers.</p>
<p><a target="_blank" href="https://https.cio.gov/faq/"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720578095416/7ad44676-150c-4a2e-8129-f748ace04e81.png" alt="From the office of the CIO it shows what parts of an HTTP request are encrypted with HTTPS" class="image--center mx-auto" /></a></p>
<h2 id="heading-what-https-doesnt-encrypt">What HTTPS Doesn't Encrypt</h2>
<p>While HTTPS provides robust encryption for data in transit, there are certain aspects it does not cover:</p>
<h3 id="heading-domain-name-information">Domain Name Information</h3>
<p>The domain name of the website being accessed is not encrypted by HTTPS. This is because the domain name must be visible to route the request to the appropriate server. However, mechanisms like <a target="_blank" href="https://en.wikipedia.org/wiki/DNS_over_HTTPS">DNS over HTTPS (DoH)</a> and <a target="_blank" href="https://en.wikipedia.org/wiki/DNS_over_TLS">DNS over TLS (DoT)</a> can help encrypt DNS queries to enhance privacy.</p>
<h3 id="heading-server-side-data">Server-Side Data</h3>
<p>Data stored on the server, such as databases, files, and logs, is not encrypted by HTTPS. While HTTPS secures data in transit, additional measures like database encryption and secure file storage are necessary to protect data at rest.</p>
<h3 id="heading-browser-and-system-logs">Browser and System Logs</h3>
<p>Logs generated by the browser or operating system, such as browsing history, cookies, and cache, are not encrypted by HTTPS. Users should take additional precautions, such as using private browsing modes and clearing their cache, to protect their local data.</p>
<h3 id="heading-third-party-resources">Third-Party Resources</h3>
<p>Resources loaded from third-party servers, such as advertisements, analytics scripts, or embedded content, may not be encrypted if those resources do not support HTTPS. This can introduce vulnerabilities if mixed content (HTTP and HTTPS) is loaded on the same page.</p>
<h2 id="heading-benefits-of-using-tls-in-https">Benefits of Using TLS in HTTPS</h2>
<h3 id="heading-data-confidentiality">Data Confidentiality</h3>
<p>TLS encrypts the data transmitted between the client and server, making it unreadable to anyone who might intercept the communication. This is crucial for protecting sensitive information such as login credentials, payment details, and personal data.</p>
<h3 id="heading-data-integrity">Data Integrity</h3>
<p>TLS ensures that the data sent between the client and server is not altered during transit. Any tampering or corruption of data can be detected, ensuring the integrity of the communication.</p>
<h3 id="heading-authentication">Authentication</h3>
<p>TLS uses digital certificates to authenticate the identity of the server. This helps prevent man-in-the-middle attacks by ensuring that the client is communicating with the legitimate server and not an imposter.</p>
<h2 id="heading-common-use-cases-of-https-and-tls">Common Use Cases of HTTPS and TLS</h2>
<h3 id="heading-e-commerce-websites">E-commerce Websites</h3>
<p>E-commerce websites handle sensitive information such as credit card details and personal addresses. HTTPS with TLS ensures that this data is securely transmitted between customers and the website, protecting it from potential attackers.</p>
<h3 id="heading-online-banking">Online Banking</h3>
<p>Online banking platforms use HTTPS to secure financial transactions and account information. TLS encryption ensures that users can safely manage their accounts and perform transactions without the risk of data breaches.</p>
<h3 id="heading-email-services">Email Services</h3>
<p>Web-based email services use HTTPS to secure email communication. TLS protects the content of emails and login credentials, ensuring that users' private information remains confidential.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>TLS plays a critical role in securing HTTPS requests by encrypting the request line, headers, and message body. This encryption ensures data confidentiality, integrity, and authentication, making the internet a safer place for users.</p>
<p>By understanding how TLS works and its importance in HTTPS, we can appreciate the robust security mechanisms that protect our online interactions.</p>
<h2 id="heading-faqs">FAQs</h2>
<h3 id="heading-what-is-the-difference-between-http-and-https">What is the difference between HTTP and HTTPS?</h3>
<p>HTTP is the standard protocol for transferring web pages, while HTTPS is the secure version of HTTP that uses TLS to encrypt data and ensure secure communication.</p>
<h3 id="heading-how-does-tls-encryption-work">How does TLS encryption work?</h3>
<p>TLS encryption involves a handshake process where the client and server establish a secure connection, exchange keys, and then use symmetric encryption to protect the data transmitted.</p>
<h3 id="heading-why-is-tls-important-for-web-security">Why is TLS important for web security?</h3>
<p>TLS is essential for web security because it encrypts data, ensures data integrity, and authenticates the server, protecting users from data breaches and man-in-the-middle attacks.</p>
<h3 id="heading-can-tls-be-used-without-https">Can TLS be used without HTTPS?</h3>
<p>TLS is primarily used with HTTPS to secure web communications, but it can also be used with other protocols like SMTP, IMAP, and FTP to provide secure communication channels.</p>
<h3 id="heading-how-can-i-tell-if-a-website-is-using-https">How can I tell if a website is using HTTPS?</h3>
<p>A website using HTTPS will have a URL that starts with "https://" and often displays a padlock icon in the browser’s address bar, indicating that the connection is secure.</p>
<p>By ensuring your website uses HTTPS with TLS, you not only protect your users' data but also build trust and credibility, which are vital for online success.</p>
<h2 id="heading-related-articles">Related Articles</h2>
<ul>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/understanding-web-cookies-navigating-the-shift-from-third-party-tracking-to-enhanced-privacy">Understanding Web Cookies: Navigating the Shift from Third-Party Tracking to Enhanced Privacy</a><strong>"</strong></p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/exploring-webassembly-the-future-of-web-development">Exploring WebAssembly: The Future of Web Development</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://https.cio.gov/faq/">Introduction to HTTPS</a><strong>"</strong></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[What is Atomic CSS?]]></title><description><![CDATA[Atomic CSS, also known as Functional CSS or Utility-First CSS, is an approach to CSS architecture that emphasizes the use of small, single-purpose classes with names based on their visual function.
This method aims to create a more modular and mainta...]]></description><link>https://blog.seancoughlin.me/what-is-atomic-css</link><guid isPermaLink="true">https://blog.seancoughlin.me/what-is-atomic-css</guid><category><![CDATA[CSS]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webdev]]></category><category><![CDATA[web]]></category><category><![CDATA[UI]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Mon, 08 Jul 2024 22:22:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720477062231/6034826e-877e-4e01-8b10-f36767286e36.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Atomic CSS, also known as Functional CSS or Utility-First CSS, is an approach to CSS architecture that emphasizes the use of small, single-purpose classes with names based on their visual function.</p>
<p>This method aims to create a more modular and maintainable CSS codebase by breaking down styles into the smallest possible units, or "atoms," which can then be composed to build complex user interfaces.</p>
<h2 id="heading-key-characteristics-of-atomic-css">Key Characteristics of Atomic CSS</h2>
<h3 id="heading-single-purpose-classes">Single-Purpose Classes</h3>
<p>Atomic CSS classes are designed to do one thing and one thing only. For example:</p>
<ul>
<li><p><code>.text-red</code> sets the text color to red.</p>
</li>
<li><p><code>.m-4</code> sets the margin to 4 units.</p>
</li>
</ul>
<h3 id="heading-encapsulation">Encapsulation</h3>
<p>By using specific classes for each style, Atomic CSS ensures that styles are tightly scoped to the elements they are applied to. This reduces the risk of unintended side effects and makes it easier to understand and manage styles.</p>
<h3 id="heading-concise-and-readable">Concise and Readable</h3>
<p>Atomic CSS can make your HTML more verbose, but it also makes it more readable and easier to understand at a glance. Each class name clearly indicates what style it applies, <a target="_blank" href="https://byteofdev.com/posts/atomic-css/">which can simplify debugging and maintenance</a>.</p>
<h3 id="heading-frameworks-and-tools">Frameworks and Tools</h3>
<p>Several frameworks and tools have been developed to facilitate the use of Atomic CSS:</p>
<ul>
<li><p><a target="_blank" href="https://tailwindcss.com"><strong>Tailwind CSS</strong></a>: A popular utility-first CSS framework that provides a comprehensive set of utility classes for building responsive designs.</p>
</li>
<li><p><a target="_blank" href="https://tachyons.io"><strong>Tachyons</strong></a>: Another utility-first CSS framework that emphasizes performance and readability.</p>
</li>
<li><p><a target="_blank" href="https://acss.io"><strong>Atomizer</strong></a>: A tool that programmatically generates Atomic CSS classes based on what it finds in your HTML.</p>
</li>
</ul>
<h3 id="heading-static-vs-programmatic-approaches">Static vs. Programmatic Approaches</h3>
<ul>
<li><p><strong>Static</strong>: Developers write Atomic CSS classes manually or use a preprocessor to generate a library of classes.</p>
</li>
<li><p><a target="_blank" href="https://css-tricks.com/lets-define-exactly-atomic-css/#aa-programmatic"><strong>Programmatic</strong></a>: Tools like Atomizer can automatically generate styles based on the HTML, optimizing the CSS by including only the styles that are actually used.</p>
</li>
</ul>
<h2 id="heading-benefits-of-atomic-css">Benefits of Atomic CSS</h2>
<h3 id="heading-modularity">Modularity</h3>
<p>Atomic CSS promotes a modular approach to styling, making it easier to reuse styles across different components and projects.</p>
<h3 id="heading-performance">Performance</h3>
<p>By generating only the necessary CSS, Atomic CSS can reduce the overall size of the CSS file, leading to faster load times and better performance.</p>
<h3 id="heading-maintainability">Maintainability</h3>
<p>With styles broken down into small, single-purpose classes, it becomes easier to maintain and update the CSS codebase. Changes to a single class do not affect other styles, reducing the risk of bugs and regressions.</p>
<h2 id="heading-criticisms-and-challenges">Criticisms and Challenges</h2>
<h3 id="heading-verbosity">Verbosity</h3>
<p>One of the main criticisms of Atomic CSS is that it can make HTML more verbose, as each element may require multiple classes to achieve the desired styling.</p>
<h3 id="heading-learning-curve">Learning Curve</h3>
<p>For developers accustomed to traditional, semantic CSS methodologies, adopting Atomic CSS can require a significant shift in mindset and workflow.</p>
<h3 id="heading-initial-setup">Initial Setup</h3>
<p>Defining all the necessary utility classes upfront can be time-consuming, although tools like Tailwind CSS and Atomizer help mitigate this by providing extensive sets of pre-defined utilities.</p>
<h2 id="heading-comparison-of-atomic-css">Comparison of Atomic CSS</h2>
<h3 id="heading-atomic-css-vs-traditional-css">Atomic CSS vs. Traditional CSS</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Aspect</td><td>Atomic CSS</td><td>Traditional CSS</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Class Naming</strong></td><td>Single-purpose, functional</td><td>Semantic, content-based</td></tr>
<tr>
<td><strong>Modularity</strong></td><td>High</td><td>Moderate</td></tr>
<tr>
<td><strong>Performance</strong></td><td>Optimized, smaller CSS files</td><td>Potentially larger, complex selectors</td></tr>
<tr>
<td><strong>Readability</strong></td><td>Verbose HTML, clear class functions</td><td>Readable HTML, complex CSS rules</td></tr>
<tr>
<td><strong>Scalability</strong></td><td>Highly scalable for large projects</td><td>Challenging in large projects</td></tr>
<tr>
<td><strong>Predictability</strong></td><td>High, due to single responsibility principle</td><td>Moderate, potential for specificity conflicts</td></tr>
<tr>
<td><strong>Collaboration</strong></td><td>Enhanced, common styling language</td><td>Moderate, depends on team practices</td></tr>
<tr>
<td><strong>Learning Curve</strong></td><td>Steep for those new to the methodology</td><td>Lower, well-established practices</td></tr>
</tbody>
</table>
</div><h3 id="heading-atomic-vs-css-paradigms">Atomic vs. CSS paradigms</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Paradigm</td><td>Description</td><td>Structure/Principles</td><td>Example</td><td>Key Benefits</td><td>Drawbacks</td><td>Common Use Cases</td></tr>
</thead>
<tbody>
<tr>
<td><a target="_blank" href="https://getbem.com/introduction/"><strong>BEM</strong></a></td><td>Block Element Modifier methodology for creating reusable components.</td><td>Block, Element, Modifier</td><td><code>.menu { } .menu__item { } .menu__item--active { }</code></td><td>Consistency, reusability, modularity</td><td>Can become verbose, naming conventions required</td><td>Component-based design, large projects</td></tr>
<tr>
<td><a target="_blank" href="http://oocss.org"><strong>OOCSS</strong></a></td><td>Object-Oriented CSS separates structure and skin for reusable visual objects.</td><td>Separation of Structure and Skin, Separation of Container and Content</td><td><code>.box { width: 200px; padding: 10px; } .box-blue { background-color: blue; }</code></td><td>Reusability, modularity, maintainability</td><td>Can lead to more complex HTML structure</td><td>Large-scale applications</td></tr>
<tr>
<td><a target="_blank" href="http://smacss.com"><strong>SMACSS</strong></a></td><td>Scalable and Modular Architecture for CSS, focusing on consistent and modular styles.</td><td>Base, Layout, Module, State, Theme</td><td><code>.m-button { } .l-header { } .is-active { }</code></td><td>Scalability, modularity, ease of maintenance</td><td>Can be complex to implement initially</td><td>Large-scale applications, complex projects</td></tr>
<tr>
<td><a target="_blank" href="https://developer.helpscout.com/seed/glossary/itcss/"><strong>ITCSS</strong></a></td><td>Inverted Triangle CSS architecture that promotes a hierarchy for specificity and cascade.</td><td>Settings, Tools, Generic, Elements, Objects, Components, Utilities</td><td><code>:root { --primary-color: #333; } .c-button { padding: 10px 20px; }</code></td><td>Scalability, maintainability, specificity control</td><td>Initial setup can be complex</td><td>Large-scale applications</td></tr>
<tr>
<td><strong>Atomic CSS</strong></td><td>Style sheet architecture using small, specific classes for styling.</td><td>Single responsibility, reusability, consistency</td><td><code>.text-center { text-align: center; } .bg-blue { background-color: blue; }</code></td><td>Reusability, maintainability, encapsulation</td><td>Increased HTML verbosity, learning curve</td><td>Large-scale applications, rapid prototyping</td></tr>
<tr>
<td><a target="_blank" href="https://www.geeksforgeeks.org/inline-css/"><strong>CSS-in-JS</strong></a></td><td>Writing CSS in JavaScript, often used in modern frameworks like React.</td><td>Scoped styles, dynamic styles</td><td><code>const buttonStyle = { padding: '10px 20px', backgroundColor: 'blue' };</code></td><td>Scoped styles, dynamic styling, modularity</td><td>Can lead to larger bundle sizes</td><td>Modern web development, React, Vue</td></tr>
<tr>
<td><strong>Functional CSS (Different name but it is the same as Atomic CSS)</strong></td><td>Focused on using utility classes for functions rather than single properties.</td><td>Utility-first classes</td><td><code>&lt;div class="p-4 m-2 bg-blue text-white"&gt;Functional CSS Example&lt;/div&gt;</code></td><td>Reusability, consistency, maintainability</td><td>Increased HTML verbosity, can be verbose</td><td>Rapid prototyping, large-scale applications</td></tr>
<tr>
<td><a target="_blank" href="https://www.w3schools.com/css/css_rwd_intro.asp"><strong>Responsive CSS</strong></a></td><td>Technique for making websites work on different screen sizes and devices.</td><td>Media queries, flexible layouts</td><td><code>.container { width: 100%; } @media (min-width: 600px) { .container { width: 50%; } }</code></td><td>Flexibility, adaptability</td><td>Requires careful planning and testing</td><td>Any web development</td></tr>
<tr>
<td><a target="_blank" href="https://envylabs.com/insights/comparing-component-and-atomic-css/"><strong>Component-Based CSS</strong></a></td><td>CSS written specifically for components, often in frameworks like React, Vue, or Angular.</td><td>Scoped styles, modularity</td><td><code>import styles from './Button.module.css'; function Button() { return &lt;button className={styles.button}&gt;Click me&lt;/button&gt;; }</code></td><td>Scoped styles, modularity, maintainability</td><td>Can lead to fragmented styling approaches</td><td>Modern web development, React, Vue</td></tr>
</tbody>
</table>
</div><h2 id="heading-conclusion">Conclusion</h2>
<p>In summary, Atomic CSS is a powerful approach to CSS architecture that offers numerous benefits in terms of modularity, performance, and maintainability. However, it also comes with its own set of challenges, particularly in terms of verbosity and the initial learning curve.</p>
<h3 id="heading-where-to-read-more">Where to Read More</h3>
<ul>
<li><p>"<a target="_blank" href="https://johnpolacek.medium.com/by-the-numbers-a-year-and-half-with-atomic-css-39d75b1263b4">By The Numbers: A Year and Half with Atomic CSS</a><strong>"</strong></p>
</li>
<li><p>"<a target="_blank" href="https://frontstuff.io/no-utility-classes-arent-the-same-as-inline-styles">No, Utility Classes Aren't the Same As Inline Styles</a><strong>"</strong></p>
</li>
</ul>
<h3 id="heading-related-articles">Related Articles</h3>
<ul>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/learn-react-hooks">Learn React Basics: React Hooks</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/comparing-modern-javascript-testing-frameworks-jest-mocha-and-vitest">Comparing Modern JavaScript Testing Frameworks: Jest, Mocha, and Vitest</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/comparing-react-angular-vue-and-svelte-a-guide-for-developers">Comparing React, Angular, Vue, and Svelte: A Guide for Developers</a>"</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Mastering the Merging of Overlapping Intervals in Python]]></title><description><![CDATA[Introduction
Merging overlapping intervals is a common problem in computer science, frequently encountered in tasks such as scheduling, calendar management, and data consolidation. The challenge lies in efficiently combining intervals that overlap, e...]]></description><link>https://blog.seancoughlin.me/mastering-the-merging-of-overlapping-intervals-in-python</link><guid isPermaLink="true">https://blog.seancoughlin.me/mastering-the-merging-of-overlapping-intervals-in-python</guid><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[array]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[interview]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Tue, 02 Jul 2024 18:35:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719945257830/cff59b6a-a369-42c0-ae3c-b671c319d024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p><a target="_blank" href="https://leetcode.com/problems/merge-intervals/description/">Merging overlapping intervals</a> is a common problem in computer science, frequently encountered in tasks such as scheduling, calendar management, and data consolidation. The challenge lies in efficiently combining intervals that overlap, ensuring that all intervals are covered without redundancy.</p>
<p>In this article, we will explore a step-by-step solution to this problem using Python, optimizing for performance and accuracy.</p>
<h3 id="heading-understanding-the-problem">Understanding the Problem</h3>
<blockquote>
<p>Given an array of <code>intervals</code> where <code>intervals[i] = [start&lt;sub&gt;i&lt;/sub&gt;, end&lt;sub&gt;i&lt;/sub&gt;]</code>, merge all overlapping intervals, and return <em>an array of the non-overlapping intervals that cover all the intervals in the input</em>.</p>
<p><strong>Example 1:</strong></p>
<pre><code class="lang-plaintext">Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlap, merge them into [1,6].
</code></pre>
<p><strong>Example 2:</strong></p>
<pre><code class="lang-plaintext">Input: intervals = [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considered overlapping.
</code></pre>
<p><strong>Constraints:</strong></p>
<ul>
<li><p><code>1 &lt;= intervals.length &lt;= 10&lt;sup&gt;4&lt;/sup&gt;</code></p>
</li>
<li><p><code>intervals[i].length == 2</code></p>
</li>
<li><p><code>0 &lt;= start&lt;sub&gt;i&lt;/sub&gt; &lt;= end&lt;sub&gt;i&lt;/sub&gt; &lt;= 10&lt;sup&gt;4&lt;/sup&gt;</code></p>
</li>
</ul>
</blockquote>
<h2 id="heading-initial-approach-and-challenges">Initial Approach and Challenges</h2>
<p>A naive approach to solving this problem might involve checking each pair of intervals for overlaps and merging them if necessary. However, this method is inefficient, especially for large datasets, as it involves multiple nested iterations. Thus, a more efficient algorithm is required.</p>
<h3 id="heading-efficient-solution-sorting-and-merging">Efficient Solution: Sorting and Merging</h3>
<p>To merge overlapping intervals efficiently, we can follow these steps:</p>
<ol>
<li><p><strong>Sort the Intervals</strong>: Start by sorting the list of intervals by their starting points. This simplifies the process of finding overlaps.</p>
</li>
<li><p><strong>Merge Intervals</strong>: Iterate through the sorted intervals and merge them if they overlap. If the current interval overlaps with the last merged interval, extend the last merged interval. Otherwise, add the current interval to the list of merged intervals.</p>
</li>
</ol>
<h2 id="heading-detailed-step-by-step-solution-in-python">Detailed Step-by-Step Solution in Python</h2>
<p>Here's the Python code to achieve this:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> List

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">merge</span>(<span class="hljs-params">intervals: List[List[int]]</span>) -&gt; List[List[int]]:</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> intervals:
        <span class="hljs-keyword">return</span> []

    <span class="hljs-comment"># Sort the intervals based on the starting points</span>
    intervals.sort(key=<span class="hljs-keyword">lambda</span> x: x[<span class="hljs-number">0</span>])

    merged_intervals = [intervals[<span class="hljs-number">0</span>]]

    <span class="hljs-keyword">for</span> current <span class="hljs-keyword">in</span> intervals[<span class="hljs-number">1</span>:]:
        last_merged = merged_intervals[<span class="hljs-number">-1</span>]

        <span class="hljs-comment"># If the current interval overlaps with the last merged interval, merge them</span>
        <span class="hljs-keyword">if</span> current[<span class="hljs-number">0</span>] &lt;= last_merged[<span class="hljs-number">1</span>]:
            last_merged[<span class="hljs-number">1</span>] = max(last_merged[<span class="hljs-number">1</span>], current[<span class="hljs-number">1</span>])
        <span class="hljs-keyword">else</span>:
            <span class="hljs-comment"># Otherwise, add the current interval to the merged list</span>
            merged_intervals.append(current)

    <span class="hljs-keyword">return</span> merged_intervals

<span class="hljs-comment"># Example 1</span>
intervals1 = [[<span class="hljs-number">1</span>, <span class="hljs-number">3</span>], [<span class="hljs-number">2</span>, <span class="hljs-number">6</span>], [<span class="hljs-number">8</span>, <span class="hljs-number">10</span>], [<span class="hljs-number">15</span>, <span class="hljs-number">18</span>]]
print(merge(intervals1))  <span class="hljs-comment"># Output: [[1, 6], [8, 10], [15, 18]]</span>

<span class="hljs-comment"># Example 2</span>
intervals2 = [[<span class="hljs-number">1</span>, <span class="hljs-number">4</span>], [<span class="hljs-number">4</span>, <span class="hljs-number">5</span>]]
print(merge(intervals2))  <span class="hljs-comment"># Output: [[1, 5]]</span>
</code></pre>
<h3 id="heading-time-and-space-complexity-analysis">Time and Space Complexity Analysis</h3>
<ul>
<li><p><strong>Time Complexity</strong>: The time complexity of this solution is <code>O(n log n)</code> due to the sorting step, where <code>n</code> is the number of intervals. The merging process itself takes <code>O(n)</code> time. Thus, the overall time complexity is dominated by the sorting step.</p>
</li>
<li><p><strong>Space Complexity</strong>: The space complexity is <code>O(n)</code> in the worst case, where all intervals are added to the merged list without any overlaps.</p>
</li>
</ul>
<h3 id="heading-edge-cases-and-testing">Edge Cases and Testing</h3>
<p>When implementing this solution, it's essential to consider and handle edge cases:</p>
<ol>
<li><p><strong>Empty Input</strong>: If the input list is empty, the function should return an empty list.</p>
</li>
<li><p><strong>Single Interval</strong>: If there is only one interval, it should be returned as is.</p>
</li>
<li><p><strong>Fully Overlapping Intervals</strong>: Intervals that completely overlap should be merged into a single interval.</p>
</li>
</ol>
<h3 id="heading-practical-applications">Practical Applications</h3>
<p>Understanding how to merge overlapping intervals can be beneficial in various domains:</p>
<ul>
<li><p><strong>Calendar Management</strong>: Combining overlapping meeting times into a single time slot.</p>
</li>
<li><p><strong>Data Consolidation</strong>: Merging overlapping data ranges in financial reports or log files.</p>
</li>
<li><p><strong>Scheduling Tasks</strong>: Ensuring tasks are scheduled without conflicts in time slots.</p>
</li>
</ul>
<h2 id="heading-faq-section">FAQ Section</h2>
<p><strong>Q1: What is the primary benefit of sorting intervals before merging?</strong></p>
<p><strong>A1:</strong> Sorting intervals by their starting points simplifies the merging process, allowing us to efficiently identify and merge overlapping intervals in a single pass.</p>
<p><strong>Q2: Can this algorithm be adapted for intervals with different types of data?</strong></p>
<p><strong>A2:</strong> Yes, the algorithm can be adapted for any type of data that can be compared and sorted based on their starting points.</p>
<p><strong>Q3: How can we handle intervals represented in different formats?</strong></p>
<p><strong>A3:</strong> The algorithm can be adjusted to handle different interval formats by converting them into a standard format before processing.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Merging overlapping intervals is a fundamental problem with numerous practical applications. By leveraging sorting and efficient merging techniques, we can solve this problem optimally. The Python solution provided in this article ensures accurate results and optimal performance.</p>
<p>Practicing this solution and understanding its nuances can greatly benefit software engineers in handling real-world data consolidation tasks.</p>
<h3 id="heading-related-articles">Related Articles</h3>
<ul>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/getting-started-with-studying-for-software-engineering-interviews-using-leetcode">Getting Started with Studying for Software Engineering Interviews Using LeetCode</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/mastering-leetcodes-insert-interval-a-comprehensive-guide?source=more_series_bottom_blogs">Mastering LeetCode's "Insert Interval": A Comprehensive Guide</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/mastering-leetcode-the-ultimate-guide-to-solving-contains-duplicate">Mastering LeetCode: The Ultimate Guide to Solving "Contains Duplicate</a>""</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Mastering LeetCode: Solving the Lowest Common Ancestor of a Binary Tree Problem]]></title><description><![CDATA[Solving the Lowest Common Ancestor of a Binary Tree on LeetCode
Introduction
Finding the Lowest Common Ancestor (LCA) of two nodes in a binary tree is a classic problem often encountered in coding interviews and algorithm studies. Understanding how t...]]></description><link>https://blog.seancoughlin.me/mastering-leetcode-solving-the-lowest-common-ancestor-of-a-binary-tree-problem</link><guid isPermaLink="true">https://blog.seancoughlin.me/mastering-leetcode-solving-the-lowest-common-ancestor-of-a-binary-tree-problem</guid><category><![CDATA[leetcode]]></category><category><![CDATA[leetcode-solution]]></category><category><![CDATA[Python]]></category><category><![CDATA[Graph]]></category><category><![CDATA[algorithms]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Tue, 02 Jul 2024 16:23:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719937302256/dcc84b35-d5e2-40d8-99e7-9dd0f3f1e74c.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-solving-the-lowest-common-ancestor-of-a-binary-tree-on-leetcode">Solving the Lowest Common Ancestor of a Binary Tree on LeetCode</h2>
<h2 id="heading-introduction">Introduction</h2>
<p><a target="_blank" href="https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/">Finding the Lowest Common Ancestor (LCA)</a> of two nodes in a binary tree is a classic problem often encountered in coding interviews and algorithm studies. Understanding how to solve this problem not only improves your problem-solving skills but also deepens your understanding of binary trees and recursive algorithms.</p>
<p>In this article, we will explore the problem, discuss a recursive approach to solving it, and implement the solution in Python.</p>
<h3 id="heading-understanding-the-problem">Understanding the Problem</h3>
<blockquote>
<p>Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.</p>
<p>According to the <a target="_blank" href="https://en.wikipedia.org/wiki/Lowest_common_ancestor">definition of LCA on Wikipedia: “The lowest common ancesto</a>r is defined between two nodes <code>p</code> and <code>q</code> as the lowest node in <code>T</code>that has both <code>p</code> and <code>q</code> as descendants (where we allow <strong>a node to be a descendant of itself</strong>).”</p>
<p><strong>Example 1:</strong></p>
<p><img src="https://assets.leetcode.com/uploads/2018/12/14/binarytree.png" alt /></p>
<pre><code class="lang-plaintext">Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output: 3
Explanation: The LCA of nodes 5 and 1 is 3.
</code></pre>
<p><strong>Example 2:</strong></p>
<p><img src="https://assets.leetcode.com/uploads/2018/12/14/binarytree.png" alt /></p>
<pre><code class="lang-plaintext">Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Output: 5
Explanation: The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.
</code></pre>
<p><strong>Example 3:</strong></p>
<pre><code class="lang-plaintext">Input: root = [1,2], p = 1, q = 2
Output: 1
</code></pre>
<p><strong>Constraints:</strong></p>
<ul>
<li><p>The number of nodes in the tree is in the range <code>[2, 10^5]</code>.</p>
</li>
<li><p><code>-10^9 &lt;= Node.val &lt;= 10^9</code></p>
</li>
<li><p>All <code>Node.val</code> are <strong>unique</strong>.</p>
</li>
<li><p><code>p != q</code></p>
</li>
<li><p><code>p</code> and <code>q</code> will exist in the tree.</p>
</li>
</ul>
</blockquote>
<h2 id="heading-recursive-depth-first-search-approach">Recursive Depth-First Search Approach</h2>
<p>To solve the problem, we can use a recursive depth-first search (DFS) approach. Here's the step-by-step strategy:</p>
<h4 id="heading-base-case">Base Case</h4>
<p>The base case of the recursion checks if the current node is <code>None</code>. If it is, we return <code>None</code>, indicating that we have reached the end of a branch without finding <code>p</code> or <code>q</code>.</p>
<h4 id="heading-match-case">Match Case</h4>
<p>If the current node is either <code>p</code> or <code>q</code>, we return the current node. This indicates that we have found one of the nodes we are looking for.</p>
<h4 id="heading-recursive-search">Recursive Search</h4>
<p>We recursively search the left and right subtrees of the current node. If both left and right recursive calls return non-<code>None</code> values, it means <code>p</code> and <code>q</code> are found in different subtrees, making the current node the LCA. If only one of the recursive calls returns a non-<code>None</code> value, it means both <code>p</code> and <code>q</code> are located in the same subtree, and we return the non-<code>None</code> result.</p>
<h3 id="heading-implementing-the-solution-in-python">Implementing the Solution in Python</h3>
<p>Here’s the Python implementation of the recursive DFS approach:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> Optional

<span class="hljs-comment"># Definition for a binary tree node.</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TreeNode</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, val: int = <span class="hljs-number">0</span>, left: Optional[<span class="hljs-string">'TreeNode'</span>] = None, right: Optional[<span class="hljs-string">'TreeNode'</span>] = None</span>):</span>
        self.val = val
        self.left = left
        self.right = right

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">lowestCommonAncestor</span>(<span class="hljs-params">self, root: Optional[TreeNode], p: TreeNode, q: TreeNode</span>) -&gt; Optional[TreeNode]:</span>
        <span class="hljs-comment"># Base case: if root is None, there's no LCA</span>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> root:
            <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>

        <span class="hljs-comment"># If the current node is either p or q, return it</span>
        <span class="hljs-keyword">if</span> root == p <span class="hljs-keyword">or</span> root == q:
            <span class="hljs-keyword">return</span> root

        <span class="hljs-comment"># Recursively search the left and right subtrees</span>
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)

        <span class="hljs-comment"># If both left and right are non-None, current node is the LCA</span>
        <span class="hljs-keyword">if</span> left <span class="hljs-keyword">and</span> right:
            <span class="hljs-keyword">return</span> root

        <span class="hljs-comment"># Otherwise, return non-None value from left or right</span>
        <span class="hljs-keyword">return</span> left <span class="hljs-keyword">if</span> left <span class="hljs-keyword">else</span> right
</code></pre>
<h3 id="heading-explanation-of-the-code">Explanation of the Code</h3>
<ul>
<li><p><strong>Base Case</strong>: The check <code>if not root</code> ensures we return <code>None</code> if the current node is <code>None</code>, indicating the end of a branch.</p>
</li>
<li><p><strong>Match Case</strong>: The check <code>if root == p or root == q</code> returns the current node if it matches either <code>p</code> or <code>q</code>.</p>
</li>
<li><p><strong>Recursive Search</strong>: The recursive calls <code>left = self.lowestCommonAncestor(root.left, p, q)</code> and <code>right = self.lowestCommonAncestor(root.right, p, q)</code> search for <code>p</code> and <code>q</code> in the left and right subtrees.</p>
</li>
<li><p><strong>Determine LCA</strong>: The check <code>if left and right</code> returns the current node as the LCA if both recursive calls are non-<code>None</code>. Otherwise, it returns the non-<code>None</code> result from the left or right subtree.</p>
</li>
</ul>
<h4 id="heading-edge-cases-and-considerations">Edge Cases and Considerations</h4>
<ul>
<li><p>If <code>p</code> and <code>q</code> are the same node, the algorithm correctly returns that node as the LCA.</p>
</li>
<li><p>The solution assumes that both <code>p</code> and <code>q</code> exist in the tree, as specified in the problem constraints.</p>
</li>
</ul>
<h2 id="heading-faq-section">FAQ Section</h2>
<h4 id="heading-what-is-the-time-complexity-of-the-solution">What is the time complexity of the solution?</h4>
<p>The time complexity of the solution is <code>O(N)</code>, where <code>N</code> is the number of nodes in the tree. This is because, in the worst case, the algorithm may need to traverse all the nodes in the tree.</p>
<h4 id="heading-can-this-solution-be-adapted-for-a-non-binary-tree">Can this solution be adapted for a non-binary tree?</h4>
<p>Yes, the solution can be adapted for a non-binary tree. However, the recursive search would need to be modified to iterate over all children of a node instead of just left and right children.</p>
<h4 id="heading-what-are-some-common-mistakes-to-avoid">What are some common mistakes to avoid?</h4>
<ul>
<li><p>Not handling the case where one of the nodes is <code>None</code>.</p>
</li>
<li><p>Assuming that the nodes <code>p</code> and <code>q</code> are always different and exist in the tree without checking for it.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Understanding and implementing the Lowest Common Ancestor problem in a binary tree is a valuable exercise in recursive problem-solving and binary tree traversal. By using a recursive depth-first search approach, we can efficiently find the LCA of two nodes, ensuring our solution is both correct and optimal.</p>
<p>Practice similar problems to further strengthen your grasp of these concepts.</p>
<h3 id="heading-related-articles">Related Articles</h3>
<ul>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/mastering-leetcodes-lowest-common-ancestor-in-a-bst-a-comprehensive-guide">Mastering LeetCode's "Lowest Common Ancestor in a BST": A Comprehensive Guide</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/mastering-the-backspace-string-compare-on-leetcode-a-comprehensive-guide">Mastering the Backspace String Compare on LeetCode: A Comprehensive Guide</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/mastering-leetcode-counting-the-number-of-islands-in-a-2d-binary-grid"><strong>Mastering LeetCode: Counting the Number of Islands in a 2D Binary Grid</strong></a><strong>"</strong></p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/getting-started-with-studying-for-software-engineering-interviews-using-leetcode">Getting Started with Studying for Software Engineering Interviews Using LeetCode</a>"</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Mastering LeetCode: Generating All Permutations of an Array]]></title><description><![CDATA[Introduction
Generating permutations is a fundamental problem in computer science, often appearing in coding interviews and algorithm challenges. Understanding how to efficiently generate permutations can provide insights into various combinatorial p...]]></description><link>https://blog.seancoughlin.me/mastering-leetcode-generating-all-permutations-of-an-array</link><guid isPermaLink="true">https://blog.seancoughlin.me/mastering-leetcode-generating-all-permutations-of-an-array</guid><category><![CDATA[Python]]></category><category><![CDATA[interview]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[Recursion]]></category><category><![CDATA[algorithms]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Mon, 01 Jul 2024 15:29:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719847285146/b9ceccfc-15ab-415e-bdbc-6da9b861155f.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p><a target="_blank" href="https://leetcode.com/problems/permutations/description/">Generating permutations</a> is a fundamental problem in computer science, often appearing in coding interviews and algorithm challenges. Understanding how to efficiently generate permutations can provide insights into various combinatorial problems and improve your problem-solving skills.</p>
<p>In this article, we'll explore the "Permutations" problem on LeetCode and solve it using a backtracking approach.</p>
<h3 id="heading-leetcode-problem-statement">LeetCode Problem Statement:</h3>
<blockquote>
<p>Given an array <code>nums</code> of distinct integers, return <em>all the possible permutations</em>. You can return the answer in <strong>any order</strong>.</p>
<p><strong>Example 1:</strong></p>
<pre><code class="lang-plaintext">Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
</code></pre>
<p><strong>Example 2:</strong></p>
<pre><code class="lang-plaintext">Input: nums = [0,1]
Output: [[0,1],[1,0]]
</code></pre>
<p><strong>Example 3:</strong></p>
<pre><code class="lang-plaintext">Input: nums = [1]
Output: [[1]]
</code></pre>
<p><strong>Constraints:</strong></p>
<ul>
<li><p><code>1 &lt;= nums.length &lt;= 6</code></p>
</li>
<li><p><code>-10 &lt;= nums[i] &lt;= 10</code></p>
</li>
<li><p>All the integers of <code>nums</code> are <strong>unique</strong>.</p>
</li>
</ul>
</blockquote>
<h2 id="heading-understanding-permutations">Understanding Permutations</h2>
<p>Permutations refer to all possible arrangements of a set of elements. For an array of <code>n</code> distinct elements, there are <code>n!</code> (n factorial) possible permutations. Generating these permutations is useful in various applications, including solving puzzles, optimizing routes, and more.</p>
<h2 id="heading-solution-approach">Solution Approach</h2>
<p>To solve the permutations problem, we'll use a backtracking approach. <a target="_blank" href="https://en.wikipedia.org/wiki/Backtracking">Backtracking</a> is an algorithmic technique for solving recursive problems by trying to build a solution incrementally and removing solutions that fail to satisfy the problem constraints.</p>
<h2 id="heading-detailed-solution-breakdown">Detailed Solution Breakdown</h2>
<h3 id="heading-step-1-function-definition">Step 1: Function Definition</h3>
<p>We'll start by defining the main function <code>permute</code> that will take the list of integers <code>nums</code> as input and return a list of lists containing all possible permutations.</p>
<h3 id="heading-step-2-helper-function">Step 2: Helper Function</h3>
<p>We'll define a helper function <code>backtrack</code> that will be used to generate permutations by swapping elements. This function will take the current position <code>start</code> as an argument.</p>
<h3 id="heading-step-3-swapping-elements">Step 3: Swapping Elements</h3>
<p>In the <code>backtrack</code> function, we'll loop through the elements starting from the <code>start</code> index to the end of the list. For each index <code>i</code>, we'll swap the elements at indices <code>start</code> and <code>i</code>, recursively call <code>backtrack</code> with the next position <code>start + 1</code>, and then swap the elements back to their original positions.</p>
<h3 id="heading-code-implementation">Code Implementation</h3>
<p>Here's the complete Python code for generating permutations:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> List

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">permute</span>(<span class="hljs-params">nums: List[int]</span>) -&gt; List[List[int]]:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">backtrack</span>(<span class="hljs-params">start: int</span>):</span>
        <span class="hljs-keyword">if</span> start == len(nums):
            result.append(nums[:])
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(start, len(nums)):
            nums[start], nums[i] = nums[i], nums[start]  <span class="hljs-comment"># swap</span>
            backtrack(start + <span class="hljs-number">1</span>)
            nums[start], nums[i] = nums[i], nums[start]  <span class="hljs-comment"># swap back</span>

    result = []
    backtrack(<span class="hljs-number">0</span>)
    <span class="hljs-keyword">return</span> result

<span class="hljs-comment"># Test cases</span>
print(permute([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]))  <span class="hljs-comment"># Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]</span>
print(permute([<span class="hljs-number">0</span>, <span class="hljs-number">1</span>]))    <span class="hljs-comment"># Output: [[0,1],[1,0]]</span>
print(permute([<span class="hljs-number">1</span>]))       <span class="hljs-comment"># Output: [[1]]</span>
</code></pre>
<h3 id="heading-explanation-of-the-code">Explanation of the Code</h3>
<ol>
<li><p><strong>Function Definition</strong>:</p>
<ul>
<li>The <code>permute</code> function takes a list <code>nums</code> and returns a list of lists containing all permutations.</li>
</ul>
</li>
<li><p><strong>Backtracking Function</strong>:</p>
<ul>
<li><p>We define a nested function <code>backtrack</code> that takes the current position <code>start</code> as an argument.</p>
</li>
<li><p>If <code>start</code> equals the length of <code>nums</code>, we've reached a complete permutation, so we append a copy of <code>nums</code> to the <code>result</code> list.</p>
</li>
</ul>
</li>
<li><p><strong>Swapping Elements</strong>:</p>
<ul>
<li><p>We loop through the elements starting from the <code>start</code> index.</p>
</li>
<li><p>For each index <code>i</code>, we swap the elements at indices <code>start</code> and <code>i</code>.</p>
</li>
<li><p>We recursively call <code>backtrack</code> with <code>start + 1</code>.</p>
</li>
<li><p>After the recursive call, we swap the elements back to their original positions.</p>
</li>
</ul>
</li>
<li><p><strong>Result Storage</strong>:</p>
<ul>
<li><p>We initialize an empty list <code>result</code> to store all permutations.</p>
</li>
<li><p>We call <code>backtrack</code> starting from index 0.</p>
</li>
<li><p>Finally, we return the <code>result</code> list containing all permutations.</p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719847629932/4ea1b1a3-4fbf-44a5-8717-c9ad0306b077.png" alt="hart showing the recursive calls and swaps.  Alt Text: &quot;Flowchart of recursive calls and element swaps in the backtracking algorithm." class="image--center mx-auto" /></p>
<h2 id="heading-time-complexity-analysis">Time Complexity Analysis</h2>
<p>The time complexity of this solution is O(n * n!), where <code>n</code> is the length of the input list. This is because there are <code>n!</code> permutations, and we need to copy each permutation of length <code>n</code> to the result list. Given the constraint (1 &lt;= nums.length &lt;= 6), this complexity is acceptable.</p>
<h2 id="heading-common-questions-and-pitfalls">Common Questions and Pitfalls</h2>
<h3 id="heading-q1-what-is-the-maximum-length-of-the-input-list">Q1: What is the maximum length of the input list?</h3>
<ul>
<li>A1: The length of the input list is between 1 and 6.</li>
</ul>
<h3 id="heading-q2-are-duplicate-elements-allowed-in-the-input-list">Q2: Are duplicate elements allowed in the input list?</h3>
<ul>
<li>A2: No, all integers in the input list are unique.</li>
</ul>
<h3 id="heading-q3-why-use-backtracking-for-this-problem">Q3: Why use backtracking for this problem?</h3>
<ul>
<li>A3: Backtracking efficiently explores all possible permutations by making choices and undoing them when necessary.</li>
</ul>
<h2 id="heading-faq-section">FAQ Section</h2>
<h3 id="heading-what-is-the-maximum-length-of-the-input-list">What is the maximum length of the input list?</h3>
<p>The input list can have a length between 1 and 6.</p>
<h3 id="heading-are-duplicate-elements-allowed-in-the-input-list">Are duplicate elements allowed in the input list?</h3>
<p>No, all integers in the input list must be unique.</p>
<h3 id="heading-why-use-backtracking-for-this-problem">Why use backtracking for this problem?</h3>
<p>Backtracking is efficient for generating all permutations by making choices and backtracking to previous states when necessary.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Generating permutations is a classic problem that can be efficiently solved using a backtracking approach. By understanding and implementing the solution step-by-step, you can enhance your problem-solving skills and tackle similar combinatorial problems with confidence.</p>
<p>Practice more permutation problems to deepen your understanding and improve your coding abilities.</p>
<h3 id="heading-related-articles">Related Articles</h3>
<ul>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/conquer-the-binary-search-mastering-leetcodes-rotated-sorted-array-challenge">Conquer the Binary Search: Mastering LeetCode’s Rotated Sorted Array Challenge</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/solving-leetcodes-combination-sum-problem-optimized-techniques-for-efficient-solutions">Solving LeetCode's Combination Sum Problem: Optimized Techniques for Efficient Solutions</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/getting-started-with-studying-for-software-engineering-interviews-using-leetcode">Getting Started with Studying for Software Engineering Interviews Using LeetCode</a>"</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Conquer the Binary Search: Mastering LeetCode’s Rotated Sorted Array Challenge]]></title><description><![CDATA[Introduction
Leetcode problems are a staple in coding interviews, challenging developers to optimize their problem-solving skills. One particularly intriguing problem involves finding an element in a rotated sorted array.
This task not only tests you...]]></description><link>https://blog.seancoughlin.me/conquer-the-binary-search-mastering-leetcodes-rotated-sorted-array-challenge</link><guid isPermaLink="true">https://blog.seancoughlin.me/conquer-the-binary-search-mastering-leetcodes-rotated-sorted-array-challenge</guid><category><![CDATA[Python]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[leetcode-solution]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[interview]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Mon, 01 Jul 2024 14:25:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719843152564/ea1d632b-c10f-499d-bfc6-d20c2c33ba13.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>Leetcode problems are a staple in coding interviews, challenging developers to optimize their problem-solving skills. One particularly intriguing problem <a target="_blank" href="https://leetcode.com/problems/search-in-rotated-sorted-array/description/">involves finding an element in a rotated sorted array</a>.</p>
<p>This task not only tests your understanding of <a target="_blank" href="https://en.wikipedia.org/wiki/Binary_search">binary search</a> but also your ability to adapt this algorithm to more complex scenarios.</p>
<p>In this article, we will walk through the problem statement, explore the logic behind the solution, and provide a step-by-step guide to implementing it in Python.</p>
<h3 id="heading-understanding-the-problem">Understanding the Problem</h3>
<p>The problem is as follows:</p>
<blockquote>
<p>There is an integer array <code>nums</code> sorted in ascending order (with <strong>distinct</strong> values).</p>
<p>Prior to being passed to your function, <code>nums</code> is <strong>possibly rotated</strong> at an unknown pivot index <code>k</code> (<code>1 &lt;= k &lt; nums.length</code>) such that the resulting array is <code>[nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]</code> (<strong>0-indexed</strong>). For example, <code>[0,1,2,4,5,6,7]</code> might be rotated at pivot index <code>3</code> and become <code>[4,5,6,7,0,1,2]</code>.</p>
<p>Given the array <code>nums</code> <strong>after</strong> the possible rotation and an integer <code>target</code>, return <em>the index of</em> <code>target</code> <em>if it is in</em> <code>nums</code><em>, or</em> <code>-1</code> <em>if it is not in</em> <code>nums</code>.</p>
<p>You must write an algorithm with <code>O(log n)</code> runtime complexity.</p>
<p><strong>Example 1:</strong></p>
<pre><code class="lang-plaintext">Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
</code></pre>
<p><strong>Example 2:</strong></p>
<pre><code class="lang-plaintext">Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1
</code></pre>
<p><strong>Example 3:</strong></p>
<pre><code class="lang-plaintext">Input: nums = [1], target = 0
Output: -1
</code></pre>
<p><strong>Constraints:</strong></p>
<ul>
<li><p><code>1 &lt;= nums.length &lt;= 5000</code></p>
</li>
<li><p><code>-10&lt;sup&gt;4&lt;/sup&gt; &lt;= nums[i] &lt;= 10&lt;sup&gt;4&lt;/sup&gt;</code></p>
</li>
<li><p>All values of <code>nums</code> are <strong>unique</strong>.</p>
</li>
<li><p><code>nums</code> is an ascending array that is possibly rotated.</p>
</li>
<li><p><code>-10&lt;sup&gt;4&lt;/sup&gt; &lt;= target &lt;= 10&lt;sup&gt;4&lt;/sup&gt;</code></p>
</li>
</ul>
</blockquote>
<h3 id="heading-the-approach-leveraging-binary-search">The Approach: Leveraging Binary Search</h3>
<p>To solve this problem with <code>O(log n)</code> runtime complexity, we need to leverage the binary search algorithm. The key challenge is to determine which part of the array is properly sorted, allowing us to effectively narrow down our search space.</p>
<h3 id="heading-step-by-step-solution">Step-by-Step Solution</h3>
<p>Let's dive into the implementation details.</p>
<h4 id="heading-initialize-variables">Initialize Variables</h4>
<p>First, we initialize two pointers, <code>left</code> and <code>right</code>, to represent the start and end of the array, respectively.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> List

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">search</span>(<span class="hljs-params">nums: List[int], target: int</span>) -&gt; int:</span>
    left, right = <span class="hljs-number">0</span>, len(nums) - <span class="hljs-number">1</span>
</code></pre>
<h4 id="heading-binary-search-loop">Binary Search Loop</h4>
<p>Next, we enter a loop that continues as long as <code>left</code> is less than or equal to <code>right</code>.</p>
<pre><code class="lang-python">    <span class="hljs-keyword">while</span> left &lt;= right:
        mid = (left + right) // <span class="hljs-number">2</span>
</code></pre>
<h4 id="heading-check-for-target-at-midpoint">Check for Target at Midpoint</h4>
<p>We check if the midpoint element is the target. If it is, we return the index.</p>
<pre><code class="lang-python">        <span class="hljs-keyword">if</span> nums[mid] == target:
            <span class="hljs-keyword">return</span> mid
</code></pre>
<h4 id="heading-determine-which-part-is-sorted">Determine Which Part is Sorted</h4>
<p>We determine which part of the array is sorted by comparing the values at the <code>left</code>, <code>mid</code>, and <code>right</code> indices.</p>
<pre><code class="lang-python">        <span class="hljs-keyword">if</span> nums[left] &lt;= nums[mid]:
            <span class="hljs-comment"># Left part is sorted</span>
            <span class="hljs-keyword">if</span> nums[left] &lt;= target &lt; nums[mid]:
                right = mid - <span class="hljs-number">1</span>
            <span class="hljs-keyword">else</span>:
                left = mid + <span class="hljs-number">1</span>
        <span class="hljs-keyword">else</span>:
            <span class="hljs-comment"># Right part is sorted</span>
            <span class="hljs-keyword">if</span> nums[mid] &lt; target &lt;= nums[right]:
                left = mid + <span class="hljs-number">1</span>
            <span class="hljs-keyword">else</span>:
                right = mid - <span class="hljs-number">1</span>
</code></pre>
<h4 id="heading-target-not-found">Target Not Found</h4>
<p>If the loop exits without finding the target, we return <code>-1</code>.</p>
<pre><code class="lang-python">    <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>
</code></pre>
<h3 id="heading-full-implementation">Full Implementation</h3>
<p>Here is the complete code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> List

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">search</span>(<span class="hljs-params">nums: List[int], target: int</span>) -&gt; int:</span>
    left, right = <span class="hljs-number">0</span>, len(nums) - <span class="hljs-number">1</span>

    <span class="hljs-keyword">while</span> left &lt;= right:
        mid = (left + right) // <span class="hljs-number">2</span>

        <span class="hljs-keyword">if</span> nums[mid] == target:
            <span class="hljs-keyword">return</span> mid

        <span class="hljs-keyword">if</span> nums[left] &lt;= nums[mid]:
            <span class="hljs-comment"># Left part is sorted</span>
            <span class="hljs-keyword">if</span> nums[left] &lt;= target &lt; nums[mid]:
                right = mid - <span class="hljs-number">1</span>
            <span class="hljs-keyword">else</span>:
                left = mid + <span class="hljs-number">1</span>
        <span class="hljs-keyword">else</span>:
            <span class="hljs-comment"># Right part is sorted</span>
            <span class="hljs-keyword">if</span> nums[mid] &lt; target &lt;= nums[right]:
                left = mid + <span class="hljs-number">1</span>
            <span class="hljs-keyword">else</span>:
                right = mid - <span class="hljs-number">1</span>

    <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>

<span class="hljs-comment"># Example usage</span>
nums = [<span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>]
target = <span class="hljs-number">0</span>
print(search(nums, target))  <span class="hljs-comment"># Output: 4</span>

target = <span class="hljs-number">3</span>
print(search(nums, target))  <span class="hljs-comment"># Output: -1</span>

nums = [<span class="hljs-number">1</span>]
target = <span class="hljs-number">0</span>
print(search(nums, target))  <span class="hljs-comment"># Output: -1</span>
</code></pre>
<h3 id="heading-common-questions-and-answers">Common Questions and Answers</h3>
<h4 id="heading-q1-why-do-we-use-binary-search-for-this-problem">Q1: Why do we use binary search for this problem?</h4>
<p><strong>A1</strong>: Binary search is used because it allows us to achieve <code>O(log n)</code> time complexity by repeatedly dividing the search space in half. This is essential for handling large datasets efficiently.</p>
<h4 id="heading-q2-how-do-we-determine-which-part-of-the-array-is-sorted">Q2: How do we determine which part of the array is sorted?</h4>
<p><strong>A2</strong>: We compare the values at the <code>left</code>, <code>mid</code>, and <code>right</code> indices. If <code>nums[left] &lt;= nums[mid]</code>, the left part is sorted. Otherwise, the right part is sorted.</p>
<h4 id="heading-q3-what-if-the-array-is-not-rotated">Q3: What if the array is not rotated?</h4>
<p><strong>A3</strong>: The algorithm still works because the conditions for determining the sorted part will be true for the entire array, effectively making it a standard binary search.</p>
<h4 id="heading-q4-can-this-algorithm-handle-duplicate-values-in-the-array">Q4: Can this algorithm handle duplicate values in the array?</h4>
<p><strong>A4</strong>: No, this implementation assumes all values are distinct. Handling duplicates would require additional checks to avoid ambiguity in determining the sorted part.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Solving the rotated sorted array problem on Leetcode is an excellent way to hone your binary search skills.</p>
<p>By understanding how to identify the sorted part of the array and efficiently narrow down the search space, you can tackle this problem with confidence.</p>
<p>Happy coding!</p>
<h3 id="heading-related-articles">Related Articles</h3>
<ul>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/solving-leetcodes-combination-sum-problem-optimized-techniques-for-efficient-solutions">Solving LeetCode's Combination Sum Problem: Optimized Techniques for Efficient Solutions</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/rotting-oranges-a-comprehensive-guide-to-solving-with-bfs-in-python">Rotting Oranges: A Comprehensive Guide to Solving with BFS in Python</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/mastering-leetcode-solving-the-product-of-array-except-self-problem">Mastering LeetCode: Solving the "Product of Array Except Self" Problem</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/getting-started-with-studying-for-software-engineering-interviews-using-leetcode">Getting Started with Studying for Software Engineering Interviews Using LeetCode</a>"</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Decoding Large Language Models: Unveiling the Secrets of AI Powerhouses]]></title><description><![CDATA[Introduction
Artificial Intelligence (AI) has undergone significant advancements, particularly with the development of Large Language Models (LLMs). These models have revolutionized natural language processing (NLP), enabling machines to understand a...]]></description><link>https://blog.seancoughlin.me/decoding-large-language-models-unveiling-the-secrets-of-ai-powerhouses</link><guid isPermaLink="true">https://blog.seancoughlin.me/decoding-large-language-models-unveiling-the-secrets-of-ai-powerhouses</guid><category><![CDATA[AI]]></category><category><![CDATA[llm]]></category><category><![CDATA[neural networks]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[machine learning models]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Mon, 01 Jul 2024 03:37:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719804754483/f11f96f7-6b69-49da-baf5-2ea625cec95b.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Artificial_intelligence">Artificial Intelligence (AI)</a> has undergone significant advancements, particularly with the development of <a target="_blank" href="https://en.wikipedia.org/wiki/Large_language_model">Large Language Models (LLMs)</a>. These models have revolutionized <a target="_blank" href="https://en.wikipedia.org/wiki/Natural_language_processing">natural language processing (NLP)</a>, enabling machines to understand and generate human language with remarkable accuracy.</p>
<p>LLMs are the driving force behind many modern AI applications, including virtual assistants, automated translation, and content generation. This article delves into the technical aspects of LLMs, exploring their neural network foundations, self-attention mechanisms, unsupervised pretraining, and more, providing a comprehensive understanding of how these models work and their potential.</p>
<h3 id="heading-neural-networks-and-transformer-architectures">Neural Networks and Transformer Architectures</h3>
<h4 id="heading-neural-networks-the-foundation-of-llms">Neural Networks: The Foundation of LLMs</h4>
<p>At the heart of LLMs are <a target="_blank" href="https://en.wikipedia.org/wiki/Neural_network_(machine_learning)">neural networks</a>, which mimic the human brain's interconnected neurons to process information. These networks consist of layers of nodes, or neurons, each performing computations to transform input data into output. Early neural networks, such as <a target="_blank" href="https://en.wikipedia.org/wiki/Feedforward_neural_network">Feedforward Neural Networks (FNNs)</a> and <a target="_blank" href="https://en.wikipedia.org/wiki/Convolutional_neural_network">Convolutional Neural Networks (CNNs)</a>, were pivotal in advancing machine learning but had limitations in handling sequential data, like text.</p>
<h4 id="heading-the-rise-of-recurrent-neural-networks-rnns">The Rise of Recurrent Neural Networks (RNNs)</h4>
<p>To address these limitations, <a target="_blank" href="https://en.wikipedia.org/wiki/Recurrent_neural_network">Recurrent Neural Networks (RNNs)</a> were developed. RNNs introduced the concept of recurrent connections, allowing information to persist and be used across sequential steps. This made them suitable for tasks involving time-series data and natural language. However, RNNs struggled with long-term dependencies due to the <a target="_blank" href="https://en.wikipedia.org/wiki/Vanishing_gradient_problem">vanishing gradient problem</a>, which hindered their ability to retain information over extended sequences.</p>
<h4 id="heading-transformer-architectures-a-paradigm-shift">Transformer Architectures: A Paradigm Shift</h4>
<p>The introduction of <a target="_blank" href="https://en.wikipedia.org/wiki/Transformer_(deep_learning_architecture)">transformer architectures</a> marked a significant breakthrough in neural network design. <a target="_blank" href="https://arxiv.org/abs/1706.03762">Transformers, proposed by Vaswani et al. in 2017</a>, eliminated the need for recurrent connections by employing a self-attention mechanism. This allowed transformers to handle sequences in parallel, significantly improving training efficiency and performance on large datasets.</p>
<p>Transformers consist of two main components: encoders and decoders. The encoder processes the input sequence, while the decoder generates the output sequence. Each component is made up of multiple layers, with each layer containing a self-attention mechanism and a feedforward neural network.</p>
<h3 id="heading-self-attention-mechanism">Self-Attention Mechanism</h3>
<h4 id="heading-understanding-self-attention">Understanding Self-Attention</h4>
<p>Self-attention is the core innovation of transformer models. It enables the model to weigh the importance of different parts of the input sequence when generating output. This mechanism computes a weighted sum of all positions in the sequence, allowing the model to focus on relevant parts of the input regardless of their distance from the current position.</p>
<h4 id="heading-how-self-attention-works">How Self-Attention Works</h4>
<p>Self-attention operates using three key components: queries, keys, and values. For each position in the input sequence, the model generates a query, key, and value vector. The attention score is calculated as the dot product of the query and key vectors, determining the relevance of each position in the sequence. These scores are then normalized using a softmax function, resulting in attention weights. Finally, the output is computed as a weighted sum of the value vectors, using the attention weights.</p>
<h4 id="heading-benefits-of-self-attention">Benefits of Self-Attention</h4>
<p>The self-attention mechanism offers several advantages over traditional RNNs:</p>
<ul>
<li><p><strong>Parallelism</strong>: Since self-attention processes all positions in the sequence simultaneously, it allows for parallel computation, significantly speeding up training and inference.</p>
</li>
<li><p><strong>Long-Range Dependencies</strong>: Self-attention can capture dependencies between distant positions in the sequence, addressing the vanishing gradient problem faced by RNNs.</p>
</li>
<li><p><strong>Scalability</strong>: Self-attention scales well with increasing sequence lengths and model sizes, making it suitable for training large models on vast datasets.</p>
</li>
</ul>
<p>Great! Let's continue with the next sections on Unsupervised Pretraining and Transfer Learning.</p>
<h3 id="heading-unsupervised-pretraining">Unsupervised Pretraining</h3>
<h4 id="heading-the-concept-of-unsupervised-pretraining">The Concept of Unsupervised Pretraining</h4>
<p><a target="_blank" href="https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/35536.pdf">Unsupervised pretraining</a> is a crucial step in the development of Large Language Models (LLMs). In this phase, the model is trained on vast amounts of unlabeled text data to learn general language patterns. This process involves predicting words or sentences within the text, enabling the model to understand the structure and semantics of the language without requiring explicit labels.</p>
<h4 id="heading-process-of-unsupervised-pretraining">Process of Unsupervised Pretraining</h4>
<p>The unsupervised pretraining process typically involves two main tasks: masked language modeling and next sentence prediction.</p>
<ul>
<li><p><strong>Masked Language Modeling (MLM)</strong>: In MLM, certain words in a sentence are masked, and the model is trained to predict these masked words based on the surrounding context. For example, in the sentence "The cat sat on the [MASK]," the model learns to predict "mat" as the masked word.</p>
</li>
<li><p><strong>Next Sentence Prediction (NSP)</strong>: NSP involves training the model to predict whether a given sentence logically follows another sentence. This helps the model understand sentence-level coherence and context. For instance, given the sentences "The sky is blue. The weather is nice," the model learns that the second sentence is likely to follow the first one.</p>
</li>
</ul>
<h4 id="heading-advantages-of-unsupervised-pretraining">Advantages of Unsupervised Pretraining</h4>
<p>Unsupervised pretraining offers several benefits:</p>
<ul>
<li><p><strong>Rich Feature Extraction</strong>: By learning from a large corpus of text, the model extracts rich linguistic features that can be leveraged for various downstream tasks.</p>
</li>
<li><p><strong>Language Understanding</strong>: The model gains a deep understanding of language syntax, semantics, and context, which is essential for generating coherent and contextually appropriate text.</p>
</li>
<li><p><strong>Foundation for Transfer Learning</strong>: Unsupervised pretraining provides a strong foundation for transfer learning, where the pretrained model can be fine-tuned on specific tasks with less data.</p>
</li>
</ul>
<h3 id="heading-transfer-learning">Transfer Learning</h3>
<h4 id="heading-the-concept-of-transfer-learning">The Concept of Transfer Learning</h4>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Transfer_learning">Transfer learning</a> involves taking a pretrained model and adapting it to perform specific tasks with much less data and computational resources. This approach leverages the knowledge gained during the pretraining phase, allowing the model to quickly adapt to new tasks by fine-tuning on smaller, task-specific datasets.</p>
<h4 id="heading-process-of-transfer-learning">Process of Transfer Learning</h4>
<p>The <a target="_blank" href="https://aws.amazon.com/what-is/transfer-learning/">transfer learning process</a> typically involves the following steps:</p>
<ol>
<li><p><strong>Pretraining</strong>: The model is pretrained on a large corpus of unlabeled text data, as described in the unsupervised pretraining section.</p>
</li>
<li><p><strong>Fine-Tuning</strong>: The pretrained model is fine-tuned on a smaller, labeled dataset specific to the task at hand. This involves adjusting the model's parameters to optimize performance on the new task.</p>
</li>
</ol>
<h4 id="heading-examples-of-transfer-learning">Examples of Transfer Learning</h4>
<ul>
<li><p><strong>Sentiment Analysis</strong>: A pretrained LLM can be fine-tuned on a labeled dataset of movie reviews to classify the sentiment (positive or negative) of new reviews.</p>
</li>
<li><p><strong>Machine Translation</strong>: The model can be fine-tuned on parallel corpora (e.g., English-French sentence pairs) to perform language translation.</p>
</li>
<li><p><strong>Question Answering</strong>: Fine-tuning on datasets like SQuAD (Stanford Question Answering Dataset) enables the model to answer questions based on provided passages.</p>
</li>
</ul>
<h4 id="heading-benefits-of-transfer-learning">Benefits of Transfer Learning</h4>
<ul>
<li><p><strong>Reduced Data Requirements</strong>: Transfer learning significantly reduces the amount of labeled data needed for training, as the model already possesses general language knowledge from pretraining.</p>
</li>
<li><p><strong>Improved Performance</strong>: Fine-tuning a pretrained model often results in better performance compared to training a model from scratch on a specific task.</p>
</li>
<li><p><strong>Efficiency</strong>: Transfer learning speeds up the training process and requires fewer computational resources, making it accessible for a wider range of applications.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719804782779/2a610123-2e3c-4bf8-9ce2-c02e2b88f8ce.webp" alt="Friendly and vibrant illustration depicting elements of Large Language Models (LLMs) with abstract shapes, neural networks, self-attention mechanisms, and symbols of AI and technology blended into the background." class="image--center mx-auto" /></p>
<h3 id="heading-scaling-laws">Scaling Laws</h3>
<h4 id="heading-understanding-scaling-laws">Understanding Scaling Laws</h4>
<p>Scaling laws <a target="_blank" href="https://arxiv.org/abs/2001.08361">describe the predictable improvement in the performance of Large Language Models (LLMs)</a> as the model size and the amount of training data increase. These laws have been <a target="_blank" href="https://dynomight.net/scaling/">empirically observed in various studies</a>, indicating that larger models and more data lead to better performance on a wide range of tasks.</p>
<h4 id="heading-key-findings-in-scaling-laws">Key Findings in Scaling Laws</h4>
<ul>
<li><p><strong>Model Size</strong>: Increasing the number of parameters in a model generally leads to improved performance. For instance, models like GPT-3, with 175 billion parameters, outperform smaller models on numerous benchmarks.</p>
</li>
<li><p><strong>Training Data</strong>: More training data allows the model to learn better representations and generalize more effectively. This is evident in models trained on massive datasets comprising diverse text sources.</p>
</li>
<li><p><strong>Compute Resources</strong>: Greater computational power enables the training of larger models on larger datasets, further enhancing performance.</p>
</li>
</ul>
<h4 id="heading-implications-of-scaling-laws">Implications of Scaling Laws</h4>
<ul>
<li><p><strong>Investment in Resources</strong>: Scaling laws suggest that investing in larger models and extensive training data can yield significant performance gains. This has led to substantial investments in AI research and infrastructure.</p>
</li>
<li><p><strong>Research Directions</strong>: Understanding scaling laws helps researchers and practitioners make informed decisions about model architecture, training protocols, and resource allocation.</p>
</li>
<li><p><strong>Emergent Abilities</strong>: As models scale, they often exhibit emergent abilities—capabilities that were not present in smaller models. These abilities include better language understanding, improved reasoning, and more coherent text generation.</p>
</li>
</ul>
<h3 id="heading-few-shot-learning">Few-Shot Learning</h3>
<h4 id="heading-concept-of-few-shot-learning">Concept of Few-Shot Learning</h4>
<p><a target="_blank" href="https://blog.seancoughlin.me/explaining-ai-few-shot-one-shot-and-zero-shot-learning">Few-shot learning</a> refers to the ability of Large Language Models (LLMs) to perform new tasks with just a few examples. This capability is particularly valuable in scenarios where labeled data is scarce or expensive to obtain.</p>
<h4 id="heading-mechanism-of-few-shot-learning">Mechanism of Few-Shot Learning</h4>
<p>Few-shot learning leverages the extensive pretraining of LLMs. When presented with a few examples of a new task, the model uses its prior knowledge to generalize and perform the task effectively. This involves:</p>
<ul>
<li><p><strong>Prompting</strong>: Providing the model with a prompt that includes a few examples of the task. For example, to perform sentiment analysis, a prompt might include a few labeled sentences along with their sentiments.</p>
</li>
<li><p><strong>Inference</strong>: The model generates responses based on the provided examples, demonstrating its ability to understand and apply the task with minimal data.</p>
</li>
</ul>
<h4 id="heading-practical-examples">Practical Examples</h4>
<ul>
<li><p><strong>Text Classification</strong>: Given a few labeled examples of different text categories, the model can classify new text into the appropriate categories.</p>
</li>
<li><p><strong>Named Entity Recognition (NER)</strong>: With a few annotated sentences highlighting entities, the model can identify entities in new sentences.</p>
</li>
<li><p><strong>Translation</strong>: Providing a few sentence pairs in two languages enables the model to translate new sentences between those languages.</p>
</li>
</ul>
<h4 id="heading-benefits-of-few-shot-learning">Benefits of Few-Shot Learning</h4>
<ul>
<li><p><strong>Data Efficiency</strong>: Few-shot learning reduces the need for large labeled datasets, making it practical for a wider range of applications.</p>
</li>
<li><p><strong>Flexibility</strong>: The model can quickly adapt to new tasks, demonstrating versatility and robustness.</p>
</li>
<li><p><strong>Cost-Effectiveness</strong>: Fewer labeled examples mean lower costs associated with data annotation and preparation.</p>
</li>
</ul>
<h3 id="heading-emergent-abilities">Emergent Abilities</h3>
<h4 id="heading-understanding-emergent-abilities">Understanding Emergent Abilities</h4>
<p><a target="_blank" href="https://cset.georgetown.edu/article/emergent-abilities-in-large-language-models-an-explainer">Emergent abilities refer to unexpected capabilities that arise in large-scale models</a> but are not present in smaller versions. As LLMs grow in size and complexity, they begin to exhibit behaviors and skills that were not explicitly programmed or anticipated during their development.</p>
<h4 id="heading-examples-of-emergent-abilities">Examples of Emergent Abilities</h4>
<ul>
<li><p><strong>Language Translation</strong>: Larger models, even if not specifically trained on translation tasks, can perform rudimentary translations between languages.</p>
</li>
<li><p><strong>Reasoning and Logic</strong>: Advanced LLMs show improved reasoning capabilities, solving puzzles and logical problems with greater accuracy.</p>
</li>
<li><p><strong>Creative Writing</strong>: These models can generate creative content, such as poetry or short stories, that mimics human-like creativity.</p>
</li>
</ul>
<h4 id="heading-implications-of-emergent-abilities">Implications of Emergent Abilities</h4>
<ul>
<li><p><strong>Surprising Utility</strong>: Emergent abilities can provide additional value without extra training, making large models versatile and multifunctional.</p>
</li>
<li><p><strong>Research Opportunities</strong>: Studying these abilities helps researchers understand the underlying mechanics of LLMs and how they develop complex behaviors.</p>
</li>
<li><p><strong>Ethical Considerations</strong>: Emergent abilities also pose challenges, as they can lead to unpredictable outcomes, necessitating careful monitoring and control.</p>
</li>
</ul>
<h3 id="heading-prompt-engineering">Prompt Engineering</h3>
<h4 id="heading-the-importance-of-prompt-engineering">The Importance of Prompt Engineering</h4>
<p><a target="_blank" href="https://platform.openai.com/docs/guides/prompt-engineering">Prompt engineering</a> involves crafting input prompts that effectively guide the behavior of LLMs. Since LLMs respond to the text they are given, the quality and structure of the prompt significantly influence the output.</p>
<h4 id="heading-techniques-for-effective-prompt-engineering">Techniques for Effective Prompt Engineering</h4>
<ul>
<li><p><strong>Clear Instructions</strong>: Providing explicit instructions helps the model understand the task. For example, "Translate the following text from English to French."</p>
</li>
<li><p><strong>Examples and Patterns</strong>: Including examples within the prompt can help the model learn the desired output pattern. For instance, showing a few labeled examples before asking the model to classify new data.</p>
</li>
<li><p><strong>Context and Constraints</strong>: Adding contextual information and constraints can refine the model's responses. For example, specifying a formal tone or limiting the response length.</p>
</li>
</ul>
<h4 id="heading-practical-applications">Practical Applications</h4>
<ul>
<li><p><strong>Content Generation</strong>: Crafting prompts for blog posts, articles, or creative writing to ensure coherent and relevant outputs.</p>
</li>
<li><p><strong>Customer Support</strong>: Designing prompts for chatbots to provide accurate and helpful responses to customer inquiries.</p>
</li>
<li><p><strong>Educational Tools</strong>: Creating prompts that help students understand concepts through interactive Q&amp;A sessions or personalized tutoring.</p>
</li>
</ul>
<h3 id="heading-alignment-and-ethics">Alignment and Ethics</h3>
<h4 id="heading-the-challenge-of-alignment">The Challenge of Alignment</h4>
<p><a target="_blank" href="https://www.anthropic.com/research#alignment">Alignment</a> in AI refers to ensuring that models behave in ways that are consistent with human values and intentions. As LLMs become more powerful, aligning their behavior with ethical standards and societal norms becomes increasingly critical.</p>
<h4 id="heading-approaches-to-alignment">Approaches to Alignment</h4>
<ul>
<li><p><strong>Human-in-the-Loop</strong>: Involving human oversight in the training and deployment of AI models to ensure they align with desired outcomes.</p>
</li>
<li><p><strong>Value-Based Learning</strong>: Incorporating ethical guidelines and value-based learning into the training process to guide the model's behavior.</p>
</li>
<li><p><strong>Robust Evaluation</strong>: Continuously evaluating and testing models for unintended behaviors and biases, and refining them to minimize these issues.</p>
</li>
</ul>
<h4 id="heading-ethical-considerations">Ethical Considerations</h4>
<ul>
<li><p><strong>Bias and Fairness</strong>: Addressing inherent biases in training data and ensuring fair treatment across different demographic groups.</p>
</li>
<li><p><strong>Privacy</strong>: Protecting user data and ensuring that models do not inadvertently leak sensitive information.</p>
</li>
<li><p><strong>Transparency</strong>: Making the workings of LLMs understandable and transparent to users, fostering trust and accountability.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Large Language Models (LLMs) represent a significant advancement in the field of artificial intelligence.</p>
<p>From their neural network foundations to the intricacies of self-attention mechanisms, unsupervised pretraining, and transfer learning, these models have revolutionized natural language processing and numerous applications.</p>
<p>Understanding the scaling laws, emergent abilities, prompt engineering, and alignment challenges is crucial for leveraging LLMs effectively and responsibly.</p>
<p>As AI continues to evolve, staying informed about these technical aspects will help practitioners harness the full potential of LLMs while addressing ethical and societal considerations.</p>
<h3 id="heading-faq-section">FAQ Section</h3>
<h4 id="heading-what-are-large-language-models-llms">What are Large Language Models (LLMs)?</h4>
<p>Large Language Models (LLMs) are advanced AI models trained to understand and generate human language. They are based on deep neural networks, particularly transformer architectures.</p>
<h4 id="heading-how-does-self-attention-work-in-llms">How does self-attention work in LLMs?</h4>
<p>Self-attention allows LLMs to weigh the importance of different parts of the input when generating output, enabling the model to handle long-range dependencies in text.</p>
<h4 id="heading-what-is-unsupervised-pretraining-in-llms">What is unsupervised pretraining in LLMs?</h4>
<p>Unsupervised pretraining involves training LLMs on vast amounts of unlabeled text data to learn general language patterns before fine-tuning on specific tasks.</p>
<h4 id="heading-what-is-transfer-learning-in-the-context-of-llms">What is transfer learning in the context of LLMs?</h4>
<p>Transfer learning refers to the process of adapting a pretrained LLM to perform specific tasks with much less data, leveraging the knowledge gained during pretraining.</p>
<h4 id="heading-what-are-scaling-laws-in-llms">What are scaling laws in LLMs?</h4>
<p>Scaling laws describe the predictable improvement in LLM performance as the model size and amount of training data increase.</p>
<h4 id="heading-what-is-few-shot-learning">What is few-shot learning?</h4>
<p>Few-shot learning enables LLMs to perform new tasks with just a few examples, demonstrating the model's adaptability and versatility.</p>
<h4 id="heading-what-are-emergent-abilities-in-llms">What are emergent abilities in LLMs?</h4>
<p>Emergent abilities are unexpected capabilities that arise in large-scale models, such as improved reasoning, translation, and creative writing, not present in smaller versions.</p>
<h4 id="heading-what-is-prompt-engineering">What is prompt engineering?</h4>
<p>Prompt engineering involves crafting input prompts that effectively guide the behavior of LLMs, influencing their output quality and relevance.</p>
<h4 id="heading-why-is-alignment-important-in-ai">Why is alignment important in AI?</h4>
<p>Alignment ensures that AI models behave in ways consistent with human values and intentions, addressing ethical considerations like bias, fairness, and transparency.</p>
<h3 id="heading-related-articles">Related Articles</h3>
<ul>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/understanding-tokenization-in-large-language-models">Understanding Tokenization in Large Language Models</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/explaining-ai-few-shot-one-shot-and-zero-shot-learning">Explaining AI: Few-Shot, One-Shot, and Zero-Shot Learning</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://www.understandingai.org/p/large-language-models-explained-with">Large language models, explained with a minimum of math and jargon</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://www.nvidia.com/en-us/glossary/large-language-models/">Large Language Models Explained</a>"</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Solving LeetCode's Combination Sum Problem: Optimized Techniques for Efficient Solutions]]></title><description><![CDATA[The Combination Sum problem is a classic challenge on LeetCode that tests your algorithmic skills and your ability to implement efficient backtracking techniques. It's a problem frequently encountered in coding interviews, making it an essential part...]]></description><link>https://blog.seancoughlin.me/solving-leetcodes-combination-sum-problem-optimized-techniques-for-efficient-solutions</link><guid isPermaLink="true">https://blog.seancoughlin.me/solving-leetcodes-combination-sum-problem-optimized-techniques-for-efficient-solutions</guid><category><![CDATA[Python]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[leetcode-solution]]></category><category><![CDATA[array]]></category><category><![CDATA[interview questions]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Mon, 01 Jul 2024 03:03:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719802921833/ae22305c-fa01-45aa-88dd-02a175789a76.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <a target="_blank" href="https://leetcode.com/problems/combination-sum/description/">Combination Sum problem</a> is a classic challenge on <a target="_blank" href="https://leetcode.com">LeetCode</a> that tests your algorithmic skills and your ability to implement efficient backtracking techniques. It's a problem frequently encountered in coding interviews, making it an essential part of your preparation toolkit.</p>
<p>In this guide, we'll walk you through solving the Combination Sum problem using an optimized <a target="_blank" href="https://en.wikipedia.org/wiki/Backtracking">backtracking approach</a>. You'll learn how to implement the algorithm step-by-step and understand the improvements that can enhance its efficiency.</p>
<h3 id="heading-problem-description">Problem Description</h3>
<p>The Combination Sum problem can be described as follows:</p>
<blockquote>
<p>Given an array of <strong>distinct</strong> integers <code>candidates</code> and a target integer <code>target</code>, return <em>a list of all</em> <strong><em>unique combinations</em></strong> <em>of</em> <code>candidates</code> <em>where the chosen numbers sum to</em> <code>target</code><em>.</em> You may return the combinations in <strong>any order</strong>.</p>
<p>The <strong>same</strong> number may be chosen from <code>candidates</code> an <strong>unlimited number of times</strong>. Two combinations are unique if the frequency of at least one of the chosen numbers is different.</p>
<p>The test cases are generated such that the number of unique combinations that sum up to <code>target</code> is less than <code>150</code> combinations for the given input. </p>
<p><strong>Example 1:</strong></p>
<pre><code class="lang-plaintext">Input: candidates = [2,3,6,7], target = 7
Output: [[2,2,3],[7]]
Explanation:
2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times.
7 is a candidate, and 7 = 7.
These are the only two combinations.
</code></pre>
<p><strong>Example 2:</strong></p>
<pre><code class="lang-plaintext">Input: candidates = [2,3,5], target = 8
Output: [[2,2,2,2],[2,3,3],[3,5]]
</code></pre>
<p><strong>Example 3:</strong></p>
<pre><code class="lang-plaintext">Input: candidates = [2], target = 1
Output: []
</code></pre>
</blockquote>
<h2 id="heading-python-solution">Python Solution</h2>
<h3 id="heading-initial-approach-backtracking">Initial Approach: Backtracking</h3>
<p>Backtracking is a powerful technique for solving combinatorial problems where we need to explore all possible combinations. In this problem, we use backtracking to explore different combinations of <code>candidates</code> that sum up to <code>target</code>.</p>
<h4 id="heading-initial-python-code-implementation">Initial Python Code Implementation</h4>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> List

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">combinationSum</span>(<span class="hljs-params">candidates: List[int], target: int</span>) -&gt; List[List[int]]:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">backtrack</span>(<span class="hljs-params">remaining, start, path, result</span>):</span>
        <span class="hljs-keyword">if</span> remaining &lt; <span class="hljs-number">0</span>:
            <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">if</span> remaining == <span class="hljs-number">0</span>:
            result.append(list(path))
            <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(start, len(candidates)):
            path.append(candidates[i])
            backtrack(remaining - candidates[i], i, path, result)
            path.pop()

    result = []
    backtrack(target, <span class="hljs-number">0</span>, [], result)
    <span class="hljs-keyword">return</span> result

<span class="hljs-comment"># Example usage:</span>
candidates1 = [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>]
target1 = <span class="hljs-number">7</span>
print(combinationSum(candidates1, target1))  <span class="hljs-comment"># Output: [[2, 2, 3], [7]]</span>

candidates2 = [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>]
target2 = <span class="hljs-number">8</span>
print(combinationSum(candidates2, target2))  <span class="hljs-comment"># Output: [[2, 2, 2, 2], [2, 3, 3], [3, 5]]</span>

candidates3 = [<span class="hljs-number">2</span>]
target3 = <span class="hljs-number">1</span>
print(combinationSum(candidates3, target3))  <span class="hljs-comment"># Output: []</span>
</code></pre>
<h4 id="heading-step-by-step-breakdown">Step-by-Step Breakdown</h4>
<ol>
<li><p><strong>Function Definition and Initial Setup</strong></p>
<ul>
<li><p>The <code>combinationSum</code> function takes two parameters: <code>candidates</code> (a list of distinct integers) and <code>target</code> (an integer).</p>
</li>
<li><p>Inside this function, a helper function called <code>backtrack</code> is defined for the recursive exploration of combinations.</p>
</li>
</ul>
</li>
<li><p><strong>Backtracking Helper Function</strong></p>
<ul>
<li><p>The <code>backtrack</code> function uses recursion to explore different combinations.</p>
</li>
<li><p>Parameters:</p>
<ul>
<li><p><code>remaining</code>: the remaining value to reach the target.</p>
</li>
<li><p><code>start</code>: the current index in the <code>candidates</code> list.</p>
</li>
<li><p><code>path</code>: the current combination of numbers.</p>
</li>
<li><p><code>result</code>: the list of valid combinations found so far.</p>
</li>
</ul>
</li>
<li><p>Base cases:</p>
<ul>
<li><p>If <code>remaining</code> is less than 0, terminate the current path as it exceeds the target.</p>
</li>
<li><p>If <code>remaining</code> is 0, add the current path to the result list as it is a valid combination.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Recursive Exploration</strong></p>
<ul>
<li><p>Iterate through the candidates starting from the current index.</p>
</li>
<li><p>Append the current candidate to <code>path</code> and recursively call <code>backtrack</code> with updated parameters.</p>
</li>
<li><p>After the recursive call, remove the last candidate from <code>path</code> to explore the next combination.</p>
</li>
</ul>
</li>
<li><p><strong>Initialization and Function Call</strong></p>
<ul>
<li>Initialize the result list and call <code>backtrack</code> with initial parameters.</li>
</ul>
</li>
</ol>
<h3 id="heading-optimizing-the-backtracking-solution">Optimizing the Backtracking Solution</h3>
<p>To improve the efficiency of our backtracking solution, we can use the following optimizations:</p>
<ol>
<li><p><strong>Sorting the Candidates</strong></p>
<ul>
<li>Sorting the <code>candidates</code> array helps us to stop early in the loop if the current candidate exceeds the remaining target.</li>
</ul>
</li>
<li><p><strong>Pruning the Search Space</strong></p>
<ul>
<li>Once a candidate exceeds the remaining target, break out of the loop early since all subsequent candidates (being larger) will also exceed the target.</li>
</ul>
</li>
</ol>
<h4 id="heading-optimized-python-code-implementation">Optimized Python Code Implementation</h4>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> List

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">combinationSum</span>(<span class="hljs-params">candidates: List[int], target: int</span>) -&gt; List[List[int]]:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">backtrack</span>(<span class="hljs-params">remaining, start, path, result</span>):</span>
        <span class="hljs-keyword">if</span> remaining == <span class="hljs-number">0</span>:
            result.append(list(path))
            <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(start, len(candidates)):
            <span class="hljs-keyword">if</span> candidates[i] &gt; remaining:
                <span class="hljs-keyword">break</span>
            path.append(candidates[i])
            backtrack(remaining - candidates[i], i, path, result)
            path.pop()

    candidates.sort()
    result = []
    backtrack(target, <span class="hljs-number">0</span>, [], result)
    <span class="hljs-keyword">return</span> result

<span class="hljs-comment"># Example usage:</span>
candidates1 = [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>]
target1 = <span class="hljs-number">7</span>
print(combinationSum(candidates1, target1))  <span class="hljs-comment"># Output: [[2, 2, 3], [7]]</span>

candidates2 = [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>]
target2 = <span class="hljs-number">8</span>
print(combinationSum(candidates2, target2))  <span class="hljs-comment"># Output: [[2, 2, 2, 2], [2, 3, 3], [3, 5]]</span>

candidates3 = [<span class="hljs-number">2</span>]
target3 = <span class="hljs-number">1</span>
print(combinationSum(candidates3, target3))  <span class="hljs-comment"># Output: []</span>
</code></pre>
<h3 id="heading-explanation-of-optimizations">Explanation of Optimizations</h3>
<ol>
<li><p><strong>Sorting the Candidates</strong></p>
<ul>
<li>By sorting the <code>candidates</code> array, we ensure that once we encounter a candidate larger than the remaining target, all subsequent candidates (which are larger) will also be invalid. This allows us to break out of the loop early.</li>
</ul>
</li>
<li><p><strong>Pruning the Search Space</strong></p>
<ul>
<li>If the current candidate exceeds the remaining target, break out of the loop early to prevent unnecessary recursive calls.</li>
</ul>
</li>
</ol>
<h3 id="heading-comparison-of-approaches">Comparison of Approaches</h3>
<h4 id="heading-initial-backtracking-solution">Initial Backtracking Solution</h4>
<ul>
<li><p><strong>Pros:</strong></p>
<ul>
<li><p>Straightforward implementation.</p>
</li>
<li><p>Explores all possible combinations.</p>
</li>
</ul>
</li>
<li><p><strong>Cons:</strong></p>
<ul>
<li>Can be slow for larger inputs due to exhaustive search.</li>
</ul>
</li>
</ul>
<h4 id="heading-optimized-backtracking-solution">Optimized Backtracking Solution</h4>
<ul>
<li><p><strong>Pros:</strong></p>
<ul>
<li><p>Faster due to early termination and pruning.</p>
</li>
<li><p>Reduces the number of recursive calls.</p>
</li>
</ul>
</li>
<li><p><strong>Cons:</strong></p>
<ul>
<li>Additional step of sorting the candidates.</li>
</ul>
</li>
</ul>
<h2 id="heading-faq-section">FAQ Section</h2>
<p><strong>How to handle large inputs efficiently?</strong></p>
<ul>
<li><p>Prune the search space aggressively by checking the remaining target before making recursive calls.</p>
</li>
<li><p>Use memoization to store and reuse results of previously computed subproblems if applicable.</p>
</li>
</ul>
<h4 id="heading-what-if-there-are-duplicate-candidates">What if there are duplicate candidates?</h4>
<ul>
<li>If duplicates are allowed, ensure each combination is unique by modifying the recursive call to avoid revisiting the same element index.</li>
</ul>
<h4 id="heading-how-to-adapt-the-solution-for-different-constraints">How to adapt the solution for different constraints?</h4>
<ul>
<li>Adjust the starting index or the conditions in the recursive function to fit the specific constraints, such as limited candidate usage or different target values.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this comprehensive guide, we've explored how to solve LeetCode's Combination Sum problem using a backtracking approach. By implementing optimizations like sorting and pruning, we can significantly improve the efficiency of our solution.</p>
<p>Understanding these techniques is crucial for mastering combinatorial problems and enhancing your algorithmic skills. Keep practicing with similar problems to further strengthen your grasp of these concepts.</p>
<p>By following this guide, you should now have a solid understanding of how to approach the Combination Sum problem and apply these techniques to other algorithmic challenges. Happy coding!</p>
<h3 id="heading-related-articles">Related Articles</h3>
<ul>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/rotting-oranges-a-comprehensive-guide-to-solving-with-bfs-in-python">Rotting Oranges: A Comprehensive Guide to Solving with BFS in Python</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/mastering-leetcode-counting-the-number-of-islands-in-a-2d-binary-grid">Mastering LeetCode: Counting the Number of Islands in a 2D Binary Grid</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/mastering-the-3sum-problem-a-guide-for-leetcode-and-coding-interviews">Mastering the 3Sum Problem: A Guide for LeetCode and Coding Interviews</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/mastering-the-staircase-dynamic-programming-solutions-for-leetcodes-climbing-stairs-problem">Mastering the Staircase: Dynamic Programming Solutions for LeetCode's Climbing Stairs Problem</a>"</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[NestJS and the JavaScript Backend Ecosystem: A Developer's Journey]]></title><description><![CDATA[As a developer who's spent years wrangling Java Spring Boot applications and dabbling in various JavaScript frameworks, I've watched the backend JS world explode with options. It's a jungle out there, and today I want to talk about a framework that's...]]></description><link>https://blog.seancoughlin.me/nestjs-and-the-javascript-backend-ecosystem-a-developers-journey</link><guid isPermaLink="true">https://blog.seancoughlin.me/nestjs-and-the-javascript-backend-ecosystem-a-developers-journey</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[backend]]></category><category><![CDATA[nestjs]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Sean Coughlin]]></dc:creator><pubDate>Sun, 30 Jun 2024 00:58:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719708815535/8345b689-eb91-4613-9e03-5722c25fbbfa.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a developer who's spent years wrangling Java Spring Boot applications and dabbling in various JavaScript frameworks, I've watched the backend JS world explode with options. It's a jungle out there, and today I want to talk about a framework that's caught my eye: <a target="_blank" href="https://nestjs.com">NestJS</a>.</p>
<h2 id="heading-what-is-nestjs">What is NestJS?</h2>
<p>NestJS is a TypeScript-based web application framework that's been gaining traction in recent years. It's often dubbed the "Angular for backend" due to its architectural similarities with the popular frontend framework.</p>
<p><a target="_blank" href="https://docs.nestjs.com">Key features that make NestJS stand out</a>:</p>
<ul>
<li><p>First-class TypeScript support</p>
</li>
<li><p>Modular architecture that promotes code reusability</p>
</li>
<li><p>Dependency injection system (reminiscent of Spring Boot)</p>
</li>
<li><p>Decorators for clean, expressive code</p>
</li>
<li><p>Support for both RESTful and GraphQL APIs</p>
</li>
<li><p>Extensive testing utilities built-in</p>
</li>
</ul>
<h2 id="heading-the-javascript-backend-ecosystem-a-brief-tour">The JavaScript Backend Ecosystem: A Brief Tour</h2>
<p>Before we dive deeper into NestJS, let's take a quick tour of the JavaScript backend landscape. It's a diverse ecosystem with options to suit almost any development style or project need:</p>
<ol>
<li><p><a target="_blank" href="https://expressjs.com"><strong>Express.js</strong></a>: The granddaddy of Node.js frameworks. Minimalist, flexible, and still wildly popular (you know software is popular when it gets its <a target="_blank" href="https://en.wikipedia.org/wiki/Express.js">own Wikipedia page</a>).</p>
</li>
<li><p><a target="_blank" href="https://koajs.com"><strong>Koa</strong></a>: Express's spiritual successor, focusing on a smaller footprint and greater expressive power.</p>
</li>
<li><p><a target="_blank" href="https://hapi.dev"><strong>Hapi</strong></a>: A feature-rich framework that's found favor in enterprise settings.</p>
</li>
<li><p><a target="_blank" href="https://fastify.dev"><strong>Fastify</strong></a>: The new kid on the block, promising blazing fast performance.</p>
</li>
<li><p><a target="_blank" href="https://sailsjs.com"><strong>Sails.js</strong></a>: An MVC framework for Node.js that follows the familiar Rails-style structure.</p>
</li>
</ol>
<p>Each of these has its strengths, but NestJS offers something a bit different.</p>
<h2 id="heading-nestjs-spring-boot-for-javascript-developers">NestJS: Spring Boot for JavaScript Developers?</h2>
<p>As someone who's spent a lot of time in the Java world, NestJS immediately felt familiar. It's like the framework designers asked, "What if we built Spring Boot for JavaScript?" The result is a structured, opinionated framework that brings many of Spring's strengths to the <a target="_blank" href="https://nodejs.org/en">Node.js</a> ecosystem.</p>
<p>Some key parallels:</p>
<ul>
<li><p><a target="_blank" href="https://docs.nestjs.com/modules"><strong>Modules</strong></a>: Just like in Spring, NestJS applications are composed of modules that encapsulate related functionality.</p>
</li>
<li><p><strong>Dependency Injection</strong>: NestJS has a built-in <a target="_blank" href="https://docs.nestjs.com/fundamentals/injection-scopes">DI container</a> that works similarly to Spring's.</p>
</li>
<li><p><strong>Decorators</strong>: If you've used annotations in Spring, NestJS's <a target="_blank" href="https://docs.nestjs.com/custom-decorators">decorators</a> will feel right at home.</p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Aspect-oriented_programming"><strong>AOP</strong></a>: While not as extensive as Spring's AspectJ integration, <a target="_blank" href="https://docs.nestjs.com/interceptors">NestJS offers interceptors</a> and <a target="_blank" href="https://docs.nestjs.com/middleware">middleware</a> for cross-cutting concerns.</p>
</li>
</ul>
<h2 id="heading-deep-dive-nestjs-features">Deep Dive: NestJS Features</h2>
<p>Let's explore some of NestJS's features in more depth:</p>
<h3 id="heading-typescript-integration">TypeScript Integration</h3>
<p>NestJS is built with TypeScript from the ground up. This means you get:</p>
<ul>
<li><p>Strong typing</p>
</li>
<li><p>Enhanced IDE support</p>
</li>
<li><p>Decorators for metadata</p>
</li>
<li><p>Easy refactoring</p>
</li>
</ul>
<p>Here's a quick example of a NestJS controller:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Controller</span>(<span class="hljs-string">'cats'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsController {
  <span class="hljs-meta">@Get</span>()
  findAll(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">'This action returns all cats'</span>;
  }
}
</code></pre>
<h3 id="heading-dependency-injection">Dependency Injection</h3>
<p>NestJS's DI system is powerful and flexible. It supports constructor injection, property injection, and even circular dependencies (though I'd advise against those).</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsService {
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> cats: Cat[] = [];

  create(cat: Cat) {
    <span class="hljs-built_in">this</span>.cats.push(cat);
  }

  findAll(): Cat[] {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.cats;
  }
}

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'cats'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> catsService: CatsService</span>) {}

  <span class="hljs-meta">@Post</span>()
  <span class="hljs-keyword">async</span> create(<span class="hljs-meta">@Body</span>() createCatDto: CreateCatDto) {
    <span class="hljs-built_in">this</span>.catsService.create(createCatDto);
  }
}
</code></pre>
<h3 id="heading-testing">Testing</h3>
<p>NestJS comes with a robust testing framework out of the box. It provides utilities for unit testing, integration testing, and e2e testing.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Test, TestingModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/testing'</span>;
<span class="hljs-keyword">import</span> { CatsController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cats.controller'</span>;

describe(<span class="hljs-string">'CatsController'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">let</span> controller: CatsController;

  beforeEach(<span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> <span class="hljs-keyword">module</span>: TestingModule = await Test.createTestingModule({
      controllers: [CatsController],
    }).compile();

    controller = <span class="hljs-built_in">module</span>.get&lt;CatsController&gt;(CatsController);
  });

  it(<span class="hljs-string">'should be defined'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(controller).toBeDefined();
  });
});
</code></pre>
<h2 id="heading-when-to-choose-nestjs">When to Choose NestJS</h2>
<p>In my experience, NestJS really shines in certain scenarios:</p>
<ol>
<li><p><strong>Large, Complex Applications</strong>: The structured approach helps manage complexity as your app grows.</p>
</li>
<li><p><strong>Enterprise Environments</strong>: The familiar architecture makes it easier for teams transitioning from Java or .NET backgrounds.</p>
</li>
<li><p><a target="_blank" href="https://docs.nestjs.com/microservices/basics"><strong>Microservices</strong></a>: NestJS has excellent support for building <a target="_blank" href="https://blog.seancoughlin.me/what-are-microservices">microservice architectures</a>.</p>
</li>
<li><p><strong>Long-term Projects</strong>: The enforced structure helps maintain consistency over time, even as team members come and go.</p>
</li>
</ol>
<h2 id="heading-nestjs-vs-express-a-personal-take">NestJS vs Express: A Personal Take</h2>
<p>Having used both extensively, here's my take on the NestJS vs Express debate:</p>
<ul>
<li><p><strong>Express</strong> is like the Wild West. It's fast, flexible, and if you know what you're doing, you can build anything. But it's easy for things to get messy, especially in larger projects or with less experienced developers.</p>
</li>
<li><p><strong>NestJS</strong> is more like a planned city. There's structure, there are rules, but once you learn them, you can build complex systems that are easy to maintain and scale.</p>
</li>
</ul>
<p>Express is great for small projects, MVPs, or when you need maximum flexibility. NestJS shines in larger, more complex applications where maintainability and scalability are key concerns.</p>
<h3 id="heading-quick-comparison-table-nestjs-vs-express">Quick Comparison Table: NestJS vs Express</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Criteria</td><td>NestJS</td><td>Express</td></tr>
</thead>
<tbody>
<tr>
<td>Learning Curve</td><td>Steeper due to TypeScript and architecture</td><td>Gentler, easier to pick up</td></tr>
<tr>
<td>Flexibility</td><td>Structured, opinionated</td><td>Highly flexible, minimal structure</td></tr>
<tr>
<td>Performance</td><td>Slightly slower due to additional features</td><td>Faster for small, simple applications</td></tr>
<tr>
<td>Community Support</td><td>Growing, active community</td><td>Large, well-established community</td></tr>
</tbody>
</table>
</div><h2 id="heading-my-opinions-on-nestjs-and-the-javascript-ecosystem">My Opinions on NestJS and the JavaScript Ecosystem</h2>
<p>After spending time with NestJS and various other frameworks, here are some of my personal thoughts:</p>
<ol>
<li><p><strong>Learning Curve</strong>: NestJS has a steeper learning curve than Express, but it pays off in the long run for larger projects.</p>
</li>
<li><p><strong>TypeScript Advantage</strong>: The TypeScript-first approach of NestJS is a major plus. It catches errors early and makes refactoring much easier.</p>
</li>
<li><p><strong>Team Dynamics</strong>: In my experience, NestJS is excellent for larger teams with varying skill levels. The enforced structure helps maintain consistency.</p>
</li>
<li><p><strong>Performance</strong>: While NestJS adds some overhead compared to bare Express, the difference is negligible for most applications, and the benefits in maintainability often outweigh this.</p>
</li>
<li><p><strong>Ecosystem Growth</strong>: I'm impressed by how quickly the NestJS ecosystem is growing. There are now packages for most common tasks, which wasn't the case a couple of years ago.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719708887572/0f7b20ee-3f00-4a63-83f0-f2b51bd0e5da.webp" alt="NestJS framework ecosystem illustration with colorful hexagonal icons and code snippets" class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>NestJS represents a shift towards more structured, opinionated frameworks in the JavaScript backend world. It's not the right choice for every project, but for complex, long-lived applications, especially in enterprise settings, it's become my go-to framework.</p>
<p>The JavaScript backend ecosystem is vast and varied, and that's one of its strengths. Whether you choose NestJS, Express, or any other framework, the key is to understand your project's needs and your team's capabilities.</p>
<p>As for me, I'm excited to see how NestJS continues to evolve. It's brought a level of structure and maintainability to my Node.js projects that I previously associated only with Java applications. And in today's world of microservices and complex distributed systems, that's no small feat.</p>
<p>Remember, the best framework is the one that makes your team most productive and your application most maintainable in the long run.</p>
<p>Happy coding, and may your builds always be green!</p>
<hr />
<h3 id="heading-where-to-learn-more-about-nest">Where to Learn More about Nest</h3>
<ul>
<li><p><a target="_blank" href="https://docs.nestjs.com">NestJS Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://www.npmjs.com/package/@nestjs/cli">NestJS CLI</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/Scc33/nestjs-learning">NestJS Example</a></p>
</li>
</ul>
<h3 id="heading-related-articles">Related Articles</h3>
<ul>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/front-end-build-tools">Navigating Front-End Build Tools: A Comprehensive Guide for Developers</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/learn-react-basics-nextjs">Learn React Basics: NextJS</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/bun-the-comprehensive-toolkit-for-javascript-and-typescript">Bun: The Comprehensive Toolkit for JavaScript and TypeScript</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://blog.seancoughlin.me/comparing-react-angular-vue-and-svelte-a-guide-for-developers">Comparing React, Angular, Vue, and Svelte: A Guide for Developers</a>"</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>