<?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" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Anshuman on Medium]]></title>
        <description><![CDATA[Stories by Anshuman on Medium]]></description>
        <link>https://medium.com/@aansh0611?source=rss-a30f3e59663a------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*XVLQRhsbML7_T8XhwvccmA.png</url>
            <title>Stories by Anshuman on Medium</title>
            <link>https://medium.com/@aansh0611?source=rss-a30f3e59663a------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 30 May 2026 06:33:56 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@aansh0611/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Mastering Network Protocols in System Design: A High-Level Guide for Architects and Engineers]]></title>
            <link>https://medium.com/@aansh0611/mastering-network-protocols-in-system-design-a-high-level-guide-for-architects-and-engineers-d0930febd35a?source=rss-a30f3e59663a------2</link>
            <guid isPermaLink="false">https://medium.com/p/d0930febd35a</guid>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[computer-network]]></category>
            <category><![CDATA[system-design-concepts]]></category>
            <category><![CDATA[network-design]]></category>
            <category><![CDATA[network-protocols]]></category>
            <dc:creator><![CDATA[Anshuman]]></dc:creator>
            <pubDate>Mon, 07 Jul 2025 14:05:07 GMT</pubDate>
            <atom:updated>2025-07-07T14:05:07.576Z</atom:updated>
            <content:encoded><![CDATA[<h3>Introduction: Network Protocols Aren’t Just for Network Engineers</h3><p>When we talk about system design at a high level, most people jump straight to microservices, databases, caching, or load balancing. But there’s a silent hero underlying all of that: <strong>network protocols</strong>.<br>If architecture is the blueprint of your system, then <strong>network protocols are the language that glues all its parts together</strong>. APIs, databases, services, queues — they all communicate using specific protocols. Understanding those protocols is the difference between designing systems that merely <em>work</em> and those that <em>scale</em> reliably, securely, and efficiently.<br>Whether you’re building a real-time ride-sharing app, a scalable SaaS platform, or an e-commerce system, your <strong>protocol choices shape the very DNA of your system</strong>.<br>So let’s demystify this foundational layer of system design.</p><h3>What Are Network Protocols, Really?</h3><p>At their core, <strong>network protocols are standardized rules</strong> that determine <em>how</em> devices communicate over a network. They specify how data is structured, transmitted, received, and acknowledged between machines.<br>In High-Level Design (HLD), you don’t need to dive into bits and bytes — but you <em>do</em> need to understand:</p><ul><li><strong>Which protocols are available</strong></li><li><strong>When to use each</strong></li><li><strong>How they affect reliability, latency, security, and scalability</strong></li></ul><p>Because choosing the wrong protocol could mean poor performance, dropped data, or even architectural failure at scale.</p><h3>The Core Protocol Layers You Should Know (and When to Use Them)</h3><p>Let’s organize protocols into logical layers that align with your system’s components. This helps you visualize <strong>how data flows</strong> from user to server to internal microservices.</p><h3>1. Transport Layer Protocols: “How the Data Travels”</h3><p>This layer deals with <em>how</em> data packets move between systems.</p><h4>1.1 TCP (Transmission Control Protocol)</h4><p>TCP is the default for most client-server architectures because it. guarantees delivery — but it comes with <strong>latency overhead</strong> due to. handshaking and acknowledgments.</p><ul><li><strong>Use when</strong> you need <strong>reliable</strong>, <strong>ordered</strong>, and <strong>complete</strong> delivery.</li><li>Ideal for: REST APIs, database communication, payment systems.</li><li>Built-in features: Retransmission, congestion control, and flow control.</li></ul><h4>1.2 UDP (User Datagram Protocol)</h4><p>If you’re building something <strong>real-time</strong> (like a live location tracker), UDP’s lack of overhead gives you speed, but you’ll need to handle packet loss manually.</p><ul><li><strong>Use when</strong> speed matters more than reliability.</li><li>Ideal for: Video streaming, VoIP, gaming, real-time location updates.</li><li>Doesn’t guarantee delivery or order.</li></ul><h4>1.3. QUIC</h4><ul><li>Google’s next-gen protocol, built on UDP.</li><li><strong>Use when</strong> you want HTTP/3-level performance with lower latency.</li><li>Gaining popularity for modern web and API traffic.</li></ul><h3>2. Application Layer Protocols: “What the Data Is”</h3><p>Once transport is handled, these define <strong>what kind of communication</strong> is happening.</p><h4>2.1. HTTP/HTTPS</h4><ul><li>The backbone of the web.</li><li><strong>Use for</strong> client-server APIs, web pages, and general service requests.</li><li>Stateless by nature; each request is independent.</li></ul><h4>2.2. gRPC</h4><p>Perfect for internal service-to-service communication in large-scale, latency-sensitive systems.</p><ul><li>Modern alternative to REST; based on HTTP/2 and uses Protocol Buffers.</li><li><strong>Use for</strong> internal microservices where performance matters.</li><li>Supports bidirectional streaming, multiplexing, and is more efficient than JSON.</li></ul><h4>2.3. WebSockets</h4><p>WebSockets keep a persistent connection open — unlike HTTP — which reduces overhead and enables instant updates.</p><ul><li><strong>Use when</strong> you need real-time, bidirectional communication.</li><li>Great for: Chat apps, notifications, collaborative tools.</li></ul><h4>2.4. MQTT</h4><ul><li>Lightweight publish/subscribe protocol.</li><li><strong>Use for</strong> IoT devices or low-bandwidth environments.</li></ul><h3>3. Serialization Protocols: “How the Data Is Structured”</h3><p>Serialization protocols define how data is encoded and decoded across systems.</p><h4>3.1. JSON</h4><ul><li>Human-readable, widely supported.</li><li><strong>Use when</strong> human debugging or client-facing APIs are involved.</li></ul><h4>3.2. Protocol Buffers (Protobuf)</h4><ul><li>Efficient, compact, binary format.</li><li><strong>Use for</strong> gRPC and internal systems where performance matters.</li></ul><h4>3.3. Apache Avro / Thrift</h4><ul><li>Schema-driven, used in data pipelines and big data systems.</li><li><strong>Use when</strong> schema evolution and forward/backward compatibility are essential.</li></ul><h3>Real-World Architecture Examples: Protocols in Action</h3><h3>E-Commerce System</h3><p><strong>Scenario:</strong> A customer places an order through a web app.<br><strong>Flow:</strong></p><ul><li>Frontend communicates with the backend over <strong>HTTPS</strong>.</li><li>Backend services talk to each other using <strong>gRPC</strong>.</li><li>Real-time inventory updates are pushed via <strong>WebSockets</strong>.</li><li>Analytics pipeline uses <strong>Kafka</strong> with <strong>Avro</strong> serialization.</li></ul><blockquote><em>Choosing protocols like gRPC here cuts latency between services, while WebSockets ensure customers see inventory updates in real-time.</em></blockquote><h3>Ride-Hailing App</h3><p><strong>Scenario:</strong> A rider tracks a driver’s real-time location.<br><strong>Flow:</strong></p><ul><li>Client app sends ride requests via <strong>HTTPS</strong>.</li><li>Location updates flow from driver to server via <strong>UDP</strong> for speed.</li><li>Live tracking is maintained via <strong>WebSocket</strong>.</li><li>Microservices communicate internally using <strong>gRPC</strong>.</li></ul><blockquote><em>UDP gives you the speed you need, but WebSocket ensures the UI remains live and interactive. The system uses different protocols depending on context.</em></blockquote><h3>Tips for Architects</h3><ul><li><strong>Design with protocol layering in mind.</strong><br> Choose your <strong>transport</strong>, <strong>application</strong>, and <strong>serialization</strong> protocols with intention.</li><li><strong>Benchmark protocol performance</strong> in your environment.<br> gRPC may beat REST for internal services — but test before committing.</li><li><strong>Build for fallback.</strong><br> For example, HTTP/3 should gracefully fall back to HTTP/2 if unsupported.</li><li><strong>Enable observability.</strong><br> Choose protocols that support <strong>tracing, logging, and metrics collection</strong>. Without visibility, you can’t debug distributed issues.</li></ul><h3>Visualizing Protocols in a System</h3><blockquote><em>Imagine a system where multiple services speak different languages but still work harmoniously. That’s the power of well-chosen protocols.</em></blockquote><pre>  [ Client Browser ]<br>           |<br>         HTTPS<br>           |<br>     [ API Gateway ]<br>           |<br>      +----------+<br>      | Services |<br>      +----------+<br>     /    |    |  \<br>  gRPC  WebSocket  Kafka<br>    |       |         |<br>   DB  Notification  Analytics</pre><p>Each path uses a different protocol — each optimized for the role it plays.</p><h3>Final Takeaways</h3><ul><li><strong>Network protocols are architectural choices</strong>, not implementation details.</li><li>Every communication channel in your system must be <strong>intentionally designed</strong>.</li><li>Understanding protocols lets you make <strong>trade-offs in reliability, latency, and throughput</strong>.</li><li>There’s no single best protocol — <strong>only the best fit</strong> for a specific use case.</li></ul><p>So next time you’re designing a system, don’t just sketch services — <strong>sketch their conversations</strong>. That’s where true architecture happens.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d0930febd35a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Ultimate Guide to API Design and Communication Patterns in System Architecture]]></title>
            <link>https://medium.com/@aansh0611/the-ultimate-guide-to-api-design-and-communication-patterns-in-system-architecture-c5b042e8f574?source=rss-a30f3e59663a------2</link>
            <guid isPermaLink="false">https://medium.com/p/c5b042e8f574</guid>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[rest-api]]></category>
            <category><![CDATA[high-level-design]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[system-design-concepts]]></category>
            <dc:creator><![CDATA[Anshuman]]></dc:creator>
            <pubDate>Sat, 05 Jul 2025 11:26:07 GMT</pubDate>
            <atom:updated>2025-07-05T11:26:07.280Z</atom:updated>
            <content:encoded><![CDATA[<h3>Why These Concepts Matter in HLD</h3><p>APIs are how systems <strong>talk</strong>. They’re not just technical endpoints — they’re architectural contracts between services. Whether you’re designing a monolith, microservices, or a hybrid system, your <strong>API design choices</strong> — including <strong>sync/async, blocking/non-blocking, REST</strong>, and <strong>rate limiting</strong> — determine:</p><ul><li>Performance under load</li><li>Developer experience</li><li>Scalability and fault tolerance</li><li>System responsiveness and user satisfaction</li></ul><p>Understanding these concepts is essential if you’re building <strong>high-availability, low-latency, and fault-resilient systems</strong>.</p><h3>What Is API Design (in HLD)?</h3><p><strong>API Design</strong> refers to how you structure the <strong>interfaces</strong> that your services expose to others (users, systems, or other services). In HLD, API design includes:</p><ul><li>Protocol (e.g., REST over HTTP, gRPC)</li><li>Structure (endpoints, resources, parameters)</li><li>Communication style (synchronous vs asynchronous)</li><li>Response strategy (blocking vs non-blocking)</li><li>Governance (rate limiting, authentication)</li></ul><blockquote><em>Think of API design as the “language” of your services. Good design is intuitive, scalable, and resilient.</em></blockquote><h3>RESTful APIs: The Common Language of the Web</h3><p><strong>REST (Representational State Transfer)</strong> is the most widely used API design paradigm. It is stateless and operates over HTTP.</p><h3>Core Concepts of REST:</h3><ul><li><strong>Resources</strong> are represented via URLs (e.g., /users/123)</li><li><strong>Standard HTTP verbs</strong>:<br>GET: Retrieve data<br>POST: Create new resource<br>PUT/PATCH: Update<br>DELETE: Remove</li></ul><h3>REST in HLD:</h3><ul><li>Used for <strong>public APIs</strong>, <strong>frontend-backend communication</strong>, and <strong>CRUD services</strong></li><li>Simple, scalable, and widely supported</li><li>Easily handled by caching, proxies, and load balancers</li></ul><h4>Common Misconception:</h4><blockquote><em>“REST is the best for everything.”<br> No — REST is great for </em><strong><em>stateless, resource-based operations</em></strong><em>, but lacks in streaming and low-latency internal service communication. Enter gRPC, GraphQL, WebSockets, etc.</em></blockquote><h3>Synchronous vs Asynchronous API Calls</h3><p>Understanding <strong>synchronous vs asynchronous communication</strong> is critical when designing APIs and inter-service messaging in distributed systems.</p><h4>Synchronous Calls</h4><p>A <strong>synchronous call</strong> is like a phone conversation — you ask a question and wait for the answer before moving on.<br><strong>In system design:<br></strong>1.<strong> </strong>Client sends a request and <strong>waits (blocks)</strong> until the response is received.<br>2. Used in HTTP APIs, database queries, RPCs.<br><strong>Pros:<br></strong>1. Simpler, easier to reason about<br>2. Useful when immediate response is needed<br><strong>Cons:<br></strong>1.<strong> </strong>Tight coupling between services<br>2. Higher latency<br>3. Vulnerable to cascading failures<br><strong>HLD Use Case: </strong>Login API, Payment processing, Real-time data validation.</p><h4>Asynchronous Calls</h4><p>An <strong>asynchronous call</strong> is like sending an email — you send it, and move on. The response may come later.<br><strong>In system design:<br></strong>1.<strong> </strong>Client sends a request and continues without waiting.<br>2. Response is handled later via callback, message, or polling.<br>3. Often implemented with <strong>queues</strong>, <strong>event buses</strong>, or <strong>webhooks</strong>.<br><strong>Pros:<br></strong>1.<strong> </strong>Decouples services<br>2. Improves resilience and scalability<br>3. Helps handle long-running operations<br><strong>Cons:<br></strong>1.<strong> </strong>Complex error handling and retry logic<br>2. Potential for eventual consistency<br><strong>HLD Use Case:</strong> Email notifications, billing, order processing, data pipelines.</p><h3>Blocking vs Non-Blocking Calls</h3><p>Closely related but <strong>not the same</strong> as sync/async.</p><h4>Blocking Call</h4><p>The thread <strong>waits</strong> until a task finishes.<br>Typical in synchronous APIs or legacy systems<br>Can lead to thread starvation in high-load environments</p><h4>Non-Blocking Call</h4><p>The thread initiates a task and moves on, using callbacks/promises/reactive streams to handle results later.<br>Improves system throughput and efficiency<br>Common in <strong>reactive programming</strong> and <strong>event-driven architectures</strong></p><h4>Example:</h4><pre>// Blocking (Java)<br>String result = httpClient.get(&quot;...&quot;); // waits<br><br>// Non-blocking (Java with CompletableFuture)<br>httpClient.getAsync(&quot;...&quot;).thenAccept(result -&gt; {<br>    // process result<br>});</pre><p><strong>HLD Relevance:</strong><br> Use <strong>non-blocking</strong> I/O for high-concurrency services (e.g., API gateways, data ingestion pipelines).</p><h3>Rate Limiting: Protecting Your System from Overload</h3><p><strong>Rate limiting</strong> controls how many requests a client can make in a time window.</p><blockquote><em>Without it, one client — or a DDoS attack — could overwhelm your system.</em></blockquote><h4>Why It’s Critical in HLD:</h4><ul><li><strong>Prevents abuse</strong></li><li><strong>Ensures fairness</strong></li><li><strong>Protects downstream services</strong></li><li><strong>Improves stability under load</strong></li></ul><h4>Common Strategies</h4><ul><li><strong>Fixed Window: </strong>Allow 100 requests per minute.</li><li><strong>Sliding Window: </strong>Smooths out bursty traffic.</li><li><strong>Token Bucket / Leaky Bucket: </strong>Controls burst and flow rate.</li><li><strong>Exponential Backoff: </strong>Slows down retries from clients.</li></ul><h4>Where to Implement Rate Limiting</h4><ul><li><strong>API Gateway (edge layer)</strong> — easiest and most common.</li><li><strong>Service level</strong> — for sensitive internal endpoints.</li><li><strong>CDN/Reverse Proxy</strong> — for globally distributed traffic.</li></ul><h3>Example: REST API with Sync + Async + Rate Limiting</h3><h4>Scenario: Order Placement API</h4><ol><li><strong>Synchronous (Blocking)</strong>:<br> /orders POST – places the order, returns success/failure immediately.</li><li><strong>Asynchronous (Non-blocking)</strong>:<br> Order fulfillment handled via a message queue and processed later by a worker.</li><li><strong>Rate Limiting</strong>:<br> Users limited to 5 order attempts per minute at the API Gateway.</li></ol><pre>    [ Client ]<br>       |<br>      HTTPS (Synchronous)<br>       |<br>   [ API Gateway ] -- Rate Limiting<br>       |<br>   [ Order Service ] -- Queues (Async)<br>       |<br>   [ Fulfillment Worker ] (Non-Blocking)<br>       |<br>   [ Inventory / Shipping ]</pre><p><strong>Benefits:</strong></p><ul><li>Immediate feedback to user</li><li>Fulfillment can scale independently</li><li>System protected from abuse or overload</li></ul><h3>Common Misconceptions</h3><ul><li><strong>Async = Non-blocking</strong><br> They’re related but distinct. Async is about timing, non-blocking is about thread usage.</li><li><strong>Rate limiting slows down users</strong><br> It improves stability for <em>all</em> users, especially under high load.</li><li><strong>REST is outdated</strong><br> REST is still excellent for many use cases. Just choose wisely — use gRPC, GraphQL, or WebSockets when REST falls short.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c5b042e8f574" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mastering Design Patterns in Low-Level Design (LLD): A Pro-Level Guide for Smart Beginners]]></title>
            <link>https://medium.com/@aansh0611/mastering-design-patterns-in-low-level-design-lld-a-pro-level-guide-for-smart-beginners-47bd0935b452?source=rss-a30f3e59663a------2</link>
            <guid isPermaLink="false">https://medium.com/p/47bd0935b452</guid>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[system-design-concepts]]></category>
            <category><![CDATA[low-level-design]]></category>
            <category><![CDATA[computer-science]]></category>
            <dc:creator><![CDATA[Anshuman]]></dc:creator>
            <pubDate>Thu, 03 Jul 2025 15:57:11 GMT</pubDate>
            <atom:updated>2025-07-03T15:57:11.442Z</atom:updated>
            <content:encoded><![CDATA[<p>Design patterns aren’t just for architects or seniors. They’re for <strong>any developer who wants to write better, smarter, and more future-proof code</strong>. In low-level design (LLD), these patterns are your building blocks. They bring structure, reusability, and predictability to your object-oriented systems.</p><p>In this guide, we’ll explore <strong>what design patterns are</strong>, <strong>why they matter</strong>, and <strong>how to master them</strong>, one pattern at a time.</p><h3>What Are Design Patterns?</h3><p>Design patterns are <strong>proven solutions</strong> to common software design problems. They’re not chunks of code you copy-paste, but rather <strong>blueprints</strong> for structuring classes, managing object creation, and handling communication between components.</p><p>They were popularized by the <strong>“Gang of Four” (GoF)</strong> in the seminal book <em>Design Patterns: Elements of Reusable Object-Oriented Software</em>, and have since become essential to professional-level software development.</p><h3>Why Use Design Patterns?</h3><p>Let’s face it — software systems grow. And when they do, they get messy unless they’re carefully designed. That’s where design patterns come in. They help you:</p><ul><li>Avoid code duplication and spaghetti logic</li><li>Stick to SOLID principles (which they often embody)</li><li>Promote clean, maintainable, and extensible architecture</li><li>Enhance team communication (patterns are a shared vocabulary)</li><li>Save time by not reinventing the wheel</li></ul><p>Think of patterns as <strong>design wisdom encoded into reusable templates</strong>.</p><h3>Types of Design Patterns</h3><p>Design patterns fall into <strong>three major categories</strong>, each with a distinct purpose:</p><ol><li><strong>Creational Patterns</strong>: Handle object creation</li><li><strong>Structural Patterns</strong>: Manage object composition and relationships</li><li><strong>Behavioral Patterns</strong>: Define communication between objects</li></ol><p>Let’s explore each, with real-world use cases and beginner-friendly examples.</p><h3>1. Creational Patterns: Smarter Object Creation</h3><p>Creational patterns abstract the instantiation process. Instead of calling new everywhere, they give you <strong>controlled and flexible ways to create objects</strong>, especially when dealing with complex structures or multiple implementations.</p><ul><li><a href="https://medium.com/@aansh0611/the-singleton-design-pattern-in-java-your-ultimate-guide-to-the-one-and-only-instance-b916ea60e2e0"><strong><em>Singleton Pattern</em></strong></a></li><li><a href="https://medium.com/@aansh0611/the-factory-design-pattern-in-java-a-powerful-guide-for-smart-beginners-d9fc9144dfb3"><strong><em>Factory Method Pattern</em></strong></a></li><li><strong>Abstract Factory Pattern</strong></li><li><strong>Builder Pattern</strong></li><li><strong>Prototype Pattern</strong></li></ul><h4>When to Use:</h4><ul><li>You have multiple related classes and want to decouple instantiation logic</li><li>You want to encapsulate the creation process to reduce duplication</li></ul><h4>Example: Factory Pattern</h4><p><strong>Scenario</strong>: You have a notification service that sends Email, SMS, or Push notifications. Without a pattern, your code might be filled with if-else or switch statements. That’s tightly coupled and brittle.</p><p><strong>Solution</strong>: Use a <strong>Factory Pattern</strong> to centralize object creation.</p><pre>interface Notification {<br>    void notifyUser();<br>}<br><br>class EmailNotification implements Notification {<br>    public void notifyUser() {<br>        System.out.println(&quot;Sending Email Notification&quot;);<br>    }<br>}<br><br>class NotificationFactory {<br>    public Notification createNotification(String type) {<br>        return switch (type) {<br>            case &quot;EMAIL&quot; -&gt; new EmailNotification();<br>            // add SMS or Push types here<br>            default -&gt; throw new IllegalArgumentException(&quot;Unknown type&quot;);<br>        };<br>    }<br>}</pre><p><strong>Why It Works</strong>:<br> Now your application doesn’t care how the notification is created — it just uses the factory. This <strong>reduces coupling</strong> and makes it <strong>easy to add new types</strong> without touching existing code.</p><h3>2. Structural Patterns:Composing Objects Gracefully</h3><p>Structural patterns deal with <strong>how classes and objects are composed</strong> to form larger, more complex structures. They help ensure that components work well together, especially when adapting existing code or working with third-party libraries.</p><ul><li><strong>Adapter Pattern</strong></li><li><strong>Bridge Pattern</strong></li><li><strong>Composite Pattern</strong></li><li><strong>Decorator Pattern</strong></li><li><strong>Facade Pattern</strong></li><li><strong>Flyweight Pattern</strong></li><li><strong>Proxy Pattern</strong></li></ul><h4>When to Use:</h4><ul><li>You want to adapt one interface to another</li><li>You need to simplify complex relationships between objects</li></ul><h4>Example: Adapter Pattern</h4><p><strong>Scenario</strong>: You’re integrating a third-party logging tool with a different interface from your app’s logging interface.</p><p><strong>Solution</strong>: Use an <strong>Adapter Pattern</strong> to bridge the mismatch.</p><pre>interface Logger {<br>    void log(String message);<br>}<br><br>class ThirdPartyLogger {<br>    void writeToConsole(String msg) {<br>        System.out.println(msg);<br>    }<br>}<br><br>class LoggerAdapter implements Logger {<br>    ThirdPartyLogger thirdPartyLogger = new ThirdPartyLogger();<br>    public void log(String message) {<br>        thirdPartyLogger.writeToConsole(message);<br>    }<br>}</pre><p><strong>Why It Works</strong>:<br> You can use the third-party logger <strong>without changing your codebase</strong>. The adapter acts as a wrapper, aligning interfaces cleanly and transparently.</p><h3>3. Behavioral Patterns: Managing Object Interactions</h3><p>Behavioral patterns define <strong>how objects interact</strong> and distribute responsibilities among them. They reduce tight coupling and make your code more flexible and testable.</p><ul><li><a href="https://medium.com/@aansh0611/mastering-the-strategy-design-pattern-write-flexible-code-like-a-pro-8240ecc2c8d2"><strong><em>Strategy Pattern</em></strong></a></li><li><strong>Observer Pattern</strong></li><li><strong>Command Pattern</strong></li><li><strong>Template Method Pattern</strong></li><li><strong>State Pattern</strong></li><li><strong>Chain of Responsibility Pattern</strong></li><li><strong>Iterator Pattern</strong></li><li><strong>Mediator Pattern</strong></li><li><strong>Memento Pattern</strong></li><li><strong>Visitor Pattern</strong></li><li><strong>Interpreter Pattern</strong></li></ul><h4>When to Use:</h4><ul><li>You have multiple algorithms for a task and want to switch between them</li><li>You want objects to communicate without being tightly bound to each other</li></ul><h4>Example: Strategy Pattern</h4><p><strong>Scenario</strong>: You’re building a payment system that supports UPI, Credit Card, and PayPal.</p><p><strong>Problem</strong>: Without a strategy, you’d hard-code payment logic in a single class, making it rigid and hard to extend.</p><p><strong>Solution</strong>: Use the <strong>Strategy Pattern</strong> to encapsulate each algorithm.</p><pre>interface PaymentStrategy {<br>    void pay(int amount);<br>}<br><br>class CreditCardPayment implements PaymentStrategy {<br>    public void pay(int amount) {<br>        System.out.println(&quot;Paid with credit card: &quot; + amount);<br>    }<br>}<br><br>class PaymentContext {<br>    private PaymentStrategy strategy;<br>    public PaymentContext(PaymentStrategy strategy) {<br>        this.strategy = strategy;<br>    }<br>    public void makePayment(int amount) {<br>        strategy.pay(amount);<br>    }<br>}</pre><p><strong>Why It Works</strong>:<br> New payment methods can be added without touching existing logic. It’s a perfect example of the <strong>Open/Closed Principle</strong> in action.</p><h3>Common Misconceptions</h3><ul><li><strong>“Design patterns are overkill for small projects.”</strong><br> Even small apps benefit from clean, modular design.</li><li><strong>“They’re too complex for beginners.”</strong><br> When taught well (like here), they become intuitive tools.</li><li><strong>“They’re rigid templates.”</strong><br> Nope — they’re flexible solutions you adapt to your context.</li></ul><h4>Real-World Use Cases</h4><p>Design patterns are everywhere:</p><ul><li><strong>Spring Framework</strong>: Singleton (beans), Proxy (AOP), Template Method (JDBC)</li><li><strong>Android SDK</strong>: Observer (Listeners), Strategy (View animations)</li><li><strong>React</strong>: Composition over inheritance, Container/Presenter pattern</li><li><strong>Microservices</strong>: Command (via message queues), Proxy (API gateways)</li></ul><h3>What’s Next?</h3><p>If you enjoyed this deep dive, stay tuned for upcoming posts where we’ll explore each design pattern in-depth — complete with diagrams, real-world scenarios, and code you can use right away.</p><p><strong>Follow, clap, and share</strong> if you’re ready to level up your design thinking. ✨</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=47bd0935b452" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Singleton Design Pattern in Java — Your Ultimate Guide to the “One and Only” Instance]]></title>
            <link>https://medium.com/@aansh0611/the-singleton-design-pattern-in-java-your-ultimate-guide-to-the-one-and-only-instance-b916ea60e2e0?source=rss-a30f3e59663a------2</link>
            <guid isPermaLink="false">https://medium.com/p/b916ea60e2e0</guid>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[system-design-concepts]]></category>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[low-level-design]]></category>
            <category><![CDATA[design-patterns]]></category>
            <dc:creator><![CDATA[Anshuman]]></dc:creator>
            <pubDate>Thu, 03 Jul 2025 15:56:06 GMT</pubDate>
            <atom:updated>2025-07-03T15:56:06.277Z</atom:updated>
            <content:encoded><![CDATA[<h3>The Singleton Design Pattern in Java — Your Ultimate Guide to the “One and Only” Instance</h3><blockquote>“When you need only one instance of a class to control a shared resource, the Singleton Pattern becomes your trusted design ally.”</blockquote><p>If you’ve ever built a logger, a configuration manager, or a database connection pool, you’ve probably needed a Singleton — even if you didn’t know it.</p><p>This pattern is more than just a coding trick. It’s a powerful design strategy that ensures consistency, prevents resource waste, and centralizes control across your application.</p><p>Let’s dive deep, from beginner-friendly basics to professional best practices, so you can wield Singleton like a pro.</p><h3>Why You Should Care About the Singleton Pattern</h3><p>Picture this: you’re building an application with the following needs:</p><ul><li>A single configuration manager that loads values once</li><li>A centralized logging service accessed by all components</li><li>A shared database connection pool</li><li>A global game state or cache</li></ul><p>Now imagine accidentally creating multiple instances of these components. You’d get:</p><ul><li>Redundant resource usage</li><li>Inconsistent state across components</li><li>Hard-to-trace bugs</li></ul><p>That’s where the <strong>Singleton Pattern</strong> steps in.</p><h3>What Is the Singleton Pattern?</h3><blockquote><strong><em>Definition (Gang of Four):</em></strong><em> “Ensure a class has only one instance and provide a global point of access to it.”</em></blockquote><p>In simpler terms:</p><ul><li>You <strong>restrict</strong> the creation of a class to a single instance.</li><li>You <strong>expose</strong> that instance globally through a controlled access point.</li></ul><p>This makes your system more consistent and predictable.</p><h3>Real-World Analogy: The President of a Country</h3><p>In any functioning democracy:</p><ul><li>There’s <strong>only one president at a time</strong>.</li><li>Everyone refers to <strong>the same person</strong>, no matter where they are.</li><li>You don’t want <strong>multiple presidents</strong> giving contradictory orders.</li></ul><p>That’s exactly what Singleton ensures in software — a <strong>single, authoritative instance</strong>.</p><h3>Core Concepts of Singleton</h3><p>To understand Singleton fully, you need to grasp a few critical pillars:</p><ul><li><strong>Single Instance</strong> — Only one object exists throughout the application’s lifetime.</li><li><strong>Global Access Point</strong> — Clients access the instance via a static method.</li><li><strong>Lazy Initialization</strong> — The object is created only when needed (to save resources).</li><li><strong>Thread Safety</strong> — In multi-threaded systems, race conditions must be avoided during instantiation.</li></ul><h3>Java Code Example: The Basic Singleton</h3><p>Let’s implement a <strong>basic, non-thread-safe Singleton</strong>. This is a good starting point but not suitable for concurrent environments.</p><pre>public class Logger {<br>    private static Logger instance;<br>    private Logger() {<br>        // Private constructor prevents instantiation<br>    }<br>    public static Logger getInstance() {<br>        if (instance == null) {<br>            instance = new Logger(); // Lazy initialization<br>        }<br>        return instance;<br>    }<br>    public void log(String message) {<br>        System.out.println(&quot;[LOG]: &quot; + message);<br>    }<br>}</pre><h3>What’s Happening Here:</h3><ul><li>private constructor blocks external object creation.</li><li>getInstance() ensures only one instance is returned.</li><li>The object is lazily initialized — created only when requested.</li></ul><p><strong>Caution:</strong> In multi-threaded environments, two threads could still create separate instances. Let’s fix that.</p><h3>Thread-Safe Singleton (Double-Checked Locking)</h3><p>To make our Singleton thread-safe <strong>without incurring synchronization cost every time</strong>, we use <strong>double-checked locking</strong>:</p><pre>public class Logger {<br>    private static volatile Logger instance;<br>    private Logger() {}<br>    public static Logger getInstance() {<br>        if (instance == null) {<br>            synchronized (Logger.class) {<br>                if (instance == null) {<br>                    instance = new Logger();<br>                }<br>            }<br>        }<br>        return instance;<br>    }<br>}</pre><h3>Why It Works:</h3><ul><li>Uses volatile to prevent instruction reordering.</li><li>Synchronizes only the first time, avoiding performance hits on repeated calls.</li></ul><p>This is a <strong>perfect balance</strong> between performance and thread safety.</p><h3>Eager Initialization (Simpler &amp; Always Safe)</h3><p>If the Singleton is lightweight and always required, you can initialize it eagerly:</p><pre>public class Logger {<br>    private static final Logger instance = new Logger();<br>    private Logger() {}<br>    public static Logger getInstance() {<br>        return instance;<br>    }<br>}</pre><p>This approach is:</p><ul><li>Simple</li><li>Thread-safe (thanks to Java classloader guarantees)</li><li>Fast, but <strong>not lazy</strong> (object created at class loading time)</li></ul><p>Use this when the object is inexpensive or critical to the app lifecycle.</p><h3>Advanced Singleton in Java: The Enum Way (Pro-Level)</h3><p>Java’s most robust Singleton implementation uses enum:</p><pre>public enum Logger {<br>    INSTANCE;<br>    public void log(String msg) {<br>        System.out.println(&quot;[LOG]: &quot; + msg);<br>    }<br>}</pre><h3>Benefits:</h3><ul><li>Thread-safe by design</li><li>Serialization-safe</li><li>Immune to reflection attacks</li><li>Simplest and most robust Singleton in Java</li></ul><h3>UML Diagram: Singleton Pattern</h3><pre>   +-------------------+<br>   |    Singleton      |<br>   +-------------------+<br>   | - instance        |  (static)<br>   | - Singleton()     |  (private)<br>   +-------------------+<br>   | + getInstance()   |  (static)<br>   | + log()           |<br>   +-------------------+</pre><ul><li>Private constructor enforces control.</li><li>getInstance() provides global access.</li><li>Ensures one — and only one — instance exists.</li></ul><h3>Real-World Uses of Singleton</h3><ul><li><strong>Logger</strong> — Consistent log stream across modules</li><li><strong>Config Manager</strong> — Load once, use globally</li><li><strong>Database Connection Pool</strong> — Heavy, shared resource</li><li><strong>Thread Pool Manager</strong> — Controls system-wide concurrency</li><li><strong>Game Engine Core</strong> — Manages global state</li></ul><h3>Common Pitfalls &amp; Misconceptions</h3><h4>1. “Singleton = Global Variable”</h4><p>Nope. A global variable can be reassigned or cloned. Singleton <strong>strictly controls</strong> its lifecycle.</p><h4>2. “All Singletons Are Thread-Safe”</h4><p>Only if explicitly implemented to be. Basic implementations fail in concurrent environments.</p><h4>3. “Use Singleton Everywhere”</h4><p>Overuse leads to tight coupling and hidden dependencies. Use it <strong>where centralization is necessary</strong>.</p><h4>4. “Singletons Are Anti-patterns”</h4><p>Singleton is only an anti-pattern <strong>when abused</strong>. Used with care, it solves real-world design challenges.</p><h3>Best Practices &amp; Pro Tips</h3><h4>1. Use Dependency Injection</h4><p>Frameworks like <strong>Spring</strong>, <strong>Dagger</strong>, or <strong>Guice</strong> let you manage singletons declaratively using @Singleton. This avoids tight coupling.</p><h4>2. Keep It Focused</h4><p>A Singleton should have <strong>one responsibility</strong>. Don’t make it the god of your system.</p><h4>3. Interface + Implementation</h4><p>Wrap your Singleton with an interface. This enables <strong>mocking</strong> in tests and keeps your design decoupled.</p><h4>4. Use Enum When Possible</h4><p>Enums are serialization-safe, reflection-proof, and concise. Use them unless lazy initialization is required.</p><h3>Final Thoughts</h3><p>The Singleton Pattern is more than a design trick — it’s a <strong>contract</strong>:<br> <em>“There shall be only one.”</em></p><p>It’s simple to implement but easy to misuse. When applied with intention and care, it becomes a cornerstone of robust software architecture. Whether you’re managing logs, configs, or shared resources — Singleton gives you <strong>controlled power</strong>.</p><p>Use it wisely. Your system will thank you.</p><p>💬 <em>Found this helpful? Share your thoughts or questions in the comments!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b916ea60e2e0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Factory Design Pattern in Java — A Powerful Guide for Smart Beginners]]></title>
            <link>https://medium.com/@aansh0611/the-factory-design-pattern-in-java-a-powerful-guide-for-smart-beginners-d9fc9144dfb3?source=rss-a30f3e59663a------2</link>
            <guid isPermaLink="false">https://medium.com/p/d9fc9144dfb3</guid>
            <category><![CDATA[factory-design-pattern]]></category>
            <category><![CDATA[system-design-concepts]]></category>
            <category><![CDATA[design-pattern-in-java]]></category>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[low-level-design]]></category>
            <dc:creator><![CDATA[Anshuman]]></dc:creator>
            <pubDate>Sat, 28 Jun 2025 15:34:53 GMT</pubDate>
            <atom:updated>2025-06-28T15:34:53.727Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong>The Factory Design Pattern in Java — A Powerful Guide for Smart Beginners</strong></h3><blockquote>“When the creation logic of objects becomes complex or dynamic, you shouldn’t scatter new all over your codebase. Let a Factory handle it.”</blockquote><p>If you’re tired of tightly coupled code, find yourself repeating the same instantiation logic, or dread adding new object types because it breaks everything — then it’s time to learn the Factory Pattern.</p><p>Let’s unpack this pattern from the ground up and help you write cleaner, scalable, and more professional code.</p><h3>The Problem: Scattered Object Creation</h3><p>Imagine you’re building a <strong>notification system</strong>. You need to support multiple delivery channels:</p><ul><li>Email</li><li>SMS</li><li>Push notifications</li></ul><p>A naïve implementation might look like this:</p><pre>Notification n1 = new EmailNotification();<br>Notification n2 = new SMSNotification();<br>Notification n3 = new PushNotification();</pre><p>Simple? Sure. But this approach:</p><ul><li>Couples your code tightly to specific implementations</li><li>Breaks when you add a new type</li><li>Makes testing harder</li><li>Violates the <strong>Open/Closed Principle</strong> (OCP) — your code isn’t closed for modification</li></ul><p>You now have instantiation logic scattered across your codebase, making it fragile and hard to evolve.</p><h3>Enter: The Factory Pattern</h3><p>The Factory Pattern comes to the rescue by <strong>centralizing object creation</strong>. Instead of creating objects directly with new, you delegate that responsibility to a <strong>factory</strong>.</p><p>This pattern offers a clean solution to separate object creation from usage — and it’s one of the most frequently used <strong>creational design patterns</strong> in Java and beyond.</p><h3>What Is the Factory Pattern?</h3><p>In the words of the <em>Gang of Four</em>:</p><blockquote>“Define an interface for creating an object, but let subclasses decide which class to instantiate.”</blockquote><p>In plain English:<br> <strong>You don’t decide what to create. The factory does.</strong></p><p>You call a method, pass some input, and the factory gives you the right object.</p><h3>Types of Factory Patterns</h3><p>Depending on your project needs, there are several flavors:</p><h4>1. Simple Factory (not a GoF pattern, but commonly used)</h4><p>A static method that returns different object types based on input.</p><h4>2. Factory Method (GoF-recognized)</h4><p>Subclasses override a factory method to decide which object to create.</p><h4>3. Abstract Factory</h4><p>Used to create <strong>families</strong> of related objects without specifying their concrete classes.</p><p>For now, we’ll focus on the <strong>Simple Factory</strong> and <strong>Factory Method</strong>, which are the most relevant for most developers getting started.</p><h3>Real-World Analogy: Ordering Coffee</h3><p>Think of a coffee shop. You don’t walk into the kitchen to make your own drink. You simply order at the counter:</p><p><strong>You (Client)</strong> → order(“Espresso”) → <strong>Barista (Factory)</strong> → Espresso (Concrete Product)</p><p>You don’t care how it’s made — you just want your coffee.</p><p>That’s the Factory Pattern in action.</p><h3>Java Implementation: Notification Factory</h3><p>Let’s build our notification system using the Factory Pattern in Java.</p><pre>      +---------------------+<br>      |  Notification       |&lt;----------------------+<br>      +---------------------+                       |<br>             ^                                      |<br>             |                                      |<br>+----------------------+         +--------------------------+<br>| SMSNotification      |         | NotificationFactory      |<br>| EmailNotification    |         |--------------------------|<br>| PushNotification     |         | + createNotification()   |<br>+----------------------+         +--------------------------+</pre><h4>Step 1: Define the Product Interface</h4><pre>public interface Notification {<br>    void notifyUser();<br>}</pre><p>This is your <strong>abstraction</strong> — the core contract that all notifications must fulfill.</p><h4>Step 2: Implement Concrete Products</h4><pre>public class SMSNotification implements Notification {<br>    public void notifyUser() {<br>        System.out.println(&quot;Sending an SMS notification.&quot;);<br>    }<br>}<br>public class EmailNotification implements Notification {<br>    public void notifyUser() {<br>        System.out.println(&quot;Sending an Email notification.&quot;);<br>    }<br>}<br>public class PushNotification implements Notification {<br>    public void notifyUser() {<br>        System.out.println(&quot;Sending a Push notification.&quot;);<br>    }<br>}</pre><p>Each class implements the interface but with its own behavior.</p><h4>Step 3: Create the Factory Class</h4><pre>public class NotificationFactory {<br>    public static Notification createNotification(String type) {<br>        if (type == null || type.isEmpty()) return null;<br>        switch (type.toUpperCase()) {<br>            case &quot;SMS&quot;: return new SMSNotification();<br>            case &quot;EMAIL&quot;: return new EmailNotification();<br>            case &quot;PUSH&quot;: return new PushNotification();<br>            default: throw new IllegalArgumentException(&quot;Unknown notification type&quot;);<br>        }<br>    }<br>}</pre><p>This factory method encapsulates the object creation logic. The rest of your app doesn’t need to worry about <em>how</em> notifications are created.</p><h4>Step 4: Client Code</h4><pre>public class Main {<br>    public static void main(String[] args) {<br>        Notification notification = NotificationFactory.createNotification(&quot;EMAIL&quot;);<br>        notification.notifyUser();<br>    }<br>}</pre><p>Simple, clean, and extensible. Want to add a WhatsApp notification? Just add a new class and extend the factory logic.</p><h3>When to Use the Factory Pattern</h3><ul><li>You don’t know the exact type of object until runtime</li><li>You want to follow <strong>Open/Closed Principle</strong></li><li>You have multiple implementations of an interface or abstract class</li><li>You want to centralize and simplify object creation logic</li></ul><h3>Avoid If:</h3><ul><li>You only have a single object type</li><li>Object creation is trivial</li><li>You need maximum performance (factories introduce a minor overhead)</li></ul><h3>Some Insights</h3><h4>1. Factories Promote Loose Coupling</h4><p>Clients depend on abstractions, not implementations. This makes your code easier to test, extend, and maintain.</p><h4>2. Testability Improves</h4><p>You can easily mock or stub out factories and inject test versions — without touching the core logic.</p><h4>3. Works Well with Other Patterns</h4><p>Combine with:</p><ul><li><strong>Strategy</strong>: to control both <em>behavior</em> and <em>creation</em></li><li><strong>Singleton</strong>: to ensure a single instance is returned by the factory</li></ul><h3>Common Pitfalls &amp; Myths</h3><h4>“It’s Just an Extra Class”</h4><p>No — it’s a central point of control. You trade a tiny bit of structure for huge flexibility.</p><h4>“I’ll Just Use new Everywhere”</h4><p>That breaks <strong>Single Responsibility Principle</strong> and makes your code hard to manage.</p><h4>“Only Big Apps Need This”</h4><p>Even small applications benefit — from notifications, logging, UI components, to file readers.</p><h3>Real-World Uses of Factory Pattern</h3><ul><li><strong>Spring Framework</strong> — ApplicationContext.getBean()</li><li><strong>JDBC</strong> — DriverManager.getConnection()</li><li><strong>Android</strong> — LayoutInflater creates view hierarchies</li><li><strong>Logging Frameworks</strong> — LoggerFactory.getLogger()</li></ul><p>These aren’t just academic — they’re <em>everywhere</em> in professional codebases.</p><h3>Final Thoughts</h3><p>The Factory Pattern is a must-have in your design pattern toolbox.</p><p>Whether you’re building a game, an e-commerce site, or a microservice backend — <strong>you will encounter situations where object creation needs to be decoupled from object usage</strong>.</p><p>Start using it early. You’ll thank yourself later.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d9fc9144dfb3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mastering Execution Context in JavaScript: The Ultimate Q&A Guide]]></title>
            <link>https://medium.com/@aansh0611/mastering-execution-context-in-javascript-the-ultimate-q-a-guide-9f07d6abeecf?source=rss-a30f3e59663a------2</link>
            <guid isPermaLink="false">https://medium.com/p/9f07d6abeecf</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[javascript-tips]]></category>
            <category><![CDATA[javascript-interview]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[javascript-development]]></category>
            <dc:creator><![CDATA[Anshuman]]></dc:creator>
            <pubDate>Sat, 28 Jun 2025 15:27:07 GMT</pubDate>
            <atom:updated>2025-06-28T15:27:07.598Z</atom:updated>
            <content:encoded><![CDATA[<h3>1. What is an Execution Context in JavaScript?</h3><p>An <strong>Execution Context</strong> is a conceptual environment where the code is evaluated and executed. It is a container for variables, functions, and the code itself, where the JavaScript engine keeps track of the current state during execution. When a script is run, an execution context is created for it, and this context manages things like scope, variables, and function calls.</p><p>There are several components that make up the execution context:</p><ul><li><strong>Variable environment</strong>: Holds variables, functions, and parameters.</li><li><strong>Scope chain</strong>: A chain of references to variable environments that allows variable resolution.</li><li><strong>this value</strong>: A reference to the current object in context.</li></ul><h3>2. What are the types of execution contexts in JavaScript?</h3><p>There are <strong>three main types</strong> of execution contexts in JavaScript:</p><p><strong>Global Execution Context (GEC):</strong></p><ul><li>This is the default or outermost context where the entire code runs initially.</li><li>When the code is executed, a single global execution context is created first.</li><li>In the browser, this context refers to the window object, and in Node.js, it refers to the global object.</li><li>Variables declared globally (outside of any function) exist within this context.</li></ul><p><strong>Function Execution Context (FEC)</strong>:</p><ul><li>Each time a function is invoked, a new execution context is created for that function.</li><li>This context holds the function’s parameters, local variables, and its scope chain.</li><li>Functions have their own this value, which can differ depending on how the function is invoked.</li></ul><p><strong>Eval Execution Context</strong> (rarely used):</p><ul><li>If you use the eval() function (which is not recommended), a new execution context is created.</li><li>Code inside eval() is executed in the current context but can create new variables or modify existing ones.</li></ul><h3>3. What is the difference between Global Execution Context and Function Execution Context?</h3><p><strong>Global Execution Context (GEC)</strong>:</p><ul><li>This context is created when the JavaScript code starts running. It represents the environment for any code not inside a function.</li><li>In the browser, it is associated with the window object, and in Node.js, it’s associated with the global object.</li><li>Variables declared outside of any function are stored here.</li><li>There is only <strong>one</strong> global execution context in the lifecycle of a script.</li></ul><p><strong>Function Execution Context (FEC)</strong>:</p><ul><li>Every time a function is called, a new execution context is created for that function.</li><li>The function’s local variables, parameters, and its this value are stored in the function’s execution context.</li><li>Each function has its own <strong>execution context</strong>, and the context is created and destroyed as the function is invoked and completed.</li></ul><p><strong>Key Difference</strong>:</p><ul><li>The global execution context exists only once for the entire execution, whereas function execution contexts are created every time a function is called and destroyed once the function execution completes.</li></ul><h3>4. What are the phases of creation of an Execution Context?</h3><p>An execution context goes through <strong>two phases</strong> during its lifecycle: <strong>Creation Phase</strong> and <strong>Execution Phase</strong>.</p><h4>1. Creation Phase:</h4><p><strong>1.2. Global Execution Context</strong>:</p><ul><li>The global object (e.g., window in the browser or global in Node.js) is created.</li><li>The this value is set to the global object.</li><li>Memory is allocated for all variables and functions declared in the code, but they are initially set to undefined (for variables) or the function body (for functions).</li></ul><p><strong>1.3. Function Execution Context</strong>:</p><ul><li>A new <strong>activation object</strong> (AO) is created, which holds the function’s parameters and local variables.</li><li>The this value for the function is set based on how it’s called.</li><li>The scope chain for that function is established (based on lexical scoping).</li></ul><h4>2. Execution Phase:</h4><p><strong>2.1. Global Execution Context</strong>:</p><ul><li>The JavaScript engine starts executing the code line by line.</li><li>Variables and functions are assigned their values (or function bodies).</li><li>The call stack starts to fill as functions are called.</li></ul><p><strong>2.2. Function Execution Context</strong>:</p><ul><li>The function code is executed.</li><li>Local variables are assigned their values, and if there are function calls inside, new execution contexts are created for those calls.</li></ul><h3>5. What is the Call Stack in JavaScript and how does it relate to Execution Context?</h3><p>The <strong>Call Stack</strong> is a mechanism that the JavaScript engine uses to keep track of function calls in the order they are made.</p><ul><li>When a function is invoked, a new <strong>execution context</strong> is created and pushed onto the call stack.</li><li>Each new function invocation creates a new <strong>function execution context</strong>, which is pushed to the stack. This context holds information such as local variables, parameters, and the scope chain for that function.</li><li>When a function finishes executing, its execution context is popped off the call stack.</li><li>The <strong>Global Execution Context</strong> is always the bottom-most context in the call stack, and it remains there until the program finishes running.</li><li>If the call stack overflows (e.g., due to too many nested function calls), it results in a <strong>stack overflow</strong> error.</li></ul><h4>How the Call Stack relates to Execution Context:</h4><ul><li>Each time the JavaScript engine encounters a function call, it pushes a new <strong>function execution context</strong> onto the call stack.</li><li>The engine continues to execute the code in the current execution context (which is on top of the stack).</li><li>Once the function execution finishes, its context is removed from the stack, and the execution returns to the context below it (usually the global context or the previous function context).</li></ul><p>In simpler terms, the call stack is a stack of execution contexts, with the <strong>top of the stack</strong> representing the currently executing context. The <strong>bottom</strong> represents the global context, and the stack grows and shrinks as functions are called and executed.</p><h3>6. Lifecycle of a Function Execution Context</h3><p>The <strong>lifecycle</strong> of a <strong>Function Execution Context</strong> involves several distinct phases, each occurring when the function is invoked. Here’s how it works:</p><h4>1. Creation Phase:</h4><ul><li><strong>Activation Object (AO)</strong>: When a function is called, a new Activation Object (AO) is created. This object will hold the following:</li><li>The function’s <strong>parameters</strong>.</li><li>Local <strong>variables</strong>.</li><li>The <strong>this</strong> reference (determined by how the function is invoked).</li><li>The <strong>scope chain</strong>, which is an array of objects representing the current scope and all parent scopes (this will be discussed in detail below).</li><li><strong>this Binding</strong>: The value of this is determined based on how the function was invoked. For example:</li><li>In a regular function call, this refers to the global object (e.g., window in the browser).</li><li>In a method call, this refers to the object that invoked the method.</li><li><strong>Scope Chain</strong>: The function’s scope chain is created by linking the AO to the parent execution context’s scope (i.e., the scope of the context where the function was called). This allows the function to access variables from its own scope and from outer scopes.</li><li><strong>Hoisting</strong>: During the creation phase, variable declarations (but not initializations) and function declarations are hoisted. This means that the variables are placed into memory but are initially set to undefined (for variables). Function declarations are hoisted entirely.</li></ul><h4>2. Execution Phase:</h4><ul><li>Once the creation phase is complete, the <strong>execution phase</strong> begins. In this phase:</li><li><strong>Function code execution</strong> starts.</li><li>Local variables and parameters are assigned values.</li><li>If there are any inner functions, they will also get their own execution contexts.</li><li>If there are function calls inside the function, a new execution context will be created for each call.</li><li>The function’s code is run line-by-line. When the function returns, the function’s execution context is removed from the call stack.</li></ul><h3>7. How does JavaScript manage memory for execution contexts?</h3><p>JavaScript uses a mechanism called <strong>garbage collection</strong> to manage memory. Here’s how it works in the context of execution contexts:</p><p><strong>Memory Allocation</strong>:</p><ul><li>When an execution context is created (either global or function), memory is allocated for variables, functions, and parameters that are part of that context.</li><li>This memory includes space for storing <strong>primitive values</strong> (like numbers or strings) and <strong>references</strong> to objects or arrays.</li></ul><p><strong>Garbage Collection</strong>:</p><ul><li>When an execution context is removed from the call stack (e.g., when a function finishes execution), JavaScript will look at all the variables and objects within the context.</li><li>If any objects or variables are no longer in use or reachable (i.e., no references point to them), they become <strong>eligible for garbage collection</strong>. This means the JavaScript engine will clean up that memory space.</li></ul><p><strong>Scope Chain</strong>:</p><ul><li>When a function execution context is created, it gets its own scope chain, linking it to the global or outer context.</li><li>As long as there are references to variables in the current scope (either directly or via closures), that memory is retained.</li></ul><p><strong>Memory Cleanup</strong>:</p><ul><li>After a function call completes, the function’s execution context is popped from the call stack. If there are no references to any variables, memory can be freed.</li></ul><h3>8. What happens when a function is invoked in terms of execution context?</h3><p>When a function is invoked, the following steps take place:</p><p><strong>1. A New Execution Context is Created:</strong></p><ul><li>A new <strong>Function Execution Context</strong> is created for that function invocation.</li><li>An <strong>Activation Object (AO)</strong> is created to store the function’s parameters, local variables, and this value.</li><li><strong>Memory Allocation: </strong>The parameters and variables within the function are initialized. If a variable is declared but not initialized, it will be set to undefined during the <strong>creation phase</strong>.</li><li><strong>this Binding</strong>: The value of this is determined based on the type of invocation (e.g., method invocation, function invocation, or arrow function).</li><li><strong>Scope Chain</strong>: The function’s scope chain is created, linking it to the outer execution context (i.e., the context from where the function was called). This allows access to variables from the outer context.</li></ul><p><strong>2. Execution of Code</strong>:</p><ul><li>The code inside the function is executed, and as the code runs, any nested function calls will trigger the creation of new execution contexts (thus adding to the call stack).</li><li>Once the function finishes execution, its execution context is popped off the call stack, and execution returns to the previous context (either the calling function or the global context).</li></ul><h3>9. Can you illustrate what the call stack looks like during nested function calls?</h3><p>Here’s an example of how the <strong>call stack</strong> looks when functions are called in a nested manner.</p><pre>function first() {<br>  console.log(&quot;In first function&quot;);<br>  second();  // Call second<br>}<br>function second() {<br>  console.log(&quot;In second function&quot;);<br>  third();   // Call third<br>}<br>function third() {<br>  console.log(&quot;In third function&quot;);<br>}<br>first();  // Call first</pre><h4>Call Stack Illustration:</h4><ol><li><strong>Before any function call</strong>:</li></ol><ul><li>The call stack is empty, and we are at the global execution context.</li><li>[Global Execution Context]</li></ul><p><strong>2. Calling </strong><strong>first()</strong>:</p><ul><li>The first() function is called, so a new <strong>function execution context</strong> is created for first.</li><li>[first Execution Context] [Global Execution Context]</li></ul><p><strong>3. Calling </strong><strong>second() from inside </strong><strong>first()</strong>:</p><ul><li>The second() function is called inside first(), so a new <strong>function execution context</strong> is created for second.</li><li>[second Execution Context] [first Execution Context] [Global Execution Context]</li></ul><p><strong>4. Calling </strong><strong>third() from inside </strong><strong>second()</strong>:</p><ul><li>The third() function is called inside second(), so a new <strong>function execution context</strong> is created for third.</li><li>[third Execution Context] [second Execution Context] [first Execution Context] [Global Execution Context]</li></ul><p><strong>5. Returning from </strong><strong>third()</strong>:</p><ul><li>The third() function completes, and its execution context is popped off the call stack.</li><li>[second Execution Context] [first Execution Context] [Global Execution Context]</li></ul><p><strong>6. Returning from </strong><strong>second()</strong>:</p><ul><li>The second() function completes, and its execution context is popped off the call stack.</li><li>[first Execution Context] [Global Execution Context]</li></ul><p><strong>7. Returning from </strong><strong>first()</strong>:</p><ul><li>The first() function completes, and its execution context is popped off the call stack.</li><li>[Global Execution Context]</li></ul><p><strong>8. Completion</strong>:</p><ul><li>Now the global execution context is the only remaining context in the call stack, and the script execution has finished.</li></ul><h3>10. What is the difference between Lexical Environment and Variable Environment?</h3><p>Both <strong>Lexical Environment</strong> and <strong>Variable Environment</strong> are important concepts in the JavaScript execution model, especially when it comes to scope and closure.</p><h4>Variable Environment:</h4><ul><li>The <strong>Variable Environment</strong> is part of the <strong>Execution Context</strong> and is responsible for storing variable declarations (and their values) and function declarations.</li><li>It holds <strong>variables</strong>, <strong>functions</strong>, and <strong>parameters</strong> within the scope of an execution context.</li><li>In the case of function execution contexts, this environment contains the function’s parameters and local variables.</li></ul><h4>Lexical Environment:</h4><ul><li>The <strong>Lexical Environment</strong> is essentially similar to the variable environment but with a key difference: it also includes a reference to the <strong>outer (parent) environment</strong>, allowing scope resolution to work properly.</li><li>The <strong>Lexical Environment</strong> is responsible for managing <strong>scope chains</strong>. It stores both the variable bindings (like the variable environment) and also a reference to its parent lexical environment.</li><li>The lexical environment is what makes <strong>closures</strong> work in JavaScript. Even if the parent function has finished executing, the inner function still has access to its variables because it retains a reference to the parent lexical environment.</li></ul><h4>Key Difference:</h4><ul><li><strong>Variable Environment</strong>: Focuses primarily on the storage of variable names and their values.</li><li><strong>Lexical Environment</strong>: Includes the variable environment and also the reference to its outer lexical environment, forming the scope chain.</li></ul><p>In essence, the <strong>Lexical Environment</strong> is the broader context that includes both variable bindings and the reference to its parent environment, while the <strong>Variable Environment</strong> is the inner storage of variables within the context.</p><h3>11. How does the this keyword behave in different execution contexts?</h3><p>The behavior of the <strong>this</strong> keyword in JavaScript is heavily dependent on the <strong>execution context</strong> and how the function is invoked. Here’s how this behaves in different execution contexts:</p><h4>a) Global Execution Context</h4><ul><li>In the <strong>global execution context</strong>, this refers to the <strong>global object</strong>.</li><li>In a <strong>browser</strong>, this refers to the window object.</li><li>In <strong>Node.js</strong>, this refers to the global object.</li></ul><p>Example:</p><pre>console.log(this);  // In a browser, this will log the window object.</pre><h4>b) Function Execution Context</h4><ul><li>In a <strong>regular function invocation</strong> (i.e., func()), this refers to the <strong>global object</strong>.</li><li>In the browser, this will be the window object.</li><li>In Node.js, it will be the global object.</li></ul><p>Example:</p><pre>function showThis() {<br>  console.log(this);  // In non-strict mode, this will refer to the global object.<br>}<br>showThis();</pre><ul><li>In <strong>strict mode</strong> (i.e., &quot;use strict&quot;;), this will be undefined inside functions.</li></ul><pre>&quot;use strict&quot;; <br>function showThis() {   <br>    console.log(this);  // `this` will be undefined in strict mode. <br>} <br>showThis();</pre><h4>c) Method Invocation (Object Method)</h4><ul><li>When a function is invoked as a <strong>method</strong> of an object (i.e., obj.func()), this refers to the <strong>object</strong> that owns the method.</li></ul><p>Example:</p><pre>const obj = {<br>  name: &quot;Alice&quot;,<br>  greet: function() {<br>    console.log(this.name);  // `this` refers to `obj`, so it will print &quot;Alice&quot;.<br>  }<br>};<br>obj.greet();</pre><h4>d) Constructor Function Invocation (with new)</h4><ul><li>When a function is invoked with the new keyword, this refers to the <strong>newly created instance</strong> of the object.</li></ul><p>Example:</p><pre>function Person(name) {<br>  this.name = name;<br>}<br>const p1 = new Person(&quot;John&quot;);<br>console.log(p1.name);  // `this` refers to the new instance, so it prints &quot;John&quot;.</pre><h4>e) Arrow Functions</h4><ul><li>In <strong>arrow functions</strong>, this does not have its own binding. Instead, it <strong>inherits</strong> this from its surrounding lexical context (i.e., the scope in which the arrow function was defined).</li></ul><p>Example:</p><pre>const obj = {<br>  name: &quot;Alice&quot;,<br>  greet: function() {<br>    const arrowFunc = () =&gt; {<br>      console.log(this.name);  // `this` is inherited from the outer function (greet), so it refers to `obj`.<br>    };<br>    arrowFunc();<br>  }<br>};<br>obj.greet();  // It will print &quot;Alice&quot;.</pre><h4>f) Event Listeners</h4><ul><li>When used inside an event listener, this refers to the <strong>element</strong> that fired the event.</li></ul><p>Example:</p><pre>const button = document.querySelector(&quot;button&quot;);<br>button.addEventListener(&quot;click&quot;, function() {<br>  console.log(this);  // `this` will refer to the button element that was clicked.<br>});</pre><h3>12. What is the role of the Scope Chain in execution context?</h3><p>The <strong>scope chain</strong> is crucial in <strong>execution contexts</strong> because it dictates how JavaScript resolves variable references in the code.</p><ul><li>The <strong>scope chain</strong> is a <strong>hierarchical chain</strong> of <strong>lexical environments</strong> where each <strong>execution context</strong> has its own scope and may reference variables and functions from outer (parent) scopes.</li></ul><p>The <strong>scope chain</strong> works as follows:</p><ul><li>When a function is called, it has access to its own <strong>local scope</strong> (inside the function), the <strong>scope of the function that called it</strong>, and the <strong>global scope</strong>.</li><li>The <strong>scope chain</strong> is created during the <strong>creation phase</strong> of an execution context. The scope chain starts with the function’s <strong>own lexical environment</strong> (local variables) and then includes the parent scope (the scope from where the function was called), up to the global scope.</li><li>This allows for <strong>lexical scoping</strong>, where inner functions can access variables from outer functions (closures).</li></ul><h4>Example of Scope Chain:</h4><pre>const globalVar = &quot;global&quot;;<br>function outerFunction() {<br>  const outerVar = &quot;outer&quot;;<br>  function innerFunction() {<br>    const innerVar = &quot;inner&quot;;<br>    console.log(innerVar);  // `innerVar` is found in its own scope.<br>    console.log(outerVar);  // `outerVar` is found in the outer scope.<br>    console.log(globalVar);  // `globalVar` is found in the global scope.<br>  }<br>  innerFunction();<br>}<br>outerFunction();</pre><p>The scope chain for innerFunction will be:</p><ol><li>innerFunction&#39;s own lexical environment (where innerVar is found),</li><li>The outerFunction&#39;s lexical environment (where outerVar is found),</li><li>The global execution context (where globalVar is found).</li></ol><h3>13. How are closures related to execution context?</h3><p>A <strong>closure</strong> is a <strong>function that “remembers” its lexical environment</strong>, even after the outer function has finished execution and its execution context has been popped from the call stack.</p><ul><li><strong>Closures</strong> occur when a function retains access to its <strong>lexical scope</strong> (the scope it was created in), even when the function is executed outside that scope.</li><li>Closures are closely tied to <strong>execution contexts</strong> because the <strong>lexical environment</strong> (which includes variables, functions, and the scope chain) of the outer function is <strong>preserved</strong> and accessible to the inner function even after the outer function’s execution context is destroyed.</li></ul><h4>Example of Closure:</h4><pre>function outer() {<br>  let outerVar = &quot;I&#39;m outer&quot;;<br>function inner() {<br>    console.log(outerVar);  // `inner` function has access to `outerVar` due to closure.<br>  }<br>  return inner;<br>}<br>const closureFunc = outer();  // `closureFunc` is now a reference to `inner`.<br>closureFunc();  // This still has access to `outerVar` because of closure.</pre><ul><li>In this example, inner() retains access to outerVar, even though the outer() function has finished executing. This happens because inner() <strong>closes over</strong> its lexical environment, keeping a reference to outerVar (a part of the outer function&#39;s execution context).</li></ul><h3>14. What happens when a synchronous error occurs in one execution context?</h3><p>When a <strong>synchronous error</strong> occurs during the execution of an <strong>execution context</strong>, the following happens:</p><ol><li><strong>Error Occurrence</strong>:</li></ol><ul><li>A runtime error (like a reference error, type error, etc.) happens in the current execution context while the code is running.</li><li>Example:</li></ul><pre>function faultyFunction() {   <br>    let x = 5;   <br>    console.log(x + y);  // ReferenceError: y is not defined <br>}<br>faultyFunction();</pre><p><strong>2. Error Propagation</strong>:</p><ul><li>JavaScript will look for an error handler (such as a try-catch block). If no handler is found in the current context, the error will propagate up to the <strong>call stack</strong> until it finds a matching catch block.</li></ul><p><strong>3. Call Stack Unwinding</strong>:</p><ul><li>Once the error is thrown, JavaScript stops executing the current function. It <strong>unwinds the call stack</strong> by popping the execution context where the error occurred.</li><li>If the error is not caught, the program will terminate and log the error to the console.</li></ul><p><strong>4. Unhandled Errors</strong>:</p><ul><li>If there is no try-catch block to catch the error, the error will <strong>propagate</strong> up the call stack, causing the execution of the program to halt.</li><li>In the browser, an <strong>uncaught error</strong> will be logged in the <strong>console</strong>, and the browser might stop executing subsequent JavaScript code.</li></ul><p><strong>5. Handling Errors with </strong><strong>try-catch</strong>:</p><ul><li>Errors can be handled locally using a try-catch block. When an error occurs inside a try block, it immediately jumps to the corresponding catch block.</li><li>Example:</li></ul><pre>function safeFunction() {   <br>    try {     <br>          let x = 5;    <br>          console.log(x + y);  // ReferenceError will be caught here   <br>      }<br>   catch (error) {     <br>        console.log(&quot;Caught an error: &quot; + error.message);  // Catches the error   <br>    } <br>}  <br>safeFunction();  // Will log &quot;Caught an error: y is not defined&quot;</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9f07d6abeecf" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Ultimate Guide to Scalability & Performance: How to Build Systems That Survive Growth]]></title>
            <link>https://medium.com/@aansh0611/the-ultimate-guide-to-scalability-performance-how-to-build-systems-that-survive-growth-fd48918979e8?source=rss-a30f3e59663a------2</link>
            <guid isPermaLink="false">https://medium.com/p/fd48918979e8</guid>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[system-design-concepts]]></category>
            <category><![CDATA[system-design-course]]></category>
            <category><![CDATA[scalability]]></category>
            <dc:creator><![CDATA[Anshuman]]></dc:creator>
            <pubDate>Sat, 28 Jun 2025 14:40:16 GMT</pubDate>
            <atom:updated>2025-06-28T14:40:16.619Z</atom:updated>
            <content:encoded><![CDATA[<blockquote><em>“Systems don’t fail because of bad code. They fail because they weren’t designed to scale.”<br> — Every engineer who’s been paged at 2 AM</em></blockquote><p>The internet is a battlefield of speed and reliability. Users won’t wait. Your code could be perfect, but if your system can’t handle demand, you lose users, revenue, and credibility.</p><p>That’s where <strong>scalability and performance</strong> become make-or-break fundamentals.</p><p>In this ultimate guide, we’ll explore the five pillars every engineer must understand to build systems that don’t just work — they <strong>scale</strong>.</p><p>Whether you’re launching a startup or building for billions, these concepts will transform how you think about architecture.</p><h3>What Are Scalability and Performance?</h3><p>Before we dig into patterns and systems, let’s anchor the basics.</p><ul><li><strong>Performance</strong> refers to how <strong>fast</strong> your system can respond to a request under a given load.</li><li><strong>Scalability</strong> refers to your system’s ability to <strong>handle increasing load</strong> gracefully — either by adding resources or optimizing existing ones.</li></ul><h3>Why it matters:</h3><ul><li>A slow but scalable app can be optimized.</li><li>A fast app that can’t scale will eventually <strong>fail under pressure</strong>.</li></ul><p>Think of performance as <strong>responsiveness</strong> and scalability as <strong>resilience under growth</strong>.</p><h3>Vertical vs Horizontal Scaling</h3><h3>What is scaling?</h3><p>Scaling is how we adapt infrastructure to handle more users, requests, or data.</p><h3>Vertical Scaling (Scaling Up)</h3><p>This means adding more power to a <strong>single server</strong> — like upgrading RAM, CPU, or disk.</p><ul><li>Great for quick fixes and early-stage growth</li><li>Minimal code or infrastructure change</li><li>But there’s a ceiling: hardware has limits, and failure means total downtime</li></ul><p><strong>When to use</strong>:<br> In monolith systems, legacy apps, or where simplicity matters more than elasticity.</p><h3>Horizontal Scaling (Scaling Out)</h3><p>Here, you add <strong>more servers or instances</strong> to distribute the load.</p><ul><li>Supports fault tolerance and redundancy</li><li>Enables elasticity (especially in cloud-native apps)</li><li>But introduces complexity: distributed data, service coordination, network hops</li></ul><p><strong>When to use</strong>:<br> For scalable web apps, microservices, and any modern architecture expecting growth.</p><blockquote><strong><em>Pro insight</em></strong><em>: Vertical scaling is like buying a bigger machine. Horizontal scaling is like hiring more workers. Guess which one runs Amazon.</em></blockquote><h3>Load Balancing Algorithms</h3><h3>Why load balancing?</h3><p>As traffic increases, we need to distribute incoming requests across multiple backend servers. That’s the job of a <strong>load balancer</strong> — a traffic cop in front of your app servers.</p><p>Without it, one server can choke while others sit idle. Worse, if a server crashes, users are hit with downtime.</p><h3>How it works:</h3><p>A load balancer receives incoming traffic and decides which server to forward it to. It ensures <strong>efficiency</strong>, <strong>availability</strong>, and <strong>resilience</strong>.</p><h3>Key algorithms you should know:</h3><ul><li><strong>Round Robin</strong>: Cycles through servers in order. Simple, but assumes uniform load.</li><li><strong>Least Connections</strong>: Sends traffic to the server with the fewest active connections. Better for chat or long-lived connections.</li><li><strong>IP Hash</strong>: Maps user IP to a server. Useful for sticky sessions (i.e., keeping a user on the same server).</li><li><strong>Weighted Distribution</strong>: Allocates more traffic to higher-capacity servers.</li></ul><p><strong>When it matters</strong>:<br> Load balancing is essential in horizontally scaled systems. Without it, scaling is pointless.</p><h3>CDNs (Content Delivery Networks)</h3><h3>What is a CDN?</h3><p>A <strong>CDN</strong> is a geographically distributed network of edge servers that <strong>cache and serve static content</strong> (images, CSS, JS, videos) from a location close to the user.</p><p>Imagine your website is hosted in Mumbai but has users in New York. Without a CDN, every request travels half the world. With a CDN, users get content from a local edge server — <strong>faster, cheaper, and more reliable</strong>.</p><h3>Benefits of CDNs:</h3><ul><li>Reduced latency</li><li>Decreased server load</li><li>Global fault tolerance</li><li>Faster page loads</li></ul><p><strong>Common use cases</strong>:</p><ul><li>Static files: images, scripts, fonts</li><li>Videos and large downloads</li><li>Third-party libraries and assets</li></ul><blockquote><strong><em>Pro tip</em></strong><em>: Always combine CDNs with browser caching and compression (like Brotli or GZIP) for optimal web performance.</em></blockquote><h3>Caching Strategies Demystified</h3><h3>Why cache?</h3><p><strong>Caching</strong> is the practice of storing frequently used data in a fast-access layer (often in-memory like Redis or on the edge via CDN).</p><p>Done right, it <strong>massively reduces load</strong> and <strong>accelerates performance</strong>. Done wrong, it causes bugs, data inconsistency, and even security issues.</p><h3>Caching strategies every engineer must know:</h3><h4>1. Write-Through Cache</h4><ul><li>Data is written to <strong>both cache and database</strong> at the same time.</li><li>Ensures strong consistency</li><li>Slightly slower writes, blazing fast reads</li></ul><p><strong>Best for</strong>:<br> Apps where read performance is crucial and stale data is unacceptable (e.g., shopping carts, real-time analytics)</p><h4>2. Write-Around Cache</h4><ul><li>Writes go <strong>only to the database</strong></li><li>Cache is updated on the next read</li><li>Prevents unnecessary cache pollution</li></ul><p><strong>Best for</strong>:<br> Write-heavy systems where not all data is frequently read (e.g., logging platforms)</p><h4>3. Write-Back Cache</h4><ul><li>Writes go to <strong>cache first</strong>, then flushed to DB asynchronously</li><li>Fastest write performance</li><li>Risk of data loss if cache fails</li></ul><p><strong>Best for</strong>:<br> Bulk operations where occasional data loss is acceptable or can be recovered (e.g., telemetry data)</p><h4>4. Cache-Aside (Lazy Loading)</h4><ul><li>App reads from cache → if not found, fetches from DB → stores result in cache</li><li>Most flexible and widely used</li><li>Requires manual cache invalidation</li></ul><p><strong>Best for</strong>:<br> General-purpose caching for any app with clear separation between data read and write</p><blockquote><strong><em>Mistake to avoid</em></strong><em>: Never cache sensitive or user-specific data without isolating it. Shared cache layers + session data = security nightmare.</em></blockquote><h3>Queueing Systems: Kafka &amp; RabbitMQ</h3><h3>Why use queues?</h3><p>In the real world, not everything can happen synchronously. Some tasks — like sending emails, processing images, or syncing to external APIs — should happen <strong>asynchronously</strong> to avoid blocking user flow.</p><p>That’s where <strong>message queues</strong> come in.</p><p>They allow systems to <strong>communicate and process events independently</strong>, improving both performance and resilience.</p><h3>Kafka: The High-Throughput Event Streamer</h3><p>Apache Kafka is a distributed event streaming platform.</p><ul><li>Handles <strong>millions of messages/sec</strong></li><li>Highly durable and partitioned</li><li>Ideal for real-time analytics, event-driven systems, log pipelines</li></ul><p><strong>When to use</strong>:<br> Real-time feeds (like activity tracking), microservices that publish/subscribe to data changes, log or metric aggregation.</p><h3>RabbitMQ: The Task Queue Workhorse</h3><p>RabbitMQ is a traditional message broker.</p><ul><li>Supports complex routing and acknowledgments</li><li>Great for <strong>task queues</strong>, retries, and transactional workflows</li><li>Easy to integrate and configure</li></ul><p><strong>When to use</strong>:<br> Background job processing (e.g., send email after user signs up), transactional systems where delivery guarantees matter.</p><blockquote><strong><em>Rule of thumb</em></strong><em>: Use RabbitMQ when delivery reliability matters. Use Kafka when </em><strong><em>speed and stream processing</em></strong><em> matter.</em></blockquote><h3>Wrapping Up</h3><p>Software that works for 100 users isn’t the same as software that works for 10 million. Scaling is not just about writing efficient code — it’s about <strong>designing systems that evolve with demand</strong>.</p><p>Start small, but think big. Monitor everything. Expect failure. Plan for success.</p><h3>Coming Up Next: Core Design Principles</h3><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fd48918979e8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mastering Temporal Dead Zone (TDZ) in JavaScript: The Ultimate Q&A Guide]]></title>
            <link>https://medium.com/@aansh0611/mastering-temporal-dead-zone-tdz-in-javascript-the-ultimate-q-a-guide-33e2aef16aa0?source=rss-a30f3e59663a------2</link>
            <guid isPermaLink="false">https://medium.com/p/33e2aef16aa0</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[javascript-interview]]></category>
            <category><![CDATA[javascript-tips]]></category>
            <category><![CDATA[javascript-development]]></category>
            <category><![CDATA[front-end-development]]></category>
            <dc:creator><![CDATA[Anshuman]]></dc:creator>
            <pubDate>Mon, 23 Jun 2025 15:41:25 GMT</pubDate>
            <atom:updated>2025-06-23T15:41:25.798Z</atom:updated>
            <content:encoded><![CDATA[<h3>1. What is Temporal Dead Zone (TDZ) in JavaScript?</h3><p>The <strong>Temporal Dead Zone (TDZ)</strong> is a behavior in JavaScript that occurs when you try to access a <strong>let</strong> or <strong>const</strong> variable before it has been initialized (i.e., before its declaration is executed in the code). It refers to the <strong>period of time</strong> between the <strong>start of the execution context</strong> (when the variable is hoisted) and the <strong>point at which the variable is initialized</strong> in the code.</p><p>In this period, the variable exists but is <strong>unreachable</strong> and <strong>inaccessible</strong>, and any attempts to access it during this time will result in a <strong>ReferenceError</strong>.</p><h4>Example:</h4><pre>console.log(a);  // ReferenceError: Cannot access &#39;a&#39; before initialization<br>let a = 10;</pre><p>In this example, a is hoisted but is in the <strong>TDZ</strong> until it’s assigned the value 10. Trying to access a before it’s assigned will throw an error.</p><h3>2. Which variables are affected by TDZ?</h3><p>Only variables declared with <strong>let</strong> and <strong>const</strong> are affected by the TDZ. These variables are hoisted, but their initialization is delayed until the point where they are actually assigned a value in the code.</p><h4>let and const variables:</h4><ul><li>These variables are hoisted to the top of their scope, but they cannot be accessed before the line on which they are declared and initialized.</li><li>Example:</li></ul><pre>console.log(myVar);  // ReferenceError: Cannot access &#39;myVar&#39; before initialization <br>let myVar = 5;</pre><ul><li><strong>const</strong> behaves similarly to let, but it must be initialized during declaration and cannot be reassigned.</li><li>Example:</li></ul><pre>console.log(myConst);  // ReferenceError: Cannot access &#39;myConst&#39; before initialization <br>const myConst = 10;</pre><h3>3. Why does accessing a let or const variable before its declaration throw a ReferenceError?</h3><p>When JavaScript code is executed, <strong>variables declared with </strong><strong>let and </strong><strong>const are hoisted</strong> to the top of their scope, meaning their declaration is moved to the top during the <strong>creation phase</strong> of the execution context. However, unlike var, they are <strong>not initialized immediately</strong>.</p><p>Instead, they enter a <strong>“dead zone”</strong> (the TDZ) between the <strong>start of the execution context</strong> and the <strong>line of their declaration</strong>. In the TDZ, the variables are in a <strong>temporal dead state</strong> and cannot be accessed until they are fully initialized.</p><p>Here’s why accessing them before initialization throws an error:</p><ul><li>The variable exists in memory but has no <strong>value</strong> yet.</li><li>If you try to access the variable before it’s initialized, JavaScript <strong>cannot</strong> find its value and throws a <strong>ReferenceError</strong> to prevent bugs or unintended behavior.</li></ul><h4>Example:</h4><pre>console.log(a);  // ReferenceError: Cannot access &#39;a&#39; before initialization<br>let a = 10;</pre><p>Here, a is hoisted to the top, but JavaScript doesn&#39;t allow you to access it until it reaches the point where a is assigned the value 10. Accessing it before assignment throws the error.</p><h3>4. What is the time window in which TDZ exists?</h3><p>The <strong>Temporal Dead Zone</strong> exists from the <strong>start of the execution context</strong> (when the JavaScript engine starts processing the code) until the line of code where the let or const variable is initialized.</p><ol><li><strong>Hoisting</strong>: During the creation phase, the <strong>declarations</strong> of let and const variables are hoisted, but they aren’t initialized yet. This is when they enter the <strong>TDZ</strong>.</li><li><strong>Initialization</strong>: Once the JavaScript engine encounters the line where the variable is assigned a value, the TDZ ends and the variable can be safely accessed.</li></ol><h4>Example of TDZ timing:</h4><pre>function example() {<br>  console.log(x);  // ReferenceError: Cannot access &#39;x&#39; before initialization<br>  let x = 5;<br>}<br>example();</pre><p>In the example:</p><ul><li>When example() is called, x is hoisted.</li><li>The <strong>TDZ</strong> begins when the execution context starts, and lasts until x is assigned the value 5 in the code.</li><li>Accessing x before let x = 5 results in a ReferenceError.</li></ul><h3>5. Does TDZ apply to var variables? Why or why not?</h3><p>No, the <strong>Temporal Dead Zone (TDZ)</strong> does <strong>not apply</strong> to var variables.</p><ul><li><strong>var variables</strong> are <strong>hoisted</strong> like let and const, but <strong>they are initialized</strong> during the <strong>creation phase</strong>, not at runtime.</li><li>For var variables, the <strong>hoisting process</strong> sets them to undefined immediately (in the creation phase), which means they <strong>can be accessed</strong> before they are assigned a value, but they will return undefined.</li></ul><h4>Example with var:</h4><pre>console.log(a);  // undefined<br>var a = 10;</pre><p>In this example, the variable a is hoisted and initialized with the value undefined before any code executes. When console.log(a) is called, it outputs undefined, not a ReferenceError.</p><h3>Key Differences Between var and let/const:</h3><ol><li><strong>var variables are hoisted</strong> to the top of their scope and initialized to undefined. As a result, they don’t have a <strong>Temporal Dead Zone</strong>.</li><li><strong>let and </strong><strong>const variables are hoisted</strong> to the top of their scope but are not initialized until their actual declaration is executed in the code, creating a <strong>Temporal Dead Zone</strong> between the start of execution and the declaration line.</li></ol><h3>6. What will be the output of the following code? Why?</h3><pre>console.log(x); // ?<br>let x = 5;</pre><h4>Answer:</h4><p>The output will be a <strong>ReferenceError</strong>:</p><pre>ReferenceError: Cannot access &#39;x&#39; before initialization</pre><h4>Why?</h4><p>This happens because the variable x is declared using <strong>let</strong>, and therefore it is <strong>hoisted</strong> but remains in the <strong>Temporal Dead Zone (TDZ)</strong> until the point where it is initialized (assigned the value 5). During the TDZ, the variable x is in a <strong>temporal dead state</strong>, meaning that although it exists in memory, it cannot be accessed or used until it is initialized.</p><ul><li><strong>Hoisting</strong>: let x is hoisted to the top of the scope, but it is not initialized with the value 5 until the line let x = 5; is executed.</li><li><strong>TDZ</strong>: The <strong>TDZ</strong> exists from the point where the execution context is created until the variable is initialized. During this phase, trying to access x will throw a ReferenceError.</li></ul><h3>7. Why does JavaScript allow variables to be hoisted into a TDZ instead of just making them inaccessible entirely?</h3><p>JavaScript’s behavior with the <strong>Temporal Dead Zone (TDZ)</strong> is designed to strike a balance between flexibility and safety. Here’s why JavaScript doesn’t make let and const variables entirely inaccessible and opts for a TDZ instead:</p><ul><li><strong>Safety and Predictability</strong>:<br> The TDZ provides a <strong>safety net</strong> by making variables <strong>“available”</strong> (i.e., they exist in memory) but <strong>inaccessible</strong> until they are properly initialized. This ensures that developers cannot accidentally access a variable before it is assigned a meaningful value.</li><li><strong>Without TDZ</strong>: If let and const variables were completely inaccessible until their initialization (i.e., not hoisted at all), the variables wouldn&#39;t even be available for reference, which would make the code harder to debug. You could end up with a situation where an entire function scope has no record of variables at all, which could lead to unexpected behavior.</li><li><strong>With TDZ</strong>: TDZ allows the engine to <strong>remember</strong> that the variable exists but blocks access to it, ensuring that you don’t accidentally use it in an uninitialized state.</li><li><strong>To Avoid Silent Bugs</strong>: Without TDZ, accessing a variable that has been hoisted but not yet initialized would lead to an <strong>undefined value</strong>, which is harder to debug. For example, with var, accessing a variable that hasn’t been assigned yet returns undefined, which can easily go unnoticed in code and lead to subtle bugs.</li><li><strong>TDZ</strong> forces a ReferenceError instead, making it <strong>explicit</strong> when a variable has been accessed too early, and thus alerting the developer to a mistake more clearly.</li></ul><h3>8. How does TDZ help prevent bugs compared to var?</h3><p>The <strong>Temporal Dead Zone</strong> (TDZ) plays a critical role in preventing bugs that could arise from JavaScript’s <strong>hoisting</strong> behavior with var. Here&#39;s how:</p><h4>With var:</h4><ul><li>Variables declared with var are <strong>hoisted</strong> to the top of their scope and <strong>initialized</strong> to undefined. As a result, when a var variable is accessed before its declaration, JavaScript doesn’t throw an error but instead returns undefined. This can lead to subtle bugs because you may think a variable holds a valid value when it is actually undefined.</li><li>Example:</li></ul><pre>console.log(a);  // undefined <br>var a = 10;</pre><ul><li>In this case, instead of throwing an error, JavaScript allows you to access a, but it logs undefined because a is hoisted and initialized to undefined.</li></ul><h4>With let and const (TDZ):</h4><ul><li><strong>TDZ</strong> helps avoid these types of silent bugs. When a variable is declared with let or const, it is <strong>hoisted</strong>, but it is <strong>not initialized</strong> until the declaration is encountered in the code. If you try to access it before initialization, JavaScript throws a ReferenceError instead of silently returning undefined.</li><li>Example:</li></ul><pre>console.log(b);  // ReferenceError: Cannot access &#39;b&#39; before initialization <br>let b = 10;</pre><ul><li>This <strong>explicit error</strong> makes it clear that there’s a mistake in the code: you attempted to access a variable before it was initialized.</li></ul><p>Thus, <strong>TDZ prevents errors from going unnoticed</strong> and forces you to address issues when they occur, instead of letting them silently propagate with undefined values.</p><h3>9. Does function declaration fall into a TDZ? What about arrow functions assigned to let?</h3><h4>Function Declarations and TDZ:</h4><p>Function declarations (i.e., function foo() {}) <strong>do not fall into the Temporal Dead Zone</strong>. Function declarations are <strong>hoisted completely</strong>: both their name and their body are available throughout the scope, even before the function appears in the code.</p><p>Example with a function declaration:</p><pre>foo();  // Works because function declarations are hoisted completely<br>function foo() {<br>  console.log(&quot;Hello&quot;);<br>}</pre><p>In this case, foo() can be called before the function’s definition in the code, because the function declaration is <strong>hoisted</strong> entirely, including the body.</p><h4>Arrow Functions Assigned to let and TDZ:</h4><p>Arrow functions that are assigned to variables declared with let or const <strong>do fall into the TDZ</strong> because they behave like other let or const variables.</p><p>Example:</p><pre>console.log(foo);  // ReferenceError: Cannot access &#39;foo&#39; before initialization<br>let foo = () =&gt; {<br>  console.log(&quot;Hello from arrow function!&quot;);<br>};</pre><p>In this case, foo is hoisted, but it is in the <strong>TDZ</strong> until the point where the assignment happens. Since it’s declared with let, trying to access it before the assignment will throw a ReferenceError.</p><h3>10. TDZ in the Context of ES6 Modules</h3><p>In <strong>ES6 modules</strong>, the <strong>Temporal Dead Zone (TDZ)</strong> works similarly to how it behaves in regular scripts, but there are some nuances due to how modules are loaded and executed.</p><h4>Key Points:</h4><ul><li><strong>Modules in ES6 are in strict mode by default</strong>, meaning no implicit global variables, and behavior like TDZ is strictly enforced.</li><li><strong>Modules are hoisted</strong>, but <strong>exports are not available until the module has been fully evaluated</strong>. This means that any attempt to access a module’s export before it has been evaluated will result in a ReferenceError.</li></ul><h4>Example of TDZ in ES6 Modules:</h4><p>Suppose you have two modules: <strong>moduleA.js</strong> and <strong>main.js</strong>.</p><p><strong>moduleA.js</strong>:</p><pre>export let x = 5;</pre><p><strong>main.js</strong>:</p><pre>import { x } from &#39;./moduleA.js&#39;;  // TDZ happens here<br>console.log(x);  // ReferenceError: Cannot access &#39;x&#39; before initialization</pre><p>In <strong>main.js</strong>, we try to access x right after importing it. However, <strong>the module system</strong> first loads and <strong>evaluates the module</strong> before any code in main.js runs. During this evaluation, the variable x is hoisted and exists in the <strong>TDZ</strong> until it’s fully initialized (i.e., when the module&#39;s code reaches the line export let x = 5;).</p><p>Thus, trying to use x before the module is executed results in a ReferenceError because the module&#39;s exports are in the <strong>TDZ</strong> until the export is fully evaluated.</p><h3>11. TDZ Behavior with Destructuring Assignments</h3><p>When using <strong>destructuring assignments</strong>, the <strong>TDZ</strong> is <strong>applicable</strong> to the variables that are being destructured, and <strong>they can’t be accessed before they are assigned</strong>.</p><h4>Example:</h4><pre>let obj = { a: 1, b: 2 };<br>console.log(a);  // ReferenceError: Cannot access &#39;a&#39; before initialization<br>let { a, b } = obj;  // a and b are now initialized</pre><p>In this example:</p><ul><li>The variables a and b are in the <strong>TDZ</strong> when the destructuring assignment occurs.</li><li>They <strong>cannot be accessed</strong> before the line let { a, b } = obj; is executed.</li><li>If you try to access a (or b) before the destructuring assignment, you’ll encounter a ReferenceError.</li></ul><p>This is because, just like regular let and const variables, <strong>destructured variables are hoisted into the TDZ</strong>.</p><h4>More Complex Example:</h4><pre>const obj = { x: 10, y: 20 };<br>function test() {<br>  console.log(x);  // ReferenceError: Cannot access &#39;x&#39; before initialization<br>  let { x, y } = obj;<br>}<br>test();</pre><p>Here, x and y are destructured from obj and are hoisted into the <strong>TDZ</strong>. The <strong>TDZ behavior</strong> means they cannot be accessed before the destructuring happens, hence the <strong>ReferenceError</strong> when trying to access x before it’s initialized.</p><h3>12. TDZ Behavior in For Loops with let and const</h3><p>In the context of <strong>for loops</strong>, <strong>let</strong> and <strong>const</strong> are <strong>hoisted</strong> to the top of their block, and they exist in the <strong>TDZ</strong> until the loop iterates over the declaration and initialization.</p><h4>Example with let:</h4><pre>for (let i = 0; i &lt; 3; i++) {<br>  console.log(i);  // Logs 0, 1, 2<br>}<br>console.log(i);  // ReferenceError: i is not defined</pre><ul><li>In this example:</li><li><strong>i</strong> is declared with let, and its scope is limited to the block inside the for loop.</li><li><strong>TDZ in for loops</strong>: Within the loop, i is in the <strong>TDZ</strong> until the iteration reaches the part where i is initialized. You cannot access i outside of the block scope, and attempting to access it outside the loop results in a ReferenceError.</li></ul><h4>Example with const:</h4><pre>for (const j = 0; j &lt; 3; j++) {  // This will cause an error because `const` cannot be reassigned<br>  console.log(j);<br>}</pre><p>In this example:</p><ul><li>The loop tries to reassign j during each iteration, but since j is declared with const, it <strong>cannot be reassigned</strong>.</li><li>This causes a <strong>TypeError</strong> during the loop execution, not a ReferenceError from the TDZ.</li></ul><p>However, notice that even if you have a for loop, <strong>the variable (</strong><strong>let or </strong><strong>const) is still hoisted</strong> within the loop’s block scope and remains in the TDZ until the loop starts executing. The difference is that in a for loop, you are iterating over the variable, which gives it a defined value for each loop iteration.</p><blockquote><strong><em>“The Temporal Dead Zone may sound like sci-fi, but it’s a real and important behavior in JavaScript. By understanding it, you’re not just avoiding bugs — you’re learning how JavaScript truly works under the hood. If you made it this far, you’re well on your way to becoming a JavaScript pro. Stay curious and keep asking questions — that’s how mastery begins.”</em></strong></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=33e2aef16aa0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mastering Hoisting in JavaScript: The Ultimate Q&A Guide]]></title>
            <link>https://medium.com/@aansh0611/mastering-hoisting-in-javascript-the-ultimate-q-a-guide-bfd4047a40f1?source=rss-a30f3e59663a------2</link>
            <guid isPermaLink="false">https://medium.com/p/bfd4047a40f1</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[interview-questions]]></category>
            <category><![CDATA[javascript-tips]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Anshuman]]></dc:creator>
            <pubDate>Mon, 23 Jun 2025 14:48:57 GMT</pubDate>
            <atom:updated>2025-06-23T14:48:57.726Z</atom:updated>
            <content:encoded><![CDATA[<h3>1. What is Hoisting in JavaScript?</h3><p><strong>Hoisting</strong> in JavaScript is a mechanism where <strong>variable</strong> and <strong>function declarations</strong> are moved to the top of their containing scope during the <strong>compile phase</strong> before the code has been executed. This allows variables and functions to be used before they are actually declared in the code.</p><p>However, only <strong>declarations</strong> (the part where the variable or function is declared) are hoisted, <strong>initializations</strong> (the part where they are assigned values) are not.</p><h4>Example of Hoisting:</h4><pre>console.log(a);  // undefined, because `a` is hoisted, but not initialized<br>var a = 10;</pre><p>In this case, a is hoisted and placed at the top, but since it is initialized with undefined initially, the output is undefined.</p><h3>2. Which declarations are hoisted: var, let, const, functions, classes?</h3><h4>Hoisting for different declarations:</h4><p><strong>var declarations</strong>:</p><ul><li>var declarations are <strong>hoisted</strong> to the top of their function or global scope.</li><li>Only the <strong>declaration</strong> is hoisted, but <strong>initialization</strong> is not.</li><li>When a var variable is hoisted, it is initialized with the value undefined.</li><li>Example:</li></ul><pre>console.log(x);  // undefined <br>var x = 5;</pre><p><strong>let and </strong><strong>const declarations</strong>:</p><ul><li>Both let and const are <strong>hoisted</strong> to the top of their block scope, but they are placed in the <strong>Temporal Dead Zone (TDZ)</strong>.</li><li>The variables are <strong>not initialized</strong> until the line of code where they are actually declared and assigned a value.</li><li>Accessing them before their initialization will throw a ReferenceError.</li><li>Example:</li></ul><pre>console.log(x);  // ReferenceError: Cannot access &#39;x&#39; before initialization <br>let x = 5;</pre><p><strong>Function declarations</strong>:</p><ul><li><strong>Function declarations are hoisted completely</strong>, meaning both the function <strong>name</strong> and the function <strong>body</strong> are hoisted.</li><li>You can call the function before its declaration in the code because the entire function is hoisted.</li><li>Example:</li></ul><pre>greet();  // &quot;Hello, world!&quot; - because function declaration is hoisted  <br>function greet() {   <br>  console.log(&quot;Hello, world!&quot;); <br>}</pre><p><strong>Function expressions (including arrow functions)</strong>:</p><ul><li><strong>Function expressions</strong> (whether traditional function expressions or arrow functions) are <strong>not hoisted</strong> like function declarations.</li><li>Only the variable declaration is hoisted (if using var, let, or const), but the <strong>function assignment</strong> is not hoisted.</li><li>Example with var:</li></ul><pre>greet; // undefined<br>greet();  // TypeError: greet is not a function  <br>var greet = function() {   console.log(&quot;Hello, world!&quot;); };</pre><p>Example with let (same behavior as with const):</p><pre>greet();  // ReferenceError: Cannot access &#39;greet&#39; before initialization <br>let greet = function() {   console.log(&quot;Hello, world!&quot;); };</pre><p><strong>Class declarations</strong>:</p><ul><li><strong>Class declarations</strong> are <strong>hoisted</strong> but are <strong>not initialized</strong> until the line where the class is declared.</li><li>If you try to instantiate or access the class before its declaration, it will throw a ReferenceError.</li><li>Example:</li></ul><pre>const obj = new MyClass();  // ReferenceError: Cannot access &#39;MyClass&#39; before initialization <br>class MyClass {   <br>    constructor() {     <br>        console.log(&quot;Hello from MyClass&quot;);<br>   } <br>}</pre><h3>3. How does hoisting differ between var, let, and const?</h3><p>The key differences between how var, let, and const behave when hoisted are as follows:</p><p><strong>var</strong>:</p><ul><li><strong>Hoisted to the top of the scope</strong> (global or function scope).</li><li>Initialized with the value undefined.</li><li>Can be <strong>re-declared</strong> and <strong>re-assigned</strong> within the same scope.</li><li>Example:</li></ul><pre>console.log(x);  // undefined (hoisted, but not initialized) <br>var x = 10;</pre><p><strong>let</strong> and <strong>const</strong>:</p><ul><li><strong>Hoisted</strong> to the top of the block scope (if inside a block or function).</li><li><strong>Not initialized</strong> immediately. They remain in the <strong>Temporal Dead Zone (TDZ)</strong> from the start of the block until the actual initialization.</li><li><strong>let and </strong><strong>const cannot be re-declared</strong> in the same scope.</li><li><strong>const</strong> requires initialization at the time of declaration.</li><li>Example with let:</li></ul><pre>console.log(y);  // ReferenceError: Cannot access &#39;y&#39; before initialization<br> let y = 20;</pre><pre>console.log(z);  // ReferenceError: Cannot access &#39;z&#39; before initialization <br>const z = 30;</pre><h3>4. What happens to function declarations during hoisting?</h3><p>Function declarations are <strong>hoisted completely</strong>. This means both the <strong>name</strong> and the <strong>body</strong> of the function are moved to the top of the scope. Because of this, you can <strong>call the function before its declaration</strong> in the code.</p><h4>Example:</h4><pre>foo();  // Hello, world!  Works because function declarations are hoisted<br>function foo() {<br>  console.log(&quot;Hello, world!&quot;);<br>}</pre><p>In the above example:</p><ul><li>The function foo() is <strong>hoisted</strong> entirely, including its body, so it can be called before the declaration.</li></ul><p>However, <strong>function expressions</strong> (including arrow functions) are not hoisted in the same way. Only the variable declaration (not the function definition) is hoisted.</p><h3>5. What is the difference between hoisting a function declaration vs function expression?</h3><p>The key difference between <strong>function declarations</strong> and <strong>function expressions</strong> (including arrow functions) when it comes to hoisting is that <strong>function declarations</strong> are <strong>hoisted completely</strong>, whereas <strong>function expressions</strong> are hoisted only with their variable declaration.</p><h4>Function Declaration (hoisted completely):</h4><p>A function declaration is <strong>hoisted</strong> with both its <strong>name</strong> and <strong>body</strong>, allowing you to call the function before it appears in the code.</p><p>Example:</p><pre>foo();  // Works because the entire function is hoisted<br>function foo() {<br>  console.log(&quot;Hello, world!&quot;);<br>}</pre><h4>Function Expression (not hoisted):</h4><p>A function expression (whether normal or arrow function) is <strong>hoisted only with the variable declaration</strong> and <strong>not with its value</strong> (i.e., the function itself). This means you <strong>cannot invoke the function before the expression</strong> is assigned.</p><p>Example with a function expression:</p><pre>foo();  // TypeError: foo is not a function<br>var foo = function() {<br>  console.log(&quot;Hello, world!&quot;);<br>};</pre><p>Example with an arrow function:</p><pre>foo();  // ReferenceError: Cannot access &#39;foo&#39; before initialization<br>let foo = () =&gt; {<br>  console.log(&quot;Hello, world!&quot;);<br>};</pre><p>In the case of both the function expression examples above:</p><ul><li>The variable foo is hoisted, but the function is not assigned until the execution reaches that line of code. Therefore, invoking foo() before that point results in an error.</li></ul><h3>6.What will be the output and why?</h3><pre>console.log(foo);  // ?<br>var foo = 10;</pre><h4>Output:</h4><pre>undefined</pre><h4>Explanation:</h4><p>This is a result of <strong>hoisting</strong> in JavaScript. Here’s what happens behind the scenes:</p><ol><li><strong>Variable declaration (</strong><strong>var foo) is hoisted</strong> to the top of its scope (in this case, the global scope), but <strong>only the declaration</strong>, not the initialization.</li><li>The <strong>initialization</strong> (foo = 10) happens at the line where it&#39;s written in the code, not at the top.</li><li><strong>Hoisting with </strong><strong>var</strong>: The variable foo is hoisted to the top and initialized with the value undefined (the default for uninitialized var variables).</li><li>When you log foo before it has been assigned the value 10, it outputs undefined.</li></ol><p>So, essentially, the code is interpreted like this:</p><pre>var foo;  // Hoisted declaration<br>console.log(foo);  // undefined (because it hasn&#39;t been initialized yet)<br>foo = 10;  // Initialization happens here</pre><h3>7. Why is it considered bad practice to rely on hoisting?</h3><p>Relying on hoisting is considered <strong>bad practice</strong> for several reasons:</p><p><strong>Code readability and predictability</strong>:</p><ul><li>Hoisting can make the code harder to read and reason about because the behavior of variables and functions can be different depending on where they are declared in the code. This can lead to confusion, especially for new developers or when maintaining code.</li><li>It’s harder to track what is hoisted and where the actual values are assigned.</li></ul><p><strong>Unexpected behavior</strong>:</p><ul><li>Hoisting can lead to <strong>unexpected behavior</strong>, like accessing a variable before it has been initialized. This is particularly problematic with var because it initializes variables to undefined, which can sometimes cause logical bugs that are difficult to debug.</li><li>For example, accessing a let or const variable before its declaration throws a ReferenceError, which can be confusing if hoisting behavior isn’t understood properly.</li></ul><p><strong>Difficult debugging</strong>:</p><ul><li>Hoisting can introduce subtle bugs that are difficult to debug. When the code behaves differently than expected, it might be due to hoisting, but the bug might not be immediately apparent, especially if you’re relying on var or have complex function declarations.</li></ul><p><strong>Inconsistent behavior across different variable types</strong>:</p><ul><li>Hoisting behavior differs between var, let, const, and functions. This inconsistency can lead to confusing code. For example, var is hoisted with undefined, whereas let and const are hoisted but remain in the <strong>Temporal Dead Zone (TDZ)</strong>.</li></ul><h3>8. What happens when you try to access a class before it’s declared?</h3><p>If you try to access a <strong>class</strong> before it is declared, JavaScript will throw a <strong>ReferenceError</strong>.</p><h4>Example:</h4><pre>const myInstance = new MyClass();  // ReferenceError: Cannot access &#39;MyClass&#39; before initialization<br>class MyClass {<br>  constructor() {<br>    console.log(&#39;Class Initialized&#39;);<br>  }<br>}</pre><h4>Explanation:</h4><ul><li><strong>Class declarations</strong> in JavaScript are <strong>hoisted</strong> but are <strong>not initialized</strong> until the code execution reaches the class definition. This means if you try to access or instantiate a class before it’s declared, you’ll get a ReferenceError because the class is in the <strong>Temporal Dead Zone (TDZ)</strong>.</li><li>The class itself is hoisted to the top of the scope, but it is <strong>not available for use</strong> until it’s fully initialized during the code execution.</li></ul><p>Thus, trying to access or instantiate MyClass before its declaration results in a ReferenceError because it hasn’t been fully initialized yet.</p><h3>9. Is hoisting a feature or a side-effect of how the JavaScript engine parses code?</h3><p>Hoisting is <strong>not a deliberate feature</strong> of JavaScript, but rather a <strong>side effect of how the JavaScript engine parses and compiles code</strong>.</p><p>During the <strong>compilation phase</strong>, the JavaScript engine scans the code to <strong>prepare</strong> for execution. This phase involves:</p><ul><li><strong>Variable and function declarations</strong> being processed (hoisted).</li><li>Variables declared with var are initialized with undefined, and function declarations are completely hoisted.</li><li><strong>let and </strong><strong>const variables</strong>, on the other hand, are hoisted but remain in the <strong>Temporal Dead Zone (TDZ)</strong> until they are initialized in the code.</li></ul><p>So, hoisting occurs as a consequence of how the JavaScript engine handles the <strong>initialization of variables and functions</strong> during the <strong>compilation phase</strong>. It’s more of an <strong>implementation detail</strong> than a designed feature of the language.</p><h3>10. How does the JavaScript engine handle hoisting internally during the compilation phase?</h3><p>During the <strong>compilation phase</strong>, the JavaScript engine does the following:</p><p><strong>Global Execution Context</strong>:</p><ul><li>It <strong>creates an execution context</strong> for the global scope.</li><li>It <strong>scans</strong> the entire script and makes a list of <strong>declarations</strong> (variables, functions, and classes).</li><li>For var variables, it <strong>hoists</strong> the variable names to the top of the execution context and assigns them an initial value of undefined.</li><li>Function declarations are <strong>hoisted completely</strong> (including their bodies).</li><li>For let, const, and class declarations, it only hoists the <strong>declaration</strong> but not the <strong>initialization</strong>. These variables remain in the <strong>Temporal Dead Zone (TDZ)</strong> until their actual declaration is executed.</li></ul><p><strong>Function Execution Context</strong>:</p><ul><li>When a function is invoked, the engine creates a new execution context for the function.</li><li>The function’s <strong>parameters</strong> and <strong>local variables</strong> are hoisted to the top of the function’s scope, similar to what happens at the global level.</li></ul><p><strong>The result</strong> is that, during the compilation phase:</p><ul><li>All variable and function declarations are prepared in memory (hoisted).</li><li><strong>But</strong>, the <strong>initializations</strong> (the values assigned to variables) occur when the code is actually executed in the <strong>execution phase</strong>.</li></ul><h3>11. Explain how hoisting and TDZ interact with each other.</h3><p>Hoisting and the <strong>Temporal Dead Zone (TDZ)</strong> are closely related concepts that govern <strong>variable initialization</strong>.</p><ul><li><strong>Hoisting</strong>: When a variable is declared (using var, let, const, or a function), the declaration itself is moved to the top during the compilation phase.</li><li>For var, the <strong>initialization</strong> is hoisted as well (with a default value of undefined).</li><li>For let and const, <strong>only the declaration</strong> is hoisted to the top, but they are placed in the <strong>Temporal Dead Zone (TDZ)</strong> until the line where they are assigned a value.</li><li><strong>Temporal Dead Zone (TDZ)</strong>: This is the period of time between the entering of a variable’s scope and its actual initialization. If you try to access a let or const variable before it has been initialized (but after its hoisting), the engine throws a ReferenceError.</li></ul><h4>Interaction:</h4><p><strong>For </strong><strong>var declarations</strong>:</p><ul><li>Hoisting happens with <strong>initialization</strong> to undefined. Therefore, if you try to use a var variable before its assignment, it will return undefined but <strong>not</strong> throw an error.</li></ul><p><strong>For </strong><strong>let and </strong><strong>const declarations</strong>:</p><ul><li>Only the <strong>declaration</strong> is hoisted, but they stay in the <strong>TDZ</strong> until they are initialized.</li><li>If you try to access them during the TDZ (before the initialization), a <strong>ReferenceError</strong> is thrown, indicating that you can&#39;t use the variable yet.</li></ul><h4>Example of TDZ with let and const:</h4><pre>console.log(a);  // ReferenceError: Cannot access &#39;a&#39; before initialization<br>let a = 10;</pre><p>In this case:</p><ul><li>let a is hoisted, but it remains in the <strong>TDZ</strong> until its declaration is executed.</li><li>Trying to access a before its initialization results in a ReferenceError.</li></ul><h3>12. Can hoisting lead to unexpected bugs? Can you give an example?</h3><p>Yes, hoisting <strong>can lead to unexpected bugs</strong>, especially when developers don’t fully understand how it works. The behavior of hoisted variables can be subtle, particularly when using var, and this can result in logical errors that are hard to debug.</p><h4>Example 1: Hoisting with var (unexpected undefined)</h4><pre>console.log(x);  // undefined<br>var x = 5;</pre><p>In this example, the output is undefined instead of 5. This happens because:</p><ul><li>var x is hoisted, but its initialization (x = 5) happens later in the code.</li><li>x is initialized with undefined when it is hoisted, so when console.log(x) is called, it logs undefined instead of 5.</li></ul><h4>Example 2: Hoisting with let and the Temporal Dead Zone (TDZ)</h4><pre>console.log(y);  // ReferenceError: Cannot access &#39;y&#39; before initialization<br>let y = 10;</pre><p>This example results in a <strong>ReferenceError</strong> because y is hoisted, but it remains in the TDZ until it is actually initialized. If you try to access y before its declaration, it throws an error.</p><h4>Example 3: Hoisting and Function Declarations</h4><pre>hello();  // &quot;Hello from function!&quot;<br>function hello() {<br>  console.log(&quot;Hello from function!&quot;);<br>}</pre><p>Here, the function declaration is hoisted completely, including its body. This allows you to call hello() before it is declared in the code.</p><p>However, if you mistakenly use a <strong>function expression</strong> (instead of a function declaration), you may encounter different behavior.</p><h4>Example 4: Hoisting with Function Expressions (unexpected TypeError)</h4><pre>hello();  // TypeError: hello is not a function<br>var hello = function() {<br>  console.log(&quot;Hello from function expression!&quot;);<br>};</pre><p>In this case:</p><ul><li>var hello is hoisted to the top, but the function assignment (hello = function() { ... }) is not hoisted.</li><li>So, when you try to invoke hello() before the function is assigned, it throws a TypeError because hello is undefined at that point.</li></ul><blockquote>“Hoisting in JavaScript may seem confusing at first, but once you understand how the interpreter works under the hood, it becomes a powerful concept to master. I hope this deep-dive has cleared your doubts and armed you with clarity. Keep experimenting, keep questioning — because the more curious you are, the better developer you’ll become. Happy coding!”</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bfd4047a40f1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mastering the Strategy Design Pattern: Write Flexible Code Like a Pro]]></title>
            <link>https://medium.com/@aansh0611/mastering-the-strategy-design-pattern-write-flexible-code-like-a-pro-8240ecc2c8d2?source=rss-a30f3e59663a------2</link>
            <guid isPermaLink="false">https://medium.com/p/8240ecc2c8d2</guid>
            <category><![CDATA[strategy-pattern]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[oops-concepts]]></category>
            <dc:creator><![CDATA[Anshuman]]></dc:creator>
            <pubDate>Sun, 22 Jun 2025 13:19:57 GMT</pubDate>
            <atom:updated>2025-06-22T13:19:57.677Z</atom:updated>
            <content:encoded><![CDATA[<blockquote><em>Ever felt stuck rewriting logic just to change one part of your program’s behavior? What if you could swap behaviors like LEGO blocks — without touching the core system? That’s the magic of the Strategy Design Pattern.</em></blockquote><h4>Why Strategy Pattern Matters (Even If You’re a Beginner)</h4><p>Imagine you’re building a shopping cart app. Today, it supports credit card payments. Tomorrow, your product team wants to add PayPal. Then Google Pay. If your payment logic is deeply embedded in your code, you’re now in trouble. You either:</p><ul><li>Rewrite parts of your class</li><li>Duplicate logic across payment types</li><li>Or wrap everything in messy conditionals (if, else, switch)</li></ul><p>This leads to <strong>fragile, tangled, and rigid code</strong> — the kind of system that breaks when you breathe on it.</p><h4>What if…</h4><p>You could define each behavior (like payment methods) separately and plug them into your system when needed?</p><p>That’s exactly what the <strong>Strategy Design Pattern</strong> allows you to do.</p><h3>What Is the Strategy Design Pattern?</h3><blockquote><em>“Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.” — </em>Gang of Four</blockquote><p>In simpler terms:<br> <strong>Extract a behavior from your class and put it into separate strategy classes. The main class (called the context) uses one of these strategies at runtime without knowing the details.</strong></p><p>It’s like choosing your mode of transport — car, bike, or metro — depending on the situation. You get to pick the most appropriate “strategy” without changing your daily routine (context).</p><h4>Key Concepts</h4><p>Here are the main building blocks of the Strategy pattern:</p><ul><li><strong>Strategy Interface</strong> — Declares the behavior’s contract.</li><li><strong>Concrete Strategies</strong> — Implement different versions of the behavior.</li><li><strong>Context Class</strong> — Uses a Strategy but doesn’t care which one — it just calls the interface method.</li></ul><h4>Strategy Pattern in a Nutshell</h4><pre>+---------------------+       +--------------------------+<br>|     Context         |       |      Strategy            |<br>|---------------------|       |--------------------------|<br>| - strategy:Strategy |&lt;&gt;----&gt;| +execute(): void         |<br>|---------------------|       +--------------------------+<br>| +setStrategy(s)     |                     /|\       <br>| +executeStrategy()  |                      |<br>+---------------------+                      |<br>                                             |<br>             +------------------------+  +----------------------+<br>             |   ConcreteStrategyA    |  | ConcreteStrategyB    |<br>             |------------------------|  |----------------------|<br>             | +execute(): void       |  | +execute(): void     |<br>             +------------------------+  +----------------------+</pre><h4>Real-Life Analogy: AI in Games</h4><p>In a game, enemies might:</p><ul><li>Attack aggressively</li><li>Defend when weak</li><li>Retreat if outnumbered</li></ul><p>Instead of hardcoding these decisions, you can define a BehaviorStrategy interface. Each strategy (Aggressive, Defensive, Fleeing) is a separate class, and enemies choose their behavior dynamically. That’s real-world Strategy Pattern in action.</p><h3>Let’s Code It: Payment Strategies in Java</h3><p>Before diving into code, here’s the <strong>scenario</strong>:</p><blockquote><em>You have a shopping cart app that supports multiple payment methods. You want to switch payment options without rewriting the cart logic.</em></blockquote><p>Here’s how to design that using the Strategy Pattern.</p><h4>Step 1: Define the Strategy Interface</h4><p>This interface declares a method that all payment strategies will implement.</p><pre>public interface PaymentStrategy {<br>    void pay(int amount);<br>}</pre><h4>Step 2: Create Concrete Strategies</h4><p>Each strategy implements the payment behavior in its own way.</p><pre>public class CreditCardPayment implements PaymentStrategy {<br>    public void pay(int amount) {<br>        System.out.println(&quot;Paid &quot; + amount + &quot; using Credit Card.&quot;);<br>    }<br>}</pre><pre>public class PayPalPayment implements PaymentStrategy {<br>    public void pay(int amount) {<br>        System.out.println(&quot;Paid &quot; + amount + &quot; using PayPal.&quot;);<br>    }<br>}</pre><h4>Step 3: Define the Context Class</h4><p>This is your main class that uses the strategy.</p><pre>public class ShoppingCart {<br>    private PaymentStrategy paymentStrategy;<br><br>    public void setPaymentStrategy(PaymentStrategy strategy) {<br>        this.paymentStrategy = strategy;<br>    }<br><br>    public void checkout(int amount) {<br>        paymentStrategy.pay(amount);<br>    }<br>}</pre><h4>Step 4: Use the Strategy in Your Application</h4><pre>public class Main {<br>    public static void main(String[] args) {<br>        ShoppingCart cart = new ShoppingCart();<br>        cart.setPaymentStrategy(new CreditCardPayment());<br>        cart.checkout(100);<br>        cart.setPaymentStrategy(new PayPalPayment());<br>        cart.checkout(200);<br>    }<br>}</pre><p><strong>Result</strong>: You can switch payment behaviors <strong>at runtime</strong> without modifying the core cart logic.</p><h4>Real-World Uses of Strategy Pattern</h4><p>You might already be using it without knowing:</p><ul><li><strong>Java Collections</strong> — Comparator interface lets you sort with different strategies.</li><li><strong>Spring Framework</strong> — ResourceLoader loads files via different strategies (URL, file, classpath).</li><li><strong>Authentication systems</strong> — OAuth, JWT, API Keys… all are interchangeable auth strategies.</li><li><strong>Game development</strong> — Switching AI behavior dynamically.</li></ul><h4>When to Use:</h4><ul><li>Multiple variations of the same algorithm or behavior</li><li>Need to switch logic dynamically</li><li>Want to follow <strong>Open/Closed</strong> and <strong>Single Responsibility</strong> principles</li></ul><h4>When to Avoid:</h4><ul><li>Only one fixed behavior (don’t over-engineer!)</li><li>Logic doesn’t change at runtime or between use cases</li></ul><h3>Common Pitfalls &amp; Misconceptions</h3><p>Even though the Strategy Pattern is powerful, it’s often misunderstood or misused. Let’s clear up some of the most common traps developers fall into:</p><h4>1. “It’s Just Polymorphism”</h4><p><strong>What people think:</strong><br> “Strategy is just another name for polymorphism. Why make it sound fancy?”</p><p><strong>Reality:</strong><br> Yes, Strategy uses polymorphism under the hood. But the real power lies in its ability to <strong>change behavior at runtime</strong>. Traditional polymorphism doesn’t typically offer that kind of flexibility without changing object structure or branching logic.</p><h4>2. “It Adds Unnecessary Complexity”</h4><p><strong>What people think:</strong><br> “Why create multiple classes when I can just use an if-else or switch?”</p><p><strong>Reality:</strong><br> This thinking leads to the <strong>God Object anti-pattern</strong> — one class doing too much. As your app grows, that if-else chain becomes brittle and hard to test. The Strategy Pattern simplifies maintenance by following the <strong>Single Responsibility Principle (SRP)</strong> and <strong>Open/Closed Principle (OCP)</strong>.</p><h4>3. “You Need Many Strategies to Justify It”</h4><p><strong>What people think:</strong><br> “You need at least 5–6 strategies to make the pattern worth it.”</p><p><strong>Reality:</strong><br> Even <strong>two different behaviors</strong> are enough to apply this pattern. If those behaviors are likely to evolve independently, Strategy is already a better choice than conditional branching.</p><h4>4. “It’s Only Useful for Algorithms”</h4><p><strong>What people think:</strong><br> “It’s just for sorting or payment logic.”</p><p><strong>Reality:</strong><br> Strategy works <strong>anywhere behavior changes</strong> — logging, caching, validation, game AI, notification methods, routing logic, etc.</p><h4>5.“You Can’t Use Strategy With Dependency Injection”</h4><p><strong>What people think:</strong><br> “DI frameworks don’t work well with Strategy because you don’t know the implementation at compile time.”</p><p><strong>Reality:</strong><br> Modern frameworks like <strong>Spring</strong>, <strong>Dagger</strong>, and <strong>Guice</strong> support injecting strategies via configuration, factories, or qualifiers. You can even change them dynamically.</p><h3>Pro Tips for Clean Design</h3><ul><li>Keep strategy classes <strong>stateless</strong> for reusability</li><li>Combine with <strong>Factory Pattern</strong> to dynamically select strategies</li><li>Make strategies <strong>singleton</strong> when no state is involved</li><li>Write <strong>unit tests</strong> for each strategy in isolation</li></ul><h4>Recap and Takeaways</h4><p>The <strong>Strategy Design Pattern</strong> is a tool every serious developer must master. It’s about cleanly separating what your system does from how it does it. That unlocks flexibility, maintainability, and rock-solid code.</p><h4>Remember:</h4><ul><li>Encapsulate behavior</li><li>Switch at runtime</li><li>Favor composition over inheritance</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8240ecc2c8d2" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>