<?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</title>
    <description>The most recent home feed on DEV Community.</description>
    <link>https://dev.to</link>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed"/>
    <language>en</language>
    <item>
      <title>30 Domain Templates for Your LLM Knowledge Base: Skip the Setup, Start Capturing</title>
      <dc:creator>Paul Chen</dc:creator>
      <pubDate>Tue, 15 Sep 2026 01:17:15 +0000</pubDate>
      <link>https://dev.to/paul_chen_90371fe7426cb44/30-domain-templates-for-your-llm-knowledge-base-skip-the-setup-start-capturing-3g2e</link>
      <guid>https://dev.to/paul_chen_90371fe7426cb44/30-domain-templates-for-your-llm-knowledge-base-skip-the-setup-start-capturing-3g2e</guid>
      <description>&lt;p&gt;The hardest part isn't the LLM layer&lt;/p&gt;

&lt;p&gt;The hardest part of building an LLM knowledge base for a specific domain isn't wiring up the models, it's encoding how that domain thinks. A compliance analyst's knowledge base needs every obligation mapped to a specific regulation, every control to an owner, every exception to an approver. A clinical wiki needs evidence grades on every claim. A DevOps runbook system needs incident timelines and rollback steps. The query routing, intake form fields, and quality standards are all different — and none of that comes pre-configured.&lt;/p&gt;

&lt;p&gt;Most teams spend the first two weeks not capturing knowledge but arguing about structure: what pages should exist, how routing should decompose, which source types need their own forms. By the time those questions are settled, content has already been ingested into the wrong shape and needs to be redone.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;synthadoc install --template&lt;/code&gt; solves this in one command.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Domain Template Actually Provides
&lt;/h2&gt;

&lt;p&gt;A domain template is not a demo or a sample dataset. It is a pre-made structural skeleton for a specific knowledge domain - everything that governs how knowledge is organized, ingested, and queried, without any of the actual content.&lt;/p&gt;

&lt;p&gt;One install command gives you six structural components:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Query routing table (&lt;code&gt;ROUTING.md&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The map that tells the query engine which branches of your wiki to search based on the nature of the question. A finance/investment template routes "capital structure questions" to debt financing and covenant pages, while routing "valuation questions" to financial models and comparable companies. Writing this from scratch requires domain knowledge most developers building a knowledge system do not have — and the gap shows up as poor retrieval quality until someone with that expertise intervenes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Domain-tuned agent guidelines&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each template ships with &lt;code&gt;CLAUDE.md&lt;/code&gt;, &lt;code&gt;AGENTS.md&lt;/code&gt;, and &lt;code&gt;GEMINI.md&lt;/code&gt; in the wiki root — the standard files that AI coding assistants (Claude Code, Gemini CLI, GitHub Copilot Agents) read automatically when active in a directory. The domain guidelines are injected into each file, so any AI tool you already use becomes domain-aware the moment it opens the wiki.&lt;/p&gt;

&lt;p&gt;Here is what the clinical healthcare template puts in those files:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Cite clinical guidelines by issuing body, title, year, and recommendation strength (Grade A/B/C or Level 1/2/3). Note evidence quality for every clinical claim: RCT, meta-analysis, cohort study, expert consensus, or case report. Never store identifiable patient data in wiki pages.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Compare that to the compliance template:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Map every compliance obligation to the specific regulation, rule, or contractual requirement that creates it. Track controls with the control owner, testing frequency, and last test date. Distinguish between legal requirements (non-negotiable) and internal policy requirements (adjustable). Note jurisdiction and regulated entity for every obligation.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When a compliance analyst has Claude Code running in their wiki directory and asks it to help write a page or interpret a lint warning, it already knows that regulatory citations need jurisdiction-level specificity and that control owners must be named — without configuring anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Scaffold stub pages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;8–12 stub pages covering the core knowledge areas of the domain — empty frames with the right titles, frontmatter, and a &lt;code&gt;&amp;lt;!-- synthadoc:scaffold --&amp;gt;&lt;/code&gt; zone marker that separates content you write (preserved) from content the weekly scaffold job refreshes (generated). The structural skeleton maintains itself without ever overwriting your edits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Blank intake forms&lt;/strong&gt; (&lt;code&gt;template-*.md&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Structured markdown forms in &lt;code&gt;raw_sources/&lt;/code&gt; for each document type common to the domain. A finance/investment install includes forms for deal memos, company profiles, and due diligence checklists — the same fields a professional would populate in any standard memo, now wired directly into the ingest pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Pre-validated seed sources (&lt;code&gt;seeds.md&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Curated ingest commands for public-domain reference sources - all checked for accessibility and domain appropriateness before the template was released. For finance/investment, these include SEC investor education materials and Federal Reserve H.15 interest rate releases. For healthcare/clinical, clinical guideline registries and evidence-based medicine references. Real domain context before your proprietary content lands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Scheduled maintenance jobs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A weekly lint run (Sunday 2:00 AM) and a weekly scaffold job (Sunday 3:00 AM), pre-registered at install time. Neither requires manual intervention once the wiki is running.&lt;/p&gt;




&lt;h2&gt;
  
  
  Template Library: 30 Domains, 9 Categories
&lt;/h2&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%2F88iu02g3hpcebgr5q6x7.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%2F88iu02g3hpcebgr5q6x7.png" alt="domain templates" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The selection reflects domains where knowledge is both high-stakes (wrong answers have real consequences) and naturally document-heavy (the source material already exists - it is just not queryable). Finance, healthcare, and legal are the clearest examples. Technology and research are the next tier, where the cost of an engineer not knowing the current incident runbook, or a researcher duplicating a failed experiment, is concrete and measurable.&lt;/p&gt;




&lt;h2&gt;
  
  
  From Install to First Query
&lt;/h2&gt;

&lt;p&gt;Getting a domain-template wiki to the point where it can answer real questions takes less than an hour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc templates list          &lt;span class="c"&gt;# browse all 30 options&lt;/span&gt;
synthadoc &lt;span class="nb"&gt;install &lt;/span&gt;my-wiki &lt;span class="nt"&gt;--target&lt;/span&gt; ~/wikis &lt;span class="nt"&gt;--template&lt;/span&gt; finance/investment
synthadoc serve my-wiki
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The install creates a standard wiki then applies the template: routing table, agent guidelines, stub pages, intake forms, and seeds. Staging is enabled by default — every ingested page goes to a candidates queue for review before entering the live wiki.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Ingest seed sources and your own documents&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From seeds.md — authoritative public reference material&lt;/span&gt;
synthadoc ingest &lt;span class="s2"&gt;"https://www.investor.gov/introduction-investing"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; my-wiki

&lt;span class="c"&gt;# Your own sources — batch ingest everything in raw_sources/ at once&lt;/span&gt;
synthadoc ingest raw_sources/ &lt;span class="nt"&gt;--batch&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; my-wiki
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Review candidates in Obsidian&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open the Obsidian plugin and run &lt;strong&gt;Synthadoc: Candidates: review candidate pages...&lt;/strong&gt; from the Command Palette. The modal lists every staged page with its slug, colour-coded confidence badge (&lt;code&gt;high&lt;/code&gt; / &lt;code&gt;medium&lt;/code&gt; / &lt;code&gt;low&lt;/code&gt;), and ingest timestamp — promote what passes your bar, discard what does not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Run lint&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc lint run &lt;span class="nt"&gt;-w&lt;/span&gt; my-wiki
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lint validates every page against the domain guidelines, checks citations, and flags orphans and contradictions. Clean draft pages are promoted to &lt;code&gt;active&lt;/code&gt; automatically. After lint, your wiki is queryable.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Happens After
&lt;/h2&gt;

&lt;p&gt;Once the wiki is active, maintenance is driven by the web UI rather than by you remembering to check things. After every query or lint run, the engine reads its own output and pre-fills the input box with the highest-priority next action — if it found stale pages, the prompt says "Re-ingest these pages"; if re-ingest just finished, it says "Run lint to promote them"; if contradictions surfaced, it queues the resolver. You confirm and it runs. No command to remember, no separate dashboard to check.&lt;/p&gt;

&lt;p&gt;Behind that interface, the agentic layer handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contradiction resolution&lt;/strong&gt; — conflicting pages are identified, original sources retrieved, resolution proposed interactively&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-ingest on source updates&lt;/strong&gt; — stale pages refreshed with a before/after diff for your approval&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken wikilink repair&lt;/strong&gt; — dead links scanned and repaired automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Citation integrity&lt;/strong&gt; — claims audited against source documents; drift flagged for re-ingest&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensitive data handling&lt;/strong&gt; — sanitizer strips PII at ingest time; &lt;code&gt;synthadoc retract&lt;/code&gt; rolls back a source and all pages citing it if something slips through&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled lint and scaffold&lt;/strong&gt; — weekly jobs keep the knowledge graph healthy without intervention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal: after the first few days of populating your wiki, the agentic layer handles the maintenance work that would otherwise require a dedicated knowledge engineer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc templates list                          &lt;span class="c"&gt;# browse the library&lt;/span&gt;
synthadoc &lt;span class="nb"&gt;install&lt;/span&gt; &amp;lt;name&amp;gt; &lt;span class="nt"&gt;--template&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;cat&lt;/span&gt;/domain&amp;gt;  &lt;span class="c"&gt;# install with a template&lt;/span&gt;
synthadoc templates &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &amp;lt;wiki&amp;gt;                &lt;span class="c"&gt;# sync after an upgrade&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/axoviq-ai/synthadoc/releases/tag/v1.3.3" rel="noopener noreferrer"&gt;Release notes (v1.3.3)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full template docs:&lt;/strong&gt; &lt;a href="https://github.com/axoviq-ai/synthadoc/blob/main/synthadoc/templates/README.md" rel="noopener noreferrer"&gt;template/readme&lt;/a&gt; in the installed package&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/axoviq-ai/synthadoc" rel="noopener noreferrer"&gt;Synthadoc&lt;/a&gt; is an open-source LLM knowledge compilation engine, it ingests your sources, compiles them into a queryable, citation-backed wiki, and keeps it consistent and self-growing over time. The domain template library ships in every install, no additional packages required.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>agents</category>
      <category>automation</category>
      <category>domain</category>
    </item>
    <item>
      <title>Google Brings Deep Research to Gemini Live for Voice-Based Research Conversations</title>
      <dc:creator>Ali Farhat</dc:creator>
      <pubDate>Tue, 15 Sep 2026 01:15:31 +0000</pubDate>
      <link>https://dev.to/alifar/google-brings-deep-research-to-gemini-live-for-voice-based-research-conversations-6l8</link>
      <guid>https://dev.to/alifar/google-brings-deep-research-to-gemini-live-for-voice-based-research-conversations-6l8</guid>
      <description>&lt;p&gt;Google has confirmed that &lt;strong&gt;&lt;a href="https://scalevise.com/resources/gemini/" rel="noopener noreferrer"&gt;Gemini Live&lt;/a&gt; now supports Deep Research&lt;/strong&gt;, allowing people to request and discuss in-depth research reports through voice conversations. The integration brings one of Gemini's research capabilities into its live, conversational interface, making it possible to explore a subject without first typing a detailed prompt.&lt;/p&gt;

&lt;p&gt;The update is particularly relevant for people who research while travelling, between meetings, or away from a desk. Google's &lt;a href="https://blog.google/products-and-platforms/products/education/back-to-school-2026/" rel="noopener noreferrer"&gt;Back to School 2026 announcement&lt;/a&gt; says users can request and talk through Deep Research reports with Gemini Live while on the go. Gemini Live's overview page also lists Deep Research among the experience's supported capabilities.&lt;/p&gt;

&lt;p&gt;Deep Research began as a standalone Gemini Advanced capability in 2024 and later evolved into Deep Research Max in 2026. Its arrival in Gemini Live extends that research function into a voice modality: users can initiate research and continue the conversation around the resulting report rather than treating the report as a static output.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Gemini Live integration changes
&lt;/h2&gt;

&lt;p&gt;The key change is not simply voice input. Gemini Live combines voice conversation with access to Deep Research reports, so a user can ask for a topic to be investigated and then talk through the report in the same interaction. That can make early-stage research more practical when a keyboard is inconvenient or when a question develops through discussion.&lt;/p&gt;

&lt;p&gt;For businesses, the most credible near-term use is &lt;strong&gt;faster research intake&lt;/strong&gt;. A manager preparing for a customer meeting, a marketer exploring a subject for an editorial brief, or a founder assessing a new market can use a live conversation to frame a research task and interrogate the findings. The final report can then inform a document or Drive-based research asset, although Google has not detailed a specific end-to-end content workflow for Gemini Live in the supplied materials.&lt;/p&gt;

&lt;p&gt;Gemini Live also has a broader set of capabilities, including &lt;a href="https://scalevise.com/resources/gemini-3-5-transcribe-macos-voice-workflows/" rel="noopener noreferrer"&gt;voice-driven task execution across Google apps&lt;/a&gt;, real-time visual information and memory of prior conversations. These capabilities can complement voice-based research, but they should not be confused with Deep Research itself.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Workflow element&lt;/th&gt;
      &lt;th&gt;Gemini Live status&lt;/th&gt;
      &lt;th&gt;Practical implication&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Deep Research&lt;/td&gt;
      &lt;td&gt;Users can request and discuss research reports by voice&lt;/td&gt;
      &lt;td&gt;Research can begin and be explored during an on-the-go conversation&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Google app task execution&lt;/td&gt;
      &lt;td&gt;Part of Gemini Live's broader feature set&lt;/td&gt;
      &lt;td&gt;Voice interactions can extend beyond research where supported Google app actions are relevant&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Real-time visual information&lt;/td&gt;
      &lt;td&gt;Part of Gemini Live's broader feature set&lt;/td&gt;
      &lt;td&gt;Live conversations can incorporate visual context separately from a research report&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Gems and Notebooks in an active Live session&lt;/td&gt;
      &lt;td&gt;Not available during active Live mode&lt;/td&gt;
      &lt;td&gt;Teams relying on those tools need to plan work outside the active voice session&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Where voice research may fit in everyday work
&lt;/h3&gt;

&lt;p&gt;The integration is best viewed as a front end for research exploration, not a replacement for editorial review or business judgment. Potential uses include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developing a research brief before writing a campaign, proposal or presentation.&lt;/li&gt;
&lt;li&gt;Exploring unfamiliar customer, market or product topics while commuting or travelling.&lt;/li&gt;
&lt;li&gt;Talking through a research report to identify follow-up questions before moving findings into a shared document.&lt;/li&gt;
&lt;li&gt;Giving a team member a hands-free way to start a research task before formalizing the work in an existing content or planning process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The value is likely to depend on whether the report reaches the people and systems that need it next. Companies should define how voice-generated research moves into their normal review, documentation and approval process, rather than assuming that a useful conversation alone creates a finished deliverable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Availability, pricing and workflow limits
&lt;/h3&gt;

&lt;p&gt;Google's Back to School update includes a &lt;strong&gt;one-year Google AI Pro offer in the United States for eligible college students&lt;/strong&gt;. That is the explicit onboarding and licensing context supplied with the announcement. It does not establish general business pricing, enterprise pricing, availability in every region or eligibility for organizations outside that student offer.&lt;/p&gt;

&lt;p&gt;There is also an important product limitation for teams building repeatable research workflows. During an active Gemini Live session, Live mode does not provide access to &lt;a href="https://scalevise.com/resources/notebooklm/" rel="noopener noreferrer"&gt;Gems or Notebooks&lt;/a&gt;. A business that organizes research in notebooks or uses advanced project structures should account for that boundary. The Live conversation may be useful for initiating and discussing research, while related organization work may need to happen before or after the voice session.&lt;/p&gt;

&lt;p&gt;Google's wider Deep Research documentation and developer resources describe connections to Workspace surfaces and an API, suggesting a longer-term path toward more &lt;a href="https://scalevise.com/resources/ai-workflow-automation/" rel="noopener noreferrer"&gt;integrated research workflows&lt;/a&gt;. However, the supplied material does not specify how an individual business should configure those workflows, what controls apply to corporate data, or which Deep Research and Gemini Live features are available in each market.&lt;/p&gt;

&lt;p&gt;For companies, the sensible question is not whether voice is inherently better than typing. It is whether voice removes friction at a useful stage of the research process. Teams that routinely lose ideas, questions or research momentum away from their desks may find that it does. Teams with strict requirements for project organization, data handling or repeatable publication workflows will need more implementation detail from Google before relying on the feature as a core process.&lt;/p&gt;

&lt;p&gt;If your team wants to turn AI research into a dependable business process, Scalevise can help map the right tools, handoffs and safeguards around the work. Our &lt;a href="https://scalevise.com/services/ai-consultancy" rel="noopener noreferrer"&gt;AI consultancy services&lt;/a&gt; focus on practical use cases that reduce manual effort without forcing teams to abandon the systems they already use. Identify where voice-based research can add value, define a workable review path, and avoid building a workflow around features that do not fit your needs. &lt;strong&gt;Request an AI consultation.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the Gemini Live Deep Research integration?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It lets users request and discuss Deep Research reports through Gemini Live's voice-based conversational experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can Gemini Live users talk through a Deep Research report?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Google says users can request and talk through Deep Research reports with Gemini Live while on the go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What pricing or offer has Google announced?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google's Back to School 2026 update includes a one-year Google AI Pro offer in the United States for eligible college students. The supplied information does not specify general business or enterprise pricing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can users access Gems or Notebooks during an active Gemini Live session?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Live mode does not grant access to Gems or Notebooks during an active Live session.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Deep Research in Gemini Live makes Google's research capability more conversational and mobile. It could reduce friction when users need to initiate or explore research away from a keyboard, but its practical value for businesses will depend on how reports are reviewed, organized and carried into existing workflows. The current announcement confirms the voice integration, while broader pricing, regional availability and business data controls remain areas to watch.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>tools</category>
      <category>gemini</category>
    </item>
    <item>
      <title>O que descobri medindo o Core Web Vitals de um portal de notícias em hospedagem compartilhada</title>
      <dc:creator>Ary Ribeiro</dc:creator>
      <pubDate>Tue, 15 Sep 2026 01:11:51 +0000</pubDate>
      <link>https://dev.to/aryribeiro/o-que-descobri-medindo-o-core-web-vitals-de-um-portal-de-noticias-em-hospedagem-compartilhada-ce5</link>
      <guid>https://dev.to/aryribeiro/o-que-descobri-medindo-o-core-web-vitals-de-um-portal-de-noticias-em-hospedagem-compartilhada-ce5</guid>
      <description>&lt;p&gt;Sete dias medindo um portal de notícias em WordPress numa hospedagem compartilhada. As três causas reais estavam fora da lista de suspeitos do Google, e o painel de diagnóstico apontou a imagem errada duas vezes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A apuração é do &lt;a href="https://diretonoticias.com.br" rel="noopener noreferrer"&gt;Direto Notícias&lt;/a&gt;, portal de Guarapari, no Espírito Santo. Os números foram medidos entre 6 e 14 de setembro de 2026 e estão datados por isso.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O portal estava reprovado no Core Web Vitals do Google no celular. O maior elemento da tela levava 2,8 segundos para aparecer, contra o limite de 2,5. Isso barra a entrada no Discover, que é de onde vem tráfego de descoberta para veículo pequeno.&lt;/p&gt;

&lt;p&gt;A parte fácil do diagnóstico o próprio Google entrega: o relatório aponta JavaScript bloqueando a renderização, imagens pesadas e refluxo forçado. A parte difícil é descobrir qual desses itens é a causa e qual é sintoma. Passei sete dias medindo, e as três causas reais não estavam na lista de suspeitos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeira: o site gastava o servidor gerando páginas para ninguém
&lt;/h2&gt;

&lt;p&gt;O plugin de cache tinha uma fila de pré-carregamento ligada. Ela completava entre 130 e 180 páginas a cada quinze minutos, o dia inteiro, com quase sete mil pendentes e mais de dois mil erros acumulados.&lt;/p&gt;

&lt;p&gt;Numa hospedagem compartilhada, isso não é otimização, é concorrência. Medi a home já em cache respondendo em 1,2 segundo enquanto a fila trabalhava. A mesma home, com a fila parada, responde em 0,22.&lt;/p&gt;

&lt;p&gt;O detalhe que quase me enganou: eu achava que a página estava fria. Não estava. O arquivo de cache tinha sido gravado horas antes. O servidor é que estava ocupado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Segunda: 100% dos cliques de celular caíam em matérias, e nenhum na home
&lt;/h2&gt;

&lt;p&gt;Puxei o Search Console por página e por dispositivo. Em 28 dias, todos os cliques de celular vindos da busca caíram em matérias espalhadas pelo acervo. A home recebeu zero.&lt;/p&gt;

&lt;p&gt;Isso inverte a estratégia inteira. Eu vinha otimizando a home, que é o que todo mundo mede. Quem decide a nota de campo é o acervo, e o acervo estava sempre frio: cada publicação limpava o cache do site todo, o portal publica dezenas de textos por dia, e o cache vive sete dias.&lt;/p&gt;

&lt;p&gt;A correção foi cirúrgica, por filtro: publicação nova limpa home e categoria; atualização de texto limpa apenas aquela matéria. Mais um aquecedor que mantém quentes as matérias que o Google efetivamente manda gente, com a lista vinda do próprio Search Console.&lt;/p&gt;

&lt;p&gt;E uma regra que ficou: disparar uma requisição não é aquecer. Requisição não bloqueante com tempo limite curto é descartada pela hospedagem antes de o cache gravar. Só o arquivo em disco prova. O aquecedor confere a data do arquivo e registra se gravou ou não.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terceira: a capa invisível que era baixada com prioridade máxima
&lt;/h2&gt;

&lt;p&gt;O tema imprimia a imagem de destaque num bloco próprio, acima do texto. Meses antes, uma regra de CSS tinha escondido esse bloco em todos os aparelhos, porque a mesma foto já aparecia no corpo da matéria.&lt;/p&gt;

&lt;p&gt;Esconder por CSS não impede o download. O navegador baixava 24 KB com prioridade alta para uma imagem que ninguém via, disputando banda com a foto que o leitor realmente enxerga.&lt;/p&gt;

&lt;p&gt;Fica a lição: compare sempre o que está &lt;strong&gt;visível&lt;/strong&gt; com o que está sendo &lt;strong&gt;baixado&lt;/strong&gt;. São listas diferentes, e a segunda é a que custa.&lt;/p&gt;

&lt;h2&gt;
  
  
  O painel de causas do Google apontou a imagem errada. Duas vezes
&lt;/h2&gt;

&lt;p&gt;O relatório do PageSpeed acusava a capa da matéria de "elemento de imagem sem tamanho definido", e depois o logotipo do cabeçalho.&lt;/p&gt;

&lt;p&gt;Testei segurando cada imagem por seis segundos com o navegador controlado e medindo a caixa antes e depois de carregar. Nos dois casos a caixa já estava reservada, porque os atributos de largura e altura geram proporção. Falso positivo nos dois.&lt;/p&gt;

&lt;p&gt;A causa real só apareceu ao instrumentar o próprio navegador com observador de deslocamento de layout, processador estrangulado e rede lenta, olhando quais nós se moviam. Eram dois:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A fonte dos títulos. Em Arial o título ocupava três linhas; quando a fonte condensada chegava, virava duas, e tudo abaixo subia trinta pixels. Resolvido com pré-carregamento da fonte e uma fonte reserva com métrica ajustada, para as duas ocuparem a mesma altura.&lt;/li&gt;
&lt;li&gt;O anúncio automático, que insere um bloco entre a foto e o primeiro parágrafo depois de a página já estar montada. Esse eu não toquei: é a receita do veículo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  O que eu mediria diferente da próxima vez
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nota de laboratório é ruído quando há anúncio.&lt;/strong&gt; A mesma matéria, sem nenhuma mudança no código, deu 89 e depois 66 em rodadas seguidas, só porque o anúncio sorteado travou a thread por mais tempo. Compare tempo de carregamento e deslocamento de layout, nunca a nota.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Medir logo após limpar o cache mede página fria.&lt;/strong&gt; Duas medições minhas foram para o lixo por isso.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amostra de um não mede nada.&lt;/strong&gt; Registrei como lição que o compressor de imagens não gerava formato moderno para miniaturas. Uma semana depois conferi mês a mês e estava errado: ele gera. Minha conclusão tinha saído de um único arquivo, e esse arquivo era de um lote que nunca chegou a ser processado. Voltei e corrigi o registro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Campo é janela de 28 dias.&lt;/strong&gt; Nada do que se faz hoje aparece antes de semanas. No dia das mudanças o número de campo até piorou, porque a janela ainda carregava os dias ruins.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Onde chegou
&lt;/h2&gt;

&lt;p&gt;No laboratório, em celular: a home saiu de 93 para 97 e a matéria passou a carregar o maior elemento em 2,2 segundos, contra 2,4 a 2,6 antes. O bloqueio de renderização caiu de cerca de dois segundos para pouco mais de um. As imagens do acervo recente passaram a ser servidas em formato moderno, com 29% menos peso.&lt;/p&gt;

&lt;p&gt;O número que decide, o de campo, só será lido no começo de outubro. Até lá, não se mexe em mais nada, porque cada mudança nova suja a leitura.&lt;/p&gt;




&lt;p&gt;Se o assunto for útil, o portal fica em &lt;a href="https://diretonoticias.com.br" rel="noopener noreferrer"&gt;diretonoticias.com.br&lt;/a&gt; e a página de transparência explica quem o mantém e como ele se financia.&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>wordpress</category>
      <category>php</category>
      <category>performance</category>
    </item>
    <item>
      <title>Harness engineering doesn't mean building your own harness</title>
      <dc:creator>Tilde A. Thurium</dc:creator>
      <pubDate>Tue, 15 Sep 2026 01:04:48 +0000</pubDate>
      <link>https://dev.to/annthurium/harness-engineering-doesnt-mean-building-your-own-harness-16pk</link>
      <guid>https://dev.to/annthurium/harness-engineering-doesnt-mean-building-your-own-harness-16pk</guid>
      <description>&lt;p&gt;&lt;strong&gt;It means giving the agent enough context to do the right thing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For this week's Agent Factory podcast, I interviewed &lt;a href="https://www.linkedin.com/in/ryanlopopolo/" rel="noopener noreferrer"&gt;Ryan Lopopolo&lt;/a&gt;, the engineer who coined the term "agentic harness." &lt;/p&gt;

&lt;h3&gt;
  
  
  What's in the video
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;How to Stop Writing Code Manually:&lt;/strong&gt; Ryan explains how to sculpt smaller feedback loops into long-horizon agentic workflows via harness engineering&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Harness, Deconstructed:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/billyjacobson/" rel="noopener noreferrer"&gt;Billy Jacobson&lt;/a&gt; delivers a code walkthrough of a simple harness, exploring linear and closed-loop styles. &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The Three-Layer Stack:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/smithakolan/" rel="noopener noreferrer"&gt;Smitha Kolan&lt;/a&gt; breaks down how to use &lt;a href="https://blog.google/innovation-and-ai/models-and-research/gemini-models/3-8-flash-and-3-8-flash-cyber/" rel="noopener noreferrer"&gt;Gemini 3.8 Flash&lt;/a&gt;, &lt;a href="https://antigravity.google/docs/boost/" rel="noopener noreferrer"&gt;Antigravity Boost&lt;/a&gt;, and the &lt;a href="https://github.com/google/skills" rel="noopener noreferrer"&gt;Google Skills GitHub repo&lt;/a&gt; to configure memory, tools, and guardrails.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/F8EZJAm9iO8" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The thing that struck me was how many best practices for scaling software engineering teams also apply to coding agents.&lt;/p&gt;

&lt;p&gt;How much code are you writing manually these days? Let me know in the comments! &lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Google Just Closed Another Scraping Door. Here's the Cheap Way Around It.</title>
      <dc:creator>goodpa</dc:creator>
      <pubDate>Tue, 15 Sep 2026 01:00:43 +0000</pubDate>
      <link>https://dev.to/goodpa/google-just-closed-another-scraping-door-heres-the-cheap-way-around-it-37ck</link>
      <guid>https://dev.to/goodpa/google-just-closed-another-scraping-door-heres-the-cheap-way-around-it-37ck</guid>
      <description>&lt;h3&gt;
  
  
  Hook
&lt;/h3&gt;

&lt;p&gt;Google Search is rewriting organic result links to &lt;code&gt;google.com/goto?url=…&lt;/code&gt;. The destination isn't in the query string anymore — it's an opaque reference you can only resolve by asking Google (read the &lt;code&gt;Location&lt;/code&gt; header, don't follow the redirect). As of late August 2026, it shows up consistently when you're logged out or in private mode.&lt;/p&gt;

&lt;p&gt;If you build anything on top of search-result HTML, this is the latest rent increase. Google already removed &lt;code&gt;&amp;amp;num=100&lt;/code&gt; and tightened BotGuard/SearchGuard. The pattern is obvious: &lt;strong&gt;make naive SERP scraping slower, noisier, and easier to detect.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why cross-border sellers feel this first
&lt;/h3&gt;

&lt;p&gt;Solo sellers and small agencies are the most exposed, because SERP scraping is the cheapest tool we reach for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rank tracking for your own listings&lt;/li&gt;
&lt;li&gt;Keyword and demand research before sourcing&lt;/li&gt;
&lt;li&gt;Competitor price/title monitoring across marketplaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that is evil. But most of it was built on the assumption that reading a search page was free. That assumption is what's being revoked.&lt;/p&gt;

&lt;h3&gt;
  
  
  The three-tier response
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Tier 1 — Own your data first.&lt;/strong&gt; Your best rank signal isn't scraped — it's first-party. Search Console, your storefront analytics, and your marketplace's official APIs tell you what actually converts. Scraped rankings are a proxy; your own conversion data is ground truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 2 — Use official APIs where they exist.&lt;/strong&gt; Marketplaces, ad platforms, and logistics providers increasingly expose structured endpoints. They cost money and have limits, but they're stable, and stability is the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 3 — If you must scrape, do it like you're being audited.&lt;/strong&gt; Resolve links properly (read &lt;code&gt;Location&lt;/code&gt;, don't follow), rate-limit hard, cache aggressively, and log provenance for every field. Accept that this is an arms race you don't win — you just stay one revision behind.&lt;/p&gt;

&lt;h3&gt;
  
  
  The uncomfortable part
&lt;/h3&gt;

&lt;p&gt;Every anti-scraping move is really a pricing signal. Google isn't trying to stop you; it's trying to make you pay — in latency, in detection risk, in engineering hours. Once you price that in, a lot of "free" data turns out to be expensive.&lt;/p&gt;

&lt;p&gt;The sellers who win the next cycle won't be the best scraper operators. They'll be the ones whose growth doesn't collapse when a door closes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Takeaway
&lt;/h3&gt;

&lt;p&gt;Audit your stack this week and label every data source "owned / licensed / scraped." For each scraped source, name the official API or first-party signal that could replace it. You don't have to switch today — you just need to know which door is load-bearing before it closes.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>growth</category>
      <category>ecommerce</category>
      <category>ai</category>
    </item>
    <item>
      <title>I built a bilingual quote estimator that runs entirely in the browser</title>
      <dc:creator>Maxime Brodeur</dc:creator>
      <pubDate>Tue, 15 Sep 2026 00:46:26 +0000</pubDate>
      <link>https://dev.to/nexushubstudio/i-built-a-bilingual-quote-estimator-that-runs-entirely-in-the-browser-o28</link>
      <guid>https://dev.to/nexushubstudio/i-built-a-bilingual-quote-estimator-that-runs-entirely-in-the-browser-o28</guid>
      <description>&lt;p&gt;Many service websites make visitors send an email before giving them any price context. I wanted a smaller middle ground: show a useful ballpark estimate immediately, then let the visitor start a conversation with the details already organized.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;QuoteKit&lt;/strong&gt; for freelance developers, designers, and small studios.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the visitor can do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;choose a starting package, add-ons, extra pages, and a timeline;&lt;/li&gt;
&lt;li&gt;see an itemized estimate update instantly;&lt;/li&gt;
&lt;li&gt;switch between English and French;&lt;/li&gt;
&lt;li&gt;download a plain-text summary, print or save a PDF, or open a prepared email draft.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I kept it static
&lt;/h2&gt;

&lt;p&gt;The runtime is four files: &lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;styles.css&lt;/code&gt;, &lt;code&gt;config.js&lt;/code&gt;, and &lt;code&gt;app.js&lt;/code&gt;. It runs on static hosting with no backend, build step, account, API key, or runtime dependency.&lt;/p&gt;

&lt;p&gt;The business owner edits package names, prices, add-ons, currency, tax settings, recipient email, and default language in &lt;code&gt;config.js&lt;/code&gt;. The visitor's notes and contact details stay in the browser unless they choose to email, download, or print them.&lt;/p&gt;

&lt;p&gt;The email action uses &lt;code&gt;mailto:&lt;/code&gt; and opens a draft in the visitor's email client. It never sends automatically. I also label the total as an estimate so the page starts a pricing conversation instead of pretending to generate a binding quote.&lt;/p&gt;

&lt;p&gt;I used Codex as a coding collaborator for implementation and QA. The delivered page contains no AI model or external AI API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try the flow
&lt;/h2&gt;

&lt;p&gt;Live demo: &lt;a href="https://www.nexushub.nexus/studio/demos/quotekit" rel="noopener noreferrer"&gt;https://www.nexushub.nexus/studio/demos/quotekit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would especially value feedback from people who sell services online: does an instant ballpark estimate qualify a lead, or does it anchor the conversation too early?&lt;/p&gt;

&lt;p&gt;For anyone who wants to adapt it for their own business or client projects, the editable source ZIP is &lt;strong&gt;$12 USD&lt;/strong&gt; with a reusable commercial buyer license. Delivery is by email within 24 hours: &lt;a href="https://buy.stripe.com/6oU4gA6SE9KPawh7hu4gg00" rel="noopener noreferrer"&gt;https://buy.stripe.com/6oU4gA6SE9KPawh7hu4gg00&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>freelance</category>
    </item>
    <item>
      <title>"Do you use AI?" is a process question. He answered a status question.</title>
      <dc:creator>Fuyuki0</dc:creator>
      <pubDate>Tue, 15 Sep 2026 00:40:05 +0000</pubDate>
      <link>https://dev.to/fuyuki0/do-you-use-ai-is-a-process-question-he-answered-a-status-question-1bfb</link>
      <guid>https://dev.to/fuyuki0/do-you-use-ai-is-a-process-question-he-answered-a-status-question-1bfb</guid>
      <description>&lt;p&gt;I saw someone tell this story recently, so I am going by their telling of it.&lt;/p&gt;

&lt;p&gt;They were in an interview. The interviewer asked: "do you use AI?"&lt;/p&gt;

&lt;p&gt;They took it badly. The way they told it, the question itself was out of&lt;br&gt;
line - an attempt to catch them out. So they answered with a question of&lt;br&gt;
their own: &lt;strong&gt;are you going to use a stove instead of a microwave? The world&lt;br&gt;
moves forward. They will stop making stoves eventually.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They told the story as a win. I do not think it was one, and it took me a&lt;br&gt;
while to work out why. It is not because using AI is wrong, or because&lt;br&gt;
answering back in an interview is wrong. It is that a specific and very&lt;br&gt;
common mistake is happening in that exchange, and I have made it myself.&lt;/p&gt;

&lt;h3&gt;
  
  
  They answered a question nobody asked
&lt;/h3&gt;

&lt;p&gt;"Do you use AI?" is a question about method. It has a boring, factual&lt;br&gt;
answer: yes, here, for these things, and I check it like this.&lt;/p&gt;

&lt;p&gt;What they heard was "are you a real engineer?" That is a question about&lt;br&gt;
status, and status questions feel like they need to be won rather than&lt;br&gt;
answered.&lt;/p&gt;

&lt;p&gt;The gap between those two readings is where the whole thing goes wrong. The&lt;br&gt;
interviewer asked about a tool. The candidate defended an identity. And once&lt;br&gt;
you are defending an identity, the actual content of your answer stops&lt;br&gt;
mattering to you - which is a shame, because it still matters to the person&lt;br&gt;
across the table.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the misread is reasonable
&lt;/h3&gt;

&lt;p&gt;It would be easy to say they were being oversensitive. I do not think that&lt;br&gt;
is fair, because the question genuinely has a charge on it now.&lt;/p&gt;

&lt;p&gt;"Do you use AI" in 2022 was small talk. Today it is a question people ask to&lt;br&gt;
find out which side you are on, and it gets asked from both directions.&lt;br&gt;
Somewhere there is an interviewer who wants to hear "no, I write everything&lt;br&gt;
myself" and somewhere there is another who wants to hear "yes, constantly,&lt;br&gt;
I ship three times faster". Both of those interviewers exist and neither of&lt;br&gt;
them is signposted.&lt;/p&gt;

&lt;p&gt;So the candidate is not paranoid. They are guessing which room they are&lt;br&gt;
standing in, under time pressure, with a job on the line. That is a real&lt;br&gt;
problem and it is worth naming rather than mocking.&lt;/p&gt;

&lt;p&gt;But guessing wrong has a cost, and the cost here was the whole answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  The analogy argues against him
&lt;/h3&gt;

&lt;p&gt;This is the part I keep coming back to.&lt;/p&gt;

&lt;p&gt;Stove versus microwave is not old versus new. &lt;strong&gt;They are not the same&lt;br&gt;
appliance.&lt;/strong&gt; A microwave reheats things quickly and unevenly. A stove sears,&lt;br&gt;
reduces, browns, holds a temperature. Every professional kitchen has both,&lt;br&gt;
and nobody in one thinks the microwave is winning.&lt;/p&gt;

&lt;p&gt;So the analogy, chosen to prove that the interviewer was behind the times,&lt;br&gt;
quietly concedes the interviewer's point: what you actually want in a kitchen&lt;br&gt;
is somebody who knows which one this dish needs. That is precisely what the&lt;br&gt;
question was trying to find out.&lt;/p&gt;

&lt;p&gt;An analogy that feels like it ends the argument is worth checking twice. This&lt;br&gt;
one ends it in favour of the other person.&lt;/p&gt;

&lt;h3&gt;
  
  
  "The world moves forward" is a way of not answering
&lt;/h3&gt;

&lt;p&gt;The second half - "they will stop making stoves" - is an inevitability&lt;br&gt;
argument, and inevitability arguments have a particular smell in interviews.&lt;/p&gt;

&lt;p&gt;The question was about &lt;strong&gt;your practice&lt;/strong&gt;. The answer was about &lt;strong&gt;history's&lt;br&gt;
direction&lt;/strong&gt;. Those are not the same subject, and swapping one for the other&lt;br&gt;
is one of the oldest ways to avoid saying something specific.&lt;/p&gt;

&lt;p&gt;It also cannot be wrong, which is the problem. "Things will keep changing" is&lt;br&gt;
true in every possible world, so it tells the listener nothing about you. An&lt;br&gt;
interviewer is not collecting predictions. They are trying to work out what&lt;br&gt;
you will be like on a Tuesday when something breaks.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the boring answer would have sounded like
&lt;/h3&gt;

&lt;p&gt;Something like: "yes, daily. It writes most of the first draft. I read all of&lt;br&gt;
it, I am careful with anything touching auth or money, and I have been burned&lt;br&gt;
by it inventing a library function that did not exist, so I check the imports&lt;br&gt;
first now."&lt;/p&gt;

&lt;p&gt;That is not an impressive answer. It is specific, it admits a scar, and it&lt;br&gt;
shows a line. It would have taken twenty seconds and it answers the question&lt;br&gt;
that was actually asked.&lt;/p&gt;

&lt;p&gt;The instinct that specificity is weakness gets a lot of good engineers in&lt;br&gt;
trouble. In an interview, specificity is the entire product.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who can afford to fire back
&lt;/h3&gt;

&lt;p&gt;One more thing, and it is uncomfortable.&lt;/p&gt;

&lt;p&gt;Answering an interviewer with a rhetorical question is a status move, and&lt;br&gt;
status moves are priced. If you are senior, scarce, and the company needs you&lt;br&gt;
more than you need them, it reads as confidence and it often works. If you&lt;br&gt;
are not, the same words read as brittle.&lt;/p&gt;

&lt;p&gt;Nothing about that is fair. It is just how the room works, and it is worth&lt;br&gt;
knowing the price before you spend it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where the line actually is
&lt;/h3&gt;

&lt;p&gt;The line has quietly moved, and it is no longer usage.&lt;/p&gt;

&lt;p&gt;Nobody serious is being judged for using AI in 2026. What people are being&lt;br&gt;
judged on is where they put the check: what they read, what they refuse to&lt;br&gt;
ship without understanding, and whether they can tell when the output is&lt;br&gt;
confidently wrong.&lt;/p&gt;

&lt;p&gt;That is a much harder thing to interview for than yes or no, which is&lt;br&gt;
probably why interviewers keep reaching for the crude version of the&lt;br&gt;
question. If you get the crude version, answer the real one anyway. You will&lt;br&gt;
be the only candidate that day who does. :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>I Pinned 31 GitHub Actions to Commit SHAs. One Major Tag Was Two Versions Stale.</title>
      <dc:creator>James Joyner</dc:creator>
      <pubDate>Tue, 15 Sep 2026 00:39:08 +0000</pubDate>
      <link>https://dev.to/jjoyneriv/i-pinned-31-github-actions-to-commit-shas-one-major-tag-was-two-versions-stale-b13</link>
      <guid>https://dev.to/jjoyneriv/i-pinned-31-github-actions-to-commit-shas-one-major-tag-was-two-versions-stale-b13</guid>
      <description>&lt;p&gt;Yesterday I pinned 31 GitHub Actions to commit SHAs for a set of workflows I was packaging. Every SHA was resolved from the upstream repository rather than copied from a README or a tutorial, and the process turned up three things worth writing down — including one action whose &lt;code&gt;v3&lt;/code&gt; major tag is two full major versions behind its newest release.&lt;/p&gt;

&lt;p&gt;Here is how to pin correctly, without the API and without trusting anyone's blog post, and what the exercise found.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the SHA, not the tag
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;uses: actions/checkout@v7&lt;/code&gt; runs whatever commit the &lt;code&gt;v7&lt;/code&gt; tag points to &lt;em&gt;at the moment your job starts&lt;/em&gt;. The maintainer moves that tag for every patch release — which is the feature — and anyone who takes over the repository or a maintainer's account can move it too — which is the problem. A commit SHA cannot be moved. Pinning to it means the code that runs is the code you reviewed, until you change the pin.&lt;/p&gt;

&lt;p&gt;The convention is the SHA plus the release in a comment, so a human can still read the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1&lt;/span&gt; &lt;span class="c1"&gt;# v7.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependabot's &lt;code&gt;github-actions&lt;/code&gt; ecosystem updates both halves together, so pinning does not cost you updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resolving a SHA without the API
&lt;/h2&gt;

&lt;p&gt;The GitHub REST API is rate-limited to 60 unauthenticated requests an hour, and resolving one pin can take three calls (release → tag → annotated tag object). &lt;code&gt;git ls-remote&lt;/code&gt; over HTTPS has no such limit and needs no token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git ls-remote &lt;span class="nt"&gt;--tags&lt;/span&gt; https://github.com/actions/checkout | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'refs/tags/v7(\.0\.1)?(\^\{\})?$'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3d3c42e5aac5ba805825da76410c181273ba90b1    refs/tags/v7
3d3c42e5aac5ba805825da76410c181273ba90b1    refs/tags/v7.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two facts in two lines: the &lt;code&gt;v7&lt;/code&gt; major tag and the &lt;code&gt;v7.0.1&lt;/code&gt; release point at the same commit, so &lt;code&gt;v7&lt;/code&gt; currently &lt;em&gt;means&lt;/em&gt; 7.0.1, and that is the SHA to pin.&lt;/p&gt;

&lt;p&gt;One subtlety. Some projects use &lt;strong&gt;annotated&lt;/strong&gt; tags, which are objects of their own; &lt;code&gt;ls-remote&lt;/code&gt; then prints two lines for one tag — the tag object and, with a &lt;code&gt;^{}&lt;/code&gt; suffix, the commit it points to. You want the &lt;code&gt;^{}&lt;/code&gt; one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;006b7ce8314066bdf1765b4500370d40fa6917a3    refs/tags/v0.24.2
3ad7283483fc7af8ff2b4ea19663c2d5ca935e26    refs/tags/v0.24.2^{}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pin &lt;code&gt;3ad7283…&lt;/code&gt;, not &lt;code&gt;006b7ce…&lt;/code&gt;. A tag-object SHA in a &lt;code&gt;uses:&lt;/code&gt; line fails with "unable to resolve action" — a confusing error for a correct-looking pin.&lt;/p&gt;

&lt;p&gt;I wrapped this in a short script: for each repository, take the highest &lt;code&gt;vN&lt;/code&gt; tag, its peeled commit, and whichever &lt;code&gt;vX.Y.Z&lt;/code&gt; tag shares that commit. Thirty-one actions in about a minute.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the exercise found
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. A major tag that is two majors stale.&lt;/strong&gt; &lt;code&gt;actions/dependency-review-action@v3&lt;/code&gt; resolves to a commit with no &lt;code&gt;v3.x.y&lt;/code&gt; release tag at all — the newest release is &lt;code&gt;v5.0.0&lt;/code&gt;. The &lt;code&gt;v3&lt;/code&gt; tag was never advanced to anything after v3's last patch, so anyone still on &lt;code&gt;@v3&lt;/code&gt; is on an unmaintained line and does not know it. Pin &lt;code&gt;v5.0.0&lt;/code&gt; (&lt;code&gt;a1d282b36b6f3519aa1f3fc636f609c47dddb294&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A major tag that lags its own releases.&lt;/strong&gt; &lt;code&gt;sigstore/cosign-installer@v3&lt;/code&gt; points at &lt;code&gt;v3.9.1&lt;/code&gt;; the newest release is &lt;code&gt;v4.1.2&lt;/code&gt;. Not wrong, but "I'm on the latest major" is a belief that a major tag does not support. Only the release list does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. No major tag at all.&lt;/strong&gt; &lt;code&gt;aquasecurity/trivy-action&lt;/code&gt; publishes only exact versions (&lt;code&gt;0.35.0&lt;/code&gt;), no floating &lt;code&gt;v0&lt;/code&gt;. A workflow written as &lt;code&gt;@master&lt;/code&gt; — and there are many — is pinned to a branch, the one thing worse than a tag.&lt;/p&gt;

&lt;p&gt;None of this is visible from inside a workflow file. It is visible in about a second from &lt;code&gt;ls-remote&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest of the checklist that goes with pins
&lt;/h2&gt;

&lt;p&gt;Pinning is one line of a security posture, and on its own it is the least important line. The workflows I was packaging apply the same six things everywhere, and if you copy nothing else from this post, copy this block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;              &lt;span class="c1"&gt;# read-only by default; widen per job, never here&lt;/span&gt;

&lt;span class="na"&gt;concurrency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ci-${{ github.workflow }}-${{ github.ref }}&lt;/span&gt;
  &lt;span class="na"&gt;cancel-in-progress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event_name == 'pull_request' }}&lt;/span&gt;   &lt;span class="c1"&gt;# cancel CI, never a deploy&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1&lt;/span&gt; &lt;span class="c1"&gt;# v7.0.1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;persist-credentials&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;   &lt;span class="c1"&gt;# the token is not written to .git/config&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use a branch name safely&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;REF&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.head_ref }}&lt;/span&gt;  &lt;span class="c1"&gt;# context values go through env…&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "building $REF"&lt;/span&gt;      &lt;span class="c1"&gt;# …never interpolated into the script&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the two rules that are about &lt;em&gt;events&lt;/em&gt;, not syntax: nothing that publishes or deploys runs on &lt;code&gt;pull_request&lt;/code&gt;, and &lt;code&gt;pull_request_target&lt;/code&gt; is not used at all. A fork's pull request gets a read-only token and no secrets — GitHub enforces that — but only if you never reach for the trigger that gives it your secrets back.&lt;/p&gt;

&lt;p&gt;Each of those has a free lesson behind it — &lt;a href="https://moderngitacademy.com/github-actions/security/pinning-actions/" rel="noopener noreferrer"&gt;pinning&lt;/a&gt;, &lt;a href="https://moderngitacademy.com/github-actions/security/least-privilege-permissions/" rel="noopener noreferrer"&gt;least-privilege permissions&lt;/a&gt;, &lt;a href="https://moderngitacademy.com/github-actions/security/workflow-security/" rel="noopener noreferrer"&gt;workflow security&lt;/a&gt; — and a lab where you find all of them missing from a workflow that looks fine: &lt;a href="https://moderngitacademy.com/labs/secure-unsafe-workflow/" rel="noopener noreferrer"&gt;secure an unsafe workflow&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the 31 pins ended up
&lt;/h2&gt;

&lt;p&gt;The workflows were for a product I released yesterday: the &lt;a href="https://moderngitacademy.com/products/github-actions-workflow-vault/" rel="noopener noreferrer"&gt;GitHub Actions Production Workflow Vault&lt;/a&gt; — twenty workflows (CI for Python, Node, Go, Java and .NET; Docker build-and-test, GHCR and multi-arch publishing; Terraform PR validation; Ansible with Molecule; CodeQL, dependency review, gitleaks, SBOM and attestations; release, Pages, Kubernetes; AWS, Azure and GCP via OIDC), three reusable workflows and a composite action, with every one of those six rules applied and the full pin table in the docs, verification method included. It is $19.99 once, no subscription, and it comes with the honest caveat that no workflow works unmodified — every file marks what to change.&lt;/p&gt;

&lt;p&gt;If you would rather do it yourself, the &lt;code&gt;ls-remote&lt;/code&gt; command above and the six lines of YAML are the whole method. Pin today; let Dependabot keep it current.&lt;/p&gt;

</description>
      <category>github</category>
      <category>devops</category>
      <category>security</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Part 1 - The Why: Why Architecture Matters on the Frontend</title>
      <dc:creator>Jorge Castillo</dc:creator>
      <pubDate>Tue, 15 Sep 2026 00:38:27 +0000</pubDate>
      <link>https://dev.to/schorts99/part-1-thw-why-why-architecture-matters-on-the-frontend-5586</link>
      <guid>https://dev.to/schorts99/part-1-thw-why-why-architecture-matters-on-the-frontend-5586</guid>
      <description>&lt;p&gt;Most modern React applications start out as triumphs of developer velocity. You spin up a project with Vite, pull in a few UI libraries, throw together some &lt;code&gt;useEffect&lt;/code&gt; hooks, and ship features in hours. But as team size grows and feature complexity scales, that initial speed decays into structural inertia.  &lt;/p&gt;

&lt;p&gt;Suddenly, simple UI tweaks break unrelated business workflows, refactoring network calls requires rewriting component tests, and adding a new state variable feels like diffusing a bomb.  &lt;/p&gt;

&lt;p&gt;This degradation isn't caused by bad developers or missing framework features—it is the direct consequence of accidental coupling. In this first installment of our series, we unpack why unmanaged dependencies destroy frontend maintainability, analyze the true cost of framework lock-in, and introduce the core rules that keep your domain logic bulletproof over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛑 The "Fat Component" Anti-Pattern
&lt;/h2&gt;

&lt;p&gt;In typical React applications, components naturally become magnets for every operational concern in the system. Consider a standard component responsible for checking out a shopping cart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Accidental Coupling: Everything living inside the UI layer&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CheckoutButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cartId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;cartId&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="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="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="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleCheckout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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="nf"&gt;setLoading&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="c1"&gt;// 1. Fetching raw data directly from an API endpoint&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/carts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cartId&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Business Rule: Carts over $100 get free shipping, but require a minimum of 2 items&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;shippingFee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&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;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;shippingFee&lt;/span&gt; &lt;span class="o"&gt;=&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="c1"&gt;// 3. Interfacing with local storage caching directly&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;last_checkout_total&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;shippingFee&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Executing payment network mutation&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/checkout&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cartId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;shippingFee&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;setLoading&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleCheckout&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Processing...&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;Checkout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When UI components coordinate HTTP requests, evaluate domain rules, mutate local browser storage, and manage rendering logic simultaneously, you incur severe architectural liabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework Lock-in:&lt;/strong&gt; Your core business calculations (e.g., shipping rules) are tangled directly inside React lifecycle hooks and synthetic event handlers. Switching frameworks or reusing logic outside React becomes impossible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brittle Testing:&lt;/strong&gt; To test whether the shipping rule works, you can't simply run a 2-millisecond unit test. You must mock &lt;code&gt;fetch&lt;/code&gt;, mock &lt;code&gt;localStorage&lt;/code&gt;, render a React DOM node, and simulate user clicks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Schema Leakage:&lt;/strong&gt; When backend API response schemas change, your presentation code breaks instantly across dozens of UI components.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💸 The High Cost of UI-Centric Architecture
&lt;/h2&gt;

&lt;p&gt;Why do codebases decay so rapidly when business logic lives inside presentation components? Let's break down the technical debt multiplier:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem Domain&lt;/th&gt;
&lt;th&gt;UI-Centric Approach&lt;/th&gt;
&lt;th&gt;Clean Architecture Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Testing Overhead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Heavy reliance on JSDOM, React Testing Library, and complex mock providers.&lt;/td&gt;
&lt;td&gt;Fast unit tests in pure TypeScript without DOM or network dependencies.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Instability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Breaking API payload changes require sweeping refactors across UI components.&lt;/td&gt;
&lt;td&gt;Mappers isolate external API contracts from internal domain entities.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Management Drift&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Logic gets duplicated across React state, Redux, Zustand, and query caches.&lt;/td&gt;
&lt;td&gt;Application state logic is centralized inside explicit Use Cases.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Framework Upgrades&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Major React version jumps or migration to SSR risk breaking business rules.&lt;/td&gt;
&lt;td&gt;Core business rules have zero dependencies on React or any third-party framework.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  🎯 The Core Architectural Principle: The Dependency Rule
&lt;/h2&gt;

&lt;p&gt;To eliminate accidental coupling, we apply the Dependency Rule, the central pillar of Clean Architecture:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Source code dependencies must point inward, toward high-level policies.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TB
    subgraph UI["UI &amp;amp; Frameworks&amp;lt;br/&amp;gt;(React, Browser APIs, HTTP)"]
        direction TB
    end

    UI -.-&amp;gt; Outer["Outer Layer (Volatile)"]
    UI --&amp;gt; Adapters

    subgraph Adapters["Infrastructure Adapters&amp;lt;br/&amp;gt;(Fetch Client, IndexedDB, LocalStorage)"]
        direction TB
    end

    Adapters -.-&amp;gt; AdapterLabel["Adapter Layer"]
    Adapters --&amp;gt; UseCases

    subgraph UseCases["Application Use Cases&amp;lt;br/&amp;gt;(Commands &amp;amp; Queries)"]
        direction TB
    end

    UseCases -.-&amp;gt; Orchestration["Orchestration"]
    UseCases --&amp;gt; Core

    subgraph Core["Core Domain&amp;lt;br/&amp;gt;(Entities &amp;amp; Business Rules)"]
        direction TB
    end

    Core -.-&amp;gt; Inner["Inner Layer (Stable)"]

    style UI fill:#f9f9f9,stroke:#333,stroke-width:2px
    style Adapters fill:#e8f4f8,stroke:#333,stroke-width:2px
    style UseCases fill:#e8f8e8,stroke:#333,stroke-width:2px
    style Core fill:#f8e8e8,stroke:#333,stroke-width:2px&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  The Inviolable Rule
&lt;/h3&gt;

&lt;p&gt;Nothing in an inner layer can know anything about something in an outer layer.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Domain Layer&lt;/strong&gt; (Entities, Value Objects) knows nothing about Use Cases, REST APIs, or React.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Application Layer&lt;/strong&gt; (Use Cases, Ports) knows nothing about React components or specific database drivers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Presentation &amp;amp; Infrastructure Layers&lt;/strong&gt; (React UI, Axios, IndexedDB) depend inward on abstract interfaces defined by the application layer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By forcing dependencies to point strictly inward, your core business rules become completely decoupled from UI frameworks, state management libraries, and external APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔄 Inversion of Control in Action
&lt;/h2&gt;

&lt;p&gt;How does an inner layer trigger an operation (like fetching a record or storing a token) without knowing about the concrete driver executing it? Through &lt;strong&gt;Inversion of Control (IoC)&lt;/strong&gt; via &lt;strong&gt;Ports &amp;amp; Adapters&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;Instead of importing an HTTP client directly inside a business rule, the Application layer defines an abstract Port (an interface):&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;// 1. Application Port (Owned by the core application)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ICartRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cartId&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cart&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;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&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;The outer Infrastructure layer implements this port via an &lt;strong&gt;Adapter&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="c1"&gt;// 2. Infrastructure Adapter (Outer layer)&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;ApiCartRepository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;ICartRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cartId&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cart&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/carts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cartId&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;CartMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDomain&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="c1"&gt;// Maps API schema to pure Domain Entity&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&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;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/checkout&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CartMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cart&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;Because the core domain relies solely on the &lt;code&gt;ICartRepository&lt;/code&gt; interface, you can swap &lt;code&gt;ApiCartRepository&lt;/code&gt; for an &lt;code&gt;InMemoryCartRepository&lt;/code&gt; during testing or an &lt;code&gt;IndexedDBCartRepository&lt;/code&gt; for offline support without modifying a single line of business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧪 Testing as an Architectural Indicator
&lt;/h2&gt;

&lt;p&gt;One of the most immediate feedback loops of a Clean Architecture setup is test suite velocity.&lt;/p&gt;

&lt;p&gt;When your business logic is decoupled from React and browser APIs, testing a complex domain feature doesn't require launching a headless browser or mounting virtual DOM trees.&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;// ✅ Pure Unit Test: Zero DOM, zero network mocks, runs in milliseconds&lt;/span&gt;
&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cart Shipping Calculation&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should apply free shipping for orders over $100 with at least 2 items&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="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;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;itemA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;itemB&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;totalAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calculateShippingFee&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&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;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should charge shipping for orders over $100 with less than 2 items&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="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;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;itemA&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;totalAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calculateShippingFee&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&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;Because this test interacts purely with TypeScript domain objects, hundreds of business rule scenarios can execute in a fraction of a second in your CI/CD pipeline—giving your team instant feedback without test flakiness.&lt;/p&gt;

&lt;h2&gt;
  
  
  📢 Up Next...
&lt;/h2&gt;

&lt;p&gt;Decoupling logic from the UI sounds great in theory, but how do you physically organize a codebase to enforce these boundaries without falling into folder chaos?  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coming up next in Part 2: The How — Architectural Layers &amp;amp; Domain-Driven Design&lt;/strong&gt;. We will examine how to structure a domain-driven codebase in strict TypeScript, build pure Domain Entities and Value Objects, and implement CQRS workflows using application-owned ports.  &lt;/p&gt;

&lt;p&gt;Explore the reference implementation anytime on GitHub:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/schorts99/React-Clean-Architecture" rel="noopener noreferrer"&gt;github.com/schorts99/React-Clean-Architecture&lt;/a&gt;&lt;/p&gt;

</description>
      <category>software</category>
      <category>cleancode</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Forecasting the NFL GOAT QB with Artificial Intelligence: The 2026 Update</title>
      <dc:creator>Bart Czernicki</dc:creator>
      <pubDate>Tue, 15 Sep 2026 00:37:29 +0000</pubDate>
      <link>https://dev.to/bartczernicki/forecasting-the-nfl-goat-qb-with-artificial-intelligence-the-2026-update-38e0</link>
      <guid>https://dev.to/bartczernicki/forecasting-the-nfl-goat-qb-with-artificial-intelligence-the-2026-update-38e0</guid>
      <description>&lt;p&gt;Last year I wrote an article that used an AI system to research and predict the probability of Patrick Mahomes surpassing Tom Brady as the greatest NFL quarterback. Last year's &lt;a href="https://dev.to/bartczernicki/forecasting-the-goat-with-artificial-intelligence-n88"&gt;Forecasting the NFL GOAT Quarterback with Artificial Intelligence&lt;/a&gt; put Patrick Mahomes' chance of eventually surpassing Tom Brady at &lt;strong&gt;30%&lt;/strong&gt;. The approach used ChatGPT's AI deep research, career projections, and a judgment about how fans and analysts might ultimately compare their legacies.&lt;/p&gt;

&lt;p&gt;Part 1 introduced the research concepts and their limitations. This follow-up concentrates on what changed, makes the probability calculation explicit, and refreshes the same ten career metrics.&lt;/p&gt;

&lt;p&gt;A few notes before reading the AI analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This year I updated the analysis after the 2025-2026 season, before Kansas City's Monday Night Football game. Why the wait? As you may note, Patrick Mahomes is coming off of a major injury and I wanted to have an accurate sense of the latest information. Information cutoff: September 14, 2026, before Kansas City's season opener. Career statistics include the completed 2025 NFL season; recovery and roster information extend through this cutoff. No performance from Kansas City's 2026 opener enters the analysis.&lt;/li&gt;
&lt;li&gt;The 2026 updated assessment uses agentic OpenAI Codex (Deep Research doesn't exist anymore) as the research harness.&lt;/li&gt;
&lt;li&gt;Now that we have two data points, I asked AI to create a chart. It added an assumption sensitivity range alongside the point estimate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: Everything below this line has been generated by OpenAI's Codex AI system using GPT-6-Astra (Ultra mode).&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed after the 2025 season?
&lt;/h2&gt;

&lt;p&gt;Mahomes finished 2025 with &lt;strong&gt;3,587 passing yards, 22 touchdowns, 11 interceptions, and an 89.6 passer rating in 14 games&lt;/strong&gt;. &lt;a href="https://www.nfl.com/players/patrick-mahomes/stats/career" rel="noopener noreferrer"&gt;NFL career statistics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;His career now stands at &lt;strong&gt;35,939 regular-season passing yards and 267 touchdowns&lt;/strong&gt;. The championship and postseason baselines did not advance: three Super Bowl wins, three Super Bowl MVPs, a 17–4 playoff record, and 46 playoff touchdown passes. &lt;a href="https://www.chiefs.com/team/players-roster/patrick-mahomes/" rel="noopener noreferrer"&gt;Chiefs player biography&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kansas City finished &lt;strong&gt;6–11&lt;/strong&gt;, scoring 362 points and allowing 328. That &lt;strong&gt;+34 differential&lt;/strong&gt; complicates any simple claim that the team had collapsed. The Chiefs also went &lt;strong&gt;1–9 in games decided by eight points or fewer&lt;/strong&gt;. Those totals reconcile against the &lt;a href="https://www.chiefs.com/schedule/2025/" rel="noopener noreferrer"&gt;completed schedule&lt;/a&gt; and the team's &lt;a href="https://www.chiefs.com/news/five-things-to-watch-on-monday-broncos-vs-chiefs" rel="noopener noreferrer"&gt;season-opening preview&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My interpretation is that another poor year is possible, but the win-loss record alone overstates the evidence for permanent decline. A rebound in close games is plausible; it is not guaranteed.&lt;/p&gt;

&lt;p&gt;The larger new uncertainty is physical. Mahomes injured his left knee in the December 14 loss to the Chargers that eliminated Kansas City. He underwent surgery the next day; NFL reporting identified repairs to both the ACL and LCL. The team was already losing its postseason opportunity when the injury occurred, so the entire season cannot be attributed to his absence. &lt;a href="https://amp.nfl.com/news/chiefs-qb-patrick-mahomes-undergoes-successful-surgery-to-repair-acl-lcl" rel="noopener noreferrer"&gt;NFL surgery report&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also encouraging current evidence. The September 12 injury report records full participation with no game designation, and the NFL reports that Mahomes is cleared to start against Denver. Clearance resolves availability for the opener; it does not establish restored mobility or years of future durability. &lt;a href="https://www.chiefs.com/news/week-1-injury-report-broncos-vs-chiefs-2026" rel="noopener noreferrer"&gt;Chiefs injury report&lt;/a&gt;, &lt;a href="https://amp.nfl.com/news/chiefs-qb-patrick-mahomes-knee-has-no-injury-status-cleared-for-comeback-monday-night-vs-broncos" rel="noopener noreferrer"&gt;NFL return update&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The surrounding team has changed, too. Eric Bieniemy returned as offensive coordinator, Travis Kelce returned for 2026, and Kansas City added Kenneth Walker while trading Trent McDuffie. These moves create plausible improvement paths and new uncertainties. They do not establish how competitive the roster will be a decade from now. &lt;a href="https://www.chiefs.com/news/chiefs-name-eric-bieniemy-as-offensive-coordinator" rel="noopener noreferrer"&gt;Coaching announcement&lt;/a&gt;, &lt;a href="https://www.chiefs.com/news/travis-kelce-to-return-for-14th-season" rel="noopener noreferrer"&gt;Kelce announcement&lt;/a&gt;, &lt;a href="https://www.chiefs.com/news/catching-up-on-the-chiefs-roster-moves-as-the-nfl-league-year-begins-x3713" rel="noopener noreferrer"&gt;roster transactions&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Updated career projections
&lt;/h2&gt;

&lt;p&gt;The career projections summarize the &lt;strong&gt;central scenarios and weights explained below&lt;/strong&gt;. For every metric, I assign an illustrative average within each scenario, then calculate its weighted average. These profiles are assumptions, not empirical estimates of quarterback aging.&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%2Fr2wxz3t3dw8i3z26fp5t.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%2Fr2wxz3t3dw8i3z26fp5t.png" alt="Updated career table compares Brady's final totals with Mahomes' scenario-weighted projections across ten metrics." width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Historical baselines: &lt;a href="https://www.chiefs.com/team/players-roster/patrick-mahomes/" rel="noopener noreferrer"&gt;Chiefs biography&lt;/a&gt;, &lt;a href="https://amp.nfl.com/news/tom-brady-retirement-23-seasons-in-nfl-buccaneers-patriots" rel="noopener noreferrer"&gt;NFL Brady retirement summary&lt;/a&gt;, and &lt;a href="https://www.statmuse.com/nfl/ask/brady-mahomes-playoff-record" rel="noopener noreferrer"&gt;postseason comparison&lt;/a&gt;. Mahomes' Pro Bowl total remains six; the &lt;a href="https://www.chiefs.com/news/four-chiefs-named-to-the-2026-pro-bowl-games" rel="noopener noreferrer"&gt;2026 announcement&lt;/a&gt; lists him as an alternate.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning the GOAT question into explicit scenarios
&lt;/h2&gt;

&lt;p&gt;The question remains: &lt;strong&gt;When Mahomes' career is over, how likely is broad agreement among fans and analysts that he ranks above Brady?&lt;/strong&gt; There is no official GOAT award or fixed voting population. The forecast describes an eventual legacy judgment, not simply the probability of winning eight championships.&lt;/p&gt;

&lt;p&gt;I divide the remaining possibilities into four mutually exclusive groups based on final Super Bowl wins. Each receives a weight and a conditional chance of achieving consensus GOAT status. The latter considers the wider career profile, including awards, longevity, production, and playoff performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every weight and conditional probability below is a judgment call.&lt;/strong&gt; The sources establish the evidence; they do not supply these percentages. This is a reproducible scenario assessment, not a fitted statistical model or a Monte Carlo simulation.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Final Super Bowl wins&lt;/th&gt;
&lt;th&gt;Illustrative remaining seasons&lt;/th&gt;
&lt;th&gt;Scenario weight&lt;/th&gt;
&lt;th&gt;GOAT chance within scenario&lt;/th&gt;
&lt;th&gt;Contribution to total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3–4&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;60%&lt;/td&gt;
&lt;td&gt;2%&lt;/td&gt;
&lt;td&gt;1.2 percentage points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;6.0 percentage points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;td&gt;60%&lt;/td&gt;
&lt;td&gt;6.6 percentage points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7+&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;5%&lt;/td&gt;
&lt;td&gt;90%&lt;/td&gt;
&lt;td&gt;4.5 percentage points&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;3–4-title group&lt;/strong&gt; receives the largest weight because a lost postseason opportunity, uncertain sustained recovery, and finite career length make repeated future championships difficult. It includes early retirement as well as long careers with limited further team success. Seven remaining seasons is an illustrative average, not a minimum.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;five-title group&lt;/strong&gt; assumes a successful return, about another decade of play, and two additional championships. That would create a serious GOAT argument, while leaving a substantial championship gap.&lt;/p&gt;

&lt;p&gt;The illustrative &lt;strong&gt;six-title and seven-plus profiles&lt;/strong&gt; assume increasingly exceptional longevity and repeated championship contention. Their careers extend into the early or mid-forties; the titles could also arrive sooner. Even seven titles do not mechanically settle a debate about eras, supporting casts, and individual performance.&lt;/p&gt;

&lt;p&gt;This still assigns &lt;strong&gt;40% to at least two more championships&lt;/strong&gt;, &lt;strong&gt;16% to at least three&lt;/strong&gt;, and &lt;strong&gt;5% to at least four&lt;/strong&gt;. It retains considerable upside, informed by Mahomes' established postseason ceiling and the possibility of a strong recovery. The evidence supports those possibilities; the exact allocations remain contestable.&lt;/p&gt;

&lt;p&gt;The conditional approach keeps achievements connected: the strongest championship outcomes also carry longer careers and stronger statistical profiles. It avoids treating recovery, playoff appearances, awards, and titles as independent events.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would change the forecast next?
&lt;/h2&gt;

&lt;p&gt;A sustained return to effective movement, strong passing production, and reliable availability would support shifting weight toward the upper scenarios. So would evidence that the offense can remain productive as personnel change. One impressive game would provide much less information than a healthy, effective season.&lt;/p&gt;

&lt;p&gt;Persistent limitations, further missed time, or declining effectiveness would push weight toward the lower group. Another missed postseason would consume another championship opportunity, although the underlying performance would still matter when assessing future prospects.&lt;/p&gt;

&lt;p&gt;A championship would directly change the starting point. It would also justify rebuilding the scenario distribution instead of adding a fixed number of percentage points. Awards and postseason efficiency would help distinguish team success from Mahomes' individual contribution.&lt;/p&gt;

&lt;p&gt;Sources and reproducibility&lt;/p&gt;

&lt;p&gt;Sources were checked September 14, 2026, subject to the pre-opener cutoff.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bart Czernicki, &lt;a href="https://dev.to/bartczernicki/forecasting-the-goat-with-artificial-intelligence-n88"&gt;Part 1&lt;/a&gt;, March 11, 2025; edited March 14.&lt;/li&gt;
&lt;li&gt;Chiefs and NFL, &lt;a href="https://www.chiefs.com/team/players-roster/patrick-mahomes/" rel="noopener noreferrer"&gt;Mahomes biography&lt;/a&gt; and &lt;a href="https://www.nfl.com/players/patrick-mahomes/stats/career" rel="noopener noreferrer"&gt;season statistics&lt;/a&gt;, historical tables.&lt;/li&gt;
&lt;li&gt;Chiefs, &lt;a href="https://www.chiefs.com/schedule/2025/" rel="noopener noreferrer"&gt;2025 schedule&lt;/a&gt;, historical table; &lt;a href="https://www.chiefs.com/news/five-things-to-watch-on-monday-broncos-vs-chiefs" rel="noopener noreferrer"&gt;Week 1 preview&lt;/a&gt;, September 13, 2026.&lt;/li&gt;
&lt;li&gt;NFL, &lt;a href="https://amp.nfl.com/news/chiefs-qb-patrick-mahomes-undergoes-successful-surgery-to-repair-acl-lcl" rel="noopener noreferrer"&gt;surgery report&lt;/a&gt;, December 15, 2025; &lt;a href="https://amp.nfl.com/news/chiefs-qb-patrick-mahomes-knee-has-no-injury-status-cleared-for-comeback-monday-night-vs-broncos" rel="noopener noreferrer"&gt;return update&lt;/a&gt;, September 12, 2026.&lt;/li&gt;
&lt;li&gt;Chiefs, &lt;a href="https://www.chiefs.com/news/week-1-injury-report-broncos-vs-chiefs-2026" rel="noopener noreferrer"&gt;injury report&lt;/a&gt;, September 12, 2026.&lt;/li&gt;
&lt;li&gt;Chiefs, &lt;a href="https://www.chiefs.com/news/chiefs-name-eric-bieniemy-as-offensive-coordinator" rel="noopener noreferrer"&gt;Bieniemy appointment&lt;/a&gt;, January 23; &lt;a href="https://www.chiefs.com/news/travis-kelce-to-return-for-14th-season" rel="noopener noreferrer"&gt;Kelce return&lt;/a&gt;, March 11; &lt;a href="https://www.chiefs.com/news/catching-up-on-the-chiefs-roster-moves-as-the-nfl-league-year-begins-x3713" rel="noopener noreferrer"&gt;roster moves&lt;/a&gt;, updated through March 20, 2026.&lt;/li&gt;
&lt;li&gt;Kevin Patra, NFL, &lt;a href="https://amp.nfl.com/news/tom-brady-retirement-23-seasons-in-nfl-buccaneers-patriots" rel="noopener noreferrer"&gt;Brady retirement summary&lt;/a&gt;, February 1, 2023; StatMuse, &lt;a href="https://www.statmuse.com/nfl/ask/brady-mahomes-playoff-record" rel="noopener noreferrer"&gt;playoff comparison&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Chiefs, &lt;a href="https://www.chiefs.com/news/four-chiefs-named-to-the-2026-pro-bowl-games" rel="noopener noreferrer"&gt;Pro Bowl selections&lt;/a&gt;, December 23, 2025.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final probability assessment
&lt;/h2&gt;

&lt;p&gt;The updated assessment is &lt;strong&gt;approximately 18%&lt;/strong&gt;, with an &lt;strong&gt;8%–33% assumption sensitivity range&lt;/strong&gt;. That leaves a meaningful path to the top, but the central outlook is less favorable. These are subjective estimates, not measured frequencies or betting odds.&lt;/p&gt;

&lt;p&gt;The calculation is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P(GOAT) = Σ[P(scenario) × P(GOAT | scenario)]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(0.60 × 0.02) + (0.24 × 0.25) + (0.11 × 0.60) + (0.05 × 0.90) = 0.183&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That produces &lt;strong&gt;18.3%, rounded to 18%&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sensitivity of the estimate
&lt;/h3&gt;

&lt;p&gt;The arithmetic is exact given the assumptions. The assumptions are uncertain.&lt;/p&gt;

&lt;p&gt;For sensitivity analysis, I change both the distribution of football outcomes and the standards that might shape the eventual legacy judgment. Each row below follows the same scenario order: &lt;strong&gt;3–4 / 5 / 6 / 7+ titles&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Assumption case&lt;/th&gt;
&lt;th&gt;Scenario weights&lt;/th&gt;
&lt;th&gt;Conditional GOAT chances&lt;/th&gt;
&lt;th&gt;Calculated result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pessimistic&lt;/td&gt;
&lt;td&gt;72% / 20% / 6% / 2%&lt;/td&gt;
&lt;td&gt;1% / 15% / 45% / 80%&lt;/td&gt;
&lt;td&gt;8.02%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Central&lt;/td&gt;
&lt;td&gt;60% / 24% / 11% / 5%&lt;/td&gt;
&lt;td&gt;2% / 25% / 60% / 90%&lt;/td&gt;
&lt;td&gt;18.30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimistic&lt;/td&gt;
&lt;td&gt;45% / 28% / 17% / 10%&lt;/td&gt;
&lt;td&gt;4% / 35% / 70% / 95%&lt;/td&gt;
&lt;td&gt;33.00%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The resulting &lt;strong&gt;8%–33% assumption sensitivity range is not a confidence interval&lt;/strong&gt;. It does not mean a statistical procedure has located the true probability with a stated coverage rate. It shows how far the answer moves under these selected alternative judgments.&lt;/p&gt;

&lt;p&gt;Changing only the football scenario weights gives &lt;strong&gt;11.84%–27.10%&lt;/strong&gt;. Changing only the conditional legacy judgments gives &lt;strong&gt;13.15%–23.25%&lt;/strong&gt;. Both sources of uncertainty matter, and other reasonable assumptions could produce results outside the displayed range.&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%2F4bt90c31uxlpsqt8e1zb.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%2F4bt90c31uxlpsqt8e1zb.png" alt="Two horizontal bars compare the 2025 GOAT assessment of 30% with the 2026 estimate of 18%, with an 8%–33% assumption sensitivity range." width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Forecast&lt;/th&gt;
&lt;th&gt;Headline estimate&lt;/th&gt;
&lt;th&gt;Assumption sensitivity range&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2025, Part 1&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026, this update&lt;/td&gt;
&lt;td&gt;18%&lt;/td&gt;
&lt;td&gt;8%–33%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;The bars use rounded headline estimates: a decrease of 12 percentage points. The unrounded calculation changes by 11.7 points.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The 2025 estimate remains the original &lt;strong&gt;30%&lt;/strong&gt;; I have not reconstructed it using today's method. Consequently, this comparison reflects &lt;strong&gt;both new evidence and a methodological change&lt;/strong&gt;. It cannot isolate the effect of the 2025 season, demonstrate improved forecasting skill, or establish that last year's estimate was wrong. The eventual outcome remains unresolved.&lt;/p&gt;

&lt;p&gt;That is the practical value of this AI-assisted update: current evidence, visible assumptions, and calculations that can be inspected. Both the remaining football career and the eventual public judgment remain uncertain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My updated estimate of Mahomes eventually surpassing Brady as the consensus NFL GOAT quarterback is 18%.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>genai</category>
      <category>openai</category>
      <category>statistics</category>
    </item>
    <item>
      <title>Docker for Developers: Containers, Images, and Compose Explained</title>
      <dc:creator>Aditya Rawas</dc:creator>
      <pubDate>Tue, 15 Sep 2026 00:37:18 +0000</pubDate>
      <link>https://dev.to/rawas_aditya/docker-for-developers-containers-images-and-compose-explained-31pl</link>
      <guid>https://dev.to/rawas_aditya/docker-for-developers-containers-images-and-compose-explained-31pl</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://adityarawas.in/blog/docker-for-developers" rel="noopener noreferrer"&gt;adityarawas.in&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;If you've ever heard "works on my machine" — Docker is the solution. Docker lets you package your application and all its dependencies into a single unit called a &lt;strong&gt;container&lt;/strong&gt; that runs identically everywhere: your laptop, a teammate's Linux machine, or a cloud server.&lt;/p&gt;

&lt;p&gt;This guide explains containers from first principles, then walks through building, running, and composing Docker-based applications — with a real Node.js example throughout.&lt;/p&gt;




&lt;h2&gt;
  
  
  Containers vs Virtual Machines
&lt;/h2&gt;

&lt;p&gt;Before Docker, the standard way to isolate software environments was a &lt;strong&gt;Virtual Machine (VM)&lt;/strong&gt;. A VM emulates an entire computer — CPU, memory, disk, and a full operating system — on top of a hypervisor.&lt;/p&gt;

&lt;p&gt;Containers are fundamentally different:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Virtual Machine&lt;/th&gt;
&lt;th&gt;Docker Container&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OS&lt;/td&gt;
&lt;td&gt;Full guest OS per VM&lt;/td&gt;
&lt;td&gt;Shares host OS kernel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td&gt;Gigabytes&lt;/td&gt;
&lt;td&gt;Megabytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup&lt;/td&gt;
&lt;td&gt;Minutes&lt;/td&gt;
&lt;td&gt;Milliseconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Isolation&lt;/td&gt;
&lt;td&gt;Strong (hardware-level)&lt;/td&gt;
&lt;td&gt;Good (process-level)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;~10-15% overhead&lt;/td&gt;
&lt;td&gt;Near native&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A container is just a &lt;strong&gt;process&lt;/strong&gt; running on the host OS, isolated using two Linux kernel features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Namespaces&lt;/strong&gt; — isolate the process's view of the system (filesystem, network, PID, users)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cgroups&lt;/strong&gt; — limit the process's resource usage (CPU, memory, I/O)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Docker provides the tooling to create, run, and manage these containers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Core Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Images
&lt;/h3&gt;

&lt;p&gt;A Docker &lt;strong&gt;image&lt;/strong&gt; is a read-only template that defines everything needed to run your application: the OS base layer, runtime, dependencies, app code, and startup command.&lt;/p&gt;

&lt;p&gt;Images are built in &lt;strong&gt;layers&lt;/strong&gt;. Each instruction in a Dockerfile adds a layer on top of the previous one. Layers are cached and shared — if 10 images all use the same Node.js base layer, that layer is stored once on disk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Containers
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;container&lt;/strong&gt; is a running instance of an image. You can run many containers from the same image simultaneously. The container adds a thin writable layer on top of the image layers for any changes made at runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Image (read-only layers):
  ubuntu:22.04 base
  node:20 runtime
  npm install output
  app source code

Container (writable layer on top):
  runtime logs, temp files, etc.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Registry
&lt;/h3&gt;

&lt;p&gt;Images are stored in a &lt;strong&gt;registry&lt;/strong&gt;. Docker Hub is the default public registry. Private registries include AWS ECR, GitHub Container Registry, and Google Artifact Registry.&lt;/p&gt;




&lt;h2&gt;
  
  
  Installing Docker
&lt;/h2&gt;

&lt;p&gt;Download Docker Desktop from &lt;a href="https://www.docker.com/products/docker-desktop/" rel="noopener noreferrer"&gt;docker.com&lt;/a&gt;. It includes the Docker daemon, CLI, and Docker Compose.&lt;/p&gt;

&lt;p&gt;Verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# Docker version 27.x.x&lt;/span&gt;

docker run hello-world
&lt;span class="c"&gt;# Pulls the hello-world image and runs it — confirms Docker is working&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Essential Docker Commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Images&lt;/span&gt;
docker pull node:20-alpine       &lt;span class="c"&gt;# Download an image&lt;/span&gt;
docker images                    &lt;span class="c"&gt;# List local images&lt;/span&gt;
docker rmi node:20-alpine        &lt;span class="c"&gt;# Remove an image&lt;/span&gt;

&lt;span class="c"&gt;# Containers&lt;/span&gt;
docker run node:20-alpine node &lt;span class="nt"&gt;--version&lt;/span&gt;   &lt;span class="c"&gt;# Run a command in a container&lt;/span&gt;
docker run &lt;span class="nt"&gt;-it&lt;/span&gt; ubuntu bash                 &lt;span class="c"&gt;# Interactive terminal&lt;/span&gt;
docker ps                                  &lt;span class="c"&gt;# List running containers&lt;/span&gt;
docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;                               &lt;span class="c"&gt;# List all containers (including stopped)&lt;/span&gt;
docker stop &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                           &lt;span class="c"&gt;# Stop a container&lt;/span&gt;
docker &lt;span class="nb"&gt;rm&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                             &lt;span class="c"&gt;# Remove a stopped container&lt;/span&gt;

&lt;span class="c"&gt;# Logs and inspection&lt;/span&gt;
docker logs &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                           &lt;span class="c"&gt;# View container output&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; sh                    &lt;span class="c"&gt;# Shell into a running container&lt;/span&gt;
docker inspect &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                        &lt;span class="c"&gt;# Full container metadata&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Writing a Dockerfile
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Dockerfile&lt;/strong&gt; is a text file with instructions for building an image. Each instruction becomes a layer.&lt;/p&gt;

&lt;p&gt;Here's a production-ready Dockerfile for a Node.js application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: Install dependencies&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;deps&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json package-lock.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production

&lt;span class="c"&gt;# Stage 2: Build (if needed — e.g. TypeScript)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json package-lock.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Stage 3: Production image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;runner&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; NODE_ENV=production&lt;/span&gt;

&lt;span class="c"&gt;# Copy only what's needed&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=deps /app/node_modules ./node_modules&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/dist ./dist&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json ./&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "dist/index.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This uses a &lt;strong&gt;multi-stage build&lt;/strong&gt; — a critical pattern for production images:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;deps&lt;/code&gt; and &lt;code&gt;builder&lt;/code&gt; stages contain dev tools and source files&lt;/li&gt;
&lt;li&gt;The final &lt;code&gt;runner&lt;/code&gt; stage only has the compiled output and production dependencies&lt;/li&gt;
&lt;li&gt;The final image is dramatically smaller because the intermediate stages are discarded&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common Dockerfile Instructions
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Instruction&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FROM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Base image to build from&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WORKDIR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the working directory for subsequent instructions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;COPY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Copy files from host into the image&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RUN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Execute a command during build (creates a new layer)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ENV&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set environment variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EXPOSE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Document the port the app listens on (doesn't publish it)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CMD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Default command to run when the container starts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ENTRYPOINT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed command (CMD becomes arguments to it)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Building and Running Your Image
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build the image — tag it with -t&lt;/span&gt;
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; my-app:latest &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Run a container from it&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env-file&lt;/span&gt; .env &lt;span class="se"&gt;\&lt;/span&gt;
  my-app:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flags explained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-d&lt;/code&gt; — detached mode (runs in background)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--name my-app&lt;/code&gt; — give the container a name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p 3000:3000&lt;/code&gt; — map port 3000 on the host to port 3000 in the container&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--env-file .env&lt;/code&gt; — load environment variables from a file&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The &lt;code&gt;.dockerignore&lt;/code&gt; File
&lt;/h2&gt;

&lt;p&gt;Just like &lt;code&gt;.gitignore&lt;/code&gt;, a &lt;code&gt;.dockerignore&lt;/code&gt; file tells Docker what to exclude when copying files into the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules
.git
.env
dist
*.log
.DS_Store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always add &lt;code&gt;node_modules&lt;/code&gt; — if it's not ignored, Docker copies your local modules into the image before running &lt;code&gt;npm ci&lt;/code&gt;, which bloats the image and can cause platform-specific binary conflicts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Volumes: Persisting Data
&lt;/h2&gt;

&lt;p&gt;Containers are ephemeral — when a container is removed, all its data is gone. &lt;strong&gt;Volumes&lt;/strong&gt; solve this by mounting storage that lives outside the container lifecycle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Named volume — Docker manages the storage location&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; postgres-data:/var/lib/postgresql/data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret &lt;span class="se"&gt;\&lt;/span&gt;
  postgres:16

&lt;span class="c"&gt;# Bind mount — maps a host directory into the container (useful in development)&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/src:/app/src &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  my-app:dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;strong&gt;named volumes&lt;/strong&gt; in production (Docker manages them, they survive container restarts). Use &lt;strong&gt;bind mounts&lt;/strong&gt; in development (changes to host files are immediately reflected in the container).&lt;/p&gt;




&lt;h2&gt;
  
  
  Networking
&lt;/h2&gt;

&lt;p&gt;Containers can communicate with each other through Docker networks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a network&lt;/span&gt;
docker network create my-network

&lt;span class="c"&gt;# Connect containers to it&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--network&lt;/span&gt; my-network &lt;span class="nt"&gt;--name&lt;/span&gt; app my-app:latest
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--network&lt;/span&gt; my-network &lt;span class="nt"&gt;--name&lt;/span&gt; db postgres:16

&lt;span class="c"&gt;# Inside the app container, connect to Postgres using its container name as hostname&lt;/span&gt;
&lt;span class="c"&gt;# postgresql://db:5432/mydb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Containers on the same network can reach each other by &lt;strong&gt;container name&lt;/strong&gt; — Docker's internal DNS resolves them automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  Docker Compose: Multi-Container Applications
&lt;/h2&gt;

&lt;p&gt;Real applications have multiple services — a web server, a database, a cache. &lt;strong&gt;Docker Compose&lt;/strong&gt; lets you define and run all of them with a single file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.yml&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URL=postgresql://postgres:secret@db:5432/myapp&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL=redis://cache:6379&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
      &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_started&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./src:/app/src&lt;/span&gt;   &lt;span class="c1"&gt;# hot reload in development&lt;/span&gt;

  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres-data:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;postgres"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7-alpine&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis-data:/data&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;redis-data&lt;/span&gt;&lt;span class="pi"&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 shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;          &lt;span class="c"&gt;# Start all services in the background&lt;/span&gt;
docker compose logs &lt;span class="nt"&gt;-f&lt;/span&gt; app    &lt;span class="c"&gt;# Follow logs for the app service&lt;/span&gt;
docker compose down           &lt;span class="c"&gt;# Stop and remove containers&lt;/span&gt;
docker compose down &lt;span class="nt"&gt;-v&lt;/span&gt;        &lt;span class="c"&gt;# Also remove volumes (WARNING: deletes data)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup, a new developer on your team only needs to run &lt;code&gt;docker compose up&lt;/code&gt; to get a fully working local environment — no manual database installation, no version conflicts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer Caching: Making Builds Fast
&lt;/h2&gt;

&lt;p&gt;Docker caches each layer. If a layer's instruction and its inputs haven't changed, Docker reuses the cached layer instead of re-running the instruction. This makes rebuilds fast.&lt;/p&gt;

&lt;p&gt;The order of instructions matters — put the things that change least at the top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Good — dependencies rarely change, so this layer is cached on most rebuilds&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json package-lock.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci

&lt;span class="c"&gt;# Source code changes often — copy it after installing dependencies&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you copy the entire source first and then run &lt;code&gt;npm ci&lt;/code&gt;, every code change invalidates the npm install layer and triggers a full reinstall.&lt;/p&gt;




&lt;h2&gt;
  
  
  Production Best Practices
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use specific image tags, not &lt;code&gt;latest&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Bad — unpredictable, breaks builds when the image updates&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:latest&lt;/span&gt;

&lt;span class="c"&gt;# Good — deterministic builds&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:20.17-alpine3.20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run as a non-root user:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-S&lt;/span&gt; appgroup &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser &lt;span class="nt"&gt;-S&lt;/span&gt; appuser &lt;span class="nt"&gt;-G&lt;/span&gt; appgroup
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; appuser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Don't store secrets in images:&lt;/strong&gt; Use environment variables or secret management tools (AWS Secrets Manager, HashiCorp Vault). Never &lt;code&gt;COPY .env&lt;/code&gt; into an image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scan images for vulnerabilities:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker scout cves my-app:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Keep images small:&lt;/strong&gt; Use Alpine-based images (&lt;code&gt;node:20-alpine&lt;/code&gt; instead of &lt;code&gt;node:20&lt;/code&gt;). Alpine is ~5MB vs ~150MB for the Debian-based default. Use multi-stage builds to exclude build tools from the final image.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;container&lt;/strong&gt; is an isolated process — it shares the host OS kernel but has its own filesystem, network, and process space via Linux namespaces and cgroups.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Docker image&lt;/strong&gt; is a read-only stack of layers; a container adds a writable layer on top.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Dockerfile&lt;/strong&gt; defines how to build your image — put slow-changing layers (dependencies) before fast-changing ones (source code) to maximize cache hits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-stage builds&lt;/strong&gt; keep production images small by separating build-time tools from runtime output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volumes&lt;/strong&gt; persist data beyond a container's lifecycle — use named volumes in production, bind mounts in development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Compose&lt;/strong&gt; orchestrates multi-container applications with a single YAML file, making local development reproducible.&lt;/li&gt;
&lt;li&gt;Always use &lt;strong&gt;specific image tags&lt;/strong&gt;, &lt;strong&gt;non-root users&lt;/strong&gt;, and &lt;strong&gt;externalized secrets&lt;/strong&gt; in production.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The Paperclip That Arrived Twenty Years Too Early</title>
      <dc:creator>Alice Severi Gonçalves</dc:creator>
      <pubDate>Tue, 15 Sep 2026 00:37:14 +0000</pubDate>
      <link>https://dev.to/sothiss/the-paperclip-that-arrived-twenty-years-too-early-3k5m</link>
      <guid>https://dev.to/sothiss/the-paperclip-that-arrived-twenty-years-too-early-3k5m</guid>
      <description>&lt;p&gt;In the collective memory of personal computing, the conversation about Microsoft almost always circles back to a punchline. Someone brings up Windows Vista, someone else mentions Internet Explorer, and inevitably, everyone laughs about Clippy. &lt;/p&gt;

&lt;p&gt;They remember the googly eyes, the frantic tapping against the inside of the monitor glass, and that patronizing prompt: "&lt;em&gt;It looks like you’re writing a letter.&lt;/em&gt;" To a generation navigating Office 97 in high-pressure cubicles on tight deadlines, he was an infuriating digital backseat driver.  &lt;/p&gt;

&lt;p&gt;​My memory of that era has always looked fundamentally different. &lt;/p&gt;

&lt;p&gt;I grew up with the privilege of running fully licensed, retail installations of Windows rather than cracked, fragile builds. &lt;br&gt;
To a child sitting in front of Word 97, exploring an operating system purely out of curiosity, &lt;strong&gt;Clippit&lt;/strong&gt;—his actual, forgotten name—was never an irritation. &lt;/p&gt;

&lt;p&gt;He was an ambient companion who made the machine feel alive. &lt;/p&gt;

&lt;p&gt;It took me years to discover that the rest of the world hated him.&lt;br&gt;&lt;br&gt;
​Looking back with an understanding of software architecture, the tragedy of Clippit was not that the concept was foolish; it was that it was wildly premature. &lt;/p&gt;

&lt;p&gt;​Beneath the cartoon sprite lay Microsoft Research’s &lt;em&gt;Project Lumière&lt;/em&gt;—an astonishingly ambitious effort to apply Bayesian probability to real-time human intent. &lt;/p&gt;

&lt;p&gt;Decades before modern transformers, neural networks, or massive compute clusters, Microsoft attempted to build an agentic assistant that ran on single-core processors and sixteen megabytes of RAM. Clippit quietly observed keystrokes, calculated the statistical likelihood of your next action, and tried to surface relevant tools before you had to hunt through dense menus.  &lt;/p&gt;

&lt;p&gt;​Where Clippit collapsed was not in his algorithmic ambition, but in the fragile psychology of interface design. Leaning into social-actor theory—the idea that humans instinctively anthropomorphize interactive technology—Microsoft gave the assistant an expressive face and physical gestures. But an agent that interrupts your workflow with moderate probabilistic accuracy is infinitely more aggravating than a static toolbar.&lt;/p&gt;

&lt;p&gt;When Clippit guessed wrong, he did not fail discreetly. He broke your train of thought, seized the cursor, and demanded social bandwidth without possessing the semantic comprehension to earn it. &lt;br&gt;
He was an ambient agent stranded in an era of manual tools.&lt;/p&gt;

&lt;p&gt;​Clippit was not intelligent.&lt;/p&gt;

&lt;p&gt;He was not particularly accurate.&lt;/p&gt;

&lt;p&gt;He was often distracting.&lt;/p&gt;

&lt;p&gt;​And yet, looking back, I find it difficult to laugh at him. Not because he succeeded, but because he was attempting something that the technology of his era could not possibly support.  &lt;/p&gt;

&lt;p&gt;​The paperclip sitting beside a blank Word document in 1997 was trying to do something remarkably similar to what modern AI assistants are attempting today: understand intent, reduce friction, and help people work with&lt;br&gt;
technology in a more natural way. &lt;/p&gt;

&lt;p&gt;The difference is that Clippit was trying to achieve it with a fraction of the computing power, memory, data, and contextual awareness that modern systems take for granted.&lt;/p&gt;

&lt;p&gt;​For most people, Clippy became a joke. For Microsoft, he became a lesson. &lt;/p&gt;

&lt;p&gt;​The company spent the next three decades refining the same idea through different products and technological eras. &lt;strong&gt;Cortana&lt;/strong&gt; taught Microsoft that users prefer to ask for assistance rather than have it imposed on them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Copilot&lt;/strong&gt; is teaching Microsoft how critical context, memory, and restraint are when coexisting with a user's workflow.  &lt;/p&gt;

&lt;p&gt;​Seen from that perspective, Clippit was not a dead end. He was a prototype.&lt;/p&gt;

&lt;p&gt;​The paperclip failed so that future assistants could learn when to speak, when to remain silent, and how to fit naturally into the work people were already doing. Maybe that is why I still remember him so fondly. &lt;/p&gt;

&lt;p&gt;When I was a child sitting in front of Word 97, Clippit felt like a glimpse of the future. At the time, that future never quite arrived.&lt;br&gt;&lt;br&gt;
​&lt;br&gt;
Now, nearly thirty years later, I can open Word, work with Copilot, and watch an assistant help organize ideas, refine drafts, and recall context across past conversations. For the first time, that old vision feels technically possible.  &lt;/p&gt;

&lt;p&gt;​And the more I think about it, the harder it becomes to see Clippit as a failure.&lt;/p&gt;

&lt;p&gt;Perhaps he was simply the first draft.&lt;/p&gt;

&lt;p&gt;​&lt;strong&gt;About This Series&lt;/strong&gt;: &lt;em&gt;First Drafts of the Future&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;​Rather than cataloging Microsoft through missteps, this series re-examines the visionary ideas Microsoft conceptualized years—and sometimes decades—before the hardware, software architecture, or user culture was ready to sustain them.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>microsoft</category>
      <category>software</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
