<?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>Forem: Jairo Blanco</title>
    <description>The latest articles on Forem by Jairo Blanco (@arthus15).</description>
    <link>https://forem.com/arthus15</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%2F600032%2F341f8536-7a3a-4c29-a6da-3634f5524d2f.png</url>
      <title>Forem: Jairo Blanco</title>
      <link>https://forem.com/arthus15</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/arthus15"/>
    <language>en</language>
    <item>
      <title>.NET 10 and the Next Leap in Native AOT for Cloud-Native Apps</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Wed, 15 Apr 2026 09:27:14 +0000</pubDate>
      <link>https://forem.com/arthus15/net-10-and-the-next-leap-in-native-aot-for-cloud-native-apps-a0k</link>
      <guid>https://forem.com/arthus15/net-10-and-the-next-leap-in-native-aot-for-cloud-native-apps-a0k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The evolution of .NET over the past few years has been strongly aligned with modern infrastructure demands: containers, microservices, serverless execution, and edge computing. With .NET 10, Microsoft continues this trajectory by significantly advancing Native AOT (Ahead-of-Time compilation), transforming it from a niche optimization into a practical and strategic approach for production systems.&lt;/p&gt;

&lt;p&gt;This article takes a deeper look at what makes Native AOT in .NET 10 particularly compelling, what problems it solves, and how it impacts architectural decisions in real-world applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding Native AOT in Context
&lt;/h2&gt;

&lt;p&gt;Traditionally, .NET applications rely on the Just-In-Time (JIT) compiler, which compiles Intermediate Language (IL) into machine code at runtime. While flexible, JIT introduces startup overhead and requires a runtime environment.&lt;/p&gt;

&lt;p&gt;Native AOT changes this model entirely by compiling applications directly into platform-specific machine code at build time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this matters:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Applications start almost instantly because there is no runtime compilation step&lt;/li&gt;
&lt;li&gt;Memory usage is significantly reduced since the runtime is minimized&lt;/li&gt;
&lt;li&gt;Deployment becomes simpler with self-contained executables&lt;/li&gt;
&lt;li&gt;Security improves due to a reduced attack surface&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key Enhancements in .NET 10
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Real-World Compatibility Improvements
&lt;/h3&gt;

&lt;p&gt;Earlier iterations of Native AOT often struggled with real-world applications due to heavy reliance on reflection and dynamic behaviors.&lt;/p&gt;

&lt;p&gt;.NET 10 addresses this by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expanding trimming support across the base class libraries&lt;/li&gt;
&lt;li&gt;Introducing better static analysis tools to detect incompatibilities&lt;/li&gt;
&lt;li&gt;Reducing reliance on runtime code generation in core frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means significantly fewer code changes are required to adopt AOT in existing systems.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. ASP.NET Core Becomes AOT-Friendly
&lt;/h3&gt;

&lt;p&gt;One of the most important milestones in .NET 10 is the maturity of ASP.NET Core under AOT constraints.&lt;/p&gt;

&lt;p&gt;Key improvements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better support for Minimal APIs, which align naturally with AOT principles&lt;/li&gt;
&lt;li&gt;Optimized routing and request pipelines&lt;/li&gt;
&lt;li&gt;More efficient JSON serialization with source generators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This opens the door for running high-performance APIs with extremely low startup latency.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Startup Performance and Scalability
&lt;/h3&gt;

&lt;p&gt;Cold start performance has become a critical metric in modern distributed systems.&lt;/p&gt;

&lt;p&gt;With Native AOT in .NET 10:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Startup times can drop by up to 80–90%&lt;/li&gt;
&lt;li&gt;Applications can handle burst traffic more efficiently&lt;/li&gt;
&lt;li&gt;Horizontal scaling becomes faster and more cost-effective&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is especially impactful in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes environments&lt;/li&gt;
&lt;li&gt;Serverless platforms&lt;/li&gt;
&lt;li&gt;Auto-scaling microservice architectures&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Reduced Container Footprint
&lt;/h3&gt;

&lt;p&gt;Container efficiency is a major concern in cloud-native systems.&lt;/p&gt;

&lt;p&gt;Native AOT contributes by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminating the need for a full runtime image&lt;/li&gt;
&lt;li&gt;Producing smaller binaries&lt;/li&gt;
&lt;li&gt;Reducing overall container size by 30–60%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The downstream effects include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster CI/CD pipelines&lt;/li&gt;
&lt;li&gt;Reduced network transfer times&lt;/li&gt;
&lt;li&gt;Lower storage and compute costs&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  5. Tooling and Developer Experience
&lt;/h3&gt;

&lt;p&gt;Adopting Native AOT is significantly easier in .NET 10.&lt;/p&gt;

&lt;p&gt;Developers benefit from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improved compiler warnings and diagnostics&lt;/li&gt;
&lt;li&gt;Clear guidance on unsupported patterns&lt;/li&gt;
&lt;li&gt;Streamlined publishing commands&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet publish &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;-r&lt;/span&gt; linux-x64 /p:PublishAot&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ecosystem is also evolving to support AOT-friendly patterns, such as source generators and compile-time configuration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architectural Implications
&lt;/h2&gt;

&lt;p&gt;Native AOT is not just a performance feature—it influences how applications are designed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shift Toward Compile-Time Behavior
&lt;/h3&gt;

&lt;p&gt;Developers are encouraged to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace reflection with source generation&lt;/li&gt;
&lt;li&gt;Avoid runtime type discovery&lt;/li&gt;
&lt;li&gt;Define explicit dependency graphs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Preference for Simplicity
&lt;/h3&gt;

&lt;p&gt;Framework features that rely on dynamic behavior become less attractive. Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimal APIs are favored over MVC&lt;/li&gt;
&lt;li&gt;Lightweight libraries are preferred&lt;/li&gt;
&lt;li&gt;Predictable execution paths are prioritized&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When to Use Native AOT
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Strong Candidates
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Microservices with strict latency requirements&lt;/li&gt;
&lt;li&gt;Serverless workloads&lt;/li&gt;
&lt;li&gt;CLI tools and automation scripts&lt;/li&gt;
&lt;li&gt;Edge and IoT deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Situations to Avoid
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Applications relying heavily on reflection&lt;/li&gt;
&lt;li&gt;Plugin-based or dynamically extensible systems&lt;/li&gt;
&lt;li&gt;Large monoliths with runtime composition&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Strategic Impact
&lt;/h2&gt;

&lt;p&gt;Organizations adopting Native AOT in .NET 10 can expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster application startup and response times&lt;/li&gt;
&lt;li&gt;Improved infrastructure efficiency&lt;/li&gt;
&lt;li&gt;Lower operational costs&lt;/li&gt;
&lt;li&gt;Better alignment with cloud-native principles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In highly competitive environments, these improvements are not just technical—they translate directly into business value.&lt;/p&gt;




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

&lt;p&gt;.NET 10 represents a turning point where Native AOT becomes a practical and strategic choice rather than an experimental feature.&lt;/p&gt;

&lt;p&gt;For teams building modern, distributed systems, the question is no longer whether AOT is viable—but where it provides the most leverage.&lt;/p&gt;

&lt;p&gt;Adopting it thoughtfully can unlock significant gains in performance, scalability, and operational efficiency.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;Native AOT in .NET 10 is mature and production-ready&lt;/li&gt;
&lt;li&gt;It drastically improves startup time and memory usage&lt;/li&gt;
&lt;li&gt;Ideal for cloud-native and distributed systems&lt;/li&gt;
&lt;li&gt;Requires more compile-time discipline and less runtime dynamism&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;As the ecosystem continues to evolve, Native AOT is set to become a foundational pillar of high-performance .NET applications.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>cloud</category>
      <category>dotnet</category>
      <category>performance</category>
    </item>
    <item>
      <title>The illusion of Entity Framework</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Fri, 10 Apr 2026 07:26:04 +0000</pubDate>
      <link>https://forem.com/arthus15/the-illusion-of-entity-framework-2fi1</link>
      <guid>https://forem.com/arthus15/the-illusion-of-entity-framework-2fi1</guid>
      <description>&lt;p&gt;Entity Framework (EF) is, by most reasonable standards, an excellent&lt;br&gt;
tool. It reduces boilerplate, accelerates development, and allows&lt;br&gt;
developers to operate at a higher level of abstraction. LINQ queries&lt;br&gt;
feel expressive, composable, and safe. The friction of interacting with&lt;br&gt;
relational databases is significantly reduced.&lt;/p&gt;

&lt;p&gt;That is precisely the problem.&lt;/p&gt;

&lt;p&gt;EF is so effective at hiding the database that many developers begin to&lt;br&gt;
forget that one still exists.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Illusion of "Just Objects"
&lt;/h2&gt;

&lt;p&gt;At its core, EF promotes a mental model where the database is treated as&lt;br&gt;
an object graph. Developers write queries in C#, compose them fluently,&lt;br&gt;
and rely on EF to translate them into SQL.&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;users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&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;u&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreatedAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks harmless---and often it is. But the abstraction creates a&lt;br&gt;
dangerous illusion: that this is merely in-memory filtering and sorting.&lt;br&gt;
In reality, EF is generating SQL, executing it against a database&lt;br&gt;
engine, and incurring all the costs associated with that process.&lt;/p&gt;

&lt;p&gt;When developers stop thinking in terms of execution plans, indexes, and&lt;br&gt;
I/O, performance becomes an afterthought.&lt;/p&gt;
&lt;h2&gt;
  
  
  Deferred Execution: A Double-Edged Sword
&lt;/h2&gt;

&lt;p&gt;LINQ's deferred execution is elegant but frequently misunderstood.&lt;br&gt;
Queries are not executed when they are written, but when they are&lt;br&gt;
enumerated.&lt;/p&gt;

&lt;p&gt;This leads to subtle performance pitfalls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Multiple enumerations causing repeated database calls&lt;/li&gt;
&lt;li&gt;  Complex query chains generating inefficient SQL&lt;/li&gt;
&lt;li&gt;  Accidental N+1 query patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code reads cleanly, but the runtime behavior can be highly&lt;br&gt;
inefficient.&lt;/p&gt;
&lt;h2&gt;
  
  
  The N+1 Query Problem
&lt;/h2&gt;

&lt;p&gt;One of the most common anti-patterns in EF usage is the N+1 query&lt;br&gt;
problem. Consider:&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;orders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&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;order&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&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;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Potential lazy load&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can result in one query to fetch orders, followed by N additional&lt;br&gt;
queries---one per order---to fetch related items.&lt;/p&gt;

&lt;p&gt;The developer sees a simple loop. The database sees a storm of queries.&lt;/p&gt;
&lt;h2&gt;
  
  
  Over-Fetching and Under-Fetching
&lt;/h2&gt;

&lt;p&gt;EF makes it easy to retrieve entire entities, even when only a subset of&lt;br&gt;
fields is needed. This leads to over-fetching:&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;users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Fetches all columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conversely, poor use of projections or navigation properties can lead to&lt;br&gt;
under-fetching, triggering additional queries later.&lt;/p&gt;

&lt;p&gt;Both scenarios degrade performance, yet neither is obvious from the code&lt;br&gt;
alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost of Ignoring SQL
&lt;/h2&gt;

&lt;p&gt;A recurring pattern among EF-heavy teams is the gradual erosion of SQL&lt;br&gt;
literacy. Developers become less comfortable reading execution plans,&lt;br&gt;
analyzing joins, or reasoning about indexes.&lt;/p&gt;

&lt;p&gt;This is not a failure of EF---it is a side effect of its success.&lt;/p&gt;

&lt;p&gt;When the abstraction works 95% of the time, the remaining 5% becomes&lt;br&gt;
disproportionately difficult to diagnose. Performance issues surface&lt;br&gt;
late, often under production load, and require a sudden shift back into&lt;br&gt;
database-centric thinking.&lt;/p&gt;

&lt;h2&gt;
  
  
  EF Is Not the Problem
&lt;/h2&gt;

&lt;p&gt;It is important to be precise here: EF is not inherently problematic. In&lt;br&gt;
fact, it provides mechanisms to address nearly all of the issues&lt;br&gt;
discussed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Eager loading with &lt;code&gt;Include&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Projection with &lt;code&gt;Select&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Compiled queries&lt;/li&gt;
&lt;li&gt;  Raw SQL execution when necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The issue is not capability---it is awareness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reintroducing Intentionality
&lt;/h2&gt;

&lt;p&gt;To use EF effectively, developers must maintain a dual mental model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; The object-oriented view (entities, navigation properties)&lt;/li&gt;
&lt;li&gt; The relational view (tables, joins, indexes)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every LINQ query should implicitly prompt the question: &lt;em&gt;What SQL will&lt;br&gt;
this generate?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Practical steps include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Logging generated SQL during development&lt;/li&gt;
&lt;li&gt;  Reviewing query execution plans for critical paths&lt;/li&gt;
&lt;li&gt;  Benchmarking queries with realistic data volumes&lt;/li&gt;
&lt;li&gt;  Avoiding blind reliance on lazy loading&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Entity Framework is a powerful abstraction layer, but like all&lt;br&gt;
abstractions, it trades visibility for convenience. When used without&lt;br&gt;
discipline, it encourages developers to forget that they are interacting&lt;br&gt;
with a database system governed by very real performance constraints.&lt;/p&gt;

&lt;p&gt;The goal is not to abandon EF, but to use it consciously.&lt;/p&gt;

&lt;p&gt;Because no matter how elegant your LINQ is, the database still executes&lt;br&gt;
SQL.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>csharp</category>
      <category>database</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>REPR vs MVC: A Pragmatic Comparison</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Fri, 10 Apr 2026 07:18:55 +0000</pubDate>
      <link>https://forem.com/arthus15/repr-vs-mvc-a-pragmatic-comparison-4hil</link>
      <guid>https://forem.com/arthus15/repr-vs-mvc-a-pragmatic-comparison-4hil</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When building web applications in .NET, most developers default to &lt;strong&gt;MVC (Model-View-Controller)&lt;/strong&gt;. It’s familiar, well-documented, and deeply integrated into ASP.NET Core.&lt;/p&gt;

&lt;p&gt;However, modern API design has shifted toward &lt;strong&gt;feature-oriented architectures&lt;/strong&gt;, where &lt;strong&gt;REPR (Request-Endpoint-Response)&lt;/strong&gt; is gaining traction—especially with libraries like FastEndpoints.&lt;/p&gt;

&lt;p&gt;This article provides a deeper, production-oriented comparison, including architectural implications, scalability, testing, and alignment with patterns like CQRS.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is MVC?
&lt;/h2&gt;

&lt;p&gt;MVC separates concerns into three components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model&lt;/strong&gt; → Domain/data + business logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;View&lt;/strong&gt; → UI rendering (Razor, HTML, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controller&lt;/strong&gt; → Handles HTTP requests and orchestrates responses&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&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="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/[controller]"&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;UsersController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&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;readonly&lt;/span&gt; &lt;span class="n"&gt;IUserService&lt;/span&gt; &lt;span class="n"&gt;_service&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;UsersController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IUserService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id}"&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;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetUser&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;id&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;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUserById&lt;/span&gt;&lt;span class="p"&gt;(&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&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;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;CreateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateUserDto&lt;/span&gt; &lt;span class="n"&gt;dto&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;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;CreatedAtAction&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;GetUser&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="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;
  
  
  Observations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multiple endpoints per controller&lt;/li&gt;
&lt;li&gt;Shared dependencies across actions&lt;/li&gt;
&lt;li&gt;Implicit grouping by resource (UsersController)&lt;/li&gt;
&lt;li&gt;Controllers tend to grow over time (&lt;strong&gt;controller bloat&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What is REPR?
&lt;/h2&gt;

&lt;p&gt;REPR stands for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request&lt;/strong&gt; → Input DTO&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Endpoint&lt;/strong&gt; → Single use-case handler&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response&lt;/strong&gt; → Output DTO&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each HTTP endpoint is implemented as a &lt;strong&gt;self-contained unit&lt;/strong&gt;, typically one class per use-case.&lt;/p&gt;

&lt;p&gt;This aligns closely with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vertical Slice Architecture&lt;/li&gt;
&lt;li&gt;CQRS (Command Query Responsibility Segregation)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  REPR with FastEndpoints
&lt;/h2&gt;

&lt;p&gt;FastEndpoints is a .NET library that implements REPR cleanly with minimal boilerplate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetUserRequest&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;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;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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetUserResponse&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;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;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;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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetUserEndpoint&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GetUserRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GetUserResponse&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;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IUserService&lt;/span&gt; &lt;span class="n"&gt;_service&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;GetUserEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IUserService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&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;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/users/{id}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;AllowAnonymous&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;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;HandleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetUserRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&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;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUserByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="k"&gt;is&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;SendNotFoundAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;GetUserResponse&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&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="n"&gt;user&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="n"&gt;cancellation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ct&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;
  
  
  Architectural Comparison
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Organization
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;MVC&lt;/th&gt;
&lt;th&gt;REPR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Structure&lt;/td&gt;
&lt;td&gt;Horizontal (controllers)&lt;/td&gt;
&lt;td&gt;Vertical (features)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grouping&lt;/td&gt;
&lt;td&gt;By resource&lt;/td&gt;
&lt;td&gt;By use-case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Files&lt;/td&gt;
&lt;td&gt;Fewer, larger&lt;/td&gt;
&lt;td&gt;More, smaller&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
REPR follows &lt;em&gt;"screaming architecture"&lt;/em&gt; — your folder structure reflects business capabilities.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Coupling &amp;amp; Cohesion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MVC&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High intra-controller coupling&lt;/li&gt;
&lt;li&gt;Shared dependencies across unrelated actions&lt;/li&gt;
&lt;li&gt;Risk of unintended side effects&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;REPR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High cohesion per endpoint&lt;/li&gt;
&lt;li&gt;Minimal coupling&lt;/li&gt;
&lt;li&gt;Dependencies are scoped per use-case&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Scalability (Codebase, not infra)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MVC&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controllers grow (10–20+ actions common)&lt;/li&gt;
&lt;li&gt;Navigation becomes harder&lt;/li&gt;
&lt;li&gt;Merge conflicts increase in teams&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;REPR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linear scalability (add new files, not modify existing ones)&lt;/li&gt;
&lt;li&gt;Safer parallel development&lt;/li&gt;
&lt;li&gt;Better suited for large teams&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Testing
&lt;/h3&gt;

&lt;h4&gt;
  
  
  MVC
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Requires controller setup&lt;/li&gt;
&lt;li&gt;Often involves mocking multiple dependencies&lt;/li&gt;
&lt;li&gt;Harder to isolate logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  REPR
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Endpoint = unit of test&lt;/li&gt;
&lt;li&gt;Minimal mocking&lt;/li&gt;
&lt;li&gt;Highly deterministic
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example test idea (pseudo)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;endpoint&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;GetUserEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fakeService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HandleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Alignment with CQRS
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;MVC&lt;/th&gt;
&lt;th&gt;REPR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Commands &amp;amp; Queries&lt;/td&gt;
&lt;td&gt;Mixed in controllers&lt;/td&gt;
&lt;td&gt;Naturally separated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read/Write models&lt;/td&gt;
&lt;td&gt;Often shared&lt;/td&gt;
&lt;td&gt;Easily separated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mental model&lt;/td&gt;
&lt;td&gt;Resource-centric&lt;/td&gt;
&lt;td&gt;Use-case-centric&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;REPR maps almost 1:1 with CQRS.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Performance Considerations
&lt;/h3&gt;

&lt;p&gt;FastEndpoints removes some MVC overhead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No controller discovery pipeline&lt;/li&gt;
&lt;li&gt;Less reflection-heavy execution&lt;/li&gt;
&lt;li&gt;Leaner middleware interaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While differences are often negligible, REPR frameworks can offer &lt;strong&gt;slightly better throughput and lower allocations&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  FastEndpoints: Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Strongly typed request/response models&lt;/li&gt;
&lt;li&gt;Built-in validation pipeline&lt;/li&gt;
&lt;li&gt;Pre/post processors (middleware-like)&lt;/li&gt;
&lt;li&gt;Fluent configuration&lt;/li&gt;
&lt;li&gt;Minimal boilerplate&lt;/li&gt;
&lt;li&gt;Endpoint-level dependency injection&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: Validation
&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateUserValidator&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Validator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CreateUserRequest&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="nf"&gt;CreateUserValidator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&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="nf"&gt;NotEmpty&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;
  
  
  When to Use MVC
&lt;/h2&gt;

&lt;p&gt;Use MVC if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are building &lt;strong&gt;server-rendered apps&lt;/strong&gt; (Razor Views)&lt;/li&gt;
&lt;li&gt;Your team is heavily invested in MVC&lt;/li&gt;
&lt;li&gt;You are maintaining legacy systems&lt;/li&gt;
&lt;li&gt;You prefer convention over explicit structure&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When to Use REPR (FastEndpoints)
&lt;/h2&gt;

&lt;p&gt;Use REPR if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are building &lt;strong&gt;APIs or microservices&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;feature-based organization&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You value &lt;strong&gt;low coupling and high cohesion&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You are adopting &lt;strong&gt;CQRS or Vertical Slice Architecture&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You want better &lt;strong&gt;team scalability&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  MVC Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Controller bloat&lt;/li&gt;
&lt;li&gt;Harder long-term maintainability&lt;/li&gt;
&lt;li&gt;Implicit coupling between endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  REPR Drawbacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Higher file count&lt;/li&gt;
&lt;li&gt;Initial learning curve&lt;/li&gt;
&lt;li&gt;Less "standard" in enterprise environments (for now)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Folder Structure Comparison
&lt;/h2&gt;

&lt;h3&gt;
  
  
  MVC
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controllers/
  UsersController.cs
Services/
Models/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  REPR
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Features/
  Users/
    GetUser/
      Endpoint.cs
      Request.cs
      Response.cs
    CreateUser/
      Endpoint.cs
      Validator.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;MVC is a proven and stable architectural pattern, but it shows its age in large, API-heavy systems.&lt;/p&gt;

&lt;p&gt;REPR—especially with FastEndpoints—offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better scalability&lt;/li&gt;
&lt;li&gt;Clearer separation of concerns&lt;/li&gt;
&lt;li&gt;Strong alignment with modern architectural patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building a &lt;strong&gt;new .NET API in 2026&lt;/strong&gt;, REPR is not just an alternative—it’s often the &lt;strong&gt;more maintainable default&lt;/strong&gt;.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;FastEndpoints GitHub&lt;/li&gt;
&lt;li&gt;ASP.NET Core MVC docs&lt;/li&gt;
&lt;li&gt;Vertical Slice Architecture (Jimmy Bogard)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>api</category>
      <category>architecture</category>
      <category>dotnet</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Vertical Slice Architecture: A Balanced Evaluation</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Tue, 07 Apr 2026 08:17:50 +0000</pubDate>
      <link>https://forem.com/arthus15/vertical-slice-architecture-a-balanced-evaluation-1i3f</link>
      <guid>https://forem.com/arthus15/vertical-slice-architecture-a-balanced-evaluation-1i3f</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Vertical Slice Architecture (VSA) is a feature-oriented architectural style that structures applications around use cases rather than technical layers. It is particularly popular in modern .NET development, often combined with tools like MediatR and minimal APIs.&lt;/p&gt;

&lt;p&gt;This article provides an objective assessment of VSA, outlining both its strengths and its trade-offs so you can make an informed architectural decision.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Vertical Slice Architecture?
&lt;/h2&gt;

&lt;p&gt;Vertical Slice Architecture organizes code by feature (or "slice"), where each slice contains everything required to fulfill a specific use case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Endpoint or controller&lt;/li&gt;
&lt;li&gt;Business logic&lt;/li&gt;
&lt;li&gt;Validation&lt;/li&gt;
&lt;li&gt;Data access&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Features
  /Orders
    CreateOrder.cs
    GetOrder.cs
    UpdateOrder.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each slice is intended to be independent and self-contained.&lt;/p&gt;




&lt;h2&gt;
  
  
  Advantages of Vertical Slice Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Feature-Centric Organization
&lt;/h3&gt;

&lt;p&gt;Code is grouped by business capability rather than technical concern. This aligns well with how product teams think about functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Easier mapping between requirements and implementation.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Reduced Layer Coupling
&lt;/h3&gt;

&lt;p&gt;Traditional layered architectures (Controller → Service → Repository) introduce indirection. VSA reduces or eliminates these layers.&lt;/p&gt;

&lt;p&gt;Example using a minimal API in .NET 10:&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/orders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateOrderRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;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;order&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;CustomerId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sum&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;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;Price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&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;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"/orders/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&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;order&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;Benefit:&lt;/strong&gt; Less boilerplate and fewer abstractions.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Improved Feature Isolation
&lt;/h3&gt;

&lt;p&gt;Each slice can evolve independently, making it easier to modify or remove features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Lower risk when changing isolated functionality.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Faster Development for Small Systems
&lt;/h3&gt;

&lt;p&gt;For small to medium-sized applications, VSA enables rapid development due to its simplicity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; High velocity in early stages of a project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Disadvantages of Vertical Slice Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Risk of Code Duplication
&lt;/h3&gt;

&lt;p&gt;Because slices are self-contained, shared logic is often duplicated instead of abstracted.&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;// CreateOrder slice&lt;/span&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;CreateOrderValidator&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;bool&lt;/span&gt; &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// UpdateOrder slice&lt;/span&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;UpdateOrderValidator&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;bool&lt;/span&gt; &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&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;Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increased maintenance cost&lt;/li&gt;
&lt;li&gt;Potential inconsistencies&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Weak Domain Modeling
&lt;/h3&gt;

&lt;p&gt;Business logic often lives in handlers or endpoints rather than domain entities.&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;Order&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;decimal&lt;/span&gt; &lt;span class="n"&gt;Total&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logic may instead appear in multiple slices:&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Total&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid order total"&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;Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anemic domain model&lt;/li&gt;
&lt;li&gt;Poor encapsulation&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Harder Cross-Cutting Concerns
&lt;/h3&gt;

&lt;p&gt;Handling concerns like logging, validation, or transactions consistently can be more difficult without shared layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repetition or reliance on middleware/pipelines&lt;/li&gt;
&lt;li&gt;Increased architectural complexity over time&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Discoverability Challenges
&lt;/h3&gt;

&lt;p&gt;Logic related to a single domain concept may be scattered across multiple slices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Harder onboarding for new developers&lt;/li&gt;
&lt;li&gt;Increased cognitive load&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  5. Refactoring Complexity at Scale
&lt;/h3&gt;

&lt;p&gt;As the system grows, duplicated logic and distributed rules make refactoring more expensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Higher risk of regressions&lt;/li&gt;
&lt;li&gt;Slower evolution of core business rules&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When Vertical Slice Architecture Works Well
&lt;/h2&gt;

&lt;p&gt;VSA is a good fit when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application is small to medium in size&lt;/li&gt;
&lt;li&gt;Business rules are relatively simple&lt;/li&gt;
&lt;li&gt;Rapid development is a priority&lt;/li&gt;
&lt;li&gt;Teams prefer minimal abstraction&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When to Be Cautious
&lt;/h2&gt;

&lt;p&gt;Consider alternatives when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The domain is complex or evolving&lt;/li&gt;
&lt;li&gt;Strong domain modeling is required&lt;/li&gt;
&lt;li&gt;There are many shared business rules&lt;/li&gt;
&lt;li&gt;Long-term maintainability is critical&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Practical Middle Ground
&lt;/h2&gt;

&lt;p&gt;Many teams adopt a hybrid approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use vertical slices for application flow&lt;/li&gt;
&lt;li&gt;Extract shared domain logic into domain models&lt;/li&gt;
&lt;li&gt;Centralize cross-cutting concerns via middleware or pipelines&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight 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;Order&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;decimal&lt;/span&gt; &lt;span class="n"&gt;Total&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;AddItem&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;price&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;price&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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Price must be positive"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This preserves domain integrity while maintaining feature-based organization.&lt;/p&gt;




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

&lt;p&gt;Vertical Slice Architecture is neither inherently good nor bad—it is a trade-off.&lt;/p&gt;

&lt;p&gt;It excels in simplicity, feature alignment, and rapid development, but can introduce duplication, weaker domain models, and scaling challenges if not carefully managed.&lt;/p&gt;

&lt;p&gt;The key is to evaluate your system's complexity, team structure, and long-term goals before adopting it as a default architectural pattern.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>dotnet</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>DevOps Philosophy</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Thu, 19 Mar 2026 09:22:19 +0000</pubDate>
      <link>https://forem.com/arthus15/devops-philosophy-f32</link>
      <guid>https://forem.com/arthus15/devops-philosophy-f32</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;DevOps is not a toolset or a job title---it is a philosophy. At its&lt;br&gt;
core, DevOps is about breaking down silos between development and&lt;br&gt;
operations to enable faster, safer, and more reliable software delivery.&lt;/p&gt;

&lt;p&gt;This post explores the principles behind DevOps, the mindset it&lt;br&gt;
requires, and the practices that make it effective.&lt;/p&gt;


&lt;h2&gt;
  
  
  What is DevOps?
&lt;/h2&gt;

&lt;p&gt;DevOps is a cultural and technical movement that emphasizes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Collaboration between teams&lt;/li&gt;
&lt;li&gt;  Automation of processes&lt;/li&gt;
&lt;li&gt;  Continuous delivery of value&lt;/li&gt;
&lt;li&gt;  Shared ownership of systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It aligns development (Dev) and operations (Ops) into a unified&lt;br&gt;
workflow.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Core Principles of DevOps
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Collaboration Over Silos
&lt;/h3&gt;

&lt;p&gt;Traditional models separate responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Developers write code&lt;/li&gt;
&lt;li&gt;  Operations deploy and maintain it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DevOps removes this divide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Teams share responsibility for the entire lifecycle.&lt;/p&gt;

&lt;p&gt;This leads to: - Better communication - Faster feedback - Fewer&lt;br&gt;
production surprises&lt;/p&gt;


&lt;h3&gt;
  
  
  2. Automation First
&lt;/h3&gt;

&lt;p&gt;Manual processes are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Error-prone&lt;/li&gt;
&lt;li&gt;  Slow&lt;/li&gt;
&lt;li&gt;  Hard to scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DevOps promotes automation wherever possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Builds&lt;/li&gt;
&lt;li&gt;  Testing&lt;/li&gt;
&lt;li&gt;  Deployment&lt;/li&gt;
&lt;li&gt;  Infrastructure provisioning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Reduce human intervention in repetitive tasks.&lt;/p&gt;


&lt;h3&gt;
  
  
  3. Continuous Integration and Continuous Delivery (CI/CD)
&lt;/h3&gt;

&lt;p&gt;Frequent, small changes are safer than large, infrequent ones.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Continuous Integration (CI):&lt;/strong&gt; Merge code frequently and validate
with automated tests&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Continuous Delivery (CD):&lt;/strong&gt; Ensure code is always in a deployable
state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benefits: - Faster releases - Lower risk - Easier debugging&lt;/p&gt;


&lt;h3&gt;
  
  
  4. Shift Left on Quality
&lt;/h3&gt;

&lt;p&gt;Testing and quality assurance should happen early.&lt;/p&gt;

&lt;p&gt;Instead of: - Testing at the end&lt;/p&gt;

&lt;p&gt;Adopt: - Testing during development&lt;/p&gt;

&lt;p&gt;This includes: - Unit tests - Integration tests - Static analysis&lt;/p&gt;


&lt;h3&gt;
  
  
  5. Observability and Feedback Loops
&lt;/h3&gt;

&lt;p&gt;You cannot improve what you cannot measure.&lt;/p&gt;

&lt;p&gt;DevOps relies on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Logging&lt;/li&gt;
&lt;li&gt;  Metrics&lt;/li&gt;
&lt;li&gt;  Tracing&lt;/li&gt;
&lt;li&gt;  Monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These provide feedback from production systems to developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outcome:&lt;/strong&gt; Faster detection and resolution of issues.&lt;/p&gt;


&lt;h3&gt;
  
  
  6. Infrastructure as Code (IaC)
&lt;/h3&gt;

&lt;p&gt;Infrastructure should be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Versioned&lt;/li&gt;
&lt;li&gt;  Reproducible&lt;/li&gt;
&lt;li&gt;  Automated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of manual configuration, define infrastructure in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example (simplified)&lt;/span&gt;
&lt;span class="s"&gt;resource "server" "app" {&lt;/span&gt;
  &lt;span class="s"&gt;image = "ubuntu"&lt;/span&gt;
  &lt;span class="s"&gt;size  = "small"&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits: - Consistency across environments - Easier scaling -&lt;br&gt;
Auditability&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Ownership and Accountability
&lt;/h3&gt;

&lt;p&gt;In DevOps:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"You build it, you run it"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Developers are responsible for: - Writing code - Deploying it -&lt;br&gt;
Monitoring it - Fixing it in production&lt;/p&gt;

&lt;p&gt;This creates stronger incentives for quality and reliability.&lt;/p&gt;




&lt;h2&gt;
  
  
  DevOps Mindset
&lt;/h2&gt;

&lt;p&gt;Beyond practices, DevOps requires a shift in thinking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Think in Systems
&lt;/h3&gt;

&lt;p&gt;Understand how components interact: - Services - Databases - Networks&lt;/p&gt;

&lt;p&gt;Avoid optimizing in isolation.&lt;/p&gt;




&lt;h3&gt;
  
  
  Embrace Failure as Learning
&lt;/h3&gt;

&lt;p&gt;Failures will happen.&lt;/p&gt;

&lt;p&gt;DevOps encourages: - Blameless postmortems - Root cause analysis -&lt;br&gt;
Continuous improvement&lt;/p&gt;




&lt;h3&gt;
  
  
  Prioritize Flow
&lt;/h3&gt;

&lt;p&gt;Optimize for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Faster delivery&lt;/li&gt;
&lt;li&gt;  Reduced bottlenecks&lt;/li&gt;
&lt;li&gt;  Smooth handoffs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Measure lead time and deployment frequency.&lt;/p&gt;




&lt;h3&gt;
  
  
  Continuous Improvement
&lt;/h3&gt;

&lt;p&gt;DevOps is iterative:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Measure&lt;/li&gt;
&lt;li&gt;  Learn&lt;/li&gt;
&lt;li&gt;  Improve&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Never assume the system is "done."&lt;/p&gt;




&lt;h2&gt;
  
  
  Common DevOps Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Automated testing pipelines&lt;/li&gt;
&lt;li&gt;  Continuous deployment&lt;/li&gt;
&lt;li&gt;  Blue/green or canary releases&lt;/li&gt;
&lt;li&gt;  Monitoring and alerting&lt;/li&gt;
&lt;li&gt;  Containerization (e.g., Docker)&lt;/li&gt;
&lt;li&gt;  Orchestration (e.g., Kubernetes)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Anti-Patterns to Avoid
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚫 Treating DevOps as a Role
&lt;/h3&gt;

&lt;p&gt;DevOps is not a single team responsible for everything.&lt;/p&gt;




&lt;h3&gt;
  
  
  🚫 Tool-First Approach
&lt;/h3&gt;

&lt;p&gt;Buying tools without cultural change leads to failure.&lt;/p&gt;




&lt;h3&gt;
  
  
  🚫 Ignoring Culture
&lt;/h3&gt;

&lt;p&gt;Lack of trust and communication undermines all technical improvements.&lt;/p&gt;




&lt;h3&gt;
  
  
  🚫 Over-Automation Without Understanding
&lt;/h3&gt;

&lt;p&gt;Automating broken processes just makes problems faster.&lt;/p&gt;




&lt;h2&gt;
  
  
  Measuring DevOps Success
&lt;/h2&gt;

&lt;p&gt;Common metrics (DORA metrics):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Deployment frequency&lt;/li&gt;
&lt;li&gt;  Lead time for changes&lt;/li&gt;
&lt;li&gt;  Change failure rate&lt;/li&gt;
&lt;li&gt;  Mean time to recovery (MTTR)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These help evaluate performance objectively.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example Workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Developer commits code&lt;/li&gt;
&lt;li&gt; CI pipeline runs tests&lt;/li&gt;
&lt;li&gt; Build artifact is created&lt;/li&gt;
&lt;li&gt; Deployment pipeline pushes to staging&lt;/li&gt;
&lt;li&gt; Automated tests validate&lt;/li&gt;
&lt;li&gt; Deployment to production&lt;/li&gt;
&lt;li&gt; Monitoring provides feedback&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;DevOps is about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  People&lt;/li&gt;
&lt;li&gt;  Processes&lt;/li&gt;
&lt;li&gt;  Technology&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In that order.&lt;/p&gt;

&lt;p&gt;Organizations that succeed with DevOps focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Collaboration&lt;/li&gt;
&lt;li&gt;  Automation&lt;/li&gt;
&lt;li&gt;  Feedback&lt;/li&gt;
&lt;li&gt;  Continuous improvement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is not a destination, but an ongoing evolution toward better software delivery.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>cicd</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Code Review Best Practices</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Thu, 19 Mar 2026 09:19:12 +0000</pubDate>
      <link>https://forem.com/arthus15/code-review-best-practices-3cag</link>
      <guid>https://forem.com/arthus15/code-review-best-practices-3cag</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Code reviews are a critical part of modern software engineering. When&lt;br&gt;
done well, they improve code quality, reduce defects, and spread&lt;br&gt;
knowledge across teams. When done poorly, they create friction, slow&lt;br&gt;
delivery, and damage collaboration.&lt;/p&gt;

&lt;p&gt;This guide focuses on &lt;em&gt;how to review code effectively&lt;/em&gt;, with emphasis on&lt;br&gt;
writing clear, objective, and actionable comments.&lt;/p&gt;




&lt;h2&gt;
  
  
  Goals of a Code Review
&lt;/h2&gt;

&lt;p&gt;Before reviewing code, align on the purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Improve correctness and reliability&lt;/li&gt;
&lt;li&gt;  Ensure maintainability and readability&lt;/li&gt;
&lt;li&gt;  Enforce team standards&lt;/li&gt;
&lt;li&gt;  Share knowledge&lt;/li&gt;
&lt;li&gt;  Reduce technical debt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A code review is &lt;strong&gt;not&lt;/strong&gt;: - A place to show superiority - A stylistic&lt;br&gt;
battleground - A personal critique&lt;/p&gt;




&lt;h2&gt;
  
  
  Principles of Effective Code Reviews
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Be Objective, Not Subjective
&lt;/h3&gt;

&lt;p&gt;Avoid vague or opinion-based comments.&lt;/p&gt;

&lt;p&gt;❌ Bad: &amp;gt; "This feels weird" &amp;gt; "I don't like this approach"&lt;/p&gt;

&lt;p&gt;✅ Better: &amp;gt; "This introduces tight coupling between X and Y, which may&lt;br&gt;
make testing harder" &amp;gt; "This function has multiple responsibilities;&lt;br&gt;
consider splitting it to improve maintainability"&lt;/p&gt;

&lt;p&gt;Focus on: - Readability - Complexity - Performance implications -&lt;br&gt;
Consistency with standards&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Provide Context and Reasoning
&lt;/h3&gt;

&lt;p&gt;A comment without reasoning forces the author to guess your intent.&lt;/p&gt;

&lt;p&gt;❌ Bad: &amp;gt; "Refactor this"&lt;/p&gt;

&lt;p&gt;✅ Better: &amp;gt; "Refactor this method to reduce cyclomatic complexity&lt;br&gt;
(currently 15), which makes it harder to test and maintain"&lt;/p&gt;

&lt;p&gt;Always answer: - Why is this an issue? - What is the impact?&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Suggest Improvements, Don't Just Point Out Problems
&lt;/h3&gt;

&lt;p&gt;Good reviews are constructive.&lt;/p&gt;

&lt;p&gt;❌ Bad: &amp;gt; "This is wrong"&lt;/p&gt;

&lt;p&gt;✅ Better: &amp;gt; "This may cause a null reference if &lt;code&gt;user&lt;/code&gt; is missing.&lt;br&gt;
Consider using a guard clause or null check here"&lt;/p&gt;

&lt;p&gt;Even better: &amp;gt; "Consider using &lt;code&gt;TryGetValue&lt;/code&gt; to avoid exceptions and&lt;br&gt;
improve clarity"&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Keep Comments Small and Specific
&lt;/h3&gt;

&lt;p&gt;Avoid dumping large, unfocused feedback.&lt;/p&gt;

&lt;p&gt;❌ Bad: &amp;gt; "This whole file needs improvement"&lt;/p&gt;

&lt;p&gt;✅ Better: - "Method &lt;code&gt;ProcessOrder&lt;/code&gt; mixes validation and persistence" -&lt;br&gt;
"Variable &lt;code&gt;x&lt;/code&gt; is unclear---consider renaming to &lt;code&gt;orderTotal&lt;/code&gt;"&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Separate Must-Fix vs Nice-to-Have
&lt;/h3&gt;

&lt;p&gt;Not all comments are equal. Clarify priority:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Must fix&lt;/strong&gt;: Bugs, security issues, broken logic&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Should fix&lt;/strong&gt;: Maintainability, design concerns&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Nitpick&lt;/strong&gt;: Minor style or formatting&lt;/li&gt;
&lt;/ul&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"Nit: Consider renaming this variable for clarity"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This reduces friction and helps authors prioritize.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Avoid Personal Language
&lt;/h3&gt;

&lt;p&gt;Keep feedback about the code, not the person.&lt;/p&gt;

&lt;p&gt;❌ Bad: &amp;gt; "You wrote this incorrectly"&lt;/p&gt;

&lt;p&gt;✅ Better: &amp;gt; "This implementation may fail when the input is empty"&lt;/p&gt;

&lt;p&gt;Neutral, technical language keeps discussions professional.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Don't Over-Review
&lt;/h3&gt;

&lt;p&gt;Focus on meaningful issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Logic errors&lt;/li&gt;
&lt;li&gt;  Architectural concerns&lt;/li&gt;
&lt;li&gt;  Maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid: - Rewriting code to match your personal style - Commenting on&lt;br&gt;
trivial differences (if tooling can enforce it)&lt;/p&gt;

&lt;p&gt;Use linters and formatters to automate style enforcement.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. Acknowledge Good Work
&lt;/h3&gt;

&lt;p&gt;Positive feedback matters.&lt;/p&gt;

&lt;p&gt;Examples: &amp;gt; "Nice use of pattern matching here---improves readability"&lt;br&gt;
&amp;gt; "Good test coverage for edge cases"&lt;/p&gt;

&lt;p&gt;This reinforces good practices and keeps morale high.&lt;/p&gt;




&lt;h3&gt;
  
  
  9. Review in Context
&lt;/h3&gt;

&lt;p&gt;Understand: - The feature requirements - The surrounding codebase -&lt;br&gt;
Trade-offs made by the author&lt;/p&gt;

&lt;p&gt;Avoid reviewing in isolation.&lt;/p&gt;




&lt;h3&gt;
  
  
  10. Keep Turnaround Time Short
&lt;/h3&gt;

&lt;p&gt;Timely reviews keep teams moving.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Aim to review within a few hours (or same day)&lt;/li&gt;
&lt;li&gt;  Keep pull requests small to enable faster feedback&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Structuring Review Comments
&lt;/h2&gt;

&lt;p&gt;A strong comment typically follows this structure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Observation&lt;/strong&gt; -- What you see&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Impact&lt;/strong&gt; -- Why it matters&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Suggestion&lt;/strong&gt; -- How to improve&lt;/li&gt;
&lt;/ol&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"This method performs both validation and persistence (observation),&lt;br&gt;
which increases complexity and makes testing harder (impact). Consider&lt;br&gt;
splitting it into two methods (suggestion)."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Common Anti-Patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚫 The "Drive-By Review"
&lt;/h3&gt;

&lt;p&gt;Superficial comments without understanding context.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚫 The "Rewrite Reviewer"
&lt;/h3&gt;

&lt;p&gt;Rewriting everything to match personal preferences.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚫 The "Silent Approver"
&lt;/h3&gt;

&lt;p&gt;Approving without meaningful feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚫 The "Overly Harsh Critic"
&lt;/h3&gt;

&lt;p&gt;Creates defensive responses and slows collaboration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tooling Helps
&lt;/h2&gt;

&lt;p&gt;Use tools to reduce noise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Linters (e.g., StyleCop, ESLint)&lt;/li&gt;
&lt;li&gt;  Formatters (e.g., Prettier)&lt;/li&gt;
&lt;li&gt;  Static analysis tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This lets reviews focus on &lt;em&gt;logic and design&lt;/em&gt;, not formatting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: Before vs After
&lt;/h2&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"This is confusing"&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"The nested conditionals here make the flow hard to follow. Consider&lt;br&gt;
using early returns to simplify the control flow"&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;Great code reviews are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Clear&lt;/li&gt;
&lt;li&gt;  Objective&lt;/li&gt;
&lt;li&gt;  Actionable&lt;/li&gt;
&lt;li&gt;  Respectful&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are less about catching mistakes and more about &lt;strong&gt;collaboratively&lt;br&gt;
improving the codebase&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your comments consistently help others understand &lt;em&gt;why&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt; to&lt;br&gt;
improve, your reviews will add real value.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Checklist
&lt;/h2&gt;

&lt;p&gt;Before submitting a review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  [ ] Are my comments objective?&lt;/li&gt;
&lt;li&gt;  [ ] Did I explain &lt;em&gt;why&lt;/em&gt; something matters?&lt;/li&gt;
&lt;li&gt;  [ ] Did I suggest improvements?&lt;/li&gt;
&lt;li&gt;  [ ] Am I focusing on important issues?&lt;/li&gt;
&lt;li&gt;  [ ] Is my tone neutral and respectful?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>codequality</category>
      <category>codereview</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Refit: The Elegant REST Library for .NET That Will Change How You Write API Clients</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Thu, 05 Mar 2026 13:35:18 +0000</pubDate>
      <link>https://forem.com/arthus15/refit-the-elegant-rest-library-for-net-that-will-change-how-you-write-api-clients-4am5</link>
      <guid>https://forem.com/arthus15/refit-the-elegant-rest-library-for-net-that-will-change-how-you-write-api-clients-4am5</guid>
      <description>&lt;p&gt;If you've ever written an HTTP client in .NET, you know the ritual: create an &lt;code&gt;HttpClient&lt;/code&gt;, build the URL, set headers, serialize the request body, call &lt;code&gt;SendAsync&lt;/code&gt;, check the status code, deserialize the response, and handle errors — &lt;strong&gt;for every single endpoint&lt;/strong&gt;. It's repetitive, error-prone, and buries your intent under a mountain of boilerplate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refit&lt;/strong&gt; eliminates all of that. With Refit, you define your REST API as a C# interface, and Refit generates the implementation at runtime. That's it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Refit?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/reactiveui/refit" rel="noopener noreferrer"&gt;Refit&lt;/a&gt; is a type-safe REST client library for .NET, inspired by Square's Retrofit for Android. Developed by Paul Betts and maintained by the ReactiveUI organization, it turns REST API definitions into live, callable objects — no implementation required.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Turn your REST API into a live interface."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It supports .NET 6+, .NET Framework 4.6.1+, Xamarin, and MAUI, making it a universal solution across the .NET ecosystem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Install via NuGet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Refit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using ASP.NET Core and want seamless &lt;code&gt;HttpClientFactory&lt;/code&gt; integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Refit.HttpClientFactory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Your First Refit Client
&lt;/h2&gt;

&lt;p&gt;Let's say you're consuming the &lt;a href="https://jsonplaceholder.typicode.com" rel="noopener noreferrer"&gt;JSONPlaceholder&lt;/a&gt; API. Here's how you'd build a client with raw &lt;code&gt;HttpClient&lt;/code&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="c1"&gt;// The old way — verbose and fragile&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;BaseAddress&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;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://jsonplaceholder.typicode.com"&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;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/posts/1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnsureSuccessStatusCode&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;json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStringAsync&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;post&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now here's the Refit way:&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;// 1. Define the interface&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IJsonPlaceholderApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/posts/{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetPostAsync&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;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Create the client&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RestService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;For&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IJsonPlaceholderApi&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://jsonplaceholder.typicode.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Call it&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetPostAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="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;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&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 the entire implementation. Clean, readable, and self-documenting.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  HTTP Method Attributes
&lt;/h3&gt;

&lt;p&gt;Refit supports all standard HTTP verbs:&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;IPostsApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/posts"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&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="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAllPostsAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/posts/{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetPostAsync&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;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/posts"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreatePostAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/posts/{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;UpdatePostAsync&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/posts/{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;PatchPostAsync&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;JsonPatchDocument&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/posts/{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;DeletePostAsync&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;id&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;
  
  
  Query Parameters
&lt;/h3&gt;

&lt;p&gt;Pass query string parameters as method arguments:&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;ISearchApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Generates: /search?query=refit&amp;amp;page=2&amp;amp;pageSize=10&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SearchResults&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchAsync&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;query&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;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pageSize&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;[AliasAs]&lt;/code&gt; to map parameter names to query string keys:&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="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&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="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetUsersAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;AliasAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sort_by"&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;sortBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;AliasAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order"&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;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Request Headers
&lt;/h3&gt;

&lt;p&gt;Add headers at the interface, method, or parameter level:&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;// On the interface — applies to all methods&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User-Agent: MyApp/1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Accept: application/json"&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IMyApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// On a specific method&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cache-Control: no-cache"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/sensitive-data"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SensitiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetSensitiveDataAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Dynamic header via parameter&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/user/profile"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetProfileAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&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;authorization&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;
  
  
  Request Body
&lt;/h3&gt;

&lt;p&gt;Serialize complex objects to JSON automatically:&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;IBlogApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/articles"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateArticleAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;CreateArticleRequest&lt;/span&gt; &lt;span class="n"&gt;request&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;newArticle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CreateArticleRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Getting Started with Refit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Refit makes REST easy..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"dotnet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"refit"&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;created&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateArticleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newArticle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need to send form data instead of JSON?&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="nf"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/oauth/token"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TokenResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetTokenAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BodySerializationMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UrlEncoded&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;TokenRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Working with &lt;code&gt;IApiResponse&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;By default, Refit throws an &lt;code&gt;ApiException&lt;/code&gt; on non-success HTTP responses. But sometimes you want to inspect the response without throwing. Use &lt;code&gt;IApiResponse&amp;lt;T&amp;gt;&lt;/code&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IProductsApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/products/{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IApiResponse&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;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetProductAsync&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;id&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;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetProductAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsSuccessStatusCode&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="s"&gt;$"Product: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&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;span class="k"&gt;else&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;$"Error &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Message&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;You can also use &lt;code&gt;ApiResponse&amp;lt;T&amp;gt;&lt;/code&gt; (concrete class) to access response headers:&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;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetProductAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;etag&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ETag&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Integration with &lt;code&gt;HttpClientFactory&lt;/code&gt; (ASP.NET Core)
&lt;/h2&gt;

&lt;p&gt;The recommended approach in ASP.NET Core is to use &lt;code&gt;Refit.HttpClientFactory&lt;/code&gt; for proper &lt;code&gt;HttpClient&lt;/code&gt; lifecycle management:&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;// Program.cs&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRefitClient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IGitHubApi&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseAddress&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;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.github.com"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then inject it anywhere via DI:&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;GitHubService&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;readonly&lt;/span&gt; &lt;span class="n"&gt;IGitHubApi&lt;/span&gt; &lt;span class="n"&gt;_github&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;GitHubService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IGitHubApi&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_github&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;github&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;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&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="n"&gt;Repository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetUserReposAsync&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;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetRepositoriesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&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;
  
  
  Authentication with &lt;code&gt;DelegatingHandler&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;A clean way to add Bearer tokens is via a custom &lt;code&gt;DelegatingHandler&lt;/code&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;AuthHeaderHandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DelegatingHandler&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;readonly&lt;/span&gt; &lt;span class="n"&gt;ITokenService&lt;/span&gt; &lt;span class="n"&gt;_tokenService&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;AuthHeaderHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ITokenService&lt;/span&gt; &lt;span class="n"&gt;tokenService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_tokenService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;HttpRequestMessage&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&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;token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_tokenService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTokenAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authorization&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;AuthenticationHeaderValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bearer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&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;Register it with DI:&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;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthHeaderHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRefitClient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ISecureApi&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseAddress&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;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.example.com"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddHttpMessageHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthHeaderHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Custom Serialization Settings
&lt;/h2&gt;

&lt;p&gt;Refit uses &lt;code&gt;System.Text.Json&lt;/code&gt; by default. To customize settings:&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;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;RefitSettings&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ContentSerializer&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;SystemTextJsonContentSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JsonSerializerOptions&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;PropertyNamingPolicy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonNamingPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SnakeCaseLower&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;DefaultIgnoreCondition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonIgnoreCondition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WhenWritingNull&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Converters&lt;/span&gt; &lt;span class="p"&gt;=&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;JsonStringEnumConverter&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RestService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;For&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IMyApi&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefer Newtonsoft.Json? Install &lt;code&gt;Refit.Newtonsoft.Json&lt;/code&gt; and swap the serializer:&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;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;RefitSettings&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ContentSerializer&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;NewtonsoftJsonContentSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JsonSerializerSettings&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ContractResolver&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;CamelCasePropertyNamesContractResolver&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;NullValueHandling&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NullValueHandling&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ignore&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;
  
  
  Multipart / File Upload
&lt;/h2&gt;

&lt;p&gt;Uploading files is just as simple:&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;IFileApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Multipart&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/upload"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UploadResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;UploadFileAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;AliasAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;StreamPart&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;AliasAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"description"&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;description&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;await&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OpenRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"report.pdf"&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;filePart&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;StreamPart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"report.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UploadFileAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Monthly Report"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Cancellation Token Support
&lt;/h2&gt;

&lt;p&gt;All methods support &lt;code&gt;CancellationToken&lt;/code&gt; as an optional last parameter — no special attributes needed:&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;ISlowApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/long-running-report"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Report&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetReportAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Cancel after 5 seconds&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cts&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;CancellationTokenSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetReportAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Real-World Example: GitHub API Client
&lt;/h2&gt;

&lt;p&gt;Here's a realistic, production-style Refit client for the GitHub API:&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="nf"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User-Agent: MyGitHubApp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Accept: application/vnd.github.v3+json"&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IGitHubApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/{username}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GitHubUser&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetUserAsync&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;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/{username}/repos"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&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="n"&gt;Repository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetRepositoriesAsync&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;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;AliasAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sort"&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;sort&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"updated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;AliasAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"per_page"&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;perPage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/repos/{owner}/{repo}/issues"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IApiResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&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="n"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetIssuesAsync&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;owner&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;repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;AliasAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"state"&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;state&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"open"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/repos/{owner}/{repo}/issues"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateIssueAsync&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;owner&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;repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;CreateIssueRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&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;authorization&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;
  
  
  Error Handling
&lt;/h2&gt;

&lt;p&gt;Catch &lt;code&gt;ApiException&lt;/code&gt; for structured error responses:&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;try&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;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUserAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nonexistent-user-xyz"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApiException&lt;/span&gt; &lt;span class="n"&gt;ex&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="s"&gt;$"HTTP &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&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;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;$"Reason: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReasonPhrase&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="c1"&gt;// Deserialize the error body&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetContentAsAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GitHubError&lt;/span&gt;&lt;span class="p"&gt;&amp;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;$"GitHub says: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Message&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;h2&gt;
  
  
  Testing Refit Interfaces
&lt;/h2&gt;

&lt;p&gt;Since Refit generates implementations from interfaces, mocking is trivial with any mocking library:&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;// Using NSubstitute&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockApi&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Substitute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;For&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPostsApi&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;mockApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetPostAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Test Post"&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;service&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;PostService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockApi&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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetPostTitleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test Post"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No complex HTTP mocking infrastructure needed — your business logic is fully decoupled from the HTTP layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Refit vs. Alternatives
&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;Refit&lt;/th&gt;
&lt;th&gt;Raw HttpClient&lt;/th&gt;
&lt;th&gt;RestSharp&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Interface-based contracts&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compile-time type safety&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DI / HttpClientFactory&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto serialization&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boilerplate required&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Heavy&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testability&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning curve&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;p&gt;Refit is one of those libraries that, once you use it, you can't imagine going back. By expressing your API contract as a C# interface, you gain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clarity&lt;/strong&gt; — your API surface is immediately obvious from the interface definition&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type safety&lt;/strong&gt; — no more stringly-typed URLs or manual serialization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt; — mock the interface, test your logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability&lt;/strong&gt; — changes to the API are localized to the interface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less code&lt;/strong&gt; — dramatically less boilerplate per endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you're integrating with third-party APIs or consuming your own microservices, Refit is the most expressive and productive way to write HTTP clients in .NET.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Happy coding — and may your 404s be few and your 200s be plentiful.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>CQRS in .NET: Deep Analysis, Benefits, and Trade-Offs</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Wed, 25 Feb 2026 11:13:25 +0000</pubDate>
      <link>https://forem.com/arthus15/cqrs-in-net-deep-analysis-benefits-and-trade-offs-47ka</link>
      <guid>https://forem.com/arthus15/cqrs-in-net-deep-analysis-benefits-and-trade-offs-47ka</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Command Query Responsibility Segregation (CQRS) is an architectural&lt;br&gt;
pattern that separates read operations (queries) from write operations&lt;br&gt;
(commands). In modern .NET applications---especially those built with&lt;br&gt;
ASP.NET Core and Entity Framework Core---CQRS is commonly used to&lt;br&gt;
improve scalability, maintainability, and performance.&lt;/p&gt;

&lt;p&gt;This article provides a structured analysis of CQRS in .NET, including&lt;br&gt;
its conceptual model, implementation patterns, benefits, drawbacks, and&lt;br&gt;
when to apply it.&lt;/p&gt;


&lt;h2&gt;
  
  
  What is CQRS?
&lt;/h2&gt;

&lt;p&gt;CQRS divides application operations into two distinct models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Command Model&lt;/strong&gt;: Responsible for changing state (Create, Update,
Delete).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Query Model&lt;/strong&gt;: Responsible for reading state (no side effects).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation enables different optimization strategies for reads and&lt;br&gt;
writes.&lt;/p&gt;

&lt;p&gt;Unlike traditional CRUD architectures, CQRS enforces a strict separation&lt;br&gt;
between mutation and retrieval logic.&lt;/p&gt;


&lt;h2&gt;
  
  
  CQRS in the Context of .NET
&lt;/h2&gt;

&lt;p&gt;In .NET (particularly ASP.NET Core), CQRS is typically implemented&lt;br&gt;
using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;MediatR&lt;/strong&gt; for request/handler dispatching&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Entity Framework Core&lt;/strong&gt; for persistence&lt;/li&gt;
&lt;li&gt;  Separate DTOs for read and write models&lt;/li&gt;
&lt;li&gt;  Optional event sourcing for advanced scenarios&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Basic Folder Structure Example
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application/
 ├── Commands/
 │    ├── CreateOrderCommand.cs
 │    └── CreateOrderHandler.cs
 ├── Queries/
 │    ├── GetOrderByIdQuery.cs
 │    └── GetOrderByIdHandler.cs
Domain/
Infrastructure/
API/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Core Components in .NET CQRS
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Commands
&lt;/h3&gt;

&lt;p&gt;Commands represent intent to change state.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;CreateOrderCommand&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;CustomerName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Handler:&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;CreateOrderHandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CreateOrderCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&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;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;_context&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;CreateOrderHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateOrderCommand&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&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;order&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;CustomerName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerName&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cancellationToken&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;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&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;
  
  
  2. Queries
&lt;/h3&gt;

&lt;p&gt;Queries return data without modifying state.&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;record&lt;/span&gt; &lt;span class="nc"&gt;GetOrderByIdQuery&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Handler:&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;GetOrderByIdHandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GetOrderByIdQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderDto&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;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;_context&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;GetOrderByIdHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetOrderByIdQuery&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&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;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OrderDto&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CustomerName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerName&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cancellationToken&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;
  
  
  Architectural Variants
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Simple CQRS (Single Database)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Same database&lt;/li&gt;
&lt;li&gt;  Different logical models&lt;/li&gt;
&lt;li&gt;  Most common in business applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Full CQRS (Separate Databases)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Separate read/write databases&lt;/li&gt;
&lt;li&gt;  Asynchronous synchronization&lt;/li&gt;
&lt;li&gt;  Often combined with Event Sourcing&lt;/li&gt;
&lt;li&gt;  Used in high-scale systems&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Benefits of CQRS in .NET
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Clear Separation of Concerns
&lt;/h3&gt;

&lt;p&gt;Command logic and query logic evolve independently.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Optimized Read Models
&lt;/h3&gt;

&lt;p&gt;Read models can use: - Projection tables - Denormalized views - Dapper&lt;br&gt;
for fast reads - Caching strategies&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Scalability
&lt;/h3&gt;

&lt;p&gt;You can: - Scale read replicas independently - Apply different&lt;br&gt;
performance tuning strategies&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Maintainability
&lt;/h3&gt;

&lt;p&gt;Smaller handlers are easier to test and reason about.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Extensibility
&lt;/h3&gt;

&lt;p&gt;Cross-cutting concerns (logging, validation, transactions) can be added&lt;br&gt;
via MediatR pipeline behaviors.&lt;/p&gt;




&lt;h2&gt;
  
  
  Trade-Offs and Costs
&lt;/h2&gt;

&lt;p&gt;CQRS introduces complexity. It is not free.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Increased Architectural Complexity
&lt;/h3&gt;

&lt;p&gt;More files, more abstractions, more patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Learning Curve
&lt;/h3&gt;

&lt;p&gt;Developers must understand: - Domain-driven design concepts - Mediator&lt;br&gt;
pattern - Event-driven patterns (in advanced scenarios)&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Eventual Consistency (in advanced CQRS)
&lt;/h3&gt;

&lt;p&gt;If separate read/write models are used: - Data may not be immediately&lt;br&gt;
consistent - Requires careful UX considerations&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Overengineering Risk
&lt;/h3&gt;

&lt;p&gt;For small CRUD apps, CQRS may add unnecessary overhead.&lt;/p&gt;




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

&lt;p&gt;CQRS is appropriate when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The domain has complex business rules&lt;/li&gt;
&lt;li&gt;  Read/write workloads differ significantly&lt;/li&gt;
&lt;li&gt;  The system requires high scalability&lt;/li&gt;
&lt;li&gt;  The team is comfortable with architectural patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid CQRS when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The application is simple CRUD&lt;/li&gt;
&lt;li&gt;  The team lacks experience with distributed systems&lt;/li&gt;
&lt;li&gt;  Development speed is more important than architectural purity&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  CQRS and Clean Architecture
&lt;/h2&gt;

&lt;p&gt;CQRS integrates well with Clean Architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Commands and Queries live in the Application layer&lt;/li&gt;
&lt;li&gt;  Domain remains isolated&lt;/li&gt;
&lt;li&gt;  Infrastructure handles persistence and external systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This alignment improves testability and separation of concerns.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing Strategy in .NET
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Unit Testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Test handlers directly&lt;/li&gt;
&lt;li&gt;  Mock DbContext or use InMemory provider&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Integration Testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Test pipeline behaviors&lt;/li&gt;
&lt;li&gt;  Validate end-to-end command/query flow&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Performance Considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Use lightweight ORMs (e.g., Dapper) for query side&lt;/li&gt;
&lt;li&gt;  Avoid over-fetching in query handlers&lt;/li&gt;
&lt;li&gt;  Consider caching for high-read endpoints&lt;/li&gt;
&lt;li&gt;  Apply indexing strategies in read models&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;CQRS in .NET is a powerful architectural pattern that enhances&lt;br&gt;
separation of concerns, scalability, and maintainability. However, it&lt;br&gt;
introduces additional complexity and should be applied deliberately.&lt;/p&gt;

&lt;p&gt;For enterprise-grade systems with complex domains and scaling&lt;br&gt;
requirements, CQRS provides significant long-term benefits. For small&lt;br&gt;
applications, traditional layered architecture may be sufficient.&lt;/p&gt;

&lt;p&gt;Architectural discipline---not trend adoption---should guide your&lt;br&gt;
decision.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>SQL Server vs PostgreSQL: A Practical Comparison for Modern Developers</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Tue, 10 Feb 2026 13:38:35 +0000</pubDate>
      <link>https://forem.com/arthus15/sql-server-vs-postgresql-a-practical-comparison-for-modern-developers-588o</link>
      <guid>https://forem.com/arthus15/sql-server-vs-postgresql-a-practical-comparison-for-modern-developers-588o</guid>
      <description>&lt;p&gt;Choosing a database is a strategic decision. It affects performance, cost, scalability, hiring, tooling, and even your deployment architecture. Two of the most common choices in production systems today are &lt;strong&gt;Microsoft SQL Server&lt;/strong&gt; and &lt;strong&gt;PostgreSQL&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Both are mature, powerful relational database management systems (RDBMS). Both support ACID transactions, indexing, stored procedures, and advanced querying. But they differ significantly in philosophy, ecosystem, and real-world usage.&lt;/p&gt;

&lt;p&gt;This article compares SQL Server and PostgreSQL across the dimensions that matter most to engineering teams.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Overview
&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;SQL Server&lt;/th&gt;
&lt;th&gt;PostgreSQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Proprietary (Express free)&lt;/td&gt;
&lt;td&gt;Open source (PostgreSQL License)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vendor&lt;/td&gt;
&lt;td&gt;Microsoft&lt;/td&gt;
&lt;td&gt;Community-driven&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platforms&lt;/td&gt;
&lt;td&gt;Windows, Linux&lt;/td&gt;
&lt;td&gt;Windows, Linux, macOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language&lt;/td&gt;
&lt;td&gt;T-SQL&lt;/td&gt;
&lt;td&gt;SQL + PL/pgSQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON Support&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extensions&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Rich ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud Integration&lt;/td&gt;
&lt;td&gt;Azure-first&lt;/td&gt;
&lt;td&gt;Cloud-agnostic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Can be expensive&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Philosophy and Ecosystem
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SQL Server
&lt;/h3&gt;

&lt;p&gt;SQL Server is a &lt;strong&gt;commercial, vendor-controlled&lt;/strong&gt; product developed by Microsoft. It integrates tightly with the Microsoft ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Azure&lt;/li&gt;
&lt;li&gt;Active Directory&lt;/li&gt;
&lt;li&gt;Power BI&lt;/li&gt;
&lt;li&gt;.NET&lt;/li&gt;
&lt;li&gt;SSIS / SSRS / SSAS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your organization already lives in Microsoft land, SQL Server fits naturally.&lt;/p&gt;

&lt;p&gt;Microsoft provides polished tooling such as &lt;strong&gt;SQL Server Management Studio (SSMS)&lt;/strong&gt; and Azure Data Studio, along with enterprise-grade support.&lt;/p&gt;

&lt;h3&gt;
  
  
  PostgreSQL
&lt;/h3&gt;

&lt;p&gt;PostgreSQL is &lt;strong&gt;open source and community-driven&lt;/strong&gt;. Its design emphasizes standards compliance, extensibility, and correctness.&lt;/p&gt;

&lt;p&gt;Postgres is often described as “the world’s most advanced open source database” because of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A powerful extension system&lt;/li&gt;
&lt;li&gt;Custom data types&lt;/li&gt;
&lt;li&gt;Advanced indexing methods&lt;/li&gt;
&lt;li&gt;Strong support for modern workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Postgres integrates well with virtually every programming language and cloud provider.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;This is often decisive.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL Server
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Express edition is free (but heavily limited).&lt;/li&gt;
&lt;li&gt;Standard and Enterprise editions are licensed per core.&lt;/li&gt;
&lt;li&gt;Costs can reach tens of thousands of dollars annually at scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are paying for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Official support&lt;/li&gt;
&lt;li&gt;Enterprise tooling&lt;/li&gt;
&lt;li&gt;Tight Azure integration&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  PostgreSQL
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Completely free.&lt;/li&gt;
&lt;li&gt;No licensing fees.&lt;/li&gt;
&lt;li&gt;You only pay for hosting and support if you choose managed services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For startups and cost-sensitive teams, Postgres is usually the clear winner.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Both databases are fast when properly tuned.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL Server Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Excellent performance on Windows workloads&lt;/li&gt;
&lt;li&gt;Sophisticated query optimizer&lt;/li&gt;
&lt;li&gt;Columnstore indexes for analytics&lt;/li&gt;
&lt;li&gt;Strong OLAP capabilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SQL Server shines in enterprise reporting and data warehousing scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  PostgreSQL Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Extremely efficient for OLTP workloads&lt;/li&gt;
&lt;li&gt;Superior concurrency model (MVCC)&lt;/li&gt;
&lt;li&gt;Rich indexing options (GIN, GiST, BRIN)&lt;/li&gt;
&lt;li&gt;Better handling of complex queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Postgres often outperforms SQL Server in high-concurrency web applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  JSON and Modern Data
&lt;/h2&gt;

&lt;p&gt;Modern applications frequently mix relational and document-style data.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL Server
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Supports JSON via functions like &lt;code&gt;OPENJSON&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;JSON is stored as plain text&lt;/li&gt;
&lt;li&gt;Limited indexing options&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  PostgreSQL
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Native &lt;code&gt;json&lt;/code&gt; and &lt;code&gt;jsonb&lt;/code&gt; types&lt;/li&gt;
&lt;li&gt;Indexable JSON fields&lt;/li&gt;
&lt;li&gt;Advanced querying operators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Postgres effectively acts as a hybrid relational/document database.&lt;/p&gt;

&lt;p&gt;This is a major advantage for modern APIs and microservices.&lt;/p&gt;




&lt;h2&gt;
  
  
  Extensibility
&lt;/h2&gt;

&lt;p&gt;This is where PostgreSQL truly differentiates itself.&lt;/p&gt;

&lt;p&gt;Postgres supports extensions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostGIS (geospatial)&lt;/li&gt;
&lt;li&gt;TimescaleDB (time series)&lt;/li&gt;
&lt;li&gt;pgvector (AI embeddings)&lt;/li&gt;
&lt;li&gt;Citus (distributed Postgres)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SQL Server offers far fewer extension capabilities and is much more closed.&lt;/p&gt;

&lt;p&gt;If you need specialized data workloads, Postgres is dramatically more flexible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Developer Experience
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SQL Server
&lt;/h3&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Excellent GUI tools&lt;/li&gt;
&lt;li&gt;Strong integration with Visual Studio&lt;/li&gt;
&lt;li&gt;Familiar for enterprise developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;T-SQL is non-standard&lt;/li&gt;
&lt;li&gt;Less friendly for containerized workflows&lt;/li&gt;
&lt;li&gt;Heavier footprint&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  PostgreSQL
&lt;/h3&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard SQL&lt;/li&gt;
&lt;li&gt;Lightweight&lt;/li&gt;
&lt;li&gt;Docker-friendly&lt;/li&gt;
&lt;li&gt;Massive open-source tooling ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires more manual tuning&lt;/li&gt;
&lt;li&gt;GUI tools are less polished (though improving)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most modern DevOps pipelines favor Postgres.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cloud and Deployment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SQL Server
&lt;/h3&gt;

&lt;p&gt;Optimized for Azure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Azure SQL Database&lt;/li&gt;
&lt;li&gt;Azure Managed Instance&lt;/li&gt;
&lt;li&gt;Azure Synapse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While SQL Server runs on Linux, Azure remains its natural home.&lt;/p&gt;

&lt;h3&gt;
  
  
  PostgreSQL
&lt;/h3&gt;

&lt;p&gt;Runs everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS RDS / Aurora&lt;/li&gt;
&lt;li&gt;Google Cloud SQL&lt;/li&gt;
&lt;li&gt;Azure Database for PostgreSQL&lt;/li&gt;
&lt;li&gt;Self-hosted Kubernetes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Postgres is cloud-agnostic by design.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security and Reliability
&lt;/h2&gt;

&lt;p&gt;Both systems provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encryption at rest and in transit&lt;/li&gt;
&lt;li&gt;Role-based access control&lt;/li&gt;
&lt;li&gt;Replication&lt;/li&gt;
&lt;li&gt;Backup tooling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Postgres is known for its conservative approach to data integrity. SQL Server offers excellent enterprise compliance features.&lt;/p&gt;

&lt;p&gt;Neither choice is weak here.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Choose SQL Server
&lt;/h2&gt;

&lt;p&gt;SQL Server makes sense if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are deeply invested in Microsoft technologies&lt;/li&gt;
&lt;li&gt;You need SSRS/SSIS/SSAS&lt;/li&gt;
&lt;li&gt;You run large enterprise BI workloads&lt;/li&gt;
&lt;li&gt;You require official vendor support&lt;/li&gt;
&lt;li&gt;Budget is less of a concern&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When to Choose PostgreSQL
&lt;/h2&gt;

&lt;p&gt;PostgreSQL is ideal if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want zero licensing costs&lt;/li&gt;
&lt;li&gt;You build cloud-native applications&lt;/li&gt;
&lt;li&gt;You need JSON or hybrid workloads&lt;/li&gt;
&lt;li&gt;You value extensibility&lt;/li&gt;
&lt;li&gt;You prefer open-source ecosystems&lt;/li&gt;
&lt;li&gt;You care about portability and vendor independence&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;SQL Server and PostgreSQL are both excellent databases — but they serve different philosophies.&lt;/p&gt;

&lt;p&gt;SQL Server is a polished enterprise platform tightly coupled to Microsoft’s ecosystem.&lt;/p&gt;

&lt;p&gt;PostgreSQL is a flexible, open, developer-friendly database that excels in modern application architectures.&lt;/p&gt;

&lt;p&gt;For most startups and cloud-native teams in 2026, &lt;strong&gt;PostgreSQL is usually the better default choice&lt;/strong&gt;. For established enterprises already standardized on Microsoft, &lt;strong&gt;SQL Server remains a strong contender&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The right answer depends less on raw performance — and more on your organization’s ecosystem, budget, and long-term strategy.&lt;/p&gt;

</description>
      <category>database</category>
      <category>microsoft</category>
      <category>postgres</category>
      <category>sql</category>
    </item>
    <item>
      <title>Result Pattern vs Exception Flow in .NET</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Thu, 05 Feb 2026 08:28:24 +0000</pubDate>
      <link>https://forem.com/arthus15/result-pattern-vs-exception-flow-in-net-2a09</link>
      <guid>https://forem.com/arthus15/result-pattern-vs-exception-flow-in-net-2a09</guid>
      <description>&lt;p&gt;Error handling is one of those design choices that quietly shapes an&lt;br&gt;
entire codebase.&lt;/p&gt;

&lt;p&gt;In .NET, we usually reach for exceptions by default. It's what the&lt;br&gt;
framework teaches, what most samples show, and what feels "natural" at&lt;br&gt;
first.&lt;/p&gt;

&lt;p&gt;But as systems grow, many teams start to feel friction: - Too many&lt;br&gt;
&lt;code&gt;try/catch&lt;/code&gt; blocks - Unclear method contracts - Hard-to-follow control&lt;br&gt;
flow - Performance issues under load - Business logic hidden behind&lt;br&gt;
thrown exceptions&lt;/p&gt;

&lt;p&gt;This is where the &lt;strong&gt;Result pattern&lt;/strong&gt; enters the picture.&lt;/p&gt;

&lt;p&gt;Both approaches are valid. The key is understanding &lt;strong&gt;what problem each&lt;br&gt;
one is meant to solve&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Familiar Way: Exception Flow
&lt;/h2&gt;

&lt;p&gt;This is classic .NET:&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;User&lt;/span&gt; &lt;span class="nf"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&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;UserNotFoundException&lt;/span&gt;&lt;span class="p"&gt;(&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;return&lt;/span&gt; &lt;span class="n"&gt;user&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;Caller:&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;try&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;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserNotFoundException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// handle it&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's nothing "wrong" with this. Exceptions are deeply built into the&lt;br&gt;
runtime and the language.&lt;/p&gt;

&lt;p&gt;But there's an assumption baked into this style:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Something unusual or truly unexpected happened.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  The Alternative: The Result Pattern
&lt;/h2&gt;

&lt;p&gt;The Result pattern treats failures as &lt;strong&gt;normal outcomes&lt;/strong&gt;, not&lt;br&gt;
interruptions.&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;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&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;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fail&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"User not found"&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;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caller:&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;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsFailure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// handle it&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&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;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the method is honest about what can happen. No surprises.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Difference
&lt;/h2&gt;

&lt;p&gt;This is the mental model that clears up most confusion:&lt;/p&gt;




&lt;p&gt;Exceptions                          Results&lt;/p&gt;




&lt;p&gt;For things that &lt;strong&gt;shouldn't         For things that **happen as part of&lt;br&gt;
  normally happen&lt;/strong&gt;                   the domain**&lt;/p&gt;

&lt;p&gt;Break the flow                      Keep the flow linear&lt;/p&gt;

&lt;p&gt;Implicit contract                   Explicit contract&lt;/p&gt;

&lt;p&gt;Expensive when thrown               Cheap to return&lt;/p&gt;

&lt;p&gt;Hard to compose                     Easy to compose&lt;/p&gt;




&lt;h2&gt;
  
  
  A Rule of Thumb That Helps
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Use exceptions for system failures.&lt;/strong&gt;\&lt;br&gt;
&lt;strong&gt;Use results for business outcomes.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you start thinking this way, most design decisions become obvious.&lt;/p&gt;


&lt;h2&gt;
  
  
  When Exceptions Make Perfect Sense
&lt;/h2&gt;

&lt;p&gt;Use exceptions when the caller cannot realistically recover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Database connection dropped&lt;/li&gt;
&lt;li&gt;  File system unavailable&lt;/li&gt;
&lt;li&gt;  Network timeout&lt;/li&gt;
&lt;li&gt;  Serialization failure&lt;/li&gt;
&lt;li&gt;  A library throws&lt;/li&gt;
&lt;li&gt;  A programmer broke an invariant&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&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;ReadConfigAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllTextAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"config.json"&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 shouldn't wrap this in a Result. If this fails, something is wrong&lt;br&gt;
with the environment, not the business logic.&lt;/p&gt;


&lt;h2&gt;
  
  
  When Results Are the Better Choice
&lt;/h2&gt;

&lt;p&gt;Use Results when the caller is expected to handle the situation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Validation failures&lt;/li&gt;
&lt;li&gt;  Entity not found&lt;/li&gt;
&lt;li&gt;  Business rule violations&lt;/li&gt;
&lt;li&gt;  Authorization problems&lt;/li&gt;
&lt;li&gt;  Duplicate records&lt;/li&gt;
&lt;li&gt;  Insufficient balance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not exceptional. They are &lt;strong&gt;part of how the system works&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="n"&gt;Result&lt;/span&gt; &lt;span class="nf"&gt;Withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Money&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;Balance&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;amount&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;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Insufficient funds"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;Balance&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&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;Throwing here would be misleading. Nothing "broke".&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Exceptions Get Painful in Business Logic
&lt;/h2&gt;

&lt;p&gt;As a codebase grows, exception-driven business flow starts to hurt:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; The method signature lies --- it doesn't show what can happen&lt;/li&gt;
&lt;li&gt; You end up wrapping everything in &lt;code&gt;try/catch&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Performance suffers when exceptions are used frequently&lt;/li&gt;
&lt;li&gt; Composing operations becomes awkward&lt;/li&gt;
&lt;li&gt; Async and LINQ flows become harder to reason about&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Compare 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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&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;account&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="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="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't know where it might blow up.&lt;/p&gt;

&lt;p&gt;With Results:&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;return&lt;/span&gt; &lt;span class="nf"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetAccount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flow is obvious and safe.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Simple Result Implementation
&lt;/h2&gt;

&lt;p&gt;You don't need a big library. A small type is enough:&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;Result&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;IsSuccess&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="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsFailure&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;IsSuccess&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;Error&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;protected&lt;/span&gt; &lt;span class="nf"&gt;Result&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;isSuccess&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;IsSuccess&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;error&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;static&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&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="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&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;Result&lt;/span&gt; &lt;span class="nf"&gt;Fail&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&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;Result&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="n"&gt;Result&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;T&lt;/span&gt; &lt;span class="n"&gt;Value&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;protected&lt;/span&gt; &lt;span class="nf"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="k"&gt;value&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;isSuccess&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Value&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Result&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;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&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;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&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="k"&gt;true&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;Empty&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="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Result&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;Fail&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&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 a helper for composition:&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="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Bind&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;,&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;Result&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;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Func&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;,&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;func&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsFailure&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;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fail&lt;/span&gt;&lt;span class="p"&gt;(&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;Error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&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;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;h2&gt;
  
  
  How Mature .NET Systems Use Both
&lt;/h2&gt;

&lt;p&gt;It's not either/or.&lt;/p&gt;

&lt;p&gt;A healthy architecture looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controllers → Results
Application Layer → Results
Domain Layer → Results
Infrastructure → Exceptions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Exceptions stay at the edges. Results live where business decisions&lt;br&gt;
happen.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example in an ASP.NET Core Controller
&lt;/h2&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="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id}"&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;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;{&lt;/span&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;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsFailure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;(&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;Error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&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;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 &lt;code&gt;try/catch&lt;/code&gt;. Clear intent.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Note on Performance
&lt;/h2&gt;

&lt;p&gt;Exceptions are expensive when thrown. In high-traffic APIs, using them&lt;br&gt;
for normal control flow can become a real bottleneck.&lt;/p&gt;

&lt;p&gt;Results avoid this entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Practical Guideline
&lt;/h2&gt;

&lt;p&gt;If the caller is &lt;strong&gt;expected to handle&lt;/strong&gt; the outcome → return a&lt;br&gt;
&lt;strong&gt;Result&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If the caller &lt;strong&gt;cannot reasonably recover&lt;/strong&gt; → throw an &lt;strong&gt;Exception&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's it.&lt;/p&gt;




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

&lt;p&gt;This isn't about being clever or following a trend. It's about making&lt;br&gt;
your code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Easier to read&lt;/li&gt;
&lt;li&gt;  Easier to reason about&lt;/li&gt;
&lt;li&gt;  More explicit&lt;/li&gt;
&lt;li&gt;  More composable&lt;/li&gt;
&lt;li&gt;  More predictable under load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you start separating &lt;em&gt;system failures&lt;/em&gt; from &lt;em&gt;business outcomes&lt;/em&gt;,&lt;br&gt;
your APIs become much clearer --- both for you and for everyone else who&lt;br&gt;
reads your code.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>codequality</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Edge Day: Turning AI from Theory into Everyday Practice</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Mon, 19 Jan 2026 09:20:04 +0000</pubDate>
      <link>https://forem.com/arthus15/edge-day-turning-ai-from-theory-into-everyday-practice-3edp</link>
      <guid>https://forem.com/arthus15/edge-day-turning-ai-from-theory-into-everyday-practice-3edp</guid>
      <description>&lt;h1&gt;
  
  
  Edge Day: Turning AI from Theory into Everyday Practice
&lt;/h1&gt;

&lt;p&gt;Edge Day was dedicated to one clear goal: accelerating practical AI adoption across engineering, design, and product. This was not a day of abstract talks or speculative futures. Instead, it focused on real workflows, concrete examples, and battle-tested practices that teams can apply immediately in their day-to-day work.&lt;/p&gt;

&lt;p&gt;We openly acknowledged the realities of working with AI today. The tools can be unpredictable, prone to hallucinations, and sometimes frustratingly inconsistent. That is precisely why the sessions centered on actionable techniques, guardrails, and patterns that help teams achieve more reliable, repeatable outcomes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why We Ran Edge Day
&lt;/h2&gt;

&lt;p&gt;AI is already reshaping how we design, build, and ship products. Edge Day was designed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expand horizons on how teams across R&amp;amp;D are using AI to improve productivity and workflow quality
&lt;/li&gt;
&lt;li&gt;Provide hands-on, practical examples that participants could try on their own machines
&lt;/li&gt;
&lt;li&gt;Showcase how AI usage is transforming collaboration between design, product, and engineering
&lt;/li&gt;
&lt;li&gt;Share hard-earned lessons on what works, what fails, and how to avoid common pitfalls
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The emphasis throughout the day was on &lt;em&gt;doing&lt;/em&gt;: live demos, real code, real prompts, and real trade-offs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Highlights from the Day
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Designing and Prototyping with AI
&lt;/h3&gt;

&lt;p&gt;The day opened with practical examples of how AI-assisted tools can accelerate design prototyping. The focus was on shortening feedback loops, rapidly exploring ideas, and turning early concepts into tangible artifacts without sacrificing design intent.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Tooling for Large Codebases
&lt;/h3&gt;

&lt;p&gt;Several sessions addressed a core challenge: making AI genuinely useful in complex, real-world codebases. Topics included configuring tools for monoliths, managing context effectively, and avoiding the trap of blindly accepting generated code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompting for Production, Not Demos
&lt;/h3&gt;

&lt;p&gt;A recurring theme was the importance of strong prompting and clear specifications. One session contrasted “copy-paste” AI usage with structured prompting approaches that dramatically reduce debugging time and improve code quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agentic and Autonomous Workflows
&lt;/h3&gt;

&lt;p&gt;From open-source agentic coding to building autonomous AI agents, multiple talks explored what agents actually are, where they make sense, and where they do not. The emphasis was on realistic architectures, constraints, and maintainability rather than hype.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI in Data Science Workflows
&lt;/h3&gt;

&lt;p&gt;AI-assisted driver–navigator workflows demonstrated how data science problems can be broken down more effectively, with AI acting as a collaborator rather than a black box.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long-Term Collaboration with AI
&lt;/h3&gt;

&lt;p&gt;One session tackled a common frustration: AI systems that “forget everything.” Practical approaches to structured issue tracking and long-term context management showed how agents can support sustained collaboration over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  End-to-End Product Workflows
&lt;/h3&gt;

&lt;p&gt;Later sessions connected the dots from design to code, illustrating how AI-powered tools can support an end-to-end product workflow—from wireframes to working applications—while keeping humans firmly in control of decisions and quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building Agents with Agents
&lt;/h3&gt;

&lt;p&gt;The day concluded with lessons learned from using coding agents to build other agents, highlighting both the potential and the operational challenges of this approach.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;AI delivers the most value when paired with clear intent, strong constraints, and human judgment
&lt;/li&gt;
&lt;li&gt;Better prompts and specifications often matter more than better models
&lt;/li&gt;
&lt;li&gt;Hands-on experimentation is essential to understanding where AI fits into real workflows
&lt;/li&gt;
&lt;li&gt;Reliability, observability, and control are critical for production use
&lt;/li&gt;
&lt;li&gt;AI is a multiplier for good practices, not a replacement for them
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Looking Ahead
&lt;/h2&gt;

&lt;p&gt;Edge Day reinforced that successful AI adoption is not about chasing trends. It is about thoughtfully integrating tools into existing workflows, learning from real usage, and continuously refining how humans and machines collaborate.&lt;/p&gt;

&lt;p&gt;The conversations, experiments, and lessons from the day will continue to shape how we build, design, and ship products—practically, responsibly, and with impact.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>A Comprehensive Guide to Application Logging</title>
      <dc:creator>Jairo Blanco</dc:creator>
      <pubDate>Tue, 13 Jan 2026 08:35:35 +0000</pubDate>
      <link>https://forem.com/arthus15/a-comprehensive-guide-to-application-logging-1ee1</link>
      <guid>https://forem.com/arthus15/a-comprehensive-guide-to-application-logging-1ee1</guid>
      <description>&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;Logging is one of those fundamental practices that separates maintainable software from debugging nightmares. Yet despite its importance, logging is often treated as an afterthought—something developers sprinkle throughout their code without much consideration. This guide explores the different logging levels, best practices, and common pitfalls to help you build better observability into your applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Log Levels
&lt;/h2&gt;

&lt;p&gt;Most logging frameworks provide a hierarchy of log levels, each serving a distinct purpose. Understanding when to use each level is crucial for creating useful logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  TRACE
&lt;/h3&gt;

&lt;p&gt;The most granular level of logging, TRACE captures extremely detailed information about program execution. This level is typically used for diagnostic purposes during development and is rarely enabled in production environments.&lt;/p&gt;

&lt;p&gt;Use TRACE when you need to follow the exact path of execution through your code, including entry and exit points of methods, loop iterations, or detailed state transitions. For example, you might log every iteration of a data processing loop or every step in a complex algorithm.&lt;/p&gt;

&lt;h3&gt;
  
  
  DEBUG
&lt;/h3&gt;

&lt;p&gt;DEBUG level provides detailed information useful for debugging during development and troubleshooting in production. Unlike TRACE, DEBUG logs should focus on meaningful events and state changes rather than exhaustive execution details.&lt;/p&gt;

&lt;p&gt;Use DEBUG for variable values, conditional branch decisions, intermediate calculation results, and other information that helps you understand why your application behaved a certain way. For instance, logging the parameters passed to a function or the result of a database query would be appropriate at this level.&lt;/p&gt;

&lt;h3&gt;
  
  
  INFO
&lt;/h3&gt;

&lt;p&gt;INFO is the standard logging level for recording normal application behavior. These logs document significant events in your application's lifecycle and business logic execution.&lt;/p&gt;

&lt;p&gt;Use INFO for application startup and shutdown, configuration values being loaded, successful completion of major operations, user actions, and state transitions that matter to your business logic. INFO logs should tell the story of what your application is doing under normal circumstances.&lt;/p&gt;

&lt;h3&gt;
  
  
  WARN
&lt;/h3&gt;

&lt;p&gt;WARN indicates something unexpected happened, but the application can continue functioning. These are potential problems that don't prevent the current operation from completing but might cause issues later.&lt;/p&gt;

&lt;p&gt;Use WARN for deprecated API usage, fallback to default values when configuration is missing, recoverable errors like temporary network issues with retry logic, performance degradation, or approaching resource limits. A warning suggests that while things are working now, someone should probably investigate.&lt;/p&gt;

&lt;h3&gt;
  
  
  ERROR
&lt;/h3&gt;

&lt;p&gt;ERROR indicates a serious problem that prevented a specific operation from completing. The application can usually continue running, but something definitely went wrong.&lt;/p&gt;

&lt;p&gt;Use ERROR for exceptions that prevent business logic from completing, failed database transactions, failed external API calls without a fallback, invalid user input that can't be processed, or missing required resources. ERROR logs should always provide enough context to understand what went wrong and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Logging Too Much or Too Little
&lt;/h3&gt;

&lt;p&gt;One of the most common mistakes is finding the wrong balance. Too much logging creates noise that obscures important information and can impact performance. Too little logging leaves you blind when problems occur.&lt;/p&gt;

&lt;p&gt;Avoid logging inside tight loops at INFO level or above, logging the same information repeatedly, or creating massive log files that are expensive to store and process. Equally problematic is having no logs around critical business logic, catching exceptions without logging them, or failing to log enough context to diagnose issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Poor Log Messages
&lt;/h3&gt;

&lt;p&gt;Vague messages like "Error occurred" or "Processing complete" provide almost no value. Your logs should tell a clear story to someone who wasn't present when the code was written.&lt;/p&gt;

&lt;p&gt;Include relevant context such as identifiers, parameters, and state information. Use structured logging with key-value pairs rather than string concatenation. Avoid including sensitive information like passwords, tokens, credit card numbers, or personally identifiable information unless you have proper redaction in place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inconsistent Formatting
&lt;/h3&gt;

&lt;p&gt;When every developer on your team uses different logging styles, searching and parsing logs becomes a nightmare. Establish conventions for your team and stick to them.&lt;/p&gt;

&lt;p&gt;Inconsistencies appear in timestamp formats, how exceptions are logged, naming conventions for log fields, and the structure of log messages. Using a structured logging framework can help enforce consistency automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging at the Wrong Level
&lt;/h3&gt;

&lt;p&gt;Misusing log levels makes it difficult to filter logs effectively. If everything is logged at ERROR, you can't distinguish real problems from routine events. If business-critical events are logged at DEBUG, they'll be invisible in production.&lt;/p&gt;

&lt;p&gt;A common mistake is logging every caught exception as ERROR when many exceptions represent expected business logic outcomes. Similarly, logging successful operations at WARN or DEBUG undermines the purpose of INFO level logging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance Impact
&lt;/h3&gt;

&lt;p&gt;Logging isn't free. String concatenation, formatting, and I/O operations all consume resources. Logging inside performance-critical code paths without consideration can significantly impact application performance.&lt;/p&gt;

&lt;p&gt;Be especially careful about logging in tight loops, constructing expensive log messages unconditionally even when that log level is disabled, and synchronous logging in high-throughput code paths. Use asynchronous logging and guard clauses to check if a log level is enabled before constructing expensive messages.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Use Structured Logging
&lt;/h3&gt;

&lt;p&gt;Modern applications should embrace structured logging formats like JSON. Structured logs are machine-readable, making them much easier to search, filter, and analyze at scale.&lt;/p&gt;

&lt;p&gt;Instead of logging &lt;code&gt;"User John logged in from 192.168.1.1"&lt;/code&gt;, structure it as key-value pairs with fields for user, action, and IP address. This allows you to easily query all login events or all actions by a specific user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Include Correlation IDs
&lt;/h3&gt;

&lt;p&gt;In distributed systems, tracking a single request across multiple services is essential. Include correlation or trace IDs in your logs to connect related events across service boundaries.&lt;/p&gt;

&lt;p&gt;When a request enters your system, generate or extract a correlation ID and include it in every log statement related to that request. This allows you to reconstruct the complete journey of a request through your infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Log Contextual Information
&lt;/h3&gt;

&lt;p&gt;Every log statement should include enough context for someone to understand what was happening without reading the code. This includes relevant identifiers, operation being performed, input parameters, and environmental context.&lt;/p&gt;

&lt;p&gt;However, balance this with privacy and security concerns. Use redaction libraries to automatically scrub sensitive data, and ensure your logging practices comply with regulations like GDPR.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Appropriate Default Levels
&lt;/h3&gt;

&lt;p&gt;Configure production environments to log at INFO by default, with the ability to dynamically increase verbosity to DEBUG when troubleshooting. Development environments can default to DEBUG. TRACE should almost never be enabled in production due to its volume and performance impact.&lt;/p&gt;

&lt;p&gt;Implement the ability to change log levels without restarting your application. This allows you to increase verbosity when investigating issues without downtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make Logs Actionable
&lt;/h3&gt;

&lt;p&gt;Every ERROR log should suggest a clear path forward. If a database connection fails, log not just the error but also which database, what operation was attempted, and relevant configuration details.&lt;/p&gt;

&lt;p&gt;Similarly, WARN logs should indicate what the potential impact is and what action might be needed. A warning about approaching disk space limits is only useful if it includes how much space remains and where.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Logging Frameworks
&lt;/h3&gt;

&lt;p&gt;Don't write logs directly to stdout or files. Use established logging frameworks like Log4j, Logback, Serilog, or Python's logging module. These frameworks provide features like log rotation, filtering, asynchronous logging, and multiple output destinations.&lt;/p&gt;

&lt;p&gt;Logging frameworks also allow you to configure logging behavior without changing code, making it easier to adjust logging in different environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample High-Volume Logs
&lt;/h3&gt;

&lt;p&gt;For very high-traffic operations, consider sampling your logs. You don't need to log every single request at INFO level if you're handling millions per minute. Logging 1% of successful requests with full DEBUG logging for errors provides good observability without overwhelming your log storage.&lt;/p&gt;

&lt;p&gt;Implement intelligent sampling that always logs errors and warnings while sampling routine successful operations based on configured rates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration with Observability
&lt;/h2&gt;

&lt;p&gt;Modern logging doesn't exist in isolation. Integrate your logs with metrics and tracing to build comprehensive observability.&lt;/p&gt;

&lt;p&gt;When an error occurs, your logs should reference relevant metric names and trace IDs. When investigating a performance issue, you should be able to jump from a slow trace to the corresponding detailed logs. This integration transforms logs from isolated events into part of a cohesive narrative about your application's behavior.&lt;/p&gt;

&lt;p&gt;Use log aggregation tools like the ELK stack (Elasticsearch, Logstash, Kibana), Splunk, or cloud-native solutions like CloudWatch or Stackdriver. These tools make it possible to search across millions of log entries, create alerts based on log patterns, and visualize trends over time.&lt;/p&gt;

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

&lt;p&gt;Effective logging is a skill that develops over time. It requires understanding your application's behavior, anticipating what information will be valuable during troubleshooting, and balancing detail with readability and performance.&lt;/p&gt;

&lt;p&gt;Start by establishing clear conventions for your team, use structured logging from the beginning, and regularly review your logs to ensure they're providing the value you need. Good logging transforms debugging from guesswork into detective work, where the clues you need are already waiting in your log files.&lt;/p&gt;

&lt;p&gt;Remember that logs are written once but read many times, usually under stressful circumstances when something is broken. Invest the time to make them clear, consistent, and useful. Your future self, your teammates, and your on-call rotation will thank you.&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>devops</category>
      <category>monitoring</category>
    </item>
  </channel>
</rss>
