Today Quincy Larson interviews Andrea Griffiths, who taught herself programming using freeCodeCamp while working in construction. She moved to the US from Colombia when she was 17, and within 6 months she joined the US Army. She ran a chain of gyms before landing a support role at a tech company, then ascending to Product Manager and ultimately Developer Advocate at GitHub.
We talk about:
Tips for busy parents who want to learn new skills.
How AI tools are no substitute for your own critical thinking and problem solving skills.
How even though it's getting easier every day to learn programming for free, people are so distracted, and for many it feels harder and harder to sit down and do it.
Support for this podcast is provided by a grant from AlgoMonster. AlgoMonster is a platform that teaches data structure and algorithm patterns in a structured sequence, so you can approach technical interview questions more systematically. Their curriculum covers patterns like sliding window, two-pointers, graph search, and dynamic programming, helping you learn each pattern once and apply it to solve many problems. Start a structured interview prep routine at https://algo.monster/freecodecamp
Support also comes from the 10,338 kind folks who donate to our charity each month. Join them and support our mission at https://donate.freecodecamp.org
1. freeCodeCamp just published this beginner-friendly back-end development course. You'll learn how to build your own web servers and APIs using Node.js, Express, and MongoDB. freeCodeCamp's website and mobile apps are built using these tools, which make up the popular MERN stack. You'll also get some exposure to database architecture, security principles, testing best practices, and more. (2 hour YouTube course): https://www.freecodecamp.org/news/intro-to-backend-web-development-nodejs-express-mongodb/
2. freeCodeCamp also published a comprehensive Blender and Three.js course where you'll build your own 3D portfolio piece: a render of an adorable home office. If you're interested in 3D rendering and computer graphics, this is the course for you. You'll learn key concepts like Quad Topology, Raycasting, OrbitControls, and more. By the end of the course, your 3D model will be live on the web so you can share it with your friends. (9 hour YouTube course): https://www.freecodecamp.org/news/create-a-cute-room-portfolio-with-threejs-blender-javascript/
3. freeCodeCamp also published a handbook on using Docker with Node.js. You'll learn how to set up Docker and Docker Compose. You'll also learn fundamental concepts like Volumes, Images, and Containers. This is an excellent resource for you to read through and code along with. Bookmark it for future reference. (full length handbook): https://www.freecodecamp.org/news/how-to-use-to-docker-with-nodejs-handbook/
4. Level up your JavaScript implementation skills with this new freeCodeCamp course on Clean Code. You'll learn how to detect “code smells” and refactor your JavaScript accordingly. You'll also learn how to use ESLint and Prettier to automate some of the more error-prone aspects of shipping code. (1 hour watch): https://www.freecodecamp.org/news/level-up-your-javascript-detect-smells-and-write-clean-code/
5. Classic text adventure games Zork I, II, and III are now open source with an MIT license. Microsoft has published their full source code on GitHub: https://github.com/historicalsource/zork1
6. Today's song of the week is 1985 classic "Something About You" by Level 42. I love the slap bass, the vocal harmony, the falsetto, and the huge synth sounds. It's impossible to listen to this song and still be in a bad mood: https://www.youtube.com/watch?v=zpdQQoc-gkk
A customer was writing a Win32 program and was looking for something like a combo box, in that it gave the user a choice among various fixed options, but sometimes the program would come up with a new option that wasn’t on the list, and it would want to show that as the selection. On the other hand, the customer didn’t want to give the user the option to enter arbitrary text. Users still had to choose among the fixed items in the combo box or the new option that was generated on the fly. The customer didn’t want to add the new option to the dropdown list, which means that the CBS_DROPDOWNLIST style would not be appropriate, since that forces the selection to come from the list. What they wanted was for the combo box to act like a traditional combo box with edit control, except that the user can’t change the text in the edit control.
The solution here is to make the edit control read-only.
You can get the edit control handle by calling GetComboBoxInfo and then sending the EM_SETREADONLY message to the window identified by the hwndItem member.
The GetComboBoxInfo function is admittedly a bit hard to find because it’s not a message or window style, so it’s not in a place that you naturally look when trying to find information about a combo box.
Walk into almost any long-lived enterprise codebase, and you will find the same pattern:
Controllers that know about routing, JSON, SQL, and domain rules
Repositories that reach up into HttpContext
Business rules scattered across UI, stored procedures, and helper classes
At that point, adding a new feature feels like surgery without a map. You poke at one place, something bleeds somewhere else, and nobody is sure why.
Layered architecture exists to stop that.
In this post, we will walk through a practical version of Fowler’s layered architecture in ASP.NET Core and C#. You will see:
What each layer is allowed to know
How to wire up a fundamental feature using three layers
How does this structure make change cheaper and failure less chaotic
The example centers on a simple use case: creating an order.
The core idea: three layers, three distinct responsibilities
Fowler’s baseline looks like this:
Presentation layer Handles input and output. In web apps, this means HTTP, routing, model binding, and formatting responses.
Domain layer Holds business rules, domain services, and aggregates. It talks about orders, customers, payments, not controllers or DbContext.
Data source layer Owns persistence. It uses EF Core, raw SQL, caching, and talks to any external data store.
A simple rule captures the intent:
If your controllers know SQL or your repositories know HTTP, you already lost separation.
The rest of this post shows what it looks like when you refuse to cross those lines.
The scenario: placing an order in three slices
We will build a feature that lets a client create an order.
Requirements:
Clients call POST /orders with customer and line items
An order must contain at least one line item
The system persists the order in a relational database
We will implement that with:
A presentation layer endpoint
A domain service and aggregate
A data source layer using EF Core
Presentation layer: thin HTTP endpoint
The presentation layer should only:
Accept input
Call the domain layer
Shape the HTTP response
It should not:
Reach into DbContext
Perform business rules beyond basic request validation
Use EF Core directly
Example with ASP.NET Core minimal APIs:
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddScoped<IOrderRepository, EfCoreOrderRepository>();
var app = builder.Build();
app.MapPost("/orders", async (CreateOrderDto dto, IOrderService orderService) =>
{
// Basic request-level validation only
if (dto.Lines is null || dto.Lines.Count == 0)
{
return Results.BadRequest("Order must contain at least one line item.");
}
var orderId = await orderService.CreateOrderAsync(dto.CustomerId, dto.Lines);
return Results.Created($"/orders/{orderId}", new { Id = orderId });
});
app.Run();
public record CreateOrderDto(Guid CustomerId, List<OrderLineDto> Lines);
public record OrderLineDto(Guid ProductId, int Quantity);
Notice what the endpoint does not do:
It does not call AppDbContext
It does not calculate totals
It does not decide how orders are stored
It simply coordinates HTTP and the domain service.
Domain layer: business rules and language of the problem
The domain layer decides what an order is allowed to do.
It should:
Enforce invariants
Capture domain rules in one place
Express intent through the language of the business
public class OrderService : IOrderService
{
private readonly IOrderRepository _orders;
public OrderService(IOrderRepository orders)
{
_orders = orders;
}
public async Task<Guid> CreateOrderAsync(
Guid customerId,
IReadOnlyCollection<OrderLineDto> lines)
{
if (!lines.Any())
{
throw new InvalidOperationException("Order must contain at least one line item.");
}
var order = Order.Create(
customerId,
lines.Select(l => new OrderLine(l.ProductId, l.Quantity)).ToList());
await _orders.AddAsync(order);
return order.Id;
}
}
Domain model for Order and OrderLine:
public class Order
{
private readonly List<OrderLine> _lines = new();
private Order(Guid customerId)
{
Id = Guid.NewGuid();
CustomerId = customerId;
Status = OrderStatus.Draft;
CreatedAt = DateTime.UtcNow;
}
public Guid Id { get; }
public Guid CustomerId { get; }
public OrderStatus Status { get; private set; }
public DateTime CreatedAt { get; }
public IReadOnlyCollection<OrderLine> Lines => _lines.AsReadOnly();
public decimal TotalAmount => _lines.Sum(l => l.Total);
public static Order Create(Guid customerId, IEnumerable<OrderLine> lines)
{
var order = new Order(customerId);
foreach (var line in lines)
{
order.AddLine(line.ProductId, line.Quantity, line.UnitPrice);
}
if (!order._lines.Any())
{
throw new InvalidOperationException("Order must have at least one line item.");
}
return order;
}
public void AddLine(Guid productId, int quantity, decimal unitPrice)
{
if (Status != OrderStatus.Draft)
{
throw new InvalidOperationException("Cannot modify a non draft order.");
}
if (quantity <= 0)
{
throw new ArgumentOutOfRangeException(nameof(quantity));
}
if (unitPrice <= 0)
{
throw new ArgumentOutOfRangeException(nameof(unitPrice));
}
_lines.Add(new OrderLine(productId, quantity, unitPrice));
}
public void Submit()
{
if (Status != OrderStatus.Draft)
{
throw new InvalidOperationException("Only draft orders can be submitted.");
}
if (!_lines.Any())
{
throw new InvalidOperationException("Cannot submit an empty order.");
}
// Save Order
Status = OrderStatus.Submitted;
}
}
public class OrderLine
{
public OrderLine(Guid productId, int quantity, decimal unitPrice)
{
ProductId = productId;
Quantity = quantity;
UnitPrice = unitPrice;
}
public Guid ProductId { get; }
public int Quantity { get; }
public decimal UnitPrice { get; }
public decimal Total => Quantity * UnitPrice;
}
public enum OrderStatus
{
Draft = 0,
Submitted = 1,
Cancelled = 2
}
Key observation: the domain layer expresses business concepts directly.
“Order must contain at least one line item” lives close to the Order aggregate
Status transitions are enforced inside the entity
Nothing here references controllers, HTTP, or EF Core
Data source layer: persistence without domain leakage
The repository understands EF Core and the database schema. The domain does not.
How does this structure make change cheaper
The layered structure looks simple until you try to change things. That is where it earns its keep.
1. Business rule changes
Suppose the business wants new rules:
Orders below a specific total should be rejected
Some customers have higher minimum totals
Where does that logic go?
Not in the controller
Not in the repository
It belongs in the domain layer, near the Order aggregate or in domain services.
You might extend OrderService:
public async Task<Guid> CreateOrderAsync(
Guid customerId,
IReadOnlyCollection<OrderLineDto> lines)
{
if (!lines.Any())
{
throw new InvalidOperationException("Order must contain at least one line item.");
}
var order = Order.Create(
customerId,
lines.Select(l => new OrderLine(l.ProductId, l.Quantity)).ToList());
var minimum = await GetCustomerMinimumAsync(customerId);
if (order.TotalAmount < minimum)
{
throw new InvalidOperationException(
$"Order total must be at least {minimum} for this customer.");
}
await _orders.AddAsync(order);
return order.Id;
}
private Task<decimal> GetCustomerMinimumAsync(Guid customerId)
{
// Look up from a configuration service or customer settings
return Task.FromResult(100m);
}
Presentation and data source layers stay unchanged.
Imagine you want to process orders from a message queue and via HTTP.
With a layered design, you write a message handler that calls the same IOrderService:
public class OrderCreatedMessageHandler
{
private readonly IOrderService _orderService;
public OrderCreatedMessageHandler(IOrderService orderService)
{
_orderService = orderService;
}
public async Task HandleAsync(OrderCreatedMessage message)
{
var dtoLines = message.Lines
.Select(l => new OrderLineDto(l.ProductId, l.Quantity))
.ToList();
await _orderService.CreateOrderAsync(message.CustomerId, dtoLines);
}
}
public record OrderCreatedMessage(Guid CustomerId, List<OrderLineDto> Lines);
No duplication of rules. No extra data access logic. You add another presentation layer entry point.
3. Swapping EF Core for another persistence mechanism
If you ever need to switch persistence, the blast radius is clear.
Domain layer remains the same
Presentation layer remains the same
Only IOrderRepository implementations and AppDbContext related types change
You can introduce another repository, for example DapperOrderRepository, and swap registrations in the DI container.
How teams quietly destroy their layers
Codebases rarely lose layering due to a single catastrophic decision. They lose it through a stream of small, “temporary” shortcuts.
Shortcut 1: “Just this one query in the controller”
A developer needs a special report. They already have access to AppDbContext in the controller, so they write:
public class ReportsController : ControllerBase
{
private readonly AppDbContext _dbContext;
public ReportsController(AppDbContext dbContext)
{
_dbContext = dbContext;
}
[HttpGet("reports/orders")]
public async Task<IActionResult> GetOrdersReport()
{
var data = await _dbContext.Orders
.Include(o => o.Lines)
.Where(o => o.CreatedAt >= DateTime.UtcNow.AddDays(-7))
.ToListAsync();
// Transform into view model
return Ok(data);
}
}
It works. It ships. It also teaches the team that controllers are fair game for data access. After a few months, there is no clear separation at all.
Better approach: move data access to a query service or repository and call that from the controller.
Shortcut 2: Repositories returning view models
Another developer builds a dashboard. They want to avoid extra mapping, so they let the repository spit out DTOs used by the UI.
public interface IOrderRepository
{
Task<IReadOnlyCollection<OrderSummaryDto>> GetRecentSummariesAsync();
}
That feels efficient. It also tangles the data source layer with a specific presentation need.
Six months later, a background worker wants a different representation, and the repository keeps growing special cases.
Better approach: keep repositories returning domain objects or well-defined query models that are not tied directly to controllers.
Shortcut 3: Domain services reading HttpContext
Sometimes, domain services need user information or tenant context. The easy path is to inject IHttpContextAccessor directly.
public class DiscountService
{
private readonly IHttpContextAccessor _accessor;
public DiscountService(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public decimal GetDiscount()
{
var user = _accessor.HttpContext?.User;
// ...
}
}
This locks the domain to ASP.NET Core. Reusing the domain in background services or tests becomes painful.
Better approach: define an abstraction such as ICurrentUser or ICurrentTenant in the domain layer, and implement it in the presentation or infrastructure layer using HttpContext.
Enforcing layers with project structure
Code style and good intentions are not enough. The solution’s physical structure should reinforce the boundaries.
A common layout:
MyApp.Domain
Entities, value objects, domain services, domain interfaces
MyApp.Application (optional, if you separate application from pure domain)
Use cases, application services, DTOs
MyApp.Infrastructure
EF Core mappings, repositories, integration with external services
MyApp.Web
ASP.NET Core host, controllers, endpoints, filters
Dependency rules:
MyApp.Web references MyApp.Domain and MyApp.Application
MyApp.Infrastructure references MyApp.Domain and MyApp.Application
MyApp.Domain does not reference any other project
MyApp.Application references MyApp.Domain only
You can even add build checks or analyzers to prevent forbidden references.
Raising the stakes: what you lose without layers
If this sounds abstract, consider the cost of ignoring it.
You lose the ability to isolate a single change. Every change becomes a search through controllers, EF queries, and domain objects.
You lose optionality. Moving to messaging, splitting services, or swapping databases becomes nearly impossible without a rewrite.
You lose trust. Diagrams and architecture documents claim there are layers. The code says otherwise. Eventually, the team stops listening to both.
Layered architecture will not save you from every problem. It does something more modest and more powerful:
It gives you clear seams to cut, adapt, and evolve.
A simple challenge for your current system
Pick one feature in your application. Then:
Identify the presentation, domain, and data source pieces.
Count how many times each one crosses its boundary.
Move a single business rule out of a controller into a domain service or aggregate.
Move a single data access concern from a controller to a repository.
You do not fix an entire enterprise codebase in one refactor. You fix it one layer at a time, one leak at a time.
Once your controllers stop talking to SQL and your repositories stop knowing HTTP, everything else gets easier.
If your ASP.NET solution contains controllers that talk straight to SQL, services that return HTTP responses, and entities that call SaveChanges, you are already remixing Fowler’s patterns. You are just doing it implicitly and at great expense.
This series takes the opposite route. We will name the patterns, show where they fit, and implement each one in C# with concrete examples.
You will see where these patterns help, where they hurt, and how they combine into real architectures instead of diagram fantasies.
How this series will work
In each article, I will:
Explain a pattern in plain language, with the original intent from Fowler’s catalog
Show how it typically shows up in C# and .NET projects
Give a focused example of when to use it and when to avoid it
Connect it to neighboring patterns so you see design options, not isolated tricks
This introduction maps the territory. Every item in the index below links to a short description, a definition, and an example scenario. Each of those sections will become a full post with code.
Pattern index
Use these links to jump to the pattern you care about right now.
Each section below is both a preview and a contract for the dedicated C# article that will follow.
Layered Architecture Pattern
Definition
Layered Architecture splits an application into distinct layers with clear responsibilities. Fowler’s baseline is:
Presentation: handles input and output
Domain: holds business rules and domain logic
Data source: manages persistence and integration with data stores
The core rule is brutal and simple: if your controllers know SQL or your repositories know HTTP, the layers have already collapsed.
Where to use it
Layered Architecture fits:
ASP.NET Core applications that will grow beyond a few controllers
Systems where different teams own UI, business rules, and infrastructure
Codebases that must survive several technology shifts over their lifetime
In the dedicated post you will see a C# solution where projects align with layers, controllers stay thin, domain services stay ignorant of transport, and repositories encapsulate EF Core without leaking it upward.
Transaction Script Pattern
Definition
Transaction Script organizes business logic as procedures that handle a single request or use case end to end. Each script:
Reads input
Performs calculations and decisions
Persists changes
There is minimal domain modeling. The focus stays on the flow of a transaction.
Where to use it
Transaction Script works best when:
The domain logic is simple and shallow
You are building reports, admin utilities, or migration tools
You need results quickly and long term complexity is limited
In C#, this often appears as an application service or handler class that works directly with DbContext and simple DTOs. In the article you will see both the benefits and the trap: it feels efficient until rules start to repeat across scripts.
Domain Model Pattern
Definition
Domain Model concentrates business rules inside a rich object model. Entities and value objects express invariants and behavior.
Instead of treating data as passive structures, you treat the domain as the center of gravity. Controllers and repositories orbit around it rather than injecting rules into every edge of the system.
Where to use it
Domain Model earns its weight when:
The business rules are complex and interdependent
Invariants matter more than raw throughput
You expect requirements to evolve frequently
In C# this means entities with methods that enforce rules, factories that control creation, and services that orchestrate multiple aggregates. The dedicated post will show an aggregate in code, along with tests that lock in behavior before you worry about EF mapping.
Service Layer Pattern
Definition
Service Layer defines a set of application operations that sit between the outside world and the domain model. It:
Coordinates multiple domain objects
Handles transactions and security policies
Exposes a clear API for controllers, message handlers, or other clients
It is the point where use cases live.
Where to use it
Service Layer fits when:
You have multiple clients hitting the same core logic: web, background jobs, workers
You want to expose a stable application API while the UI evolves
Cross cutting concerns such as logging, permissions, and transaction boundaries must stay consistent
In .NET this often becomes a set of application service classes injected into controllers and workers. In the article you will see a C# service layer that makes HTTP a detail, not the boss.
Active Record Pattern
Definition
Active Record merges domain objects with persistence. Each entity:
Maps directly to a database row
Contains business logic
Knows how to load and save itself
Fowler treats it as a close fit for simple domains where the object model mirrors the database closely.
Where to use it
Active Record suits:
Small systems with straightforward tables
Prototypes where getting something working matters more than deep abstraction
Places where simple CRUD with light behavior is enough
In C#, you often see Active Record flavor when EF Core entities call SaveChanges directly or static methods perform global queries. The dedicated post will show a disciplined version of Active Record and explain when to retire it in favor of a separate Data Mapper.
Data Mapper Pattern
Definition
Data Mapper sits between domain objects and the database. It:
Loads domain objects from data stores
Persists changes back
Shields the domain from knowledge of how persistence works
The domain classes stay persistence ignorant. The mapper takes on the burden of translation.
Where to use it
Data Mapper pays off when:
You have a rich Domain Model
The database schema must evolve independently of the object model
You want to test domain logic without a database in the way
In .NET, EF Core already plays the Data Mapper role. The article will show how to design domain classes that do not depend on EF, then map them using configurations and repositories that wrap the mapper.
Repository Pattern
Definition
Repository represents a collection-like interface for accessing aggregates. It:
Hides queries and persistence details
Exposes methods that work in domain terms, such as GetById, FindActiveForCustomer, Add, Remove
Lets the domain talk in its own language instead of in SQL or query APIs
Fowler includes Repository in the object relational patterns as a way to further isolate domain logic from data access.
Where to use it
Repository helps when:
The same aggregate appears across many use cases
You want consistent access patterns for aggregates
You expect to support multiple query strategies or stores behind the same domain interface
In C#, this usually means interface definitions in the domain layer and implementations in an infrastructure project. The dedicated post will include concrete repository designs, and also examples of where a repository introduces more indirection than it earns.
Unit of Work Pattern
Definition
Unit of Work tracks changes to domain objects during a business transaction and writes them out as a single logical batch. It:
Records inserts, updates, and deletes
Coordinates commit or rollback
Provides a boundary for transactional behavior
Fowler presents it as a way to stop writes from spreading unpredictably through a codebase.
Where to use it
Unit of Work is valuable when:
A single operation touches multiple aggregates or tables
You need clear transactional boundaries for consistency
You want to keep domain logic free of save calls
In .NET, DbContext already behaves as a Unit of Work, yet many codebases hide that fact. The article will show how to embrace this pattern explicitly and how to wrap EF Core in a higher level unit of work abstraction when needed.
Identity Map Pattern
Definition
Identity Map ensures that each logical entity from the database exists only once in memory per scope. It:
Tracks loaded objects by identity
Returns existing instances instead of creating new ones for the same key
Helps avoid inconsistent in memory states for the same row
This pattern often works with Unit of Work and Data Mapper.
Where to use it
Identity Map matters when:
The same entity is loaded through different paths in one request
You attach domain behavior to entities and depend on reference equality
You care about performance costs of repeated materialization
ORMs such as EF Core implement identity maps under the surface. The dedicated post will explain what EF is doing for you and show how to apply Identity Map explicitly when you move outside of ORMs or use multiple contexts.
Lazy Load Pattern
Definition
Lazy Load defers loading of related data until it is actually needed. Instead of fetching entire object graphs, you:
Load a root entity
Represent associations as placeholders
Trigger actual loading when code accesses the association
The pattern targets performance and memory by avoiding unnecessary work.
Where to use it
Lazy Load helps when:
Most use cases do not need full graphs
Some navigations are expensive or remote
You have to control query explosions carefully
In .NET, EF Core can use lazy loading proxies, or you can code your own lazy associations. The article will show both approaches and highlight the risk: invisible queries that surprise you in performance profiles.
Front Controller Pattern
Definition
Front Controller centralizes request handling for a web application. Instead of letting every page or endpoint own its own entry point, you:
Route all requests through a single handler
Apply cross cutting logic in one place
Delegate to controllers or handlers for detailed work
Fowler introduces it as a response to duplicated request handling logic.
Where to use it
Front Controller aligns with:
Web applications that need consistent logging, authentication, and error handling
Systems that must make routing decisions based on shared policies
Architectures that use pipelines and middleware
In ASP.NET Core, the combination of the hosting pipeline and routing already forms a Front Controller. The dedicated post will show how to control that pipeline intentionally instead of treating it as framework magic.
Model View Controller (MVC) Pattern
Definition
Model View Controller splits UI logic into three parts:
Model: the underlying data and behavior
View: rendering logic
Controller: input handling and coordination
Fowler’s version focuses on server side web MVC.
Where to use it
MVC suits:
Applications with complex UI interactions that depend on domain rules
Teams that want clear separation between presentation logic and domain logic
Systems that must support multiple views on the same model
In ASP.NET Core MVC, controllers speak to application services, views render models, and domain rules stay out of both. The article will show how to keep controller code lean instead of letting it morph into a second application layer.
Data Transfer Object (DTO) Pattern
Definition
Data Transfer Object carries data across process boundaries. It:
Aggregates fields into a serializable shape
Avoids sending full domain objects across the wire
Provides a contract between services, clients, or layers
DTOs trade object richness for stability and clarity at integration points.
Where to use it
DTOs are worth the effort when:
You are exposing public APIs
Multiple clients consume your service, each with their own evolution pace
You want to keep domain classes internal to your application
In C#, DTOs typically appear as record types in API projects or as message contracts in messaging systems. The article will show mapping patterns between domain objects and DTOs and how to keep them from overflowing with accidental complexity.
What comes next
The rest of this series will go pattern by pattern:
Each pattern gets its own post
Each post includes C# examples, tests where relevant, and context from real projects
The focus stays on tradeoffs, not worship of diagrams
You can read the series start to finish, or you can drop directly into the pattern that matches the pain in your current system and work outward from there.
If your code already resembles these patterns, this series gives you language and structure. If it does not, the upcoming posts will show how to reshape it piece by piece without pausing delivery.