<?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[Kamal abou eid]]></title><description><![CDATA[Software Engineer blending deep algorithmic problem solving with scalable Frontend Architecture. Obsessed with high-performance web systems, Core Web Vitals, accessibility, and modern UI engineering.]]></description><link>https://kamalaboueid.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Thu, 05 Nov 2026 11:31:47 GMT</lastBuildDate><atom:link href="https://kamalaboueid.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Proxy Pattern: React State with Valtio]]></title><description><![CDATA[xplore how Valtio uses JavaScript Proxies to simplify React state management with mutable objects, automatic reactivity, and optimized renders.]]></description><link>https://kamalaboueid.hashnode.dev/proxy-pattern-react-state-with-valtio</link><guid isPermaLink="true">https://kamalaboueid.hashnode.dev/proxy-pattern-react-state-with-valtio</guid><category><![CDATA[State Management ]]></category><category><![CDATA[React]]></category><category><![CDATA[proxy design pattern]]></category><category><![CDATA[proxy]]></category><category><![CDATA[state]]></category><category><![CDATA[valtio]]></category><dc:creator><![CDATA[kamal aboueid]]></dc:creator><pubDate>Mon, 02 Nov 2026 23:26:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/33a646fb-0769-40c7-905f-f3312c213656.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3><strong><mark>Introduction</mark></strong></h3>
<p>Managing state in React often starts with a simple idea: keep data in one place and update it when something changes. But as an application grows, state management can become more complicated than the UI itself.</p>
<p>Traditional approaches often require immutable updates, carefully structured reducers, selectors, and additional boilerplate to keep components synchronized with application state.</p>
<p>These patterns work, but they introduce an extra layer of complexity. Developers spend more time describing how state should change rather than focusing on what the application actually needs.</p>
<p>This is where <strong>Valtio</strong> offers a different approach.</p>
<p>Instead of relying on manually managed immutable updates, Valtio uses JavaScript Proxies to make state reactive. You work with ordinary JavaScript objects, while Valtio tracks changes behind the scenes</p>
<p>The result is a simpler way to manage shared state without sacrificing performance or control.</p>
<h2>The Core Concept: JavaScript Proxies</h2>
<p>At the heart of Valtio is the JavaScript <code>Proxy</code> object.</p>
<p>A Proxy allows you to intercept fundamental operations on another object, such as reading, writing, and deleting properties. This gives libraries the ability to observe how an object is being accessed and modified without changing how developers interact with it.</p>
<p>Valtio builds its state management model around this capability.</p>
<p>Instead of creating a reducer or defining update functions for every state transition, you can create a proxy around a regular JavaScript object.</p>
<pre><code class="language-js">import { proxy } from 'valtio'

const state = proxy({
  count: 0,
  user: { name: 'Alex' }
})

state.count++
</code></pre>
<p>The important detail is that the state looks and behaves like a <mark>normal JavaScript object.</mark></p>
<p>You can directly modify its properties, update nested objects, and work with familiar JavaScript patterns. Valtio handles the tracking and notification process internally.</p>
<p>This removes much of the ceremony associated with traditional state management.</p>
<h2>Fine-Grained Reactivity with <code>useSnapshot</code></h2>
<p>Making state reactive is only part of the solution. In React, the real challenge is knowing when a component should render again.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/db9688c0-2597-4e9b-ac02-a21cb3ee61d6.png" alt="" style="display:block;margin:0 auto" />

<p>Valtio solves this through <code>useSnapshot</code>.</p>
<p>ather than giving components direct access to the mutable proxy, <code>useSnapshot</code> provides a snapshot of the current state. It also tracks which properties a component actually reads.</p>
<pre><code class="language-jsx">import { useSnapshot } from 'valtio'

function Counter() {
  const snap = useSnapshot(state)

  return &lt;p&gt;{snap.count}&lt;/p&gt;
}
</code></pre>
<p>Here, the component depends only on <code>count</code>.</p>
<p>If another property changes, such as <code>state.user.name</code>, the Counter component does not need to re-render because of that unrelated update.</p>
<p>This is the key advantage of Valtio's fine-grained reactivity.</p>
<p>With many traditional state management approaches, developers may need to write selectors or carefully organize subscriptions to prevent unnecessary renders.</p>
<p>Valtio tracks property access automatically and uses that information to determine which components need to update.</p>
<p>This makes component subscriptions more precise without requiring additional configuration.</p>
<h2>Beyond the Basics</h2>
<p>Valtio also provides a useful foundation for patterns that commonly appear in modern frontend applications.</p>
<p><strong>Persistence :</strong></p>
<p>Application state can be synchronized with browser storage, such as <code>localStorage</code>, allowing selected data to survive page refreshes.</p>
<p>This is particularly useful for user preferences, interface settings, and lightweight application data. Persistence is handled separately from the proxy itself, keeping storage concerns independent from state updates.</p>
<p><strong>Derived State :</strong></p>
<p>Valtio supports derived values through JavaScript getters.</p>
<p>Instead of manually updating a calculated value whenever its dependencies change, you can define logic that derives it from existing state.</p>
<p>This keeps related data together while avoiding unnecessary synchronization between multiple state properties.</p>
<p>Both patterns demonstrate an important idea: Valtio does not attempt to replace JavaScript. It builds on the language's existing capabilities.</p>
<p><strong>Valitio in one</strong></p>
<p>Valtio takes a different approach to React state management by using JavaScript Proxies as its foundation.</p>
<p>It removes much of the boilerplate associated with immutable updates while preserving the simplicity of working with regular JavaScript objects.</p>
<p>More importantly, its snapshot-based subscription model provides fine-grained reactivity, allowing components to respond to the exact parts of state they depend on.</p>
<p>The architecture is straightforward:</p>
<ul>
<li><strong>Proxies</strong> make ordinary objects observable and mutable.</li>
<li><strong>Snapshots</strong> provide a consistent view of application state.</li>
<li><strong>Fine-grained tracking</strong> keeps React components synchronized with the data they actually use.</li>
</ul>
<p>For modern frontend applications, this combination offers a practical balance between simplicity, performance, and maintainability.</p>
<p>Valtio is a good example of how understanding native JavaScript features can lead to cleaner abstractions and a better developer experience.</p>
<p>Sometimes, the best state management solution is not another layer of complexity, but a smarter way to work with the JavaScript we already know.</p>
]]></content:encoded></item><item><title><![CDATA[How I Design Scalable Frontend Systems (The RADIO Framework)]]></title><description><![CDATA[When we get a new project idea or a hard problem in an interview, our brain gets excited. We often want to start coding immediately. We think about React…]]></description><link>https://kamalaboueid.hashnode.dev/how-i-design-scalable-frontend-systems-the-radio-framework</link><guid isPermaLink="true">https://kamalaboueid.hashnode.dev/how-i-design-scalable-frontend-systems-the-radio-framework</guid><category><![CDATA[radio]]></category><category><![CDATA[RADIO Framework]]></category><category><![CDATA[System Design]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[kamal aboueid]]></dc:creator><pubDate>Sun, 11 Oct 2026 14:39:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/84e9842b-781c-4802-a3aa-893024d12499.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When we get a new project idea or a hard problem in an interview, our brain gets excited. We often want to start coding immediately. We think about React, Next.js, Redux, or CSS frameworks in the first few minutes.</p>
<p>Most of the time, this leads to messy code, confusing bugs, and a system that breaks easily when it grows.</p>
<p>To build a clean, stable product that actually works in production, you need a clear step-by-step thinking process.</p>
<p>A great system design framework for frontend developers is called <strong>RADIO</strong>. It is an easy checklist of 5 steps:</p>
<ul>
<li><p><strong>R</strong> - Requirements Explorations</p>
</li>
<li><p><strong>A</strong> - Architecture &amp; High Level Design</p>
</li>
<li><p><strong>D</strong> - Data Model &amp; Core Entities</p>
</li>
<li><p><strong>I</strong> - Interface (API)</p>
</li>
<li><p><strong>O</strong> - Optimization &amp; Deep Dive</p>
</li>
</ul>
<p>Each step prepares you for the next one. <mark class="bg-yellow-200 dark:bg-yellow-500/30"> When you follow this order, you never feel lost</mark>, and your final product becomes <strong>solid and maintainable.</strong></p>
<p>Let us walk through this framework from scratch using a real-world example: <strong>Building a Social Media Feed (like Facebook or Twitter)</strong>.</p>
<h2>1. Requirements (Understand What You Are Building)</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/24acc690-37b5-4632-89e0-6217b319ee7b.webp" alt="" style="display:block;margin:0 auto" />

<p>Before writing any logic, you must be 100% sure about what you need to build. Never build on assumptions. <mark class="bg-yellow-200 dark:bg-yellow-500/30">Always ask questions to understand the goals and the limits.</mark></p>
<p>We split requirements into two simple parts:</p>
<h3>Functional Requirements</h3>
<p>This is what the <mark class="bg-yellow-200 dark:bg-yellow-500/30">app actually does</mark>:</p>
<ul>
<li><p>Users can view a feed of posts with text and pictures.</p>
</li>
<li><p>Users can write and publish a new post.</p>
</li>
<li><p>Users can like and comment on posts.</p>
</li>
<li><p>Users can scroll down continuously to load more posts.</p>
</li>
</ul>
<h3>Non-Functional Requirements</h3>
<p><mark class="bg-yellow-200 dark:bg-yellow-500/30">This is about system quality, speed, and reliability</mark>:</p>
<ul>
<li><p>The app must load fast and scroll smoothly without lag.</p>
</li>
<li><p>It must work nicely on both phones and laptops.</p>
</li>
<li><p>It must handle poor internet connections gracefully.</p>
</li>
<li><p>It must handle hundreds of posts without crashing the browser memory.</p>
</li>
</ul>
<h2>2. Architecture (The Big Picture)</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/ac3da41d-0660-4680-8b9d-2282ae04861a.webp" alt="" style="display:block;margin:0 auto" />

<p>Now that you know the goals, step back and look at the whole system from above.</p>
<p>Architecture is not about small HTML tags or buttons. It is simply a<mark class="bg-yellow-200 dark:bg-yellow-500/30">bout big modules (boxes) and the flow of data between them</mark> (arrows).</p>
<p>We start by imagining the screen layout:</p>
<ul>
<li><p>A post creator at the top where users write.</p>
</li>
<li><p>A post card that contains a user avatar, username, content, and a comments area.</p>
</li>
</ul>
<p>Next, we c<mark class="bg-yellow-200 dark:bg-yellow-500/30">onnect these parts in a clean data flow</mark>:</p>
<ul>
<li><p>When a user writes a post or adds a comment, that input component talks to a central Controller.</p>
</li>
<li><p>The Controller talks directly to the backend Server to save the data.</p>
</li>
<li><p>When the Server replies, the Controller sends the fresh data into a central Store (our client cache).</p>
</li>
<li><p>All view components (the post header, post body, and comment list) read from this Store and display the information.</p>
</li>
</ul>
<p>This keeps our logic tidy. The visual components do not worry about the network, and the network layer does not care about how things look.</p>
<h2>3. Data Model (What Data Exists and Where It Lives)</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/69ab04c9-def7-4d14-b224-a28f2163a505.webp" alt="" style="display:block;margin:0 auto" />

<p>Every app is built around data. In this step, we identify our core entities, what fields they have, and where they live on the client side.</p>
<p>We divide all frontend data into two main sources:</p>
<h3>Server Originated Data</h3>
<p>This is data that lives inside a <mark class="bg-yellow-200 dark:bg-yellow-500/30"> remote database</mark>. The server is the real owner of this data.</p>
<ul>
<li><p>Examples: User profile details, published posts, and comments.</p>
</li>
<li><p>In the frontend, this data lives inside a central cache or store.</p>
</li>
</ul>
<h3>Client Only Data</h3>
<p>This is data that starts on the user's device:</p>
<ul>
<li><p><strong>Persisted data:</strong> Data the user writes locally that will soon be saved to the database (for example, the <mark class="bg-yellow-200 dark:bg-yellow-500/30">text inside a new post box before clicking send</mark>).</p>
</li>
<li><p><strong>Temporary data:</strong> Short-lived visual flags that we never save to a database (for example, showing a loading spinner, or keeping a dropdown open).</p>
</li>
</ul>
<h3>The Core Entities in Our Feed</h3>
<ul>
<li><p><strong>New Post Draft:</strong> Lives in the post composer component. It contains the text content and any selected media files.</p>
</li>
<li><p><strong>User:</strong> Lives in the central store. It contains <code>id</code>, <code>username</code>, and <code>profile_pic</code>.</p>
</li>
<li><p><strong>Post:</strong> Lives in the central store. It contains <code>id</code>, <code>date</code>, <code>content</code>, <code>media</code>, and the <code>comments</code> list.</p>
</li>
</ul>
<h3>Important Rules for Data</h3>
<ul>
<li><p>Describe your entities clearly using TypeScript notation.</p>
</li>
<li><p>Keep state minimal. Less state means fewer bugs.</p>
</li>
<li><p>Never create a state variable for something you can calculate. For example, do not save <code>totalComments</code> in a state if you can just read <code>comments.length</code>.</p>
</li>
</ul>
<h2>4. Interface (API Definition)</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/3a8c9c03-8c38-4449-b986-2c6da432f831.webp" alt="" style="display:block;margin:0 auto" />

<p>An API is simply an interface or a contract that <mark class="bg-yellow-200 dark:bg-yellow-500/30"> connects two layers together</mark>.</p>
<p>Many developers think an API is only between the frontend and the backend. But in frontend system design, an <mark class="bg-yellow-200 dark:bg-yellow-500/30">API can also be between two frontend components (Client to Client)</mark>.</p>
<p>Every API needs three main things:</p>
<ol>
<li><p><strong>Functionality:</strong> What does it do?</p>
</li>
<li><p><strong>Parameters (Input):</strong> What information does it take?</p>
</li>
<li><p><strong>Response (Output):</strong> What does it return?</p>
</li>
</ol>
<h3>Real Example: Infinite Feed Pagination</h3>
<p>You cannot load 10,000 posts all at once when a page opens. You fetch them in small batches (chunks) using pagination.</p>
<p>To do this, we use <strong>Cursor-based Pagination</strong>:</p>
<ul>
<li><p><strong>Functionality:</strong> Get a batch of posts for the feed.</p>
</li>
<li><p><strong>Input Parameters:</strong> We send the batch <code>size</code> (for example: 10 posts) and a pointer called <code>next_cursor</code>. On the very first request, the cursor is empty.</p>
</li>
<li><p><strong>Output Response:</strong> The server sends back an array with 10 post objects, plus a new <code>next_cursor</code> token.</p>
</li>
</ul>
<p>When the user scrolls near the bottom of their screen, the app catches this event, grabs that new cursor token, and sends another request to get the next 10 posts smoothly without duplicating anything.</p>
<p>At the component level, components communicate the same way: a parent component passes props down to a child component, and the child returns events (like an <code>onLike</code> click) back up to the parent.</p>
<h2>5. Optimization (Making It Production-Ready)</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/b376e5b2-9224-445d-af0c-92237594d51a.webp" alt="" style="display:block;margin:0 auto" />

<p>This is the final step, where you turn your initial design into a fast, secure, production-grade application.</p>
<p>Here are the most important areas to think about:</p>
<h3>Performance &amp; Rendering</h3>
<ul>
<li><p><strong>Virtualization (Windowing):</strong> If a user scrolls through 500 posts, having 500 post items inside the browser DOM will make the page slow. With virtualization, we only render the few posts visible on the screen and discard the rest until the user scrolls back.</p>
</li>
<li><p><strong>Image Optimization:</strong> Load images only when they appear near the screen (lazy loading), and use modern lightweight formats like WebP.</p>
</li>
<li><p><strong>Optimistic UI:</strong> When a user clicks like, update the UI and increase the like counter immediately so the app feels instant. If the network call fails later, revert the counter and show a friendly message.</p>
</li>
</ul>
<h3>Network &amp; Security</h3>
<ul>
<li><p><strong>Debouncing:</strong> When someone types in a search box, wait until they pause typing for 300 milliseconds before sending the network request.</p>
</li>
<li><p><strong>Security (XSS):</strong> Always clean and sanitize any text or comments written by users before displaying them, so nobody can inject harmful scripts.</p>
</li>
</ul>
<h3>Localization (i18n)</h3>
<p>Make sure the app supports different languages and layouts easily. This means your UI can switch smoothly between Left-to-Right (English) and Right-to-Left (Arabic), and only loads the language translation file that the user needs.</p>
<h3>Testing &amp; Stability</h3>
<ul>
<li><p>Use Error Boundaries so that if one single comment or post crashes, it does not bring down the entire website.</p>
</li>
<li><p>Write tests for critical user flows to make sure core features never break.</p>
</li>
</ul>
<h2>Putting It All Together</h2>
<p>Solving system design challenges is not about memorizing complex tools or showing off jargon. It is about having a clear, calm way of thinking.</p>
<p>Whenever you face a new feature at work or a question in an interview, do not rush into code. Take a breath, write down the word <strong>RADIO</strong>, and follow the steps one by one:</p>
<ol>
<li><p>Understand the <strong>Requirements</strong></p>
</li>
<li><p>Sketch the high-level <strong>Architecture</strong></p>
</li>
<li><p>Define the <strong>Data Model</strong></p>
</li>
<li><p>Specify the <strong>Interfaces</strong></p>
</li>
<li><p>Think through <strong>Optimizations</strong></p>
<p>When you follow this framework, you will build applications that are clean, easy to maintain, and ready for real users.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Demystifying OAuth 2.0 and OpenID Connect]]></title><description><![CDATA[Learn OAuth 2.0 and OpenID Connect architecture: why they exist, token mechanics, and the secure Authorization Code flow.]]></description><link>https://kamalaboueid.hashnode.dev/demystifying-oauth-2-0-and-openid-connect</link><guid isPermaLink="true">https://kamalaboueid.hashnode.dev/demystifying-oauth-2-0-and-openid-connect</guid><category><![CDATA[OAuth2]]></category><category><![CDATA[OpenID Connect]]></category><category><![CDATA[Web Security]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[Software Engineering]]></category><dc:creator><![CDATA[kamal aboueid]]></dc:creator><pubDate>Thu, 08 Oct 2026 19:31:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/bc75dce5-298c-4ce6-96b9-d3c2560625ae.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When developers implement features like <strong>"Sign in with Google"</strong>, they often encounter a set of confusing terms: <strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Client ID</mark></strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">,</mark> <strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Client Secret</mark> ,</strong> <strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Authorization Code</mark></strong>, <strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Access Token</mark></strong>, and <strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">ID Token</mark></strong></p>
<p>To understand why these components exist and how they work together, we need to look back at how third-party authorization started, the architectural flaws that appeared, and the standardized solutions we use today.</p>
<h3>1. The Historical Problem: The Password Anti-Pattern</h3>
<p>In the early days of the web, photo-sharing platforms like <strong>Flickr</strong> became very popular. Soon, third-party services emerged to offer additional features, such as printing photos onto physical books, t-shirts, or mugs.</p>
<p>To access private photos from Flickr, these print services used a dangerous approach known as the <strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Password Anti-Pattern</mark></strong>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/0149ae4b-0377-49f7-95ad-74fd4ba1f876.webp" alt="" style="display:block;margin:0 auto" />

<h4>Why this design was broken:</h4>
<h4>1 . <em><mark class="bg-yellow-200 dark:bg-yellow-500/30">Unrestricted Access</mark> :</em> The third-party website received full administrative power over your account. It could view private messages, delete photos, or change your account details.</h4>
<h4>2 . <mark class="bg-yellow-200 dark:bg-yellow-500/30">Credential Storage</mark> <em>:</em> External services stored raw or reversibly encrypted passwords in their own databases. A single data breach on a small service exposed primary user credentials.</h4>
<h4>3 . <mark class="bg-yellow-200 dark:bg-yellow-500/30">No Granular Revocation</mark> <em>:</em> You could not revoke access for one service without changing your actual account password, which broke every other linked application.</h4>
<h3>2. The First Solution: OAuth 2.0 for Authorization</h3>
<p>To solve the Flickr problem, the industry created <strong>OAuth 2.0</strong>.</p>
<p>OAuth 2.0 is an <strong>Authorization Framework</strong>. It allows a user to grant a third-party application limited access to their protected resources without sharing their password.</p>
<p>Instead of handing over credentials, the authorization server grants a scoped key called an <strong>Access Token</strong>:</p>
<ul>
<li><p>An Access Token acts like a hotel keycard: it opens specific doors (e.g., read photos only).</p>
</li>
<li><p>It does not disclose the user's password.</p>
</li>
<li><p>It can be revoked at any time from account security settings.</p>
</li>
</ul>
<p><strong>Crucial Concept:</strong> OAuth 2.0 answers the question: <strong>"What actions is this client allowed to perform?"</strong> (Authorization). It was never designed to prove: <strong>"Who is currently sitting in front of the screen?"</strong> (Authentication).</p>
<h3>3. The Pseudo-Authentication Pitfall</h3>
<p>As OAuth 2.0 gained widespread adoption, developers attempted to use it for single sign-on (SSO). The standard workaround looked like this:</p>
<ol>
<li><p>Obtain an <code>access_token</code> from an identity provider like Facebook or Google.</p>
</li>
<li><p>Call a profile endpoint (e.g., <code>GET /userinfo</code>).</p>
</li>
<li><p>Assume that receiving profile data confirms successful user login.</p>
</li>
</ol>
<p>This workaround caused security vulnerabilities:</p>
<ul>
<li><p><strong>Opaque Tokens:</strong> The client application cannot reliably inspect an Access Token. It is an opaque string intended strictly for the Resource Server.</p>
</li>
<li><p><strong>The Confused Deputy Attack:</strong> A malicious website could obtain a valid Access Token from a user on its own platform, send that token to a different application, and falsely authenticate as that user. The receiving application had no cryptographic proof indicating which client the token was originally issued for.</p>
</li>
<li><p><strong>No Common Standard:</strong> Every provider returned user metadata using different key names and structures (<code>user_id</code>, <code>id</code>, <code>sub</code>, <code>screen_name</code>).</p>
</li>
</ul>
<h3>4. The Standard Solution: OpenID Connect (OIDC)</h3>
<p>To address the limitations of using OAuth 2.0 for authentication, the industry introduced <strong>OpenID Connect (OIDC)</strong> as an identity layer on top of OAuth 2.0:</p>
<p>$$\text{OIDC} = \text{OAuth 2.0} + \text{Identity Layer}$$</p>
<p>OIDC adds three primary components:</p>
<h3><code>1. The openid Scope</code></h3>
<p>Adding <code>openid</code> to the requested scopes signals to the provider that this is an authentication request rather than a simple resource delegation.</p>
<h3><code>2. The ID Token</code></h3>
<p>Alongside the standard Access Token, the server issues an <strong>ID Token</strong>. The ID Token is a signed <strong>JSON Web Token (JWT)</strong> containing structured user assertions called <strong>Claims</strong>:</p>
<ul>
<li><p><code>sub</code> (Subject): A stable, unique identifier for the user.</p>
</li>
<li><p><code>iss</code> (Issuer): The identity provider that generated the token.</p>
</li>
<li><p><code>aud</code> (Audience): The exact <code>client_id</code> of the application authorized to read the token. If the value does not match your application ID, you must reject it.</p>
</li>
<li><p><code>exp</code> (Expiration): The exact timestamp when the token expires.</p>
</li>
</ul>
<h3><code>3. Standardized Discovery</code></h3>
<p>Providers expose a metadata document at a fixed endpoint:</p>
<p><code>/.well-known/openid-configuration</code></p>
<p>This endpoint allows applications to retrieve public signing keys (JWKS) and authorization endpoints automatically.</p>
<h3>5. Architectural Building Blocks</h3>
<p>Before tracing the execution sequence, review the core entities and credentials:</p>
<table style="min-width:75px"><colgroup><col style="min-width:25px"></col><col style="min-width:25px"></col><col style="min-width:25px"></col></colgroup><tbody><tr><td><p><strong>Term</strong></p></td><td><p><strong>Role</strong></p></td><td><p><strong>Security Location</strong></p></td></tr><tr><td><p><strong>Client ID</strong></p></td><td><p>A public identifier assigned to your project by the provider.</p></td><td><p>Frontend and backend (Public).</p></td></tr><tr><td><p><strong>Client Secret</strong></p></td><td><p>A private key used by your backend to verify its identity.</p></td><td><p>Backend environment variables only (Secret).</p></td></tr><tr><td><p><strong>Redirect URI</strong></p></td><td><p>A strict, pre-registered callback route on your server.</p></td><td><p>Configured inside provider console.</p></td></tr><tr><td><p><strong>Authorization Code</strong></p></td><td><p>A short-lived, single-use credential returned via URL query.</p></td><td><p>Passed safely from browser to your backend.</p></td></tr><tr><td><p><strong>Access Token</strong></p></td><td><p>A bearer token granting access to specific API endpoints.</p></td><td><p>Shared between backend and resource API.</p></td></tr><tr><td><p><strong>ID Token</strong></p></td><td><p>A cryptographically signed identity proof (JWT).</p></td><td><p>Parsed and validated by your backend.</p></td></tr></tbody></table>

<h3>6. Execution Flow: The Authorization Code Grant</h3>
<p>For web applications with an application server, the <strong>Authorization Code Flow</strong> provides a secure handoff between the untrusted browser and backend servers.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/c8b1b551-3cd6-4553-aac7-d534d659309d.webp" alt="" style="display:block;margin:0 auto" />

<h3>Why we do not send tokens directly to the browser:</h3>
<ul>
<li><p>Web browsers run client-side extensions and maintain navigation histories that could expose sensitive tokens.</p>
</li>
<li><p>A client browser cannot store a <code>Client Secret</code> without leaking it to end users.</p>
</li>
<li><p>The backend-to-backend exchange (Step 6) takes place across an encrypted, isolated channel that the browser never intercepts.</p>
</li>
</ul>
<h2>7. Authentication vs. Authorization Summary</h2>
<table style="min-width:75px"><colgroup><col style="min-width:25px"></col><col style="min-width:25px"></col><col style="min-width:25px"></col></colgroup><tbody><tr><td><p><strong>Feature</strong></p></td><td><p><strong>OAuth 2.0</strong></p></td><td><p><strong>OpenID Connect (OIDC)</strong></p></td></tr><tr><td><p><strong>Primary Purpose</strong></p></td><td><p>Delegated Authorization</p></td><td><p>User Authentication</p></td></tr><tr><td><p><strong>Output Token</strong></p></td><td><p><code>access_token</code></p></td><td><p><code>id_token</code> (JWT)</p></td></tr><tr><td><p><strong>Consumer</strong></p></td><td><p>Resource Server (APIs)</p></td><td><p>Client Application (Your App)</p></td></tr><tr><td><p><strong>Key Question</strong></p></td><td><p>What data can the client access?</p></td><td><p>Who is the authenticated user?</p></td></tr><tr><td><p><strong>Real-world Analogy</strong></p></td><td><p>Hotel door keycard</p></td><td><p>Passport or national ID card</p></td></tr></tbody></table>

<p>By keeping these responsibilities separate, modern web systems prevent credential leaks, protect sensitive API resources, and maintain clear security boundaries.</p>
]]></content:encoded></item><item><title><![CDATA[Frontend Architecture vs. Frontend System Design: Defining the Boundaries]]></title><description><![CDATA[Understand the key differences between Frontend Architecture and System Design, from core rendering strategies to tactical component decisions.]]></description><link>https://kamalaboueid.hashnode.dev/frontend-architecture-vs-frontend-system-design-defining-the-boundaries</link><guid isPermaLink="true">https://kamalaboueid.hashnode.dev/frontend-architecture-vs-frontend-system-design-defining-the-boundaries</guid><category><![CDATA[software architecture]]></category><category><![CDATA[System Design]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[React]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[kamal aboueid]]></dc:creator><pubDate>Sun, 27 Sep 2026 09:43:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/f85a72d7-57cc-4804-be70-79e194a67233.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When Software engineers hear terms like <code>System Architecture</code> and <code>System Design</code>, their minds instinctively jump to the backend: <strong>microservices</strong>, <strong>load balancers</strong>, <strong>database sharding</strong>, and <strong>message queues</strong>.</p>
<p>For a long time, people thought the frontend was just about styling buttons, moving pixels around, and calling a few APIs. But modern frontend applications are not just static pages anymore. They are <strong>complex applications running on real devices</strong> with real <strong>memory constraints</strong> and <strong>network limitations</strong>.</p>
<p><strong>The truth is, you are already doing frontend architecture and system design every single day</strong>—even if you don't call it that yet.</p>
<p>Every time you choose how your app <strong>fetches and caches data</strong>, how you <strong>split your code</strong>, how you <strong>manage state across components</strong>, or how you <strong>optimize a heavy list so the browser doesn't freeze</strong>, you are making architectural and design choices.</p>
<p>The real problem happens when we mix both concepts together:</p>
<ul>
<li><p>An <strong>architectural mistake</strong> cannot be fixed by just writing a clever custom hook.</p>
</li>
<li><p>A <strong>bad component design</strong> can still ruin a well-architected app.</p>
</li>
</ul>
<p>To build solid web applications, we need to know the difference between the <strong>big picture</strong> and the <strong>day-to-day implementation details</strong>.</p>
<blockquote>
<p>Before zooming into client-side engineering, let's step back and look at <strong>Software Architecture</strong> and <strong>Software Design</strong> in general. Understanding how they work at a high level makes it much easier to see where our frontend code fits into the bigger picture.</p>
</blockquote>
<h4>1. What is Software Architecture?</h4>
<p>software architecture has multiple perspectives depending on how you look at the system. Rather than relying on a single rigid definition, industry leaders often describe it through four complementary viewpoints:</p>
<ol>
<li><p><strong>System Structure:</strong> Architecture is about the overall structure of a system—the major building blocks and how they relate to one another.</p>
</li>
<li><p><strong>Early Critical Choices:</strong> Architecture represents the decisions you wish you could get right early in a project, because changing them later is costly and disruptive.</p>
</li>
<li><p><strong>Core Priorities:</strong> Architecture is about the "important stuff"... whatever that is for your specific business and technical context.</p>
</li>
<li><p><strong>Organizing for Quality:</strong> Architecture is the set of significant design decisions about how the software is organized to promote desired quality attributes (like scalability, reliability, maintainability, and security).</p>
</li>
</ol>
<blockquote>
<p><strong>In summary:</strong> Software Architecture is the high-level skeleton and the hard-to-change foundational choices that shape everything else.</p>
</blockquote>
<h4>2. What is Software Design?</h4>
<p>While architecture sets the boundaries, <strong>Software Design</strong> handles the detailed execution inside those boundaries. It is all about how specific modules, classes, and functions are written to solve concrete problems cleanly:</p>
<ul>
<li><p><strong>The Scope:</strong> Low-level (individual modules, components, and functions).</p>
</li>
<li><p><strong>The Core Question:</strong> <em>"How does this specific part work internally?"</em></p>
</li>
<li><p><strong>The Cost of Change:</strong> Decisions here are <strong>easy and cheap to refactor</strong> locally without breaking the whole platform.</p>
</li>
<li><p><strong>The Goal:</strong> Code maintainability, clean interfaces, and applying patterns like SOLID to write readable, reusable code</p>
</li>
</ul>
<h4>3. Architecture vs. Design: Side-by-Side</h4>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/11e431f1-d178-4653-94c8-d1f9ebe4e357.png" alt="" style="display:block;margin:0 auto" />

<h2>Why Do We Actually Need to Care About This Difference?</h2>
<p>Distinguishing between <strong>architectural decisions</strong> and <strong>design decisions</strong> isn't just theory—it actively protects the engineering team, saves time, and shields the product from painful rewrites.</p>
<p>Here is why understanding the boundary matters:</p>
<ul>
<li><p><strong>Calibrate Decision Weight:</strong> It helps the team understand exactly how seriously they should treat a choice before committing to it.</p>
</li>
<li><p><strong>Stop Underestimating Architecture:</strong> It prevents hasty, impulsive bets on fundamental system structures that take months of painful refactoring to undo.</p>
</li>
<li><p><strong>Stop Overestimating Design:</strong> It protects engineers from "analysis paralysis"—spending days debating tactical, local implementation details that can easily be changed later.</p>
</li>
</ul>
<hr />
<h2>The Transition: From General Concepts to the Browser</h2>
<p>Everything discussed so far applies to software engineering as a whole. Now, we shift our focus directly to the frontend.</p>
<p>In client-side engineering, <strong>these exact same rules govern our work</strong>—except the constraints are now the browser environment, user devices, network latency, and runtime memory.</p>
<hr />
<h2>4. Frontend Architecture (The Macro Blueprint)</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/708d0d91-297a-41be-8b3c-93cacf470af9.png" alt="" style="display:block;margin:0 auto" />

<p>Frontend Architecture is not about picking a styling framework or deciding folder structures. It focuses on the <strong>fundamental</strong>, <strong><mark class="bg-yellow-200 dark:bg-yellow-500/30"> hard-to-reverse decisions that dictate how the application is built, loaded, and served to the user.</mark></strong></p>
<h3>Core Architectural Decisions:</h3>
<ul>
<li><p><strong>Rendering and Delivery Strategy:</strong> Determining whether routes use Client-Side Rendering (CSR), Server-Side Rendering (SSR), or Static Site Generation (SSG). This directly impacts Core Web Vitals, initial load performance, and infrastructure requirements.</p>
</li>
<li><p><strong>Application Topology:</strong> Choosing between a Modular Monolith, a Monorepo setup, or decentralized Micro-Frontends to support team scale.</p>
</li>
<li><p><strong>Network and Data Boundaries:</strong> Defining how data enters the client (REST, GraphQL, or WebSockets) and establishing global caching layers with Service Workers or HTTP cache headers.</p>
</li>
<li><p><strong>State Topology:</strong> Drawing clear boundaries between server cache, persistent storage (IndexedDB/LocalStorage), and runtime memory.</p>
</li>
</ul>
<p>Key rule: <strong>If changing a decision later requires rewriting large portions of the codebase or changing deployment pipelines</strong>, it belongs to Frontend Architecture.</p>
<h2>5. Frontend System Design (The Micro Execution)</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6ab88c552e6a138abf7988a0/6b101fe0-aac9-46d5-9599-e1f0737f754b.png" alt="" style="display:block;margin:0 auto" />

<p>While Frontend Architecture sets the global boundaries, <strong>Frontend System Design</strong> handles how you construct features and components inside those boundaries. It deals with the day-to-day tactical execution to make the UI fast, resilient, and easy to maintain.</p>
<h3>Core Design Decisions:</h3>
<ul>
<li><p><strong>Component Composition:</strong> Designing reusable UI primitives and component contracts using patterns like Compound Components, Render Props, or Slots.</p>
</li>
<li><p><strong>State Encapsulation:</strong> Deciding where state lives locally (inside a component, custom hook, or context , Redux , Zustand , etc.) to prevent unnecessary re-renders across the tree.</p>
</li>
<li><p><strong>Logic Decoupling:</strong> Separating complex business logic and API calls from JSX templates by moving them into isolated Custom Hooks and utility functions (bast practice).</p>
</li>
<li><p><strong>Local Performance Optimizations:</strong> Applying techniques like virtualized lists for heavy datasets, memoization, debouncing search inputs and Abort controller, lazy Loading and dynamic component imports .</p>
</li>
<li><p><strong>Client Data &amp; API Caching:</strong> Managing server-state lifecycles at the feature level—implementing caching, background revalidation (stale-while-revalidate), and query deduplication (e.g., using TanStack Query , RTQ or SWR) to avoid redundant network requests.</p>
</li>
</ul>
<p>Key rule: <strong>If a decision can be refactored or improved locally within a feature without breaking the rest of the application, it belongs to Frontend System Design.</strong></p>
<hr />
<h2>6. The Real-World Difference: A Tale of Two Decisions</h2>
<p>To see how this distinction plays out in real projects, compare two common scenarios frontend teams face:</p>
<h3>Scenario A: Switching Core Frameworks (Architecture)</h3>
<p>Your team starts building an enterprise web application with <strong>React</strong>. Eight months into production, with hundreds of components, hooks, and routing logic already shipped, someone suggests switching to <strong>Angular</strong> or <strong>Vue</strong>.</p>
<p>Can you change this in a sprint? <strong>No</strong>. <mark class="bg-yellow-200 dark:bg-yellow-500/30">That choice requires tearing down and rewriting virtually the entire codebase from scratch</mark>. It impacts build tooling, developer hiring, libraries, and testing pipelines.</p>
<p>Because the cost of reversing it is monumental, choosing your core UI runtime is a <strong>Frontend Architecture</strong> decision.</p>
<h3>Scenario B: Changing Styling Approaches (Design)</h3>
<p>Now consider how you style that same application. You started using standard CSS Modules. As the design system scales, managing class names slows the team down, and you decide to adopt <strong>Tailwind CSS</strong>.</p>
<p>Do you have to stop shipping and rewrite the whole product? No. You can install Tailwind and begin using utility classes in new components immediately, while migrating older components gradually over time without breaking production.</p>
<p>Because <mark class="bg-yellow-200 dark:bg-yellow-500/30"> this change is localized</mark> and can be refactored step-by-step without bringing down the system, choosing your styling pattern is a <strong>Frontend System Design</strong> decision.</p>
]]></content:encoded></item></channel></rss>