<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ayush Maurya</title>
    <description>The latest articles on DEV Community by Ayush Maurya (@ayush_maurya_).</description>
    <link>https://dev.to/ayush_maurya_</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2011912%2F6879fea4-4c76-4e1d-a83a-c4cab79c3c11.jpg</url>
      <title>DEV Community: Ayush Maurya</title>
      <link>https://dev.to/ayush_maurya_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ayush_maurya_"/>
    <language>en</language>
    <item>
      <title>Your Abstractions Are Lying to You | Every File You Create Is a Debt</title>
      <dc:creator>Ayush Maurya</dc:creator>
      <pubDate>Sun, 03 May 2026 13:02:30 +0000</pubDate>
      <link>https://dev.to/ayush_maurya_/your-abstractions-are-lying-to-you-every-file-you-create-is-a-debt-25ml</link>
      <guid>https://dev.to/ayush_maurya_/your-abstractions-are-lying-to-you-every-file-you-create-is-a-debt-25ml</guid>
      <description>&lt;p&gt;There's a book from 2018 called &lt;em&gt;A Philosophy of Software Design&lt;/em&gt;. &lt;strong&gt;John Ousterhout&lt;/strong&gt; wrote it. He spent his career building operating systems and distributed systems — Tcl, RAMCloud, Raft consensus. Not exactly frontend territory.&lt;/p&gt;

&lt;p&gt;But somewhere in that book, he describes a failure mode that I've seen in more Angular codebases than I can count.&lt;/p&gt;

&lt;p&gt;He calls it a shallow module.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Module Actually Is
&lt;/h2&gt;

&lt;p&gt;Every abstraction you create — a service, a directive, a component — has two dimensions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interface&lt;/strong&gt;: the surface exposed to the caller. How much does someone need to know to use this thing?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;: the work hidden inside. How much complexity does it actually absorb?&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;deep module&lt;/strong&gt; has a narrow interface and a powerful implementation. You interact with it through a small surface, and it does a lot for you on the other side of that surface.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;shallow module&lt;/strong&gt; has an interface that costs roughly as much as what it gives back. You have to know a lot to use it, and it doesn't hide much in return.&lt;/p&gt;

&lt;p&gt;Ousterhout's canonical example is Unix file I/O. Five calls — &lt;code&gt;open&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt;, &lt;code&gt;seek&lt;/code&gt; — hide decades of complexity: file systems, permissions, buffering, disk abstraction, OS scheduling. You don't know any of that exists. You just call &lt;code&gt;read&lt;/code&gt;. That's a deep module.&lt;/p&gt;

&lt;p&gt;Now think about the last service you wrote.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem Is Worse in Frontend
&lt;/h2&gt;

&lt;p&gt;Backend engineers are often &lt;em&gt;forced&lt;/em&gt; into depth because they're hiding genuinely complex things — databases, networks, distributed state, file systems. The complexity exists before they write a single line of abstraction.&lt;/p&gt;

&lt;p&gt;Frontend developers are different. Nobody forced you to create that service. Nobody required that directive. You chose to add a layer. Which means the question of whether it justifies its existence is sharper — and the failure mode of shallow abstraction is far more common.&lt;/p&gt;

&lt;p&gt;You can write an entire Angular application full of files that follow every convention, satisfy every linter, pass every code review — and still have an app where every abstraction is lying to you. Where every layer pretends to be hiding something but is really just renaming what's below it.&lt;/p&gt;

&lt;p&gt;Let me show you what that looks like. And what the alternative looks like.&lt;/p&gt;




&lt;h2&gt;
  
  
  Services: Absorb Complexity or Don't Exist
&lt;/h2&gt;

&lt;p&gt;Here's the shallow version. You've seen it. You've probably written it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks clean. But now look at the component that uses it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component is managing loading state, error state, type casting, and retry logic. The service renamed &lt;code&gt;http.get&lt;/code&gt; and nothing else. Every component that calls this service will write this same ceremony independently.&lt;/p&gt;

&lt;p&gt;That's a shallow service. The interface costs you an import and a constructor injection. The implementation gives you almost nothing in return.&lt;/p&gt;

&lt;p&gt;Now here's what a service looks like when it earns its existence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// rxResource wraps the HTTP call and gives you .value(), .isLoading(),&lt;/span&gt;
    &lt;span class="c1"&gt;// and .error() as signals — no manual state management needed&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;rxResource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;rxResource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;put&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The caller — a standalone component, no &lt;code&gt;async&lt;/code&gt; pipe, no subscription:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-user-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    @if (userResource.isLoading()) { &amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt; }
    @if (userResource.error()) { &amp;lt;p&amp;gt;{{ normalizeError(userResource.error()) }}&amp;lt;/p&amp;gt; }
    @if (userResource.value(); as user) {
      &amp;lt;h2&amp;gt;{{ user.name }}&amp;lt;/h2&amp;gt;
      &amp;lt;p&amp;gt;{{ user.email }}&amp;lt;/p&amp;gt;
    }
  `&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserProfileComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ActivatedRoute&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="nx"&gt;userResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;normalizeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;HttpErrorResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User not found.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You don&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;t have permission to do this.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server error. Please try again later.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An unexpected error occurred.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component doesn't subscribe. Doesn't manage loading state. Doesn't catch errors manually. &lt;code&gt;rxResource&lt;/code&gt; gives it &lt;code&gt;.isLoading()&lt;/code&gt;, &lt;code&gt;.value()&lt;/code&gt;, and &lt;code&gt;.error()&lt;/code&gt; as signals — and Angular's new control flow (&lt;code&gt;@if&lt;/code&gt;) reacts to them directly.&lt;/p&gt;

&lt;p&gt;Notice that &lt;code&gt;normalizeError&lt;/code&gt; lives in the component here — and that's intentional. The service absorbs &lt;em&gt;infrastructure&lt;/em&gt; complexity: retries, caching, HTTP mechanics. Error &lt;em&gt;presentation&lt;/em&gt; — what a 404 means to the user — is a UI concern. Each layer owns what belongs to it.&lt;/p&gt;

&lt;p&gt;When the backend team changes their error format, you fix it in one place. Every component heals automatically.&lt;/p&gt;

&lt;p&gt;That's what depth looks like. The interface is a single method call. The implementation absorbs retries, caching, Observable-to-Signal bridging, and loading state — none of which the caller ever sees.&lt;/p&gt;




&lt;h2&gt;
  
  
  Directives: Hide Coordination, Not Just Classes
&lt;/h2&gt;

&lt;p&gt;The shallow version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[appHighlight]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HighlightDirective&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;HostListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mouseenter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;onMouseEnter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;highlighted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;HostListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mouseleave&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;onMouseLeave&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;highlighted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A directive that toggles one class on hover. You could replace this with a CSS &lt;code&gt;:hover&lt;/code&gt; rule. It exists as a file, needs to be declared, imported, and understood — for two lines of functionality. Shallow.&lt;/p&gt;

&lt;p&gt;A directive becomes deep when it hides something the caller genuinely cannot do cheaply: event coordination, DOM lifecycle, cleanup contracts, timing logic. Here's a real example — click-outside detection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[appClickOutside]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClickOutsideDirective&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;clickOutside&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Renderer2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;destroyRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DestroyRef&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// setTimeout defers listener attachment past the click that opened this element&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unlisten&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;document&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clickedInside&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;clickedInside&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clickOutside&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="c1"&gt;// DestroyRef replaces ngOnDestroy — cleanup is co-located with setup&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onDestroy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;unlisten&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Clean up the timer itself if directive is destroyed before it fires&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onDestroy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown"&lt;/span&gt; &lt;span class="na"&gt;appClickOutside&lt;/span&gt; &lt;span class="na"&gt;(clickOutside)=&lt;/span&gt;&lt;span class="s"&gt;"closeDropdown()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component writing this has no idea about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;setTimeout&lt;/code&gt; trick that prevents the originating click from immediately closing the element it just opened&lt;/li&gt;
&lt;li&gt;The fact that &lt;code&gt;Renderer2.listen&lt;/code&gt; returns an unlisten function that must be called manually&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;DestroyRef&lt;/code&gt; cleanup that prevents memory leaks and stale listeners — and that the timer itself needs clearing if the directive is destroyed before it fires&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;contains()&lt;/code&gt; check that correctly handles clicks on child elements&lt;/li&gt;
&lt;li&gt;The fact that &lt;code&gt;enabled&lt;/code&gt; is a signal — &lt;code&gt;this.enabled()&lt;/code&gt; — so it reads the latest value reactively inside the listener&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every component that needs click-outside behavior gets all of that for free. Without this directive, each one would reimplement it — and probably miss the &lt;code&gt;setTimeout&lt;/code&gt; trick, skip the cleanup, or break on nested clicks.&lt;/p&gt;

&lt;p&gt;Remove the directive and the caller gets substantially more complex. That's depth.&lt;/p&gt;




&lt;h2&gt;
  
  
  Smart/Dumb Components: The Split That Goes Wrong
&lt;/h2&gt;

&lt;p&gt;The smart/dumb component pattern is one of the most useful ideas in frontend architecture. It's also one of the most commonly misapplied ones.&lt;/p&gt;

&lt;p&gt;The failure mode: the smart component passes so many &lt;code&gt;@Input()&lt;/code&gt; properties down that the dumb component becomes a post box — receiving state it didn't produce, relaying events it didn't originate, and hiding nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The dumb component that isn't doing anything dumb&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-user-profile-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`...`&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserProfileCardComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;isCurrentUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;canEdit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;editMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;edit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seven inputs. Three outputs. What does this component own? Nothing. It's a template with plumbing. Remove it and paste the template into the smart component — nothing meaningful changes.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;editMode&lt;/code&gt; flag is the clearest symptom. That's pure UI state. It has nothing to do with routing, services, or the outside world. The smart component has no business owning it. But because it's passed down, the smart component now manages three methods — &lt;code&gt;onEdit&lt;/code&gt;, &lt;code&gt;onCancel&lt;/code&gt;, &lt;code&gt;onSave&lt;/code&gt; — that exist purely to shuttle state back up from a component that should have owned it locally.&lt;/p&gt;

&lt;p&gt;Here's what the split looks like when the depth is in the right place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smart component:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-user-profile-page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;app-user-profile-card
      [userResource]="userResource"
      [permissions]="permissions()"
      (save)="onSave($event)"
    /&amp;gt;
  `&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserProfilePageComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ActivatedRoute&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;authService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// rxResource gives the card .isLoading(), .value(), .error() as signals&lt;/span&gt;
  &lt;span class="nx"&gt;userResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// permissions is a signal — no async pipe, no subscription&lt;/span&gt;
  &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;permissionsFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;onSave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dumb component:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-user-profile-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
  @if (userResource.isLoading()) { &amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt; }
  @if (userResource.error()) { &amp;lt;p&amp;gt;Something went wrong.&amp;lt;/p&amp;gt; }

  @if (userResource.value(); as user) {
    &amp;lt;h2&amp;gt;{{ user.name }}&amp;lt;/h2&amp;gt;
    &amp;lt;p&amp;gt;{{ user.email }}&amp;lt;/p&amp;gt;

    @if (permissions()?.canEdit &amp;amp;&amp;amp; !editMode()) {
      &amp;lt;button (click)="editMode.set(true)"&amp;gt;Edit&amp;lt;/button&amp;gt;
    }

    @if (editMode()) {
      &amp;lt;app-user-edit-form
        [user]="user"
        (save)="handleSave($event)"
        (cancel)="editMode.set(false)"
      /&amp;gt;
    }
  }
`&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserProfileCardComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResourceRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isCurrentUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;canEdit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// editMode is local signal state — the smart component never touches it&lt;/span&gt;
  &lt;span class="nx"&gt;editMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;handleSave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;editMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seven inputs became two. Three outputs became one. &lt;code&gt;editMode&lt;/code&gt; moved to where it belongs — inside the component whose job is to manage that interaction.&lt;/p&gt;

&lt;p&gt;The dumb component got &lt;em&gt;simpler at the interface&lt;/em&gt; but &lt;em&gt;richer in behavior&lt;/em&gt;. It now owns its local state, manages its own transitions, and cleans up after itself. Remove it now and the smart component would have to absorb all of that. Which means it was actually hiding something.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Test That Unifies All Three
&lt;/h2&gt;

&lt;p&gt;Every time you create an abstraction, ask one question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If I delete this, does the caller get meaningfully more complex?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If yes — the abstraction was earning its depth. Keep it.&lt;/p&gt;

&lt;p&gt;If no — it was a layer without a reason. The complexity didn't get hidden. It got deferred upward, to be rediscovered by every caller, independently, forever.&lt;/p&gt;

&lt;p&gt;This isn't about how many files you have or how well you follow conventions. A codebase can be perfectly structured and still full of abstractions that are lying about how much work they're doing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ousterhout&lt;/strong&gt; wrote about this in the context of operating systems. But the failure mode is identical in a five-file Angular feature module. The scale is different. The pattern is the same.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Note If You've Been Reading This Series
&lt;/h2&gt;

&lt;p&gt;This post is part of an ongoing series called &lt;em&gt;&lt;a href="https://medium.com/codetodeploy/dont-fight-the-framework-part-1-your-angular-template-doesn-t-exist-at-runtime-f4e3e471fc04" rel="noopener noreferrer"&gt;Don't Fight the Framework, Embrace It&lt;/a&gt;&lt;/em&gt; — about what it actually means to understand Angular at the level where you stop guessing and start knowing.&lt;/p&gt;

&lt;p&gt;That posts covered the rendering engine, Ivy's locality principle, LView/TView internals, and how change detection actually works under the hood.&lt;/p&gt;

&lt;p&gt;This one is different. It's not about Angular internals. It's about a design principle old enough to predate Angular by decades — and why it applies to your codebase more precisely than most Angular-specific advice does.&lt;/p&gt;

&lt;p&gt;The internals tell you how the framework works. This tells you whether what you're building on top of it is worth building at all.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>softwareengineering</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Designing Multi-View Angular UIs: Router Outlets, outletContext, and Stateful View Composition</title>
      <dc:creator>Ayush Maurya</dc:creator>
      <pubDate>Fri, 12 Dec 2025 10:15:27 +0000</pubDate>
      <link>https://dev.to/ayush_maurya_/designing-multi-view-angular-uis-router-outlets-outletcontext-and-stateful-view-composition-26ga</link>
      <guid>https://dev.to/ayush_maurya_/designing-multi-view-angular-uis-router-outlets-outletcontext-and-stateful-view-composition-26ga</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7b846l3zkj6ggbezwu7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7b846l3zkj6ggbezwu7.jpg" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the previous article, we looked at why Angular UIs begin to fall apart when the view logic is controlled with if and switch. Conditional rendering means visibility not the state, and once your UI needs deep links, reload presistance, or multiple simultaneous screens, then it becomes very difficult to scale.&lt;/p&gt;

&lt;p&gt;In this article we will see how routing actually helps in all, architecture in practical.&lt;/p&gt;

&lt;p&gt;Angular gives you below three powerfull tools.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Router Outlets&lt;/li&gt;
&lt;li&gt;Named Outlets&lt;/li&gt;
&lt;li&gt;Outlet Context&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Combined, these turn Angular's router into a true view composition engine, capable of driving dashboards, tool panels, multi-pane editors, modals, overlays, and even app-within-app layouts.&lt;/p&gt;

&lt;p&gt;Let's break it all down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Router Outlets Are Independent Viewports
&lt;/h2&gt;

&lt;p&gt;Most developers only use the primary outlet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But Angular allows as many viewports as your UI needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!-- primary --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;router-outlet&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"sidebar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;router-outlet&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"inspector"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each outlet is independent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;loads its own routed component&lt;/li&gt;
&lt;li&gt;activates and deactivates separately&lt;/li&gt;
&lt;li&gt;can lazy-load its own module&lt;/li&gt;
&lt;li&gt;runs guards and resolvers on its own&lt;/li&gt;
&lt;li&gt;has its own lifecycle (OnInit/OnDestroy)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This alone lets you architect UIs that feel like VS Code, Figma, or Jira — multi-panel applications, not single-screen pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing Into Specific Outlets
&lt;/h2&gt;

&lt;p&gt;A route becomes tied to a viewport using the outlet property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;filters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FiltersComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;outlet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sidebar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigation activates it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt; &lt;span class="na"&gt;outlets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sidebar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;filters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}}]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And Angular constructs URLs that encode whole layouts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/dashboard(main:details//sidebar:filters//inspector:info)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ugly? Yes.&lt;br&gt;
Accurate representation of UI state? Absolutely.&lt;/p&gt;

&lt;p&gt;It's the browser's built-in serialization of your app's layout.&lt;/p&gt;
&lt;h2&gt;
  
  
  Handling Multiple Outlets Through Routing
&lt;/h2&gt;

&lt;p&gt;You can activate several outlets simultaneously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/workspace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;outlets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;overview&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;sidebar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;filters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;inspector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;info&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one navigation call:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;loads three components&lt;/li&gt;
&lt;li&gt;initializes three route trees&lt;/li&gt;
&lt;li&gt;sets up three separate lifecycles&lt;/li&gt;
&lt;li&gt;completely represents the UI in the URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reload → same layout&lt;br&gt;
Share → same layout&lt;br&gt;
Back → outlet-level navigation&lt;br&gt;
Forward → restore split views&lt;/p&gt;

&lt;p&gt;Try building that with switch and flags.&lt;/p&gt;
&lt;h2&gt;
  
  
  outletContext — Per-Outlet Configuration
&lt;/h2&gt;

&lt;p&gt;Sometimes the same component should behave differently depending on which outlet loaded it.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
A UserListComponent rendered compact in a sidebar but fully detailed in the main viewport.&lt;/p&gt;

&lt;p&gt;Create an outlet context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;router-outlet&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"sidebar"&lt;/span&gt; &lt;span class="na"&gt;[outletContext]=&lt;/span&gt;&lt;span class="s"&gt;"{ mode: 'compact' }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;router-outlet&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt; &lt;span class="na"&gt;[outletContext]=&lt;/span&gt;&lt;span class="s"&gt;"{ mode: 'full' }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access it inside the routed component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ROUTER_OUTLET_CONTEXT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the same component behaves differently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;viewMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern replaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;duplicated components&lt;/li&gt;
&lt;li&gt;over-engineered route data&lt;/li&gt;
&lt;li&gt;bloated services&lt;/li&gt;
&lt;li&gt;messy input trees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is per-viewport configuration, not global state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Use Cases for outletContext
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Same Component, Different Behavior
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sidebar version vs main-panel version&lt;/li&gt;
&lt;li&gt;Compact vs full mode&lt;/li&gt;
&lt;li&gt;Readonly vs editable mode&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Multi-pane comparison tools
&lt;/h3&gt;

&lt;p&gt;Two outlets both load ReportComponent, each with different context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;router-outlet&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"left"&lt;/span&gt; &lt;span class="na"&gt;[outletContext]=&lt;/span&gt;&lt;span class="s"&gt;"{ reportId: 10 }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;router-outlet&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"right"&lt;/span&gt; &lt;span class="na"&gt;[outletContext]=&lt;/span&gt;&lt;span class="s"&gt;"{ reportId: 20 }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. View-level configuration that doesn't belong in URL params
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;UI mode&lt;/li&gt;
&lt;li&gt;theme variant&lt;/li&gt;
&lt;li&gt;collapsed/expanded state&lt;/li&gt;
&lt;li&gt;feature flags&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Independent dashboard panels with per-panel settings
&lt;/h3&gt;

&lt;p&gt;Each panel's routed component gets its own configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outlets as a Pattern for Modals and Overlays
&lt;/h2&gt;

&lt;p&gt;Modals are often implemented with *ngIf, making them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;invisible to routing&lt;/li&gt;
&lt;li&gt;not restorable&lt;/li&gt;
&lt;li&gt;not shareable&lt;/li&gt;
&lt;li&gt;not navigable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using a dedicated modal outlet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;router-outlet&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confirm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ConfirmDialogComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;outlet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;modal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open modal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt; &lt;span class="na"&gt;outlets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confirm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Close modal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt; &lt;span class="na"&gt;outlets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now modals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;survive refresh&lt;/li&gt;
&lt;li&gt;can be deep-linked&lt;/li&gt;
&lt;li&gt;respect back/forward&lt;/li&gt;
&lt;li&gt;can be tested as routes, not DOM state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This transforms UI behavior into application state, which is exactly where it belongs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Guidance: When to Use What
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use the primary outlet when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app has one main view region.&lt;/li&gt;
&lt;li&gt;Content is page-like.&lt;/li&gt;
&lt;li&gt;You don't need complex layouts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use named outlets when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have genuinely separate viewports.&lt;/li&gt;
&lt;li&gt;Your UI needs multiple visible screens at once.&lt;/li&gt;
&lt;li&gt;You're building a dashboard, editor, control panel, or tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use outletContext when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each outlet needs its own configuration.&lt;/li&gt;
&lt;li&gt;Behavior changes per viewport.&lt;/li&gt;
&lt;li&gt;You don't want to pollute route params or services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use modals via outlets when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want back/forward navigation for dialogs.&lt;/li&gt;
&lt;li&gt;You want deep-linkable or shareable modals.&lt;/li&gt;
&lt;li&gt;You want clean UI lifecycles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Avoid abusing routing as global state&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain state belongs in services or stores.&lt;/li&gt;
&lt;li&gt;View structure belongs in outlets.&lt;/li&gt;
&lt;li&gt;outletContext is only for per-outlet customization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Get this separation right, and your Angular application becomes both predictable and scalable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Multi-outlet routing and outlet contexts let Angular behave like a stateful UI framework, not just a page router. Once you start viewing outlets as independent viewports, routing becomes a powerful layout and state engine.&lt;/p&gt;

&lt;p&gt;In the next article, we'll dive into real examples and patterns for combining multiple outlets with outletContext to build dashboard-level applications with clean, maintainable architecture&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>javascript</category>
    </item>
    <item>
      <title>A Framework-Level Look at Angular Views: Why Your Angular UI Falls Apart — and How Routing Fixes It</title>
      <dc:creator>Ayush Maurya</dc:creator>
      <pubDate>Tue, 09 Dec 2025 11:19:42 +0000</pubDate>
      <link>https://dev.to/ayush_maurya_/a-framework-level-look-at-angular-views-why-your-angular-ui-falls-apart-and-how-routing-fixes-it-2fj0</link>
      <guid>https://dev.to/ayush_maurya_/a-framework-level-look-at-angular-views-why-your-angular-ui-falls-apart-and-how-routing-fixes-it-2fj0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh534s6wp4qo6jp86y9f4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh534s6wp4qo6jp86y9f4.jpg" alt="Angular" width="800" height="420"&gt;&lt;/a&gt;Almost every Angular developer begins with &lt;code&gt;*ngIf&lt;/code&gt; and &lt;code&gt;*ngSwitch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;They're simple, intuitive, and they work… until they don't.&lt;/p&gt;

&lt;p&gt;As your application grows, you start building heavier features — perhaps a dashboard with a side-panel inspector, or a split-screen comparison tool. You stitch pieces together with boolean flags, if checks, and switch clauses, and the UI slowly starts to feel fragile.&lt;/p&gt;

&lt;p&gt;Then the requirements expand.&lt;/p&gt;

&lt;p&gt;Users want customizable layouts.&lt;br&gt;&lt;br&gt;
They want their view state preserved.&lt;br&gt;&lt;br&gt;
They want the application to feel consistent, reloadable, and navigable.&lt;/p&gt;

&lt;p&gt;Suddenly &lt;code&gt;*ngIf&lt;/code&gt; and &lt;code&gt;*ngSwitch&lt;/code&gt; stop feeling like the right tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many components can you manage through a switch statement?&lt;/li&gt;
&lt;li&gt;How do you synchronize state across multiple visible views in a dashboard?&lt;/li&gt;
&lt;li&gt;How do you persist that state across reloads — or expose it in the URL?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eventually, everything points to routing.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Realization
&lt;/h2&gt;

&lt;p&gt;When I started with Angular, routing felt messy and overcomplicated.&lt;/p&gt;

&lt;p&gt;The thing we need to understand is that &lt;strong&gt;if or switch clause are for handling visibility of the component, not the state.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's not a rigid rule, but by the end of this article, the distinction will feel obvious — and you'll understand why routing solve problems that conditionals simply can't.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Experienced Teams Reach for Router Outlets
&lt;/h2&gt;

&lt;p&gt;Engineers reach for &lt;code&gt;*ngIf&lt;/code&gt; because it's quick. Experienced teams reach for router outlets because they want the UI to behave like a real application, not a stitched-together widget board.&lt;/p&gt;
&lt;h3&gt;
  
  
  Conditional Rendering: What If/Switch Really Do
&lt;/h3&gt;

&lt;p&gt;When you use &lt;code&gt;*ngIf&lt;/code&gt; or &lt;code&gt;ngSwitch&lt;/code&gt;, the UI state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;disappears on refresh&lt;/li&gt;
&lt;li&gt;isn't linkable&lt;/li&gt;
&lt;li&gt;isn't navigable via back/forward buttons&lt;/li&gt;
&lt;li&gt;can't be restored&lt;/li&gt;
&lt;li&gt;can't be shared through a URL&lt;/li&gt;
&lt;li&gt;isn't synchronized across components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's just &lt;strong&gt;ephemeral UI state&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Great for tiny things. Completely breaks down for structured UIs.&lt;/p&gt;
&lt;h3&gt;
  
  
  Routing: A URL as a Source of Truth
&lt;/h3&gt;

&lt;p&gt;Routing gives you something conditionals never can: &lt;strong&gt;a stable, externalized state machine.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your dashboard URL looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/dashboard(main:details//left:filters//right:info)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bookmark it&lt;/li&gt;
&lt;li&gt;reload it&lt;/li&gt;
&lt;li&gt;share it&lt;/li&gt;
&lt;li&gt;open it in a new tab&lt;/li&gt;
&lt;li&gt;use the back button&lt;/li&gt;
&lt;li&gt;restore it after browser restart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try doing that with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;showFilters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can't.&lt;/p&gt;

&lt;p&gt;This matters massively for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;admin dashboards&lt;/li&gt;
&lt;li&gt;analytics tools&lt;/li&gt;
&lt;li&gt;IDE-like applications&lt;/li&gt;
&lt;li&gt;UIs with inspectors, drawers, secondary panels&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anywhere the layout itself matters, routing becomes mandatory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing Makes UI Behavior Deterministic
&lt;/h2&gt;

&lt;p&gt;If the UI is controlled through routes, state transitions look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;click → router.navigate() → new URL → new component loads
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That chain gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clean separation between view containers and components&lt;/li&gt;
&lt;li&gt;testability (you can test routing instead of brittle DOM states)&lt;/li&gt;
&lt;li&gt;predictable teardown + instantiate cycles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With &lt;code&gt;*ngIf&lt;/code&gt;, components stick around until destroyed manually, and transitions become messy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stale subscriptions&lt;/li&gt;
&lt;li&gt;memory leaks&lt;/li&gt;
&lt;li&gt;state leftover from previous view&lt;/li&gt;
&lt;li&gt;components not re-instantiating properly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You've seen these bugs before — they're everywhere in legacy systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing Gives Independent Lifecycles Per Outlet
&lt;/h2&gt;

&lt;p&gt;Multiple outlets each manage their own component lifecycle.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;router-outlet&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"sidebar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;router-outlet&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"details"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;resolves guards&lt;/li&gt;
&lt;li&gt;runs resolvers&lt;/li&gt;
&lt;li&gt;loads modules lazily&lt;/li&gt;
&lt;li&gt;handles deactivation/activation&lt;/li&gt;
&lt;li&gt;destroys previous component cleanly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;*ngIf&lt;/code&gt; can't replicate this without manually re-implementing the router.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing Lets Your UI Behave Like a Real Application
&lt;/h2&gt;

&lt;p&gt;Does the user expect browser navigation to work?&lt;/p&gt;

&lt;p&gt;If the UI has panels that open/close, details that load, tabs, filters, etc. —&lt;/p&gt;

&lt;p&gt;Users expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ctrl+L → paste URL → exact same state&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Back → previous view&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forward → next view&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reload → same data, same layout&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An &lt;code&gt;*ngIf&lt;/code&gt;-driven UI can't honor these expectations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Reason People Avoid Routing
&lt;/h2&gt;

&lt;p&gt;Most engineers don't understand &lt;strong&gt;auxiliary routes&lt;/strong&gt; and &lt;strong&gt;named outlets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The moment they learn them, they stop writing giant "HTML Franken-templates" with 15 nested &lt;code&gt;*ngIf&lt;/code&gt; conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Routing scales. &lt;code&gt;*ngIf&lt;/code&gt; doesn't.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Clean Distinction to Remember
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use routing&lt;/strong&gt; when the user's view should be restorable, shareable, navigable, or modular.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;*ngIf&lt;/code&gt;&lt;/strong&gt; when the UI state is unimportant, temporary, or purely local.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the same reason VSCode, Figma, Jira, GitHub, and all advanced UIs use router-like state machines — not ad-hoc conditionals.&lt;/p&gt;




&lt;p&gt;At this point we've only seen why routing beats conditional rendering for complex UIs. In the next article, I'll go deeper into how to use Angular's outlet contexts and multi-outlet routing to treat the router as a true state-management layer for view composition.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>angularrouting</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Why JavaScript Never Adopted RxJS — It Solved a Problem JavaScript Never Had</title>
      <dc:creator>Ayush Maurya</dc:creator>
      <pubDate>Sat, 08 Nov 2025 10:49:51 +0000</pubDate>
      <link>https://dev.to/ayush_maurya_/why-javascript-never-adopted-rxjs-it-solved-a-problem-javascript-never-had-418o</link>
      <guid>https://dev.to/ayush_maurya_/why-javascript-never-adopted-rxjs-it-solved-a-problem-javascript-never-had-418o</guid>
      <description>&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhcnyzkvv5y17z08tzca.png" alt=" " width="800" height="533"&gt;
&lt;/h2&gt;

&lt;p&gt;A junior developer once asked me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“RxJS has been around for years, and so many developers use it.&lt;br&gt;&lt;br&gt;
Why hasn’t JavaScript just added something like it natively?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To which I answered:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reactivity is mainly a &lt;strong&gt;frontend&lt;/strong&gt; problem. It’s about dealing with one user’s continuously changing state — events, inputs, UI updates. The &lt;strong&gt;backend&lt;/strong&gt;, in contrast, deals in stateless operations. Each request stands alone. The state lives in databases, not in-memory streams. You don’t “observe” backend data changes directly — you react through messages, queues, or databases. &lt;strong&gt;Kafka&lt;/strong&gt; or &lt;strong&gt;Redis Streams&lt;/strong&gt; handle that domain, not RxJS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was my quick answer.&lt;br&gt;&lt;br&gt;
But the question was too interesting to leave there — so I dug deeper.&lt;/p&gt;




&lt;h2&gt;
  
  
  RxJS Has Proven Itself
&lt;/h2&gt;

&lt;p&gt;RxJS has powered Angular’s reactivity model for over a decade.&lt;br&gt;&lt;br&gt;
It’s elegant in handling asynchronous data, widely respected, and deeply integrated in the frontend ecosystem.  &lt;/p&gt;

&lt;p&gt;Yet despite its longevity and popularity, &lt;strong&gt;Observables never became part of JavaScript itself&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The reason is simpler — and deeper — than most realize:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;RxJS solved a problem JavaScript itself never really had.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What RxJS Actually Solves
&lt;/h2&gt;

&lt;p&gt;RxJS is built on the concept of &lt;strong&gt;Observables&lt;/strong&gt; — objects that represent streams of asynchronous data that can emit multiple values over time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Promise&lt;/strong&gt; resolves once.
&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Observable&lt;/strong&gt; keeps emitting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes it perfect for situations like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listening to continuous user input
&lt;/li&gt;
&lt;li&gt;Handling WebSocket data
&lt;/li&gt;
&lt;li&gt;Managing UI state that updates over time
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s powerful and expressive — you can &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;debounce&lt;/code&gt;, &lt;code&gt;combine&lt;/code&gt;, and &lt;code&gt;merge&lt;/code&gt; asynchronous streams just like you manipulate arrays.&lt;/p&gt;

&lt;p&gt;So, if it’s that powerful... &lt;strong&gt;why didn’t JavaScript itself embrace it?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  JavaScript’s Evolution Is Conservative by Design
&lt;/h2&gt;

&lt;p&gt;JavaScript’s core design philosophy is &lt;strong&gt;universality&lt;/strong&gt; and &lt;strong&gt;minimalism&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;a href="http://tc39.es/" rel="noopener noreferrer"&gt;TC39 committee&lt;/a&gt;&lt;/strong&gt; — the group that decides what gets added to the language — only standardizes features that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Apply across &lt;strong&gt;all JavaScript environments&lt;/strong&gt; (browser, server, embedded)&lt;/li&gt;
&lt;li&gt;Don’t introduce unnecessary &lt;strong&gt;conceptual weight or complexity&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;RxJS breaks both of those principles.&lt;/p&gt;

&lt;p&gt;Reactivity is mainly a &lt;strong&gt;frontend&lt;/strong&gt; concern — about one user’s continuously changing state.&lt;br&gt;&lt;br&gt;
The backend’s problems are different: stateless operations, distributed events, and persistence handled by external systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Observable Proposal That Never Landed
&lt;/h2&gt;

&lt;p&gt;This wasn’t just theoretical — &lt;strong&gt;JavaScript almost adopted Observables&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In 2017, a &lt;strong&gt;TC39 proposal&lt;/strong&gt; sought to introduce a minimal &lt;code&gt;Observable&lt;/code&gt; type. It reached &lt;strong&gt;Stage 1&lt;/strong&gt;, attracted attention… then quietly stalled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why It Failed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;RxJS already provided a complete, mature ecosystem.
&lt;/li&gt;
&lt;li&gt;Observables are inherently complex — &lt;strong&gt;cold vs. hot&lt;/strong&gt;, &lt;strong&gt;cancellation&lt;/strong&gt;, &lt;strong&gt;multicasting&lt;/strong&gt;, &lt;strong&gt;operator design&lt;/strong&gt;, &lt;strong&gt;interop with Promises&lt;/strong&gt;, etc.
&lt;/li&gt;
&lt;li&gt;Frameworks had already diverged:

&lt;ul&gt;
&lt;li&gt;Angular leaned on RxJS
&lt;/li&gt;
&lt;li&gt;React favored hooks and state
&lt;/li&gt;
&lt;li&gt;Vue built its own reactivity model
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The committee couldn’t justify making one paradigm &lt;em&gt;official&lt;/em&gt; when the community was already solving the same problem in multiple, incompatible ways.&lt;/p&gt;

&lt;p&gt;So JavaScript took the conservative route:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;standardize the smallest useful abstraction — Promises — and let the ecosystem handle the rest.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Promises Were the Problem JavaScript Did Have
&lt;/h2&gt;

&lt;p&gt;Promises fixed a &lt;strong&gt;universal&lt;/strong&gt; issue: callback hell.&lt;/p&gt;

&lt;p&gt;Before Promises, async code was deeply nested, hard to reason about, and full of error-handling traps. Every JS developer — frontend or backend — needed a cleaner model for single-result async work. Then &lt;code&gt;async/await&lt;/code&gt; came, making async code look synchronous — elegant and readable. That was the problem JavaScript actually &lt;strong&gt;needed&lt;/strong&gt; to solve: a &lt;strong&gt;single-value, eventual result.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Observables, on the other hand, were about ongoing reactivity — a smaller, domain-specific need mostly confined to the frontend world.&lt;/p&gt;

&lt;p&gt;So Promises became part of the language; Observables remained a &lt;strong&gt;library concern&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Signals: The Simpler Next Step in Reactivity
&lt;/h2&gt;

&lt;p&gt;But reactivity didn’t disappear — it &lt;strong&gt;evolved&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signals&lt;/strong&gt; are the next iteration: smaller, simpler, and more predictable.&lt;/p&gt;

&lt;p&gt;Signals aren’t streams of events like Observables. They’re &lt;strong&gt;reactive state containers&lt;/strong&gt; that automatically track dependencies and update when values change. You don’t subscribe to them; you just declare relationships.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const count = signal(0);
const doubled = computed(() =&amp;gt; count() * 2);

count.set(5);
console.log(doubled()); // 10 — automatically updated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;No subscription. No operators. No teardown.&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Just reactive state, tracked automatically.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Signals shift reactivity from streams of events to graphs of state — simpler, more deterministic, and easier to optimize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks for Reading ❤️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If this article helped you, share it and give it like.&lt;br&gt;
It’ll hardly take a minute, but it really motivates me to write more deep-dive articles like this.&lt;/p&gt;

&lt;p&gt;I don’t just write “how-tos” — I write about why things are designed the way they are,so you can master them inside-out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TC39 Proposal — &lt;a href="https://github.com/tc39/proposal-observable" rel="noopener noreferrer"&gt;Observable&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TC39 Proposal — &lt;a href="https://github.com/tc39/proposal-signals" rel="noopener noreferrer"&gt;Signals&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rxjs.dev/" rel="noopener noreferrer"&gt;RxJS (Reactive Extensions for JavaScript)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>rxjs</category>
      <category>angular</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Understanding Go's Context Package</title>
      <dc:creator>Ayush Maurya</dc:creator>
      <pubDate>Thu, 02 Oct 2025 21:45:24 +0000</pubDate>
      <link>https://dev.to/ayush_maurya_/understanding-gos-context-package-594j</link>
      <guid>https://dev.to/ayush_maurya_/understanding-gos-context-package-594j</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgimci03vnyruy7e6db22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgimci03vnyruy7e6db22.png" alt=" " width="800" height="457"&gt;&lt;/a&gt;&lt;br&gt;
I still see many developers struggling with Go’s &lt;code&gt;context&lt;/code&gt; package. It can be confusing not just for newcomers, but even for those who’ve been writing Go for a while.&lt;/p&gt;

&lt;p&gt;I mostly work in frontend, and during my time with Node.js, I never encountered anything quite like Go’s &lt;code&gt;context&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This guide will help you understand it better. By the end, you’ll know exactly what you’re doing — and why — whenever you use it.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Do We Need Context?
&lt;/h2&gt;

&lt;p&gt;Instead of starting with &lt;em&gt;what&lt;/em&gt; &lt;code&gt;context&lt;/code&gt; is, let’s look at the &lt;em&gt;problem it solves&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Imagine you need batteries for your remote control car, so you ask a friend to go buy them. But just as they leave, you find batteries in your drawer. Now you want your friend to stop and come back.&lt;/p&gt;

&lt;p&gt;For this to work, your friend must be aware of the situation in your room.&lt;/p&gt;

&lt;p&gt;In Go terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your “room” is like the &lt;strong&gt;background context&lt;/strong&gt; — the environment your operations run in.&lt;/li&gt;
&lt;li&gt;Your friend’s awareness of whether to continue or stop the trip is like a &lt;strong&gt;cancelable context&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another example: imagine a function that compresses an image. You don’t want to wait 20 seconds for it to finish. If it completes in 10 seconds, great; if not, you want the ability to cancel the operation.&lt;/p&gt;

&lt;p&gt;This is exactly what Go’s &lt;code&gt;context&lt;/code&gt; allows you to do: propagate deadlines, cancellations, and request-scoped values across your functions.&lt;/p&gt;


&lt;h2&gt;
  
  
  A Simple Example: Lucky Numbers
&lt;/h2&gt;

&lt;p&gt;Let’s start simple. Here’s a function that just returns a lucky number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;requestLuckyNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request failed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;requestLuckyNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;luckyNumber&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;666&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;luckyNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing fancy here — it always returns &lt;code&gt;666&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let’s turn this into a little game: we want the function to return the lucky number &lt;strong&gt;only if it completes within 500ms&lt;/strong&gt;. If it takes longer, we cancel it and return an error.&lt;/p&gt;

&lt;p&gt;This is where &lt;code&gt;context&lt;/code&gt; comes in.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a Context with Timeout
&lt;/h2&gt;

&lt;p&gt;We can create a timeout context like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;context.Background()&lt;/code&gt; is the root context. Think of it as your “room.”&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WithTimeout&lt;/code&gt; creates a child context that automatically cancels after 500ms.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cancel&lt;/code&gt; is a function to manually cancel the context (cleanup resources, stop goroutines, etc.).&lt;/li&gt;
&lt;li&gt;Always &lt;code&gt;defer cancel()&lt;/code&gt; to avoid leaks.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Using Context in Your Function
&lt;/h2&gt;

&lt;p&gt;Now let’s modify our function to respect this context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Simulate some work&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="m"&gt;666&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// context canceled or timed out&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What’s happening here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We run the “work” in a goroutine.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;select&lt;/code&gt; statement listens for two cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;-ctx.Done()&lt;/code&gt; → fires if the context is canceled or times out.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;result := &amp;lt;-ch&lt;/code&gt; → fires when the work completes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If the work finishes on time, we get our lucky number. Otherwise, the function exits early with an error.&lt;/p&gt;




&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request failed:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Lucky number is:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your function respects the 600ms limit. If the task takes too long, it gracefully cancels.&lt;/p&gt;




&lt;h2&gt;
  
  
  Other Useful Context Functions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;context.WithCancel&lt;/code&gt;&lt;/strong&gt; → Manually cancel a context from another goroutine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;context.WithDeadline&lt;/code&gt;&lt;/strong&gt; → Cancel automatically at a specific time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;context.WithValue&lt;/code&gt;&lt;/strong&gt; → Pass request-scoped values down the call chain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"userID"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"userID"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// 42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ Tip: Only use &lt;code&gt;WithValue&lt;/code&gt; for request-scoped data, not for optional parameters.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;context&lt;/code&gt; helps control long-running operations with cancellation and timeouts.&lt;/li&gt;
&lt;li&gt;Always pass &lt;code&gt;context&lt;/code&gt; explicitly to functions that may need it.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;WithTimeout&lt;/code&gt;, &lt;code&gt;WithCancel&lt;/code&gt;, and &lt;code&gt;WithDeadline&lt;/code&gt; for control.&lt;/li&gt;
&lt;li&gt;Avoid using &lt;code&gt;WithValue&lt;/code&gt; for configuration — it’s meant only for request-scoped data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By understanding &lt;code&gt;context&lt;/code&gt;, you can write Go programs that are safer, cleaner, and more responsive — avoiding goroutine leaks and stuck operations.&lt;/p&gt;




&lt;p&gt;💡 If you found this useful, leave a comment or share it. Feedback keeps me motivated to write more content like this!&lt;/p&gt;

</description>
      <category>go</category>
      <category>backend</category>
      <category>requestforpost</category>
    </item>
    <item>
      <title>I’m a Frontend Dev. Stop Forcing Me to Be a Full-Stack.</title>
      <dc:creator>Ayush Maurya</dc:creator>
      <pubDate>Thu, 02 Oct 2025 21:08:25 +0000</pubDate>
      <link>https://dev.to/ayush_maurya_/im-a-frontend-dev-stop-forcing-me-to-be-a-full-stack-3fi0</link>
      <guid>https://dev.to/ayush_maurya_/im-a-frontend-dev-stop-forcing-me-to-be-a-full-stack-3fi0</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is very different from my usual technical content — it’s raw and frustrated, based on my personal job-hunting experience. If you’re a frontend dev, you might relate.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For the last 2–3 months, I’ve been trying to switch jobs. And after dozens of interviews, I’m done pretending everything is okay.&lt;/p&gt;

&lt;p&gt;So here’s my honest, frustrated take on what’s wrong with tech interviews — especially for frontend developers in India.&lt;/p&gt;

&lt;p&gt;I’ve been in the industry for over 4 years. I’ve done the whole frontend–backend dance. Built apps, fixed bugs, fought with legacy code, dealt with design handovers that made no sense, and shipped things under pressure that somehow still worked.&lt;/p&gt;

&lt;p&gt;But I love frontend. That’s what I breathe. I like building clean UI, smooth animations, and fast and responsive designs. I know how to make a button feel right.&lt;/p&gt;

&lt;p&gt;But the interviewers?&lt;br&gt;
They don’t care.&lt;/p&gt;

&lt;h2&gt;
  
  
  “You applied for Angular dev, but let me grill you on Kafka…”
&lt;/h2&gt;

&lt;p&gt;Every other job post screams:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We’re hiring a frontend Angular developer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And yet, the interviews are like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;“How would you optimize a MongoDB query?”&lt;/li&gt;
&lt;li&gt;“Explain an event-driven system using Kafka.”&lt;/li&gt;
&lt;li&gt;“Explain how you’d build microservices.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Excuse me? Did I miss the part where this turned into a backend SDE-2 round?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No one’s asking:&lt;/p&gt;

&lt;p&gt;How would you optimize FCP or LCP?&lt;br&gt;
How do you handle memory leaks in Angular?&lt;br&gt;
Can you build a Canvas animation from scratch?&lt;br&gt;
But hey, sure, let’s test me on database indexing strategies. Because apparently, writing frontend isn’t “real development” unless you’re also knee-deep in SQL joins.&lt;/p&gt;

&lt;h2&gt;
  
  
  “Bro, you should know full stack.”
&lt;/h2&gt;

&lt;p&gt;No.&lt;br&gt;
I applied for frontend, and that’s what I want to do.&lt;/p&gt;

&lt;p&gt;Not because I can’t write backend — I can. But because I don’t want to. I like the challenge of making things feel fast, look clean, and work across a million devices. I love sweating over that last frame drop on an animation. I enjoy figuring out why a layout breaks on an iPad Mini Gen 5.&lt;/p&gt;

&lt;p&gt;But companies here?&lt;br&gt;
They don’t want frontend devs.&lt;br&gt;
They want backend devs who also happen to know HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  “Backend is harder, bro.”
&lt;/h2&gt;

&lt;p&gt;Yeah? Then why does your blazing fast API still result in a UI that takes 4 seconds to update?&lt;/p&gt;

&lt;p&gt;Have you ever debugged a performance issue caused by a bloated table component with 100 columns and an infinite scroll that crashes on Safari Mobile?&lt;br&gt;
Have you ever spent hours shaving milliseconds off paint timings just so your app feels usable on a budget Android phone?&lt;/p&gt;

&lt;p&gt;Backend is hard, sure.&lt;br&gt;
But don’t pretend frontend is just “putting buttons on a page.”&lt;br&gt;
Frontend is performance, responsiveness, accessibility, UX, and design — all tangled together with business logic, browser quirks, and user expectations.&lt;/p&gt;

&lt;p&gt;“If you can’t do it, I’ll throw it in a cursor.”&lt;br&gt;
I was debugging a UI animation bug. It was messy and took time. A senior dev (backend, obviously) said:&lt;/p&gt;

&lt;p&gt;“If you can’t fix it, give it to me — I’ll just throw it in a cursor.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Honestly?&lt;/strong&gt;&lt;br&gt;
Unless it’s some heavy backend logic, sure — I can tell the cursor to do some x-y calculation, maybe write an update query, and get it over with. That’s easy.&lt;/p&gt;

&lt;p&gt;But how the hell do you tell a cursor about the animation playing in your head?&lt;/p&gt;

&lt;p&gt;How do you explain easing curves, scroll acceleration, responsiveness across devices, or the GPU render pipeline… to a cursor?&lt;/p&gt;

&lt;p&gt;This is exactly the problem — treating frontend like it’s something you can brute force with database logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thought: Let Me Do What I’m Good At&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I’m not asking for much.&lt;/p&gt;

&lt;p&gt;If the JD says “Frontend Developer,” stop trying to test me like I’m applying for a backend-heavy full-stack role.&lt;br&gt;
I’ll happily say “I don’t know” when you throw backend problems at me — not because I’m dumb, but because I’m not applying to solve those problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let frontend devs be frontend devs.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stop wasting our time.&lt;/li&gt;
&lt;li&gt;Stop disrespecting the craft.&lt;/li&gt;
&lt;li&gt;And maybe, just maybe, let us do the work we actually love.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ayush Maurya&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Frontend Engineer. Angular, React, WebGL, and way too much patience for interviews that don’t know what they’re hiring for.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>interview</category>
      <category>programming</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How Browsers Parse and Render HTML: From Request to Paint</title>
      <dc:creator>Ayush Maurya</dc:creator>
      <pubDate>Sun, 06 Jul 2025 18:14:04 +0000</pubDate>
      <link>https://dev.to/ayush_maurya_/how-browsers-parse-and-render-html-from-request-to-paint-1ogp</link>
      <guid>https://dev.to/ayush_maurya_/how-browsers-parse-and-render-html-from-request-to-paint-1ogp</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxepsq91r24fhaz7g6sxy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxepsq91r24fhaz7g6sxy.jpg" alt="Image description" width="500" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This all started today when I was trying something like this:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const containerHeight = innerDivHeight.scrollHeight + 'px';
container.style.height = containerHeight;

const container2Height = innerDiv2Height.scrollHeight + 'px';
container2.style.height = containerHeight;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, not the best way to go about it.&lt;/p&gt;

&lt;p&gt;Just out of curiosity, I started digging into how the browser handles such changes and &lt;strong&gt;realized that even small DOM mutations can trigger a reflow or repaint.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, instead of doing it this way, you should ideally write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const containerHeight = innerDivHeight.scrollHeight + 'px';
const container2Height = innerDiv2Height.scrollHeight + 'px';

container.style.height = containerHeight;
container2.style.height = container2Height;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How HTML Works in the Browser
&lt;/h2&gt;

&lt;p&gt;It all begins when the browser requests the server for the HTML file. The moment it starts receiving the first byte, the browser doesn’t wait — it begins parsing immediately using a streaming parser.&lt;/p&gt;

&lt;p&gt;Let’s break this process down.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2f6mwwz96zen3eetbd6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2f6mwwz96zen3eetbd6p.png" alt="Image description" width="551" height="872"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Tokenization and DOM Construction
&lt;/h2&gt;

&lt;p&gt;The browser starts by converting the raw HTML into tokens (e.g. div, h1, p, etc.). Each tag, along with its attributes and values, is turned into a token.&lt;/p&gt;

&lt;p&gt;Once tokenized, the browser constructs the DOM (Document Object Model) — a tree-like structure representing the hierarchical relationships between elements.&lt;/p&gt;

&lt;p&gt;That’s why when you use JavaScript to select multiple elements, you get a NodeList. That NodeList is a slice of the DOM that the browser built during this stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. CSSOM &amp;amp; JavaScript Blocking
&lt;/h2&gt;

&lt;p&gt;Now that the DOM is ready, the browser still hasn’t rendered anything visually yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSSOM&lt;/strong&gt;&lt;br&gt;
The browser parses the CSS in a similar way — raw bytes → tokens → CSSOM (CSS Object Model). The CSSOM is a structured representation of all styling rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important point:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;CSS blocks HTML parsing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When the parser encounters a &lt;code&gt;link&lt;/code&gt; or &lt;code&gt;style&lt;/code&gt;, it pauses HTML parsing until the CSS is loaded and parsed.&lt;/p&gt;

&lt;p&gt;This happens because &lt;strong&gt;layout depends on style&lt;/strong&gt;, and the browser can’t render elements accurately without knowing how they should look.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;&lt;br&gt;
Same thing for JavaScript.&lt;/p&gt;

&lt;p&gt;When the browser hits a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag (especially one without async or defer, it pauses everything, downloads the script, executes it, and then resumes HTML parsing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; Because JavaScript can manipulate the DOM. So, the browser has to wait to avoid building a tree that JS might change anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: CSS is prioritized over JavaScript when both are blocking resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Render Tree Construction
&lt;/h2&gt;

&lt;p&gt;At this point, the DOM and CSSOM exist independently — they don’t yet know about each other.&lt;/p&gt;

&lt;p&gt;The browser engine combines them to build the Render Tree.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Render Tree = DOM (structure) + CSSOM (style)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It figures out what needs to be rendered and how — calculating layout, dimensions, positioning, margins, paddings, etc., using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Box model&lt;/li&gt;
&lt;li&gt;Flex/grid rules&lt;/li&gt;
&lt;li&gt;Relationships in the DOM&lt;/li&gt;
&lt;li&gt;This is the stage where the actual layout is determined.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Painting and Compositing
&lt;/h2&gt;

&lt;p&gt;Now comes the painting phase — the browser draws actual pixels on your screen.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text, colors, borders, shadows — everything is drawn layer by layer.&lt;/li&gt;
&lt;li&gt;Each layer is rasterized into a bitmap.&lt;/li&gt;
&lt;li&gt;These bitmaps are uploaded to the GPU as textures.&lt;/li&gt;
&lt;li&gt;The GPU composites all textures into a single frame to display.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This phase is super sensitive — &lt;strong&gt;every style change or unoptimized animation can trigger repaints or reflows&lt;/strong&gt;, which can hit performance.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The painting happens recursively — children are painted first, and then the parents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;All of this — DOM parsing, CSSOM creation, JS blocking, layout calculation, GPU compositing — happens just to render a simple HTML page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mind-blowing, right?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a deeper dive, check out this video on YouTube:&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=SmE4OwHztCc" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=SmE4OwHztCc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you liked this article, feel free to like and follow for more frontend deep dives.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>html</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Why Do We Need to Manage the State of an Application?</title>
      <dc:creator>Ayush Maurya</dc:creator>
      <pubDate>Sat, 05 Jul 2025 21:15:27 +0000</pubDate>
      <link>https://dev.to/ayush_maurya_/why-do-we-need-to-manage-the-state-of-an-application-220k</link>
      <guid>https://dev.to/ayush_maurya_/why-do-we-need-to-manage-the-state-of-an-application-220k</guid>
      <description>&lt;p&gt;A week ago, an interviewer asked me: &lt;em&gt;Why do we need to manage state in a frontend application? Why can’t HTTP handle it for us?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There can be multiple answers to this, but the simplest one is:&lt;br&gt;
&lt;strong&gt;HTTP is a stateless protocol.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does Stateless Mean?
&lt;/h2&gt;

&lt;p&gt;Each HTTP request is independent. The server doesn’t know anything about previous requests.&lt;br&gt;
It doesn’t know who is making the request — whether you’re the same user who made the previous one or not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why So? Can’t We Make HTTP Stateful?&lt;/strong&gt;&lt;br&gt;
Technically, we could. But HTTP was intentionally designed to be stateless.&lt;br&gt;
It was made this way to ensure simplicity and scalability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Exactly?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. Scalability&lt;/strong&gt;&lt;br&gt;
The server doesn’t store session information between requests.&lt;br&gt;
This makes it easy to load-balance requests across a pool of servers.&lt;/p&gt;

&lt;p&gt;When your application grows, you no longer rely on just one server.&lt;br&gt;
If HTTP were stateful, a request would always need to go back to the same server holding that user’s session/token, which limits scalability.&lt;/p&gt;

&lt;p&gt;But because it’s stateless, any server can handle any request.&lt;br&gt;
&lt;strong&gt;2. Simplicity&lt;/strong&gt;&lt;br&gt;
In a stateless protocol, each request is self-contained — it carries everything the server needs to understand and respond.&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;p&gt;No need to track sessions or store user-specific context.&lt;br&gt;
Every request must include all relevant data.&lt;br&gt;
Example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /user-profile  &lt;br&gt;
Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt;&lt;br&gt;
The server does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validates token&lt;/li&gt;
&lt;li&gt;Fetches user info&lt;/li&gt;
&lt;li&gt;Responds&lt;/li&gt;
&lt;li&gt;No memory of this is retained after the response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Stateful systems usually need to keep track of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User sessions&lt;/li&gt;
&lt;li&gt;In-progress workflows&lt;/li&gt;
&lt;li&gt;Auth states&lt;/li&gt;
&lt;li&gt;Temp files or cached data&lt;/li&gt;
&lt;li&gt;This consumes memory and resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But in stateless systems (like HTTP):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server forgets everything after responding.&lt;/li&gt;
&lt;li&gt;There’s no per-user memory cost, which is critical at web scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Imagine if a million users log in, and the server has to manage tokens or sessions for each. That’s a massive RAM overhead.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, Where Does Frontend State Management Come In?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the frontend, your application deals with dynamic data that changes over time and needs to persist across user interactions.&lt;/p&gt;

&lt;p&gt;Without state management, your UI would become chaotic — you’d lose track of what to render and when.&lt;/p&gt;

&lt;p&gt;Using a centralized or controlled state (like Signals, RxJS, NgRx, etc.) makes your app easier to debug and maintain.&lt;br&gt;
You know that when state X changes, component Y re-renders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-World Example:&lt;/strong&gt;&lt;br&gt;
Let’s say a user adds items to a shopping cart.&lt;/p&gt;

&lt;p&gt;If you don’t store the cart count on the frontend, what do you do?&lt;br&gt;
Ask the server every single time to get the updated count, even for just rendering the number on the cart icon?&lt;/p&gt;

&lt;p&gt;Instead, you get the cart data once (on load) and store it on the frontend.&lt;br&gt;
Efficient, fast, and with no unnecessary network calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But Are There Stateful Protocols?&lt;/strong&gt;&lt;br&gt;
Yes, some protocols are stateful, and for good reason.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSockets&lt;/li&gt;
&lt;li&gt;SMTP (partially stateful)&lt;/li&gt;
&lt;li&gt;FTP, and others.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;WebSockets — One You See Often:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starts as HTTP (stateless), then upgrades to a persistent, full-duplex connection.&lt;/li&gt;
&lt;li&gt;The server remembers the connection and can push data to the client at any time.&lt;/li&gt;
&lt;li&gt;Used in chat apps, games, stock tickers, and anything requiring real-time communication.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  TL;DR:
&lt;/h2&gt;

&lt;p&gt;HTTP is stateless by design — it helps with scalability, simplicity, and performance.&lt;br&gt;
Because of that, managing state on the frontend becomes crucial to maintain a smooth, dynamic, and efficient user experience.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you found this post helpful or learned something new, feel free to follow for more content like this. I regularly share insights from real-world dev experiences, especially around frontend architecture, performance, and those tricky interview moments we all face.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>redux</category>
      <category>http</category>
      <category>state</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Angular’s ngDoCheck: The Powerful but Dangerous Lifecycle Hook</title>
      <dc:creator>Ayush Maurya</dc:creator>
      <pubDate>Thu, 26 Jun 2025 19:35:10 +0000</pubDate>
      <link>https://dev.to/ayush_maurya_/angulars-ngdocheck-the-powerful-but-dangerous-lifecycle-hook-329b</link>
      <guid>https://dev.to/ayush_maurya_/angulars-ngdocheck-the-powerful-but-dangerous-lifecycle-hook-329b</guid>
      <description>&lt;p&gt;&lt;strong&gt;ngDoCheck is underrated — but dangerous if misused.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This lifecycle hook runs every time Angular performs change detection, regardless of whether the @Input() properties have changed or not.&lt;/p&gt;

&lt;p&gt;Since it gets called frequently, putting heavy logic inside ngDoCheck can make your app laggy or unresponsive. But in some scenarios, it's incredibly useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use ngDoCheck
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Detecting deep changes in Objects or Arrays&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Angular performs a &lt;em&gt;shallow comparison&lt;/em&gt; on @Input() properties. So, if an object or array is mutated, ngOnChanges() won’t fire.&lt;/p&gt;

&lt;p&gt;What do most devs do here? They often work around it by cloning the array or object and reassigning it — or worse, serializing it with JSON.stringify() and parsing it back. Gross.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Instead, use ngDoCheck to manually detect changes in such cases.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Tracking internal state changes&lt;/strong&gt;&lt;br&gt;
ngDoCheck also triggers when any internal value of the component changes — not just @Input() bindings. This makes it useful for watching component-local state too.&lt;/p&gt;
&lt;h2&gt;
  
  
  When You Should Use ngDoCheck
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Angular’s default change detection misses what you actually care about.&lt;/li&gt;
&lt;li&gt;You’re dealing with mutable data, and ngOnChanges() isn’t firing.&lt;/li&gt;
&lt;li&gt;You need fine-grained control over reactivity.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Real-World Example
&lt;/h2&gt;

&lt;p&gt;Say you have a chat UI. The parent component pushes messages into an existing array, but doesn’t create a new array. Angular won’t detect this change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'app-chat',
  template: `&amp;lt;ul&amp;gt;&amp;lt;li *ngFor="let msg of messages"&amp;gt;{{ msg }}&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;`,
})
export class ChatComponent implements DoCheck {
  @Input() messages: string[] = [];
  private prevLength = 0;
  ngDoCheck() {
    if (this.messages.length !== this.prevLength) {
      console.log('New messages received');
      this.prevLength = this.messages.length;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets you detect new messages even if the array reference didn’t change.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ngDoCheck() + IterableDiffers / KeyValueDiffers&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Angular also gives you tools for detecting changes in arrays or objects.&lt;/p&gt;

&lt;p&gt;Example using IterableDiffers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constructor(private differs: IterableDiffers) {}
private differ = this.differs.find([]).create();

ngDoCheck() {
  const changes = this.differ.diff(this.myArray);
  if (changes) {
    console.log('Array changed!');
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;This is cleaner and avoids manual comparison logic.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Avoid ngDoCheck
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;You’re using immutable data (e.g., @Input() user is reassigned, not mutated) — just use ngOnChanges()&lt;/li&gt;
&lt;li&gt;You only need to track a simple @Input() value&lt;/li&gt;
&lt;li&gt;You’re worried about performance, and this isn’t absolutely necessary&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;As Angular’s documentation clearly states:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Typically, you should not use both ngDoCheck and ngOnChanges to respond to changes on the same input.”&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use ngDoCheck only when:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You’re working with mutable data&lt;/li&gt;
&lt;li&gt;Angular’s change detection isn’t enough&lt;/li&gt;
&lt;li&gt;You know what you’re doing and you really need it&lt;/li&gt;
&lt;li&gt;Otherwise, stick with ngOnChanges().&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>ngdocheck</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
