<?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: Jose Rodriguez Marrero</title>
    <description>The latest articles on DEV Community by Jose Rodriguez Marrero (@amodelandme).</description>
    <link>https://dev.to/amodelandme</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3200326%2F45674360-07fa-4471-912c-67d45dcca873.png</url>
      <title>DEV Community: Jose Rodriguez Marrero</title>
      <link>https://dev.to/amodelandme</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amodelandme"/>
    <language>en</language>
    <item>
      <title>I Thought My Domain Entity Was Fine. A DDD Audit Said Otherwise.</title>
      <dc:creator>Jose Rodriguez Marrero</dc:creator>
      <pubDate>Thu, 30 Apr 2026 23:53:35 +0000</pubDate>
      <link>https://dev.to/amodelandme/i-thought-my-domain-entity-was-fine-a-ddd-audit-said-otherwise-2pi3</link>
      <guid>https://dev.to/amodelandme/i-thought-my-domain-entity-was-fine-a-ddd-audit-said-otherwise-2pi3</guid>
      <description>&lt;p&gt;I'm building &lt;strong&gt;Banderas&lt;/strong&gt;, an open-source feature flag management system for .NET teams on Azure. A few weeks in, I had a working API — CRUD endpoints, evaluation logic, integration tests, the works. Phase 1 was done.&lt;/p&gt;

&lt;p&gt;My entity bugged me. It just didn't look right. As I continue to study DDD, my eyes have started seeing things.&lt;/p&gt;

&lt;p&gt;Then I ran a DDD audit on my core domain entity, &lt;code&gt;Flag.cs&lt;/code&gt;. This was my first time running an audit like this using an agent. And this is also the first time that I'm being intentional in my DDD approach to this project. &lt;/p&gt;

&lt;p&gt;What I found was uncomfortable and illuminating: my entity wasn't really a domain entity. &lt;strong&gt;It was a database row wearing a domain costume.&lt;/strong&gt; This post is about what I found, why it mattered, and how I'm fixing it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Started With (yes, I know. Be gentle)
&lt;/h2&gt;

&lt;p&gt;Here's the original &lt;code&gt;Flag.cs&lt;/code&gt;, simplified slightly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Flag&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;EnvironmentType&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsEnabled&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsArchived&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsSeeded&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;RolloutStrategy&lt;/span&gt; &lt;span class="n"&gt;StrategyType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;StrategyConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;CreatedAt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;UpdatedAt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;ArchivedAt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;enabled&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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdateStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RolloutStrategy&lt;/span&gt; &lt;span class="n"&gt;strategyType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;strategyConfig&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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RolloutStrategy&lt;/span&gt; &lt;span class="n"&gt;strategyType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;strategyConfig&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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Archive&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the surface, it looks fine. Private setters, behavior on the entity, timestamps — all the right signals. But when I started asking DDD questions, problems surfaced quickly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 1: &lt;code&gt;StrategyConfig&lt;/code&gt; Is a Trust Exercise
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;StrategyConfig&lt;/code&gt; property is a raw JSON string. Its default value is &lt;code&gt;"{}"&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;That means this is completely legal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UpdateStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RolloutStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Percentage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A percentage rollout with no threshold defined. The entity accepts it without complaint. Nothing breaks until runtime, when some code downstream tries to deserialize the threshold and gets nothing.&lt;/p&gt;

&lt;p&gt;In DDD terms, this violates a core principle: &lt;strong&gt;make illegal states unrepresentable&lt;/strong&gt;. The entity's job is to protect its own consistency. Right now, &lt;code&gt;Flag&lt;/code&gt; is not doing that job for its most complex property.&lt;/p&gt;

&lt;p&gt;The fix is to replace the raw string with typed Value Objects — one per strategy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instead of: string StrategyConfig = "{}"&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PercentageConfig&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Threshold&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PercentageConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
                &lt;span class="s"&gt;"Threshold must be between 0 and 100."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Threshold&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threshold&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;Now invalid state can't be constructed. The type system enforces the rule — not a validator somewhere downstream.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 2: &lt;code&gt;IsSeeded&lt;/code&gt; Has No Business Being Here
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsSeeded&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This flag (pun intended) tells the system whether a record was inserted by the database seeder. It's an infrastructure concern — and it's sitting in the middle of a domain entity.&lt;/p&gt;

&lt;p&gt;Its presence created a rule we had to document explicitly: &lt;em&gt;"&lt;code&gt;IsSeeded&lt;/code&gt; must never appear on any DTO or API response."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That rule exists because &lt;code&gt;IsSeeded&lt;/code&gt; is in the wrong place. If it lived in the infrastructure layer where it belongs, the rule would be unnecessary. The property couldn't leak to the API because the domain entity wouldn't have it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The documented rule was a symptom. The misplaced property was the disease.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 3: The Archive Method Doesn't Enforce Its Own Invariant
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Archive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;IsArchived&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ArchivedAt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;UpdatedAt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&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;Nothing stops you from calling &lt;code&gt;Archive()&lt;/code&gt; on an already-archived flag. Nothing stops you from calling &lt;code&gt;SetEnabled(true)&lt;/code&gt; on an archived flag. Archived is supposed to be a terminal state — once a flag is archived, it's frozen. But the entity doesn't enforce that.&lt;/p&gt;

&lt;p&gt;The fix is straightforward: a guard clause at the top of every mutating method, throwing a domain exception if the flag is already archived.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Archive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IsArchived&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FlagDomainException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot archive a flag that is already archived."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;IsArchived&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ArchivedAt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;UpdatedAt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&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;Note: &lt;code&gt;FlagDomainException&lt;/code&gt; is not &lt;code&gt;ArgumentException&lt;/code&gt; or &lt;code&gt;InvalidOperationException&lt;/code&gt;. It's a domain exception — a type that lives in the domain layer and speaks the language of business rules. The distinction matters when you're debugging at 2am.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 4: The API Surface Is Confusing
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Flag&lt;/code&gt; exposes three overlapping methods for state changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;enabled&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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdateStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RolloutStrategy&lt;/span&gt; &lt;span class="n"&gt;strategyType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;strategyConfig&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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RolloutStrategy&lt;/span&gt; &lt;span class="n"&gt;strategyType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;strategyConfig&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;&lt;code&gt;Update()&lt;/code&gt; does what the other two do together, atomically. So you can change enabled state and strategy either as one operation or as two separate calls. There's no domain rule telling you which to use or when.&lt;/p&gt;

&lt;p&gt;This is what DDD practitioners call &lt;strong&gt;API confusion&lt;/strong&gt; — the entity is offering multiple paths to the same state change with no clear intent. The caller has to make an architectural decision that the domain should be making.&lt;/p&gt;

&lt;p&gt;The right approach is to separate by &lt;em&gt;concern&lt;/em&gt;, not by &lt;em&gt;field&lt;/em&gt;. Name changes are a distinct business operation. Rollout configuration changes are another. You don't need three methods covering overlapping ground.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 5: The Big One — The Wrong Aggregate Boundary
&lt;/h2&gt;

&lt;p&gt;This was the finding that surprised me most.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Flag&lt;/code&gt; in Banderas looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;EnvironmentType&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsEnabled&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;RolloutStrategy&lt;/span&gt; &lt;span class="n"&gt;StrategyType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&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;One flag. One environment. One strategy. If you want the same flag in both Production and Staging, you need &lt;strong&gt;two rows in the database&lt;/strong&gt; — two separate &lt;code&gt;Flag&lt;/code&gt; entities that happen to share a name.&lt;/p&gt;

&lt;p&gt;That's not a flag with two environments. That's two flags.&lt;/p&gt;

&lt;p&gt;Compare that to how another feature flag domain entity structures a flag in their API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alternate product page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"boolean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"variations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"environments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"on"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"fallthrough"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"rollout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"staging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"on"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"fallthrough"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"variation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flag is a &lt;strong&gt;definition&lt;/strong&gt; — name, variations, metadata. The behavior of that flag is &lt;strong&gt;environment-specific configuration&lt;/strong&gt; sitting alongside it. One flag entity, multiple environment configurations. Same concept in Production and Staging, completely independent behavior in each.&lt;/p&gt;

&lt;p&gt;In Banderas, a &lt;code&gt;Flag&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; an environment. In the example above, a flag &lt;em&gt;has&lt;/em&gt; environment configurations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fixing the Aggregate Boundary
&lt;/h2&gt;

&lt;p&gt;The DDD solution is to split &lt;code&gt;Flag&lt;/code&gt; into two distinct aggregates:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Flag&lt;/code&gt; — pure definition:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Flag&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Tags&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Variation&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Variations&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;CreatedAt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;UpdatedAt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;FlagEnvironmentConfig&lt;/code&gt; — per-environment behavior:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FlagEnvironmentConfig&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;FlagId&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c1"&gt;// reference by ID only&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;EnvironmentType&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsEnabled&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsArchived&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TargetingRule&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Rules&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Fallthrough&lt;/span&gt; &lt;span class="n"&gt;Fallthrough&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;ArchivedAt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&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;Notice &lt;code&gt;FlagId&lt;/code&gt; is a &lt;code&gt;Guid&lt;/code&gt;, not a &lt;code&gt;Flag&lt;/code&gt; navigation property. In DDD, &lt;strong&gt;aggregates reference each other by ID only&lt;/strong&gt; — never by object reference. This enforces the boundary. &lt;code&gt;FlagEnvironmentConfig&lt;/code&gt; knows a &lt;code&gt;Flag&lt;/code&gt; exists, but can't reach across the boundary and mutate it.&lt;/p&gt;

&lt;p&gt;These two aggregates also get their own repositories: &lt;code&gt;IBanderasRepository&lt;/code&gt; for flags, &lt;code&gt;IFlagEnvironmentConfigRepository&lt;/code&gt; for environment configs. Independent persistence, independent consistency boundaries.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the Enum Is Also the Problem
&lt;/h2&gt;

&lt;p&gt;Adding a new strategy type in Banderas today means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a value to the &lt;code&gt;RolloutStrategy&lt;/code&gt; enum&lt;/li&gt;
&lt;li&gt;Write a new strategy class&lt;/li&gt;
&lt;li&gt;Update the deserializer to handle the new &lt;code&gt;StrategyConfig&lt;/code&gt; shape&lt;/li&gt;
&lt;li&gt;Hope nothing silently breaks&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The enum &lt;em&gt;is&lt;/em&gt; the coupling. Every new strategy requires touching the domain model.&lt;/p&gt;

&lt;p&gt;One way to avoid this is by making rules &lt;strong&gt;data, not code&lt;/strong&gt;. Their &lt;code&gt;rules&lt;/code&gt; array holds targeting conditions — clauses like &lt;code&gt;attribute: "groups", op: "in", values: ["Top Customers"]&lt;/code&gt;. Adding a new targeting capability means adding a new clause operator, not modifying the core flag entity.&lt;/p&gt;

&lt;p&gt;Banderas isn't there yet. But it's the right direction — and it starts with replacing the rigid &lt;code&gt;StrategyConfig&lt;/code&gt; string with proper typed Value Objects and eventually moving toward a rules-based evaluation model.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned — DDD Edition
&lt;/h2&gt;

&lt;p&gt;If you take nothing else from this post, take these:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Make illegal states unrepresentable.&lt;/strong&gt;&lt;br&gt;
If bad data can be constructed, it will be. Design your types so that invalid state literally cannot exist. Value Objects are the tool for this — they validate at construction and are immutable after that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A documented workaround is a symptom.&lt;/strong&gt;&lt;br&gt;
Every time you write a rule like "this field must never appear in the API response," ask yourself why the field is there at all. The rule is usually telling you something is in the wrong layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Aggregates are about consistency boundaries, not object containment.&lt;/strong&gt;&lt;br&gt;
Two things belong in the same aggregate only if they must coordinate to stay consistent. If they're independent, make them separate aggregates. Forcing them together adds coupling with no benefit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Aggregates reference each other by ID only.&lt;/strong&gt;&lt;br&gt;
Never hold a navigation reference across an aggregate boundary. A &lt;code&gt;Guid&lt;/code&gt; is a reference. An object reference is a dependency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Reference production systems.&lt;/strong&gt;&lt;br&gt;
Looking at how others model a flag didn't give me the answer — it gave me the right &lt;em&gt;questions&lt;/em&gt;. Why does their flag not have an &lt;code&gt;EnvironmentType&lt;/code&gt;? Why is &lt;code&gt;IsEnabled&lt;/code&gt; nested under environment config? Good systems teach you what problems look like when they're solved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Refactor the model before the codebase grows.&lt;/strong&gt;&lt;br&gt;
Every week you wait, the rigid model grows more calluses — more code that works around the problem instead of solving it. The right time to fix the domain model is before the next phase, not after.&lt;/p&gt;




&lt;p&gt;If you're building something on .NET and working through similar DDD questions, I'd genuinely love to hear how you're approaching it. Drop a comment or find me on LinkedIn.&lt;/p&gt;

</description>
      <category>ddd</category>
      <category>dotnet</category>
      <category>architecture</category>
      <category>designsystem</category>
    </item>
    <item>
      <title>The AI Hype Cycle Is Lying to You About What to Learn</title>
      <dc:creator>Jose Rodriguez Marrero</dc:creator>
      <pubDate>Thu, 16 Apr 2026 23:01:35 +0000</pubDate>
      <link>https://dev.to/amodelandme/the-ai-hype-cycle-is-lying-to-you-about-what-to-learn-34gc</link>
      <guid>https://dev.to/amodelandme/the-ai-hype-cycle-is-lying-to-you-about-what-to-learn-34gc</guid>
      <description>&lt;p&gt;&lt;em&gt;Written by a human&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Proofread and diagram by Claude 4.7&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I've been back in the code for a few months after some time away dealing with family medical stuff, and I'll be honest — the landscape looks different.&lt;/p&gt;

&lt;p&gt;Every other post on my feed is telling me the same thing: fundamentals are dead, orchestration is the new skill, learn to prompt or get left behind. And I almost bought it. I'm the exact demographic these posts are aimed at — someone returning to the industry, a little anxious about whether my skills are still relevant, wondering if I should pivot.&lt;/p&gt;

&lt;p&gt;Then I sat down and actually thought about it. Here's what I came up with.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing nobody's saying out loud
&lt;/h2&gt;

&lt;p&gt;AI has collapsed the cost of producing code. It has not collapsed the cost of producing &lt;em&gt;correct systems&lt;/em&gt;. Those are different problems.&lt;/p&gt;

&lt;p&gt;When someone brags about shipping a SaaS in a weekend with an AI agent, what they usually built is code that works on the happy path. What they didn't build is a schema that won't paint them into a corner in 18 months, or a domain model that survives contact with a real business rule, or an API that degrades gracefully under load.&lt;/p&gt;

&lt;p&gt;AI is very good at producing code that looks right to someone who doesn't already know what right looks like. That's the part that matters. &lt;strong&gt;If you can't read the output critically, you're not orchestrating — you're gambling with extra steps&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The asymmetry the hype cycle misses
&lt;/h2&gt;

&lt;p&gt;Here's the part that actually changed how I'm thinking about my career:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Orchestration knowledge depreciates. Engineering knowledge compounds.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The specific techniques for prompting Claude today will be partially obsolete in a year. The multi-agent pattern that feels clever right now (Architect → Engineer → Reviewer) will either get absorbed into the tools as a default, or replaced by something better. Every six months, the playbook gets partially rewritten. You're running on a treadmill.&lt;/p&gt;

&lt;p&gt;Deep engineering doesn't work that way. The reason &lt;code&gt;IUnitOfWork&lt;/code&gt; exists today is the same reason it existed in 2008 and will exist in 2035 — it's about coordinating changes across aggregates in a single transactional boundary. Fowler wrote about it in 2002. It still applies. The pattern survives because the underlying problem survives.&lt;/p&gt;

&lt;p&gt;Here's how I've been picturing it:&lt;br&gt;
Knowledge value over time&lt;br&gt;
Engineering depth&lt;br&gt;
Value   ╱&lt;br&gt;
│    ╱&lt;br&gt;
│   ╱         AI orchestration&lt;br&gt;
│  ╱         ╱‾‾╲    ╱‾‾╲   ╱‾‾&lt;br&gt;
│ ╱         ╱    ╲&lt;strong&gt;╱    ╲_╱&lt;br&gt;
│╱&lt;/strong&gt;_______╱&lt;br&gt;
└─────────────────────────────── Time&lt;br&gt;
↑         ↑        ↑&lt;br&gt;
Tool v1   Tool v2  Tool v3&lt;br&gt;
(reset)   (reset)  (reset)&lt;br&gt;
Every tool generation forces the orchestrator to partially reset. The engineer keeps stacking.&lt;/p&gt;

&lt;p&gt;The engineer who invested in fundamentals five years ago can pick up today's AI workflow in a month. The AI-native dev who skipped the fundamentals can't acquire five years of systems thinking in a month. Or a year.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this narrative is being pushed so hard
&lt;/h2&gt;

&lt;p&gt;It's worth asking who benefits from "you don't need the fundamentals anymore."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tool vendors selling the shortcut&lt;/li&gt;
&lt;li&gt;Bootcamps pivoting their curriculum to "AI engineer" tracks&lt;/li&gt;
&lt;li&gt;Influencers selling courses to people who are anxious about being left behind&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The people actually hiring at good companies are telling a different story. They're raising the bar on fundamentals, because "can produce code" is now table stakes. &lt;strong&gt;What separates candidates is whether they can evaluate code, design systems, and make judgment calls an AI can't make for them.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So what am I actually doing about it
&lt;/h2&gt;

&lt;p&gt;I'm not anti-AI. I use Claude every day. I'm building a multi-agent spec-driven pipeline for a side project right now. The tools are real and the leverage is real.&lt;/p&gt;

&lt;p&gt;But I'm using them as a force multiplier on top of depth, not a substitute for it. My Feature Flag API in .NET isn't a portfolio prop — it's a lab where I'm actually working through DDD, Clean Architecture, and the patterns that don't depreciate.&lt;/p&gt;

&lt;p&gt;The test I'm using for whether I actually understand something: can I explain it simply, with a diagram, to a stranger on the internet?&lt;/p&gt;

&lt;p&gt;That's why this post exists.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Building a Feature Flag API in .NET as I work through these ideas. Follow along if you're also trying to figure out what to actually learn in 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>design</category>
      <category>learning</category>
    </item>
    <item>
      <title>From Vibe Coding to Real Engineering: Why the Strategy Pattern Matters</title>
      <dc:creator>Jose Rodriguez Marrero</dc:creator>
      <pubDate>Mon, 06 Apr 2026 18:08:49 +0000</pubDate>
      <link>https://dev.to/amodelandme/from-vibe-coding-to-real-engineering-why-the-strategy-pattern-matters-2fhp</link>
      <guid>https://dev.to/amodelandme/from-vibe-coding-to-real-engineering-why-the-strategy-pattern-matters-2fhp</guid>
      <description>&lt;p&gt;There’s a new kind of developer emerging.&lt;/p&gt;

&lt;p&gt;You’ve probably felt it yourself.&lt;/p&gt;

&lt;p&gt;You open your editor, describe what you want, and code &lt;em&gt;appears&lt;/em&gt;. APIs scaffold themselves. Business logic materializes. Entire features come together in minutes. It feels like magic.&lt;/p&gt;

&lt;p&gt;This is what people are calling &lt;em&gt;vibe coding&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And to be clear, it’s not a bad thing.&lt;/p&gt;

&lt;p&gt;Vibe coding is incredible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prototyping ideas quickly&lt;/li&gt;
&lt;li&gt;exploring new domains&lt;/li&gt;
&lt;li&gt;getting unstuck&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here’s the catch:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Vibe coding optimizes for speed of creation.&lt;br&gt;
Engineering optimizes for &lt;strong&gt;survivability over time&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that’s where design patterns quietly step in.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem You Don’t Notice at First
&lt;/h2&gt;

&lt;p&gt;Let’s say you’re building a payment system.&lt;/p&gt;

&lt;p&gt;You prompt your AI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Create a payment processor that supports credit card, PayPal, and crypto.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And you get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"CreditCard"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// credit card logic&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"PayPal"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// PayPal logic&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"Crypto"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// crypto logic&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;It works. It’s fast. It’s clean enough.&lt;/p&gt;

&lt;p&gt;Until…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You add Apple Pay&lt;/li&gt;
&lt;li&gt;Then Google Pay&lt;/li&gt;
&lt;li&gt;Then region-specific providers&lt;/li&gt;
&lt;li&gt;Then fraud rules&lt;/li&gt;
&lt;li&gt;Then retry policies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suddenly that method becomes a branching maze.&lt;/p&gt;

&lt;p&gt;And every change feels risky.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Smell
&lt;/h2&gt;

&lt;p&gt;This is the moment where good engineers pause and ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“What is changing in this system?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;payment &lt;em&gt;methods&lt;/em&gt; are changing&lt;/li&gt;
&lt;li&gt;payment &lt;em&gt;logic&lt;/em&gt; varies per method&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s your signal.&lt;/p&gt;




&lt;h2&gt;
  
  
  Enter the Strategy Pattern
&lt;/h2&gt;

&lt;p&gt;Instead of stuffing all behavior into one class, you &lt;strong&gt;pull the variation out&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You define a contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentStrategy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;amount&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;Then implement each behavior independently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreditCardPayment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentStrategy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PayPalPayment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentStrategy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CryptoPayment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentStrategy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And your processor becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;IPaymentStrategy&lt;/span&gt; &lt;span class="n"&gt;_strategy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IPaymentStrategy&lt;/span&gt; &lt;span class="n"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_strategy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What Just Changed?
&lt;/h2&gt;

&lt;p&gt;This is subtle, but powerful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The processor decided &lt;em&gt;how&lt;/em&gt; payments were handled&lt;/li&gt;
&lt;li&gt;Adding new behavior meant modifying existing code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  After:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The processor delegates &lt;em&gt;how&lt;/em&gt; to a strategy&lt;/li&gt;
&lt;li&gt;New behavior is added by introducing new classes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No existing code needs to change.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters (Especially in the AI Era)
&lt;/h2&gt;

&lt;p&gt;AI is very good at generating &lt;em&gt;solutions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;But it doesn’t always optimize for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;long-term maintainability&lt;/li&gt;
&lt;li&gt;extensibility&lt;/li&gt;
&lt;li&gt;fault isolation&lt;/li&gt;
&lt;li&gt;architectural clarity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s your job.&lt;/p&gt;

&lt;p&gt;The Strategy Pattern gives you:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Isolation of Change
&lt;/h3&gt;

&lt;p&gt;Each payment method lives in its own class.&lt;/p&gt;

&lt;p&gt;A bug in crypto payments doesn’t ripple into credit card logic.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Open for Extension, Closed for Modification
&lt;/h3&gt;

&lt;p&gt;You don’t rewrite your system to grow it.&lt;/p&gt;

&lt;p&gt;You extend it.&lt;/p&gt;

&lt;p&gt;That’s the difference between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a system that evolves&lt;/li&gt;
&lt;li&gt;and one that eventually collapses under its own weight&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Runtime Flexibility
&lt;/h3&gt;

&lt;p&gt;You can swap behavior dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PayPalPayment&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or more realistically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paymentType&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now behavior is driven by configuration, not conditionals.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Shift
&lt;/h2&gt;

&lt;p&gt;The Strategy Pattern isn’t really about interfaces.&lt;/p&gt;

&lt;p&gt;It’s about this mindset:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“My objects shouldn’t &lt;em&gt;own&lt;/em&gt; behavior that changes frequently.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“They should &lt;em&gt;delegate&lt;/em&gt; that behavior to something interchangeable.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s how you build systems that last.&lt;/p&gt;




&lt;h2&gt;
  
  
  Vibe Coding vs Engineering
&lt;/h2&gt;

&lt;p&gt;Vibe coding gets you to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“It works.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Design patterns get you to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“It will keep working when everything changes.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You don’t need patterns for every piece of code.&lt;/p&gt;

&lt;p&gt;But when you see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;growing conditionals&lt;/li&gt;
&lt;li&gt;branching logic&lt;/li&gt;
&lt;li&gt;behavior that varies by type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s your cue.&lt;/p&gt;




&lt;h2&gt;
  
  
  One Line to Take With You
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Strategy lets you change behavior without changing the code that uses it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you internalize that, you’ll start seeing it everywhere.&lt;/p&gt;

&lt;p&gt;And that’s when you stop just generating code…&lt;/p&gt;

&lt;p&gt;…and start designing systems.&lt;/p&gt;

&lt;p&gt;Written by Jose&lt;br&gt;
Proofread/Edited by ChatGPT 5.4&lt;/p&gt;

</description>
      <category>newbie</category>
      <category>designpatterns</category>
      <category>vibecoding</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>My Dev Environment Hated Me (And How I Fixed It)</title>
      <dc:creator>Jose Rodriguez Marrero</dc:creator>
      <pubDate>Sun, 22 Mar 2026 23:22:33 +0000</pubDate>
      <link>https://dev.to/amodelandme/my-dev-environment-hated-me-and-how-i-fixed-it-45b4</link>
      <guid>https://dev.to/amodelandme/my-dev-environment-hated-me-and-how-i-fixed-it-45b4</guid>
      <description>&lt;p&gt;&lt;em&gt;A returning developer's battle with devcontainers, Docker image tags, and OAuth callbacks that ghost you like a bad Tinder date.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I'm back. After a few months away to deal with a family medical situation (more on that at the end), I've returned to the industry with a mission: build portfolio-worthy, production-grade projects and sharpen my .NET skills back to a competitive level.&lt;/p&gt;

&lt;p&gt;My first project? A &lt;strong&gt;Feature Flag Service&lt;/strong&gt; — a clean architecture .NET API that evaluates feature flags deterministically using rollout strategies like percentage-based rollouts and role-based targeting. Think LaunchDarkly, but built by me, from scratch, with a focus on solid engineering principles.&lt;/p&gt;

&lt;p&gt;Before writing a single line of business logic, I had to do something deceptively simple: &lt;em&gt;set up my dev environment&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Two hours later, I had four separate errors and a story worth writing about.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;The plan was clean and modern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Devcontainer&lt;/strong&gt; for a reproducible, containerized development environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; inside the container for AI-assisted development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.NET 10&lt;/strong&gt; because why not use the latest?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VSCode Dev Containers extension&lt;/strong&gt; to tie it all together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what my &lt;code&gt;devcontainer.json&lt;/code&gt; looked like going in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Feature Flag Service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcr.microsoft.com/devcontainers/dotnet:1-10.0-bookworm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"features"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ghcr.io/anthropics/devcontainer-features/claude-code:1.0"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ghcr.io/devcontainers/features/node:1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lts"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"forwardPorts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5001&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"postCreateCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dotnet restore &amp;amp;&amp;amp; dotnet tool restore"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks reasonable, right? &lt;em&gt;Narrator: It was not reasonable.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Bug #1 — The Image That Doesn't Exist
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error response from daemon: failed to resolve reference 
"mcr.microsoft.com/devcontainers/dotnet:1-10.0-bookworm": not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right out of the gate. Docker couldn't pull the image because &lt;strong&gt;the tag &lt;code&gt;1-10.0-bookworm&lt;/code&gt; simply does not exist&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here's the thing about Docker image tags — they're not automatically generated for every version of every framework. The &lt;code&gt;mcr.microsoft.com/devcontainers/dotnet&lt;/code&gt; image only has published tags up to &lt;code&gt;8.0&lt;/code&gt; and &lt;code&gt;9.0&lt;/code&gt;. No &lt;code&gt;10.0&lt;/code&gt; yet.&lt;/p&gt;

&lt;p&gt;But there's a second twist: &lt;strong&gt;.NET 10 dropped Debian (Bookworm) entirely&lt;/strong&gt;. Starting with .NET 10, Microsoft switched the default base OS to Ubuntu. So even if the tag existed, &lt;code&gt;-bookworm&lt;/code&gt; would be wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Drop down to the latest available devcontainer image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcr.microsoft.com/devcontainers/dotnet:9.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Always verify Docker image tags exist before assuming they do. The pattern &lt;code&gt;&amp;lt;language&amp;gt;:&amp;lt;version&amp;gt;-&amp;lt;os&amp;gt;&lt;/code&gt; isn't guaranteed — check the registry.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Bug #2 — The OAuth Callback That Ghosted Me &lt;em&gt;(Main Event)&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;This one is the real star of today's post. Container built successfully. Claude Code installed. Time to log in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude auth login &lt;span class="nt"&gt;--claudeai&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browser opens. I authenticate. I'm redirected back to VSCode and... nothing. The terminal just &lt;em&gt;hangs&lt;/em&gt;. Waiting. Forever.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed to retrieve auth status after login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's actually happening here is a fascinating networking problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Root Cause
&lt;/h3&gt;

&lt;p&gt;When you run &lt;code&gt;claude auth login&lt;/code&gt;, Claude Code spins up a &lt;strong&gt;localhost callback server on a random ephemeral port&lt;/strong&gt;. The OAuth flow works like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Claude Code starts listening on &lt;code&gt;localhost:RANDOM_PORT&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Your browser opens &lt;code&gt;claude.ai/oauth/authorize&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You authenticate in the browser&lt;/li&gt;
&lt;li&gt;The browser is redirected back to &lt;code&gt;localhost:RANDOM_PORT/callback&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Claude Code receives the token and stores it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The problem? &lt;strong&gt;You're inside a container.&lt;/strong&gt; The browser lives on your &lt;em&gt;host machine&lt;/em&gt;. The callback server lives &lt;em&gt;inside the container&lt;/em&gt;. That random port is never forwarded, so the callback from the browser never arrives. Claude Code sits there waiting for a knock on a door that nobody can reach.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HOST                          DEVCONTAINER
┌──────────────┐              ┌─────────────────────┐
│   Browser    │──callback──X─▶│  claude auth login  │
│              │  :RANDOM      │  (listening on      │
└──────────────┘  NOT FORWARDED│   RANDOM port)      │
                               └─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Fix — Bind Mount Your Host Credentials
&lt;/h3&gt;

&lt;p&gt;The cleanest solution: &lt;strong&gt;log in on your host machine once, then mount your credentials into the container&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Claude Code stores OAuth tokens in two places on your filesystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;~/.claude/&lt;/code&gt; — credentials, config, session data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/.claude.json&lt;/code&gt; — onboarding state (easy to miss this one!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Update your &lt;code&gt;devcontainer.json&lt;/code&gt; mounts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="nl"&gt;"mounts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"source=${localEnv:HOME}/.claude,target=/home/vscode/.claude,type=bind"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"source=${localEnv:HOME}/.claude.json,target=/home/vscode/.claude.json,type=bind"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then on your &lt;strong&gt;host machine&lt;/strong&gt; (not inside the container):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Complete the OAuth flow normally. Rebuild the container. Done — Claude Code inside the container picks up your credentials automatically, no login required.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; OAuth callback flows assume the browser and the listening server are on the same machine. In containerized environments, that assumption breaks. Bind mounts are your friend.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Bug #3 — &lt;code&gt;postCreateCommand&lt;/code&gt; Needs a Map
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;postCreateCommand failed with exit code 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vague. Unhelpful. Classic.&lt;/p&gt;

&lt;p&gt;Running the commands manually revealed the culprit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet restore
&lt;span class="c"&gt;# error: Specify a project or solution file.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The container doesn't automatically know which solution to restore. A simple fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="nl"&gt;"postCreateCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dotnet restore FeatureFlagService.sln &amp;amp;&amp;amp; dotnet tool restore"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Be explicit in automation. Commands that work fine interactively (where you're already in context) can fail in scripts because that context doesn't exist.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Bug #4 — The SDK vs. Target Framework Mismatch
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error NETSDK1045: The current .NET SDK does not support targeting .NET 10.0.
Either target .NET 9.0 or lower, or use a version of the .NET SDK that supports .NET 10.0.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember how we switched to the &lt;code&gt;.NET 9&lt;/code&gt; devcontainer image? Right. The SDK is .NET 9. The project targets .NET 10. They don't agree.&lt;/p&gt;

&lt;p&gt;Rather than installing a custom SDK (more complexity, more maintenance), I downgraded all project files to target &lt;code&gt;net9.0&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.csproj"&lt;/span&gt; | xargs &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'s/&amp;lt;TargetFramework&amp;gt;net10.0&amp;lt;\/TargetFramework&amp;gt;/&amp;lt;TargetFramework&amp;gt;net9.0&amp;lt;\/TargetFramework&amp;gt;/g'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command. All five &lt;code&gt;.csproj&lt;/code&gt; files updated. Verified with:&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="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"TargetFramework"&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"*.csproj"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Your container image's SDK version and your project's target framework must align. When they don't, decide which one you're willing to move — usually it's easier to adjust the project than rebuild the image.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Final &lt;code&gt;devcontainer.json&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Here's where we landed after all four fixes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Feature Flag Service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcr.microsoft.com/devcontainers/dotnet:9.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"features"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ghcr.io/anthropics/devcontainer-features/claude-code:1.0"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ghcr.io/devcontainers/features/node:1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lts"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"forwardPorts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5001&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"portsAttributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"5000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTTP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"onAutoForward"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"notify"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"5001"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTTPS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"onAutoForward"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"notify"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"mounts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"source=${localEnv:HOME}/.claude,target=/home/vscode/.claude,type=bind"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"source=${localEnv:HOME}/.claude.json,target=/home/vscode/.claude.json,type=bind"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"containerEnv"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"CLAUDE_CONFIG_DIR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/home/vscode/.claude"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ASPNETCORE_ENVIRONMENT"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Development"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"remoteUser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vscode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"containerUser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vscode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"postCreateCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dotnet restore FeatureFlagService.sln &amp;amp;&amp;amp; dotnet tool restore"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"postStartCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"git config --global --add safe.directory ${containerWorkspaceFolder}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"customizations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vscode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ms-dotnettools.csharp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ms-dotnettools.csdevkit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"humao.rest-client"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"eamodio.gitlens"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"editorconfig.editorconfig"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"streetsidesoftware.code-spell-checker"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"editor.formatOnSave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"editor.tabSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"files.eol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dotnet.defaultSolution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FeatureFlagService.sln"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Four bugs. One working dev environment. Two hours I'll never get back — but also two hours that gave me a much better understanding of how Docker networking, OAuth flows, and devcontainer configuration actually work under the hood.&lt;/p&gt;

&lt;p&gt;The Feature Flag Service itself is still ahead of me. Clean Architecture layers to wire up, a deterministic hashing strategy to implement, unit tests to write. But the foundation is solid, the tooling is in place, and Claude Code is authenticated and ready to pair program.&lt;/p&gt;

&lt;p&gt;Next post: getting into the actual code — implementing the evaluation engine and the strategy pattern at the heart of this thing.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;A note on the comeback: I stepped away from software development for a couple of years to deal with a family medical situation. That chapter is now closed, and I'm back — sharper, more intentional, and honestly more motivated than ever. If you're a developer who's taken time away for life reasons, this blog is partly for you. It's possible to come back. Let's build.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;code&gt;#dotnet&lt;/code&gt; &lt;code&gt;#devcontainers&lt;/code&gt; &lt;code&gt;#docker&lt;/code&gt; &lt;code&gt;#claudecode&lt;/code&gt; &lt;code&gt;#webdev&lt;/code&gt; &lt;code&gt;#programming&lt;/code&gt; &lt;code&gt;#cleanarchitecture&lt;/code&gt; &lt;code&gt;#debugging&lt;/code&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>dotnet</category>
      <category>containers</category>
      <category>oauth</category>
    </item>
    <item>
      <title>🧠 Backing Fields in C#: What They Are and Why You Should Care</title>
      <dc:creator>Jose Rodriguez Marrero</dc:creator>
      <pubDate>Sat, 31 May 2025 18:11:22 +0000</pubDate>
      <link>https://dev.to/amodelandme/backing-fields-in-c-what-they-are-and-why-you-should-care-5f6p</link>
      <guid>https://dev.to/amodelandme/backing-fields-in-c-what-they-are-and-why-you-should-care-5f6p</guid>
      <description>&lt;p&gt;As a C# developer, you've probably written something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&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;Short. Sweet. Gets the job done.&lt;/p&gt;

&lt;p&gt;But what if you need to sneak in a little logic? What if you want to say, “Hey! You can't set Age to -200!”?&lt;/p&gt;

&lt;p&gt;That’s when it’s time to meet your new(ish) best friend: backing fields.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔙 Wait… What’s a Backing Field?
&lt;/h2&gt;

&lt;p&gt;A backing field is just a private variable that stores the actual value for a property.&lt;/p&gt;

&lt;p&gt;Think of it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Backing field&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Property using that field&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&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;You're basically wrapping that private _email in a nice public interface (Email) so other parts of your code can use it safely.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✨ Auto-Properties: The Lazy Magic
&lt;/h2&gt;

&lt;p&gt;When you write this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&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 compiler quietly creates something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 👻 invisible to you!&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&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;No muss, no fuss — but also no customization. You can’t sneak in any logic. It’s like ordering black coffee when you really need a vanilla oat milk latte with light foam and a shot of espresso (a.k.a. validation).&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 So When Do You Need a Backing Field?
&lt;/h2&gt;

&lt;p&gt;Glad you asked. Here are a few classic cases:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Validation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;charp&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private int _age;

public int Age
{
    get =&amp;gt; _age;
    set =&amp;gt; _age = value &amp;lt; 0 ? 0 : value; // No negative ages allowed!
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. &lt;strong&gt;Logging or Side Effects&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;set&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Changing name from &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&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;h3&gt;
  
  
  3. &lt;strong&gt;Transforming Input&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Here’s a real-world example from a product filter class I'm currently building:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_brands&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Brands&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_brands&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_brands&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[..&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SelectMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringSplitOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RemoveEmptyEntries&lt;/span&gt;&lt;span class="p"&gt;))];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, instead of forcing users to send &lt;code&gt;["Nike", "Adidas"]&lt;/code&gt;, they can just send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Nike,Adidas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Puma"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you’ll still end up with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Nike"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Adidas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Puma"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's right, homeys!!✨&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Auto-Property&lt;/th&gt;
&lt;th&gt;Backing Field&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Super simple&lt;/td&gt;
&lt;td&gt;✅ Yup&lt;/td&gt;
&lt;td&gt;❌ More typing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add logic or validation&lt;/td&gt;
&lt;td&gt;❌ Nope&lt;/td&gt;
&lt;td&gt;✅ Totally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trigger side effects&lt;/td&gt;
&lt;td&gt;❌ Not a chance&lt;/td&gt;
&lt;td&gt;✅ All day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transform data on set&lt;/td&gt;
&lt;td&gt;❌ Can't do it&lt;/td&gt;
&lt;td&gt;✅ Yes, chef&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧵 Wrap-up
&lt;/h2&gt;

&lt;p&gt;Backing fields are like the secret sauce behind well-behaved properties. Sure, auto-properties are great for the everyday stuff, but when you need more control, don’t be afraid to write things out manually.&lt;/p&gt;

&lt;p&gt;Whether you're validating data, formatting input, or just want to sneak a &lt;code&gt;Console.WriteLine&lt;/code&gt; in there — backing fields have your back (literally).&lt;/p&gt;




&lt;p&gt;What’s your favorite use case for a backing field? Ever tried doing too much with an auto-property and had it backfire? Drop a comment — I’d love to hear your war stories.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>beginners</category>
      <category>coding</category>
    </item>
    <item>
      <title>Static + Generics = Trouble? Why Your C# Code Smells and How to Clean It Up</title>
      <dc:creator>Jose Rodriguez Marrero</dc:creator>
      <pubDate>Wed, 28 May 2025 02:53:45 +0000</pubDate>
      <link>https://dev.to/amodelandme/static-generics-trouble-why-your-c-code-smells-and-how-to-clean-it-up-68b</link>
      <guid>https://dev.to/amodelandme/static-generics-trouble-why-your-c-code-smells-and-how-to-clean-it-up-68b</guid>
      <description>&lt;p&gt;So there I was… writing some C# code for my, minding my own business, when &lt;em&gt;bam&lt;/em&gt; — the compiler drops this wisdom on me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;CA1000: Do not declare static members on generic types&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And I’m like...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Okay compiler, but can you explain that like I’m five?”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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




&lt;h2&gt;
  
  
  🍱 Static + Generics: What’s Actually Going On?
&lt;/h2&gt;

&lt;p&gt;You might write something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SnackBox&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;SnackCount&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;Seems harmless. But if you use it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;SnackBox&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;SnackCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;SnackBox&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;SnackCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SnackBox&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;SnackCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 5&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SnackBox&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;SnackCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You suddenly realize: 😱 &lt;strong&gt;Each version of T gets its own static member&lt;/strong&gt;.&lt;br&gt;
So now you’ve got dozens of mini snack boxes floating around in memory — each hoarding their own &lt;code&gt;SnackCount&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧽 What This Has To Do With Real Code
&lt;/h2&gt;

&lt;p&gt;Let’s say you’re writing a helper to apply specs to a query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpecificationEvaluator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BaseEntity&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IQueryable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IQueryable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ISpecification&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Criteria&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Criteria&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="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks fine, right?&lt;/p&gt;

&lt;p&gt;Well, sort of. But this triggers CA1000, and for good reason:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You now have a separate static class per type — e.g., &lt;code&gt;SpecificationEvaluator&amp;lt;Product&amp;gt;&lt;/code&gt;, &lt;code&gt;SpecificationEvaluator&amp;lt;Order&amp;gt;&lt;/code&gt;, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That increases memory usage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It’s harder to use (you have to specify the type every time)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And worst of all... the compiler is silently judging you 😬&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧹 The Fix: Static Class, Generic Method
&lt;/h2&gt;

&lt;p&gt;We can clean this up by moving the generic parameter from the class to the method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpecificationEvaluator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IQueryable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GetQuery&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;IQueryable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ISpecification&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BaseEntity&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="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Criteria&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Criteria&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="n"&gt;query&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;Now you can call it like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SpecificationEvaluator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;productSpec&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;No generic class instantiations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cleaner syntax&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The compiler stops yelling 🎉&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ TL;DR — What Did We Learn?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;❌ Don’t Do This&lt;/th&gt;
&lt;th&gt;✅ Do This Instead&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;static class MyHelper&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;static class MyHelper&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static method inside generic class&lt;/td&gt;
&lt;td&gt;Generic static method inside static class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One copy per &lt;code&gt;T&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;One reusable method for all types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CA1000 warning&lt;/td&gt;
&lt;td&gt;✨ No warning, no surprises ✨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🎯 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;If you've ever been confused by that CA1000 warning or wondered why your static generic utility felt “off,” you’re not alone.&lt;/p&gt;

&lt;p&gt;Just remember:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Static classes are like toolboxes.&lt;br&gt;
You don’t need a separate toolbox for every kind of screw. 🧰&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Happy coding! 👨‍💻👩‍💻&lt;br&gt;
Have you encountered CA1000 before? Drop a comment — I'd love to hear your story or tips!&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>cleancode</category>
      <category>programming</category>
    </item>
    <item>
      <title>IEnumerable vs IReadOnlyList in .NET: When Should You Use Each?</title>
      <dc:creator>Jose Rodriguez Marrero</dc:creator>
      <pubDate>Fri, 23 May 2025 23:10:32 +0000</pubDate>
      <link>https://dev.to/amodelandme/ienumerable-vs-ireadonlylist-in-net-when-should-you-use-each-4p5b</link>
      <guid>https://dev.to/amodelandme/ienumerable-vs-ireadonlylist-in-net-when-should-you-use-each-4p5b</guid>
      <description>&lt;p&gt;If you’re working in C# and .NET, you’ll quickly run into different collection interfaces like &lt;strong&gt;&lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;IReadOnlyList&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt;. At first glance, they seem pretty similar—both let you work with a set of items in a read-only way. So when should you use each? In this post, I’ll break down the differences, show real-world use cases, and give you code samples so you know exactly when to reach for one or the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Definitions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The simplest way to represent a sequence of items that you can iterate over (with foreach). It doesn’t let you access by index or get the count directly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;IReadOnlyList&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Represents a read-only list of items. You can access items by index and get the number of items, but you can’t change the collection.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example 1: Using &lt;strong&gt;&lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAllProductNames&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Could return from a database query, LINQ, etc.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;GetAllProductNames&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&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;When to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you only need to iterate (loop) over the items.&lt;/li&gt;
&lt;li&gt;When the results might be streamed, generated, or filtered on-the-fly.&lt;/li&gt;
&lt;li&gt;You don’t need to know the exact number of items or their positions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Example 2: Using &lt;strong&gt;&lt;code&gt;IReadOnlyList&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetFeaturedProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Return a fixed, materialized list&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;featuredProducts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsReadOnly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nf"&gt;GetFeaturedProducts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetFeaturedProducts&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&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;When to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you need to access items by their index (e.g., list[0]).&lt;/li&gt;
&lt;li&gt;When you want to expose the count (list.Count).&lt;/li&gt;
&lt;li&gt;When you want to guarantee that the collection is fixed and can’t be changed by the consumer.&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;IEnumerable&lt;/th&gt;
&lt;th&gt;IReadOnlyList&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Can loop with foreach&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access by index&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Get count&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Immutable/read-only&lt;/td&gt;
&lt;td&gt;❌ (just iterates)&lt;/td&gt;
&lt;td&gt;✅ (read-only contract)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deferred execution&lt;/td&gt;
&lt;td&gt;✅ (often)&lt;/td&gt;
&lt;td&gt;❌ (usually materialized)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How to Decide Which to Use
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use &lt;strong&gt;&lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt; when you want to keep things simple, just need to loop, or want to allow streaming of results.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;strong&gt;&lt;code&gt;IReadOnlyList&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt; when you want the safety and convenience of a fixed, read-only list that exposes both count and index-based access.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real-World Examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Repository Pattern (Read-only)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;&lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt; for large datasets you want to stream or filter on demand.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;&lt;code&gt;IReadOnlyList&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt; for methods that return a set of results you want to lock down (like the top 10 products).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;API Response&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use &lt;strong&gt;&lt;code&gt;IReadOnlyList&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt; to return a clear, fixed collection (helps with serialization and contracts).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;strong&gt;&lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt; internally, especially when chaining LINQ queries.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick Tip for Juniors
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you want to let others loop through your data, use &lt;strong&gt;&lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If you want to let others see how many items you have and access by index—but not modify anything—use &lt;strong&gt;&lt;code&gt;IReadOnlyList&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Got questions or want more real-world .NET tips? Drop a comment below!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Taming Your First Docker Build in 5 Minutes</title>
      <dc:creator>Jose Rodriguez Marrero</dc:creator>
      <pubDate>Fri, 23 May 2025 16:53:29 +0000</pubDate>
      <link>https://dev.to/amodelandme/taming-your-first-docker-build-in-5-minutes-2nod</link>
      <guid>https://dev.to/amodelandme/taming-your-first-docker-build-in-5-minutes-2nod</guid>
      <description>&lt;p&gt;Ever wished your app “just worked” on every machine? Docker gives you consistent, isolated environments—no more “it works on my machine” drama. In this hands-on guide, you’ll go from zero to a running container in five minutes flat.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠 Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Docker Desktop (macOS/Windows) or Docker Engine (Linux) installed
&lt;/li&gt;
&lt;li&gt;A simple sample app. We’ll use a minimal ASP.NET Core “Hello World” API, but you can swap in Node.js or static files.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check you have Docker:&lt;/span&gt;
docker &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📄 Crafting Your Dockerfile
&lt;/h2&gt;

&lt;p&gt;Create a file named Dockerfile in your project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 1. Base runtime image
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80

# 2. Build stage
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish

# 3. Final image
FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tip: Replace MyApp.dll with your project’s DLL name.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗 Building the Image
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t infraforge-dev-hello .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;-t infraforge-dev-hello tags your image&lt;/li&gt;
&lt;li&gt;. tells Docker to use the current folder as the build context&lt;/li&gt;
&lt;li&gt;You’ll see logs of each layer being built and cached&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ▶️ Running &amp;amp; Testing
&lt;/h2&gt;

&lt;p&gt;Start your container and map port 80 → 8080:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm -p 8080:80 infraforge-dev-hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;--rm cleans up the container when you stop it&lt;/li&gt;
&lt;li&gt;Navigate to &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt; or run:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✨ Quick Wins &amp;amp; Optimizations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;.dockerignore
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/
obj/
.vs/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Layer caching: put infrequently changing instructions (e.g., RUN dotnet restore) early.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-stage builds&lt;/strong&gt;: keeps final image slim—our example already uses one.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🐞 Troubleshooting Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Verbose output:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build --progress=plain .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Inspect broken images:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm -it infraforge-dev-hello /bin/bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Common pitfalls: wrong file paths, missing dependencies, port mismatches.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🐳 Deep Dive: Understanding the Container Lifecycle
&lt;/h2&gt;

&lt;p&gt;Docker containers transition through well-defined states. Knowing these helps you manage, debug, and automate effectively:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Created: Container exists, but not running.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps -a
# STATUS: Created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Running: Main process is executing.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps
# STATUS: Up X seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Paused: Process temporarily frozen.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker pause &amp;lt;container_id&amp;gt;
docker unpause &amp;lt;container_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Exited: Process finished or crashed.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps -a
# STATUS: Exited (1) X seconds ago
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Removed: Container deleted.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker rm &amp;lt;container_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Common Lifecycle Commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# List all containers (running + stopped)
docker ps -a

# Start a stopped container
docker start &amp;lt;container_id&amp;gt;

# Stop a running container (graceful shutdown)
docker stop &amp;lt;container_id&amp;gt;

# Force-restart
docker restart &amp;lt;container_id&amp;gt;

# Remove
docker rm &amp;lt;container_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why it matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD automation&lt;/strong&gt;: detect “Exited” states to trigger alerts or restarts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource cleanup&lt;/strong&gt;: proactively remove unused containers to free disk space.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging&lt;/strong&gt;: start a crashed container interactively to inspect logs or shell in.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;ul&gt;
&lt;li&gt;Scan for vulnerabilities:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker scan infraforge-dev-hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Push to a registry:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker tag SOURCE_IMAGE TARGET_IMAGE:TAG
# example: docker tag infraforge-dev-hello infraforge-dev/infraforge-dev-hello:v1.0
docker push infraforg-dev/infraforge-dev-hello:v1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Automate with GitHub Actions: integrate docker build &amp;amp; docker push on every PR.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Additional Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Docker Official Docs&lt;/strong&gt; – Get Started &amp;amp; Dockerfile Best Practices&lt;br&gt;
The definitive guide from Docker: an end-to-end “Get Started” tutorial plus the full Dockerfile reference and best-practices guide to optimize builds.&lt;br&gt;
&lt;a href="https://docs.docker.com/get-started/" rel="noopener noreferrer"&gt;https://docs.docker.com/get-started/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.docker.com/engine/reference/builder/" rel="noopener noreferrer"&gt;https://docs.docker.com/engine/reference/builder/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Docker Curriculum by Prakhar Srivastav&lt;/strong&gt;&lt;br&gt;
A free, community-driven, step-by-step walkthrough of Docker fundamentals, from images and containers to multi-stage builds and networking.&lt;br&gt;
&lt;a href="https://docker-curriculum.com/" rel="noopener noreferrer"&gt;https://docker-curriculum.com/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Play with Docker&lt;/strong&gt;&lt;br&gt;
An in-browser Docker playground—spin up real Docker hosts and containers without installing anything. Great for experimenting with Dockerfiles, commands, and networking.&lt;br&gt;
&lt;a href="https://labs.play-with-docker.com/" rel="noopener noreferrer"&gt;https://labs.play-with-docker.com/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;That’s it—five minutes to your first Docker build, plus a clear view of what happens under the hood. Drop a comment if you hit any snags or have tips of your own!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jose (@infraforge-dev)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>cicd</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>From Code to Purpose: Kickoff at InfraForge-dev</title>
      <dc:creator>Jose Rodriguez Marrero</dc:creator>
      <pubDate>Fri, 23 May 2025 15:45:08 +0000</pubDate>
      <link>https://dev.to/amodelandme/from-code-to-purpose-kickoff-at-infraforge-dev-40h2</link>
      <guid>https://dev.to/amodelandme/from-code-to-purpose-kickoff-at-infraforge-dev-40h2</guid>
      <description>&lt;h2&gt;
  
  
  👋 Hello Dev.to — I’m Jose!
&lt;/h2&gt;

&lt;p&gt;Ever wonder how many CI/CD pipelines it takes to deploy an e-commerce API? (Spoiler: less than you think, but more than one!)&lt;/p&gt;

&lt;p&gt;I’m Jose, a .NET backend &amp;amp; DevOps engineer on a mission to &lt;strong&gt;forge purposeful solutions&lt;/strong&gt;—not just code and configs, but the clear reasons behind each decision. After a year of deep dives into cloud architecture, containerization, and front-end wizardry (Angular 18 + TypeScript, I see you!), I’m finally sharing my experiments in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔨 What I’m Working On
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;InfraForge E-Commerce API&lt;/strong&gt;: An ASP.NET Core backend serving thousands of products in under 100 ms.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline Playground&lt;/strong&gt;: GitHub Actions → Docker → AWS Elastic Beanstalk (and yes, I’ll show you how to tame that YAML monster).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend Fun&lt;/strong&gt;: Angular 18 UI that drinks from my API’s firehose—spoiler: caching matters!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🚀 Why You’ll Stick Around
&lt;/h3&gt;

&lt;p&gt;I’m all about demystifying the “magic” of DevOps and API design. Expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deep-dive posts on performance tweaks, security hardening, and real-world trade-offs.
&lt;/li&gt;
&lt;li&gt;Code snippets you can copy/paste (and modify).
&lt;/li&gt;
&lt;li&gt;Honest “what went wrong” behind the scenes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So hit that 🌟, follow along, and drop a comment to say hi! Next up: “Taming Your First Docker Build in 5 Minutes.”&lt;/p&gt;

&lt;p&gt;— Jose (@infraforge-dev)  &lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>devops</category>
      <category>angular</category>
      <category>api</category>
    </item>
  </channel>
</rss>
