<?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: Jedidiah Weller 👑</title>
    <description>The latest articles on DEV Community by Jedidiah Weller 👑 (@jedihacks).</description>
    <link>https://dev.to/jedihacks</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F82519%2F23933713-393d-4dc4-a7f1-9a870f92e95c.jpg</url>
      <title>DEV Community: Jedidiah Weller 👑</title>
      <link>https://dev.to/jedihacks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jedihacks"/>
    <language>en</language>
    <item>
      <title>Running Frontier AI Locally Still Doesn't Add Up</title>
      <dc:creator>Jedidiah Weller 👑</dc:creator>
      <pubDate>Mon, 02 Nov 2026 16:20:46 +0000</pubDate>
      <link>https://dev.to/jedihacks/running-frontier-ai-locally-still-doesnt-add-up-2gmk</link>
      <guid>https://dev.to/jedihacks/running-frontier-ai-locally-still-doesnt-add-up-2gmk</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyh95jvnpsj8s03n2e37c.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyh95jvnpsj8s03n2e37c.png" alt=" " width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted the answer to be “buy the hardware.”&lt;/p&gt;

&lt;p&gt;Download an open-weight model. Run it on a machine you own. Stop watching a token meter. There is something deeply appealing about that, especially when AI becomes part of your daily development workflow.&lt;/p&gt;

&lt;p&gt;But after digging into what it takes to run a large flagship model locally, I keep coming back to the same conclusion: &lt;strong&gt;for a developer or small team trying to replace demanding cloud AI workflows, buying local hardware usually doesn't make financial sense yet.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Useful local models absolutely exist. The expensive part is trying to preserve the capability, context, speed, and concurrency you actually rely on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.mindstudio.ai/blog/local-ai-vs-cloud-ai-cost-math" rel="noopener noreferrer"&gt;MindStudio's cost comparison&lt;/a&gt; helped frame the question. I wanted to push it further: beyond a desktop-versus-subscription comparison, what happens when you try to replace a team's API usage with a serious self-hosted endpoint?&lt;/p&gt;

&lt;p&gt;Here is the math, with the assumptions visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The memory gap is bigger than the GPU shopping list suggests
&lt;/h2&gt;

&lt;p&gt;GLM-5.2 is a useful case study. &lt;a href="https://unsloth.ai/docs/models/glm-5.2" rel="noopener noreferrer"&gt;Unsloth's deployment guide&lt;/a&gt; describes a mixture-of-experts model with 744 billion total parameters and about 40 billion active per token. &lt;a href="https://huggingface.co/zai-org/GLM-5.2" rel="noopener noreferrer"&gt;Z.ai's model card&lt;/a&gt; advertises a one-million-token context window. It is an example of a large flagship open model, rather than a claim that it is today's best model for every task.&lt;/p&gt;

&lt;p&gt;That “40B active” number is easy to misread. It reduces the computation needed for each token; it doesn't turn the entire model into a 40B-parameter download. The other experts' weights still need to live somewhere. Offloading them to system RAM changes the memory and bandwidth tradeoff.&lt;/p&gt;

&lt;p&gt;A rough lower-bound calculation is straightforward:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Weight storage = parameter count × bits per parameter ÷ 8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For 744 billion parameters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Representation&lt;/th&gt;
&lt;th&gt;Ideal weight storage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;16-bit&lt;/td&gt;
&lt;td&gt;1,488 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8-bit&lt;/td&gt;
&lt;td&gt;744 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4-bit&lt;/td&gt;
&lt;td&gt;372 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are decimal GB and deliberately simplified figures. Real quantized formats include scales, metadata, and sometimes layers kept at higher precision. Runtime memory also needs room for working buffers and attention state.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqww19xb792vlcy8s6add.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqww19xb792vlcy8s6add.png" alt="GLM-5.2 ideal weight storage: 372 GB at 4-bit, 744 GB at 8-bit, and 1,488 GB at 16-bit, compared with 32 GB of RTX 5090 VRAM." width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For perspective, &lt;a href="https://www.nvidia.com/en-us/geforce/graphics-cards/50-series/rtx-5090/" rel="noopener noreferrer"&gt;NVIDIA specifies 32 GB of VRAM for the RTX 5090&lt;/a&gt;. The idealized 4-bit weights alone are &lt;strong&gt;11.6 times that capacity&lt;/strong&gt;. Buying one excellent consumer GPU doesn't bridge this particular gap.&lt;/p&gt;

&lt;p&gt;Unsloth lists roughly &lt;strong&gt;372–475 GB&lt;/strong&gt; for its 4-bit configurations and recommends spare memory beyond the model file size. That's the scale of the problem before a team starts sending requests.&lt;/p&gt;

&lt;p&gt;High-memory desktops offer another route. &lt;a href="https://www.apple.com/mac-studio/specs/" rel="noopener noreferrer"&gt;Apple lists Mac Studio configurations with up to 512 GB of unified memory&lt;/a&gt;. That is a meaningful option for large local models, but memory capacity alone doesn't establish useful throughput, maximum usable context, or simultaneous-user capacity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting it to load is only the first milestone
&lt;/h2&gt;

&lt;p&gt;A model answering one prompt is a different accomplishment from a model serving your team throughout the day.&lt;/p&gt;

&lt;p&gt;The serving system needs capacity for prompt processing, generated tokens, and the attention cache used while requests are in flight. Long contexts and concurrent requests compete for that capacity. &lt;a href="https://docs.vllm.ai/en/latest/configuration/optimization/" rel="noopener noreferrer"&gt;vLLM's tuning guide&lt;/a&gt; documents the tradeoffs among cache space, concurrency, preemption, and throughput.&lt;/p&gt;

&lt;p&gt;There's no honest universal rule that says “four GPUs equals production ready.” Architecture, quantization, serving software, prompt lengths, batching, and latency targets all matter.&lt;/p&gt;

&lt;p&gt;I would also be careful with “4-bit is lossless.” A quantization evaluation can show close agreement under its test conditions. That doesn't guarantee identical behavior on a difficult refactor or a long tool-using task. The configuration you intend to deploy needs to pass your own workload evaluation.&lt;/p&gt;

&lt;p&gt;The comparison I care about is &lt;strong&gt;cost per successfully completed task at an acceptable latency&lt;/strong&gt;. A cheaper token can become an expensive task if it needs more retries or more human repair.&lt;/p&gt;

&lt;h2&gt;
  
  
  Renting the GPUs doesn't automatically solve the economics
&lt;/h2&gt;

&lt;p&gt;First, separate three different purchases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A managed model API:&lt;/strong&gt; you pay for metered usage, subject to the provider's pricing and limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rented GPUs:&lt;/strong&gt; you operate the model on infrastructure billed for allocated time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Owned hardware:&lt;/strong&gt; you pay upfront and take responsibility for operating it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An open-weight model can be served through any of these arrangements. Downloadable weights don't require you to become the hosting provider.&lt;/p&gt;

&lt;p&gt;Consider an &lt;strong&gt;illustrative API budget of $1,000 per week&lt;/strong&gt;, or &lt;strong&gt;$52,000 per year&lt;/strong&gt; using 52 weeks. This is a scenario for the calculation, not a price quote for a particular token volume or model.&lt;/p&gt;

&lt;p&gt;On November 2, 2026, &lt;a href="https://lambda.ai/pricing" rel="noopener noreferrer"&gt;Lambda's eight-GPU instance pricing&lt;/a&gt; lists H100 SXM at &lt;strong&gt;$3.99 per GPU-hour&lt;/strong&gt; and B200 at &lt;strong&gt;$6.69 per GPU-hour&lt;/strong&gt;, before applicable taxes.&lt;/p&gt;

&lt;p&gt;For continuous allocation:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;8 × $3.99 × 8,760 hours = $279,619/year for H100
8 × $6.69 × 8,760 hours = $468,835/year for B200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Those are approximately &lt;strong&gt;5.4× and 9.0×&lt;/strong&gt; the illustrative API budget, before your operating labor.&lt;/p&gt;

&lt;p&gt;These are infrastructure price examples, not benchmark-equivalent replacements or minimum hardware recommendations. Other providers and commitments can change the rates. Turning a node off saves money, but also changes availability and adds startup considerations.&lt;/p&gt;

&lt;p&gt;Even at a hypothetical &lt;strong&gt;$18 per hour for the entire node&lt;/strong&gt;, continuous rental would cost &lt;strong&gt;$157,680 per year&lt;/strong&gt;. A cheap hourly price can still become an expensive always-on service.&lt;/p&gt;

&lt;h2&gt;
  
  
  The payback calculation needs operating costs
&lt;/h2&gt;

&lt;p&gt;Buying hardware sounds better because at least you eventually own it.&lt;/p&gt;

&lt;p&gt;Let's use &lt;strong&gt;$300,000 upfront&lt;/strong&gt; and &lt;strong&gt;$20,000 per year in operating costs&lt;/strong&gt; as an illustrative server scenario. These are modeling assumptions, not a vendor quote or the entry price for all local AI. A high-memory workstation could cost much less and may suit one person; it needs its own quality and speed evaluation. A workstation that meets the same requirements could reverse the conclusion; the numbers need to follow the benchmark. For this team-server scenario, replace the figures with a real bill of materials and your own power, cooling, hosting, and support estimates.&lt;/p&gt;

&lt;p&gt;Assume it completely replaces that $52,000 annual API spend:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Annual savings = $52,000 − $20,000 = $32,000
Simple payback = $300,000 ÷ $32,000 = 9.4 years
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Dividing the purchase price by the API bill alone gives 5.8 years. That calculation quietly assumes the server costs nothing to operate.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fevs19uyoqtu3urms27zl.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fevs19uyoqtu3urms27zl.png" alt="Three-year cumulative spending: $156,000 for the API scenario, $360,000 for the assumed owned server, and approximately $839,000 for eight continuously rented H100 GPUs." width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the same comparison in numbers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Three-year cash outlay&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API at $1,000/week&lt;/td&gt;
&lt;td&gt;$156,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Owned server: $300k upfront + $20k/year&lt;/td&gt;
&lt;td&gt;$360,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eight rented H100s, continuously allocated&lt;/td&gt;
&lt;td&gt;$838,858&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This simplified comparison holds rates and usage constant, ignores tax, financing and resale, and excludes engineering labor. It does &lt;strong&gt;not&lt;/strong&gt; establish equal performance between the options. The owned-server case also assumes no replacement purchase or residual API bill during the period.&lt;/p&gt;

&lt;p&gt;To recover that $300,000 purchase within three years, with $20,000 annual operations, you would need to displace &lt;strong&gt;$120,000 of API spending per year&lt;/strong&gt;, or about &lt;strong&gt;$2,308 per week&lt;/strong&gt;. You would also need enough serving capacity to handle that workload.&lt;/p&gt;

&lt;p&gt;Labor can move the threshold again. Just four hours a week valued at $100 an hour adds &lt;strong&gt;$20,800 per year&lt;/strong&gt;. Under the original $52,000 scenario, annual savings would fall to $11,200 and simple payback would stretch to &lt;strong&gt;26.8 years&lt;/strong&gt;. That isn't a forecast of hardware life; it is a sign that this set of assumptions fails the purchase test.&lt;/p&gt;

&lt;p&gt;If annual operations and labor equal or exceed the API spending you actually eliminate, there is no simple financial payback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utilization is where the argument lives or dies
&lt;/h2&gt;

&lt;p&gt;An API bill follows billable usage. An owned server ties up capital during nights, weekends, and quiet periods too.&lt;/p&gt;

&lt;p&gt;A heavily utilized deployment can spread fixed costs across more completed work. A lightly used machine can't. But “keep it busy” isn't enough: extra tokens only create savings if they replace work you would otherwise pay for.&lt;/p&gt;

&lt;p&gt;This is why I would measure a representative week before buying anything: completed tasks, input and output volume, latency, peak concurrency, failures, and time spent correcting results. Then I would benchmark the proposed local setup against those same tasks.&lt;/p&gt;

&lt;p&gt;A consumer subscription, metered API access, and a dedicated endpoint also have different limits and operating terms. Their sticker prices aren't interchangeable measures of capacity.&lt;/p&gt;

&lt;h2&gt;
  
  
  There are good reasons to run locally
&lt;/h2&gt;

&lt;p&gt;Some of them can outweigh a disappointing spreadsheet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need offline operation or strict control over where data is processed.&lt;/li&gt;
&lt;li&gt;A smaller model already passes a narrow, valuable workload.&lt;/li&gt;
&lt;li&gt;You already own suitable hardware and are evaluating the incremental cost.&lt;/li&gt;
&lt;li&gt;You have predictable volume, high utilization, and the expertise to operate the service.&lt;/li&gt;
&lt;li&gt;Learning, experimentation, or independence is part of what you're buying.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are legitimate objectives. A local model doesn't have to match every flagship cloud model to be useful or economical.&lt;/p&gt;

&lt;p&gt;For many teams, a hybrid approach deserves consideration: use smaller local models for tasks they handle reliably and reserve expensive remote inference for work that needs it. Measure whether the added routing and maintenance are worth the savings.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would change my mind?
&lt;/h2&gt;

&lt;p&gt;I expect to revisit this. More capable small models, better quantization, faster memory, and cheaper high-memory hardware could all improve the local proposition.&lt;/p&gt;

&lt;p&gt;But I wouldn't build a purchase decision around a promise that hardware prices must fall on a particular schedule. Cloud model prices and capabilities can improve too. The target keeps moving.&lt;/p&gt;

&lt;p&gt;Before committing six figures, I would first test whether a less expensive managed model can meet the same acceptance criteria, remove unnecessary context, and measure any caching or batching discounts available for the workload. Those changes can reduce spending without adding a server to maintain.&lt;/p&gt;

&lt;p&gt;I still want the machine-on-my-desk version to win. For a lot of focused tasks, it already can.&lt;/p&gt;

&lt;p&gt;For replacing demanding, general-purpose AI work across a small team, though, the combination of memory, throughput, utilization, and upkeep remains difficult to justify. &lt;strong&gt;Today, I'm more interested in buying useful results than owning the hardware that generates them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Research and listed prices checked November 2, 2026. Charts are original calculations, not hardware performance measurements. Start with the linked primary sources and substitute your own workload and quotes before making a purchase.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>devops</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How We Cut 80 % of Our Backend Calls in Summon Worlds</title>
      <dc:creator>Jedidiah Weller 👑</dc:creator>
      <pubDate>Fri, 01 Aug 2025 17:40:00 +0000</pubDate>
      <link>https://dev.to/openforge/how-we-cut-80-of-our-backend-calls-in-summon-worlds-3jk7</link>
      <guid>https://dev.to/openforge/how-we-cut-80-of-our-backend-calls-in-summon-worlds-3jk7</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reduce redundant API calls by centralizing loading logic in a shared helper.
&lt;/li&gt;
&lt;li&gt;Always expose a domain model (class instance) instead of raw state slices.
&lt;/li&gt;
&lt;li&gt;Cache with &lt;code&gt;shareReplay&lt;/code&gt; so multiple subscribers share one request.
&lt;/li&gt;
&lt;li&gt;Dispatch only plain-object payloads—no class instances in actions.
&lt;/li&gt;
&lt;li&gt;Inspired by our experience in the &lt;a href="https://www.summonworlds.com" rel="noopener noreferrer"&gt;Summon Worlds&lt;/a&gt; AI world-building app.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  0. The Backstory 🏗️
&lt;/h2&gt;

&lt;p&gt;First things first - a story.  In September of last year, we took over an AI World Building App called &lt;a href="https://www.summonworlds.com" rel="noopener noreferrer"&gt;Summon Worlds&lt;/a&gt;.  The app was a cool idea, had an great community, and scratched that gaming itch that all developers have. &lt;/p&gt;

&lt;p&gt;So after we took it on, we rebuilt the (very hacky) flutter prototype in Ionic + Angular, and we decided to use NGRX to help with performance and storage calls.  Since we were in a hurry, that was about all the thought we put into the &lt;em&gt;pattern&lt;/em&gt; in which we were implementing NGRX and we &lt;em&gt;thought&lt;/em&gt; it would be an easy process.  &lt;/p&gt;

&lt;p&gt;It was not.&lt;/p&gt;

&lt;p&gt;So, fast forward till today - there were a &lt;em&gt;ton&lt;/em&gt; of architecture and pattern decisions that I wish we did differently, and I'd like to share some of them with you so that hopefully you do not make the same mistakes as we did. &lt;/p&gt;

&lt;p&gt;This particular article is focused on an "accidental" antipattern of NGRX + Clone Deep that caused major issues.  If you like it let me know, and I'll write a couple more about some other anti-patterns to avoid!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. How We Discovered The Antipattern 🏗️
&lt;/h2&gt;

&lt;p&gt;The State was managed via NgRx and persisted to Firebase. One morning we noticed our billing spike—and Cloud Functions logs revealed that loading our simple “feed” screen fired &lt;strong&gt;42&lt;/strong&gt; &lt;code&gt;loadEntity&lt;/code&gt; calls every time. On slower networks, users waited ages. We knew something had to change.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Recognizing the Anti-Pattern
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 The Over-eager Helper
&lt;/h3&gt;

&lt;p&gt;A common helper service looked like this:&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;GenericHelperService&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;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppState&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="c1"&gt;// Raw state slice used everywhere&lt;/span&gt;
  &lt;span class="nx"&gt;getEntityState&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EntityState&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;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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectEntityState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Lightweight shortcut mapping to a class&lt;/span&gt;
  &lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EntityModel&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;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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectEntityData&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;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EntityModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="c1"&gt;// Dispatching class instances directly&lt;/span&gt;
  &lt;span class="nf"&gt;updateEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EntityModel&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;updateEntity&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;model&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;Every component calling &lt;code&gt;getEntity$()&lt;/code&gt; would dispatch &lt;code&gt;loadEntity&lt;/code&gt; again and again, re-instantiate the model, and violate NgRx’s serialization rules.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Core Principles of the Fix
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Raw slice only for edge cases.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Instantiate your domain model exactly once in a shared helper.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dispatch only plain JSON payloads—no class instances in actions.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These principles rescued our performance in Summon Worlds and will help any NgRx project.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. A Generic Refactor Recipe
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Strengthen the Helper
&lt;/h3&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;GenericHelperService&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;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppState&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="cm"&gt;/** Raw slice — cache and reuse sparingly */&lt;/span&gt;
  &lt;span class="nx"&gt;getEntityState&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EntityState&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;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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectEntityState&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;shareReplay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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="cm"&gt;/** Central loader + model emitter */&lt;/span&gt;
  &lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="nf"&gt;$&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;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EntityModel&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Trigger load exactly once per id&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;loadEntity&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;combineLatest&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;selectEntityById&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;selectEntityLoading&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;data&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;new&lt;/span&gt; &lt;span class="nc"&gt;EntityModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="nf"&gt;shareReplay&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;bufferSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;refCount&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="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/** Mutations accept model, dispatch plain data */&lt;/span&gt;
  &lt;span class="nf"&gt;saveChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EntityModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&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;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPlainObject&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;updateEntity&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;ul&gt;
&lt;li&gt;
&lt;code&gt;shareReplay(1)&lt;/code&gt; shares one subscription, caching the latest value.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;combineLatest + filter&lt;/code&gt; waits until data is ready before emitting.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;toPlainObject()&lt;/code&gt; strips methods, leaving a serializable payload.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4.2 Use the Async Pipe Everywhere
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before (Summon Worlds style):&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="nf"&gt;ngOnInit&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;sub&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;helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="nf"&gt;$&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="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;ngOnDestroy&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;sub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&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;After:&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="nx"&gt;value$&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;helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="nf"&gt;$&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;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compute&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{{ value$ | async }}&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;No manual subscriptions, no memory leaks, no boilerplate.&lt;/p&gt;




&lt;h3&gt;
  
  
  4.3 Remove Deep-Clone Workarounds
&lt;/h3&gt;

&lt;p&gt;Swap out:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;safeData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cloneDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawData&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For:&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;computed$&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;helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="nf"&gt;$&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;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;optionalProp&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&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;TypeScript strict checks catch missing properties, eliminating the &lt;code&gt;cloneDeep&lt;/code&gt; band-aid.&lt;/p&gt;




&lt;h3&gt;
  
  
  4.4 Centralize Error Handling
&lt;/h3&gt;

&lt;p&gt;Instead of catching errors in every 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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="nf"&gt;$&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;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Handle failures in an effect:&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;loadEntityFailure$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEffect&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;actions$&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;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loadEntityFailure&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;error&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;toast&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="s2"&gt;`Load failed: &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="s2"&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="na"&gt;dispatch&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your components only worry about rendering the happy path.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Migration Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Helper overhaul&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;shareReplay&lt;/code&gt; on raw-slice methods.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Implement &lt;code&gt;getEntity$()&lt;/code&gt; with load dispatch, &lt;code&gt;combineLatest&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, mapping, and &lt;code&gt;shareReplay&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Component cleanup&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Replace manual subscriptions with async-pipe streams.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Payload serialization&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add &lt;code&gt;.toPlainObject()&lt;/code&gt; to your models.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dispatch only JSON in actions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Remove &lt;code&gt;cloneDeep&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Delete all deep-clone code.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Centralize error flow&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Catch errors in effects only.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enable runtime checks&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;StoreModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;runtimeChecks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;strictStateImmutability&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;strictActionImmutability&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="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Measuring Success
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Improvement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend calls per view&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;−90%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory on initial render (MB)&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;−36%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time to first paint (s)&lt;/td&gt;
&lt;td&gt;4.2&lt;/td&gt;
&lt;td&gt;2.7&lt;/td&gt;
&lt;td&gt;−1.5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(These are some of the actual numbers we achieved, fyi)&lt;/p&gt;




&lt;h2&gt;
  
  
  7. FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; Why not dispatch class instances?&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; They break DevTools serialization, effect replay, and cross-tab sync. POJOs are the safest contract.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; Aren’t selectors memoized?&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; Yes—but extra &lt;code&gt;loadEntity&lt;/code&gt; dispatches before data arrives bypass selector caching. &lt;code&gt;shareReplay&lt;/code&gt; fixes that gap.&lt;/p&gt;


&lt;h2&gt;
  
  
  8. Generic Snippets to Copy
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Model Skeleton&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EntityModel&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;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EntityData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&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="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;data&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="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* domain logic */&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;toPlainObject&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;EntityData&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="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;data&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;Helper Skeleton&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;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;GenericHelperService&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;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppState&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="nx"&gt;getEntity&lt;/span&gt;&lt;span class="nf"&gt;$&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;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EntityModel&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;loadEntity&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;combineLatest&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;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;selectEntityById&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;selectEntityLoading&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;data&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;new&lt;/span&gt; &lt;span class="nc"&gt;EntityModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="nf"&gt;shareReplay&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;bufferSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;refCount&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="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;h2&gt;
  
  
  9. Next Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Measure&lt;/strong&gt; your own before/after metrics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refactor&lt;/strong&gt; one entity at a time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share&lt;/strong&gt; this guide and (of course) check out &lt;a href="https://www.summonworlds.com" rel="noopener noreferrer"&gt;Summon Worlds&lt;/a&gt; if you are into AI world-building.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy refactoring—and may your selectors be ever memoized!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>ngrx</category>
      <category>typescript</category>
      <category>performance</category>
    </item>
    <item>
      <title>What to Do After the Coding Academy</title>
      <dc:creator>Jedidiah Weller 👑</dc:creator>
      <pubDate>Wed, 19 Dec 2018 20:46:34 +0000</pubDate>
      <link>https://dev.to/openforge/what-to-do-after-the-coding-academy-4g3p</link>
      <guid>https://dev.to/openforge/what-to-do-after-the-coding-academy-4g3p</guid>
      <description>&lt;h2&gt;
  
  
  TOC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction - What to Do After The Coding Academy&lt;/li&gt;
&lt;li&gt;Step 1 - Learn The True Fundamentals&lt;/li&gt;
&lt;li&gt;Step 2 - Create a very simple C++ application&lt;/li&gt;
&lt;li&gt;Step 3 - Translate that C++ Application into a Web Application&lt;/li&gt;
&lt;li&gt;Step 4 - Understand the Internet&lt;/li&gt;
&lt;li&gt;Step 5 - Understand your environment&lt;/li&gt;
&lt;li&gt;Step 6 - Go HAM on a Web Dev Framework - but be well-rounded too&lt;/li&gt;
&lt;li&gt;Step 7 - Practice Being Systematic&lt;/li&gt;
&lt;li&gt;Closing Remarks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to Do After The Coding Academy &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Hello everyone!   For about 5 years now I've owned and operated a development shop, and in that time I have had the privilege of seeing many developers grow their skills (both professionally and personally) as they entered the workplace.  However; I quickly noticed some trends from individuals coming from Coding Academies and Bootcamps.&lt;/p&gt;

&lt;p&gt;While teaching our young padawans, I quickly learned that there is a lot of information missing from most Coding Academy curriculums.  I chalk it up to the programs being so short and attempting to cram so much knowledge into their brains at a time.  Most people gain the knowledge of "what is" software development, but lack the wisdom of "how to" use it.&lt;/p&gt;

&lt;p&gt;If this is you (or one of your team members) - you're not alone.  It's nearly impossible to become a full-fledged software engineer in 3-6 months, although places like NYDCA would like you to believe otherwise. &lt;a href="https://technical.ly/philly/2018/11/09/new-york-code-design-academy-is-shutting-down/" rel="noopener noreferrer"&gt;And perhaps that is why they shut down&lt;/a&gt;.  But fear not; there is hope!  Coding Academies are a great &lt;em&gt;start&lt;/em&gt; to your journey so long as they are followed by the right mentorship and guidance on where to go next.&lt;/p&gt;

&lt;p&gt;So, I'd like to provide exactly that - mentorship and guidance on "What to do next". I hope this article will graduates, as well as Senior Devs and Managers out there tasked with training them.  We're all in this career together, so let's help each other make it an amazing one for everyone.  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S.  If anyone has additional items you think are useful; I'll update this article to be a culmination of best practices/wisdom.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 - Learn The True Fundamentals &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;You may have thought you learned the fundamentals at your coding academy; but alas you actually learned the fundamentals of web development.  What you did not yet learn is the fundamentals of the "how" and "why" of computer science.  Questions like "What is an IP address?", "What is a var (under the hood)?", and "How can I step-through debug this problem?" are never asked nor taught, so it's up to us to fix that.&lt;/p&gt;

&lt;p&gt;To get this understanding I'd recommend traveling to the past so that you can understand the future.  Scripting languages are NOT the place to learn fundamentals; however, C++ is built on the fundamentals.   You'll probably never use this language again - but I DO want you to take 2-3 days to go through the following tutorials.  I promise they'll be beneficial - so here's the steps&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download Visual Studio Code&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.learncpp.com/#Chapter0" rel="noopener noreferrer"&gt;Take yourself through this C++ tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Complete chapters 0, 1, 2, 4, 5, 6, 7:&lt;/li&gt;
&lt;li&gt;While completing the Chapters answer the following questions:

&lt;ul&gt;
&lt;li&gt;What did you learn from this chapter?&lt;/li&gt;
&lt;li&gt;What questions/difficulties did you have during the chapter?&lt;/li&gt;
&lt;li&gt;What questions or things do you want to try, at the end of the chapter?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2 - Create a very simple C++ application.  &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I'd recommend the following:&lt;/p&gt;

&lt;p&gt;Create an application that &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When launched via the command line, says 
"Hello, what would you like to create?  "1: A Dog", "2: A Cat""&lt;/li&gt;
&lt;li&gt;When the user types "1" and hits enter, a Dog class is created.&lt;/li&gt;
&lt;li&gt;In the Dog Class Constructor, have a print function "I am a dog, I am born"&lt;/li&gt;
&lt;li&gt;In the Cat Class Constructor, have a print function "I am a cat, I am born!"&lt;/li&gt;
&lt;li&gt;Abstract Dog and Cat class to be part of an Animal class, and inherit from it.&lt;/li&gt;
&lt;li&gt;Complete some other small changes to reflect what you've just learned in your tutorials&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 3 - Translate that C++ Application into a Web Application. &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Now, create a Web Application using the technology you've been taught at your coding academy - but instead of the command line, have a GUI through a web browser.  Either an Angular Application or a Rails Application will do just fine, then answer the following questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How does C++ compare to javascript/ruby?
&lt;/li&gt;
&lt;li&gt;What are the differences?
&lt;/li&gt;
&lt;li&gt;Which parts were easier?  Which parts were harder?&lt;/li&gt;
&lt;li&gt;Have a friend introduce an error in both - but not show you where. Now, try to debug the error on both.  Do you see a difference in debugging?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4 - Understand the Internet.  &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Most people don't understand what the internet actually is; and it's truly magic. &lt;br&gt;
 Did you know there is all this hidden data in every packet that's sent over the web?  Do you know how your ISP works?   Well, to get started let's read this &lt;a href="https://web.stanford.edu/class/msande91si/www-spr04/readings/week1/InternetWhitepaper.htm" rel="noopener noreferrer"&gt;Stanford whitepaper on what the Internet actually is.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 - Understand your environment. &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This step is a controversial step and is best done on an old crappy computer you don't use anymore.  If you don't have one - make sure to back everything up on your current system.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; (Assuming you're creating an Angular App) Download and install Homebrew, Node, NPM, Bower, and Grunt.
&lt;/li&gt;
&lt;li&gt; Try to install and run &lt;a href="http://mean.io/" rel="noopener noreferrer"&gt;A MEAN Stack sample app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Uninstall the current version of node, and install an older version.  Play with versioning through &lt;a href="https://github.com/creationix/nvm" rel="noopener noreferrer"&gt;NVM&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Try to run the same app.&lt;/li&gt;
&lt;li&gt; Now, do the same thing on someone &lt;em&gt;else's&lt;/em&gt; computer.  Doesn't matter what type - there's learning on all OS :) &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You may or may not have issues - guess what; version dependencies are a BIG BIG challenge for a lot of developers.  5 people with macs may all have different environments - and that's not even including all the variations of Windows / Windows + Ubuntu / Linux distros.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;(Bonus) Wipe your computer - and re-install everything.   That's the controversial part, but often when you're doing development and you don't quite understand filepaths and chmod/sudo consequences you'll mess up your dev environment.  You can spend hours debugging it, or you can wipe and restart - your choice.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, you must be thinking to yourself "There's got to be a way to standardize environments".  Yes, there are plenty of ways.  A well-known approach is a tool called &lt;a href="https://medium.com/phytochemia-tech-blog/how-docker-can-improve-your-development-environments-731cdfda0b9a" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;.  I'll let you read up on the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6 - Go HAM on a Web Dev Framework - but be well-rounded too &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I personally love the Angular + Ionic combination for Web &amp;amp; Mobile apps, but there are a ton out there.  React.js is awesome and I'll be at the Vue.js conference in Amsterdam in February.  Once our interns at OpenForge are done with the above steps (and some 1-1 sessions), we ask them to start completing some online courses through Udemy.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; First, I'd take a quick debugging class here to learn about &lt;a href="https://www.udemy.com/mastering-web-and-mobile-debugging-using-chrome-dev-tools/learn/v4/overview" rel="noopener noreferrer"&gt;Chrome dev tools&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Second, complete the entirety of this &lt;a href="https://www.udemy.com/the-complete-guide-to-angular-2/learn/v4/overview" rel="noopener noreferrer"&gt;Angular 7 course&lt;/a&gt;.  It covers a LOT&lt;/li&gt;
&lt;li&gt; Third, take appreciation for my array numbering to the left &amp;lt;-- If you know your basics, you know why I did this :) &lt;/li&gt;
&lt;li&gt; Fourth, practice creating a MEAN stack app and deploying it.  Here's some links&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.hongkiat.com/blog/node-js-server-side-javascript/" rel="noopener noreferrer"&gt;http://www.hongkiat.com/blog/node-js-server-side-javascript/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devcenter.heroku.com/articles/mean-apps-restful-api" rel="noopener noreferrer"&gt;https://devcenter.heroku.com/articles/mean-apps-restful-api&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.modulus.io/build-your-first-http-server-in-nodejs" rel="noopener noreferrer"&gt;http://blog.modulus.io/build-your-first-http-server-in-nodejs&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 7 - Practice Being Systematic &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;PAY ATTENTION TO THIS - This is the most important piece of advice I can give you. &lt;/p&gt;

&lt;p&gt;When you're working on a feature, debugging, or any type of development - commit after every meaningful change.  Do NOT wait for the feature/bug to be finished.&lt;/p&gt;

&lt;p&gt;Computer Science is a &lt;em&gt;science&lt;/em&gt;, and science is systematic.  We try, measure, and come to conclusions.  I promise you that if you break down large commits and large problems into super small ones; you will accomplish tasks 10x quicker and be happier for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Remarks &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I hope this is helpful - it's been the 'time-tested mother-approved' formula for us for a couple years now.  &lt;/p&gt;

&lt;p&gt;If anyone has anything else to add (or recommends modifications) I am all ears, please comment below!&lt;/p&gt;

&lt;p&gt;Best Regards,&lt;br&gt;
&lt;a href="https://dev.to~Jedi"&gt;www.twitter.com/jedihacks&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>help</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Passion Projects are Fun - Except In Production</title>
      <dc:creator>Jedidiah Weller 👑</dc:creator>
      <pubDate>Sun, 25 Nov 2018 15:45:55 +0000</pubDate>
      <link>https://dev.to/openforge/passion-projects-are-fun---except-in-production-1lmj</link>
      <guid>https://dev.to/openforge/passion-projects-are-fun---except-in-production-1lmj</guid>
      <description>&lt;p&gt;Right around the time that the Ionic team came out with &lt;a href="https://stenciljs.com/" rel="noopener noreferrer"&gt;Stencil.js&lt;/a&gt; our company made a brand transition from Webjunto to &lt;a href="http://openforge.io" rel="noopener noreferrer"&gt;OpenForge&lt;/a&gt;.  Since we are all massively in love with all things technology; we said "OMG - An opportunity to play with Stencil!  Let's build our Website using Stencil as a web-component pre-compiler and scratch that Wordpress B.S. It will be &lt;em&gt;so&lt;/em&gt; much faster!".&lt;/p&gt;

&lt;p&gt;From a business owner's perspective, it was a perfect opportunity to transition from Wordpress to something that we built with our own hands. We could &lt;a href="https://github.com/openforge/OPENFORGE.IO" rel="noopener noreferrer"&gt;Open Source&lt;/a&gt; and talk about it.  It allowed us to train our team on a new technology while simultaneously applying it to something useful.  &lt;/p&gt;

&lt;p&gt;But - we were unprepared.  That's when the pain hit.&lt;/p&gt;

&lt;h1&gt;
  
  
  Our Assumption
&lt;/h1&gt;

&lt;p&gt;We drastically underestimated how much is truly built into Wordpress that we never think about.  Between Blog, Page, User Management, and SEO capabilities - it's a huge set of features, and eliminates a lot of need for &lt;em&gt;process&lt;/em&gt; internally in the team between the design, dev, and business departments.&lt;/p&gt;

&lt;p&gt;We also assumed that anything that was in Wordpress we could easily build, and to our team's credit we &lt;strong&gt;can&lt;/strong&gt; build the features; however - what we don't have is the process for identifying &lt;strong&gt;what&lt;/strong&gt; needs to be reviewed across departments.&lt;/p&gt;

&lt;p&gt;For instance; how many business people think about the manifest.json file? How many people (in a full design &amp;amp; dev team) are qualified to identify SEO mismatches between content and url routing?  These things are automatically provided and identified by Wordpress and Yoast, and we didn't even realize it.&lt;/p&gt;

&lt;p&gt;The benefit was that it created a need to more tightly integrate the 3 major departments at our company (Design, Dev, Business); however, the down side was that we had to create a process for this and we were &lt;strong&gt;completely&lt;/strong&gt; unprepared.&lt;/p&gt;

&lt;h1&gt;
  
  
  My Advice
&lt;/h1&gt;

&lt;p&gt;Was it worth it?  I &lt;em&gt;think&lt;/em&gt; so due to the training to the team, PWA expertise, and lessons learned; however, on a scale of 'how worth it' it was not as clearly a win as I expected.&lt;/p&gt;

&lt;p&gt;I'll break down my advice into a bulleted list of what was worth it, and what pieces we missed.  My hope is if you would like to try the same thing for your company, you'll have a bit of a headstart on what troubles may arise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worth It
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The experience &amp;amp; training (as we move into single-source PWA's)&lt;/li&gt;
&lt;li&gt;The speed (It feels like the road-runner compared to WP)&lt;/li&gt;
&lt;li&gt;The control (fully customizable, without any plugin development)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Harder Than Expected / Unexpected
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;SEO Management.  What's the replacement for Yoast?

&lt;ul&gt;
&lt;li&gt;Robots.txt&lt;/li&gt;
&lt;li&gt;Manifest File&lt;/li&gt;
&lt;li&gt;URL Routing Strategy (and who reviews this?)&lt;/li&gt;
&lt;li&gt;404 Page for old I.E. (we just redirect)&lt;/li&gt;
&lt;li&gt;Canonical Links&lt;/li&gt;
&lt;li&gt;Alt Text to images (we keep forgetting - need to update process)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Polyfills&lt;/li&gt;
&lt;li&gt;Lighthouse Optimizations (local vs. deployed)&lt;/li&gt;
&lt;li&gt;Smooth Scrolling&lt;/li&gt;
&lt;li&gt;Accessibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There were some more items that didn't make it into our &lt;a href="https://github.com/openforge/OPENFORGE.IO/blob/master/CHANGELOG.md" rel="noopener noreferrer"&gt;changelog&lt;/a&gt;, as I think of them I'll update the post.&lt;/p&gt;

&lt;p&gt;Hope this helps folks!&lt;/p&gt;

&lt;p&gt;&lt;a href="//www.twitter.com/jedihacks"&gt;~Jedi&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>devops</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Tutorial 1,000 - A Real Production App</title>
      <dc:creator>Jedidiah Weller 👑</dc:creator>
      <pubDate>Wed, 24 Oct 2018 14:25:42 +0000</pubDate>
      <link>https://dev.to/openforge/tutorial-1000---a-real-production-app-134b</link>
      <guid>https://dev.to/openforge/tutorial-1000---a-real-production-app-134b</guid>
      <description>&lt;p&gt;Hey everyone,&lt;/p&gt;

&lt;p&gt;Yesterday we released (and open-sourced) a full production mobile app, and wrote a guest blog about it through Ionic's Blog.  It's not everyday we get to see the 'nuts-and-bolts' of a full app, so I figured I'd share it with the community here as well :) &lt;/p&gt;

&lt;p&gt;It took around 400 hours to design and build the Ionic 3 app.  We used a serverless architecture, Firebase, and Ionic 3.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Why we built it
&lt;/h2&gt;

&lt;p&gt;We're developers - although we always scope work the scoping process can get messy.   &lt;/p&gt;

&lt;p&gt;It's very easy to be 'peer pressured' (even unknowingly) into changing your estimates when your friends and colleagues think differently.  This is exacerbated when you have junior and senior developers in the same room providing estimates together.  The junior devs are often afraid to provide real estimates, because they are much longer than the senior's.&lt;/p&gt;

&lt;p&gt;We used to use planningpoker.com for scoping sessions; but everyone could see each others estimates and then during a session team members would change their answers to avoid confrontation.  This often leads to inaccurate scopes; because the person who's answer wins is not always the person tasked with completing the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we open-sourced it
&lt;/h2&gt;

&lt;p&gt;It's aggravatingly difficult to find examples of real production applications that are open sourced (but still simple to follow).  When I train new team members, I find that going from Angular's "tutorial 101" to building a full application is about a 10 foot step, and no one has 10 foot legs. &lt;/p&gt;

&lt;p&gt;So, when the dev team proposed designing and building this tool we agreed to open source it and write about it.  It's got some cool features, such as&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teamwork Projects integration&lt;/li&gt;
&lt;li&gt;Serverless architecture&lt;/li&gt;
&lt;li&gt;Ionic 3 application&lt;/li&gt;
&lt;li&gt;Live scoping via Firebase&lt;/li&gt;
&lt;li&gt;Firebase. Firebase. Firebase.  We're loving Firebase :D &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We wrote a full guest blog post about the architecture and decisions we made on &lt;a href="https://blog.ionicframework.com/built-with-ionic-juntoscope/" rel="noopener noreferrer"&gt;Ionic's Blog&lt;/a&gt;, so rather than re-invent the wheel I'd encourage everyone to read the full breakdown there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you download it?
&lt;/h2&gt;

&lt;p&gt;No - you should &lt;a href="https://github.com/openforge/JuntoScope" rel="noopener noreferrer"&gt;Clone it from Github&lt;/a&gt; and use it yourself.  However; we figured it may be hard to get some project managers on board if it didn't have a least a semblance of an established app.  So go ahead, use it if you'd like, but seriously - feel free to take it as well :) &lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;We had a lot of positive feedback from the product; so we'll be releasing another full production app next month (open sourced) and blogging about the process.   We don't intend to build any more integrations besides Teamwork because that's what we use internally at &lt;a href="https://openforge.io" rel="noopener noreferrer"&gt;OpenForge.io&lt;/a&gt;; however, if you are using another tool and would like to create a PR we'd be happy to help support it.&lt;/p&gt;

&lt;p&gt;Thanks everyone, stay cool and dev on!&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/jedihacks" rel="noopener noreferrer"&gt;Jedi&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
