About this course
About this course
This free course teaches you to structure real applications - the decisions that shape a codebase for years and are painful to change later. You'll start with what architecture actually is (and how it differs from design patterns), the map of common styles, and the one distinction everything rests on: keeping business logic separate from infrastructure.
From there you'll compare monolith and microservices, learn Domain-Driven Design (strategic and tactical), organize code with hexagonal architecture (ports and adapters), and go event-driven with events, CQRS, event sourcing and the saga pattern. A dedicated chapter maps all of it onto a real Laravel app, and the final chapter covers the pitfalls (the anemic domain model, over-engineering) and how to evolve a monolith safely.
Every lesson builds on the previous one, with short PHP examples you can adapt - though the ideas apply in any language. By the end you'll choose an architecture on purpose, defend the choice, and know when the simplest option is the right one.
It's written for developers who can build features and now want to design systems.
Course curriculum
- What is software architecture? What is software architecture? The high-level structure of a system and the decisions that are expensive to change - and how it differs from design patterns.
- A map of architectural styles A quick tour of common architectural styles: layered, hexagonal, event-driven and microservices, plus SOA, serverless and vertical slice.
- Boundaries and coupling Coupling at the architecture level: draw good boundaries between modules, keep cohesion high inside and coupling low across them.
- Domain vs infrastructure The core distinction in software architecture: business logic (domain) vs infrastructure (database, HTTP, framework). Why keeping them apart matters.
- The layered architecture The classic layered architecture: presentation, application, domain and infrastructure, the dependency direction, and the common domain-database leak.
- How to read this course Get the most from this software architecture course: principles vs styles, why examples are PHP and Laravel, and why architecture is trade-offs, not rules.
- What is a monolith What is a monolith? One deployable application - and often the smartest default. Learn its real strengths and the distributed-monolith trap that costs you both ways.
- The modular monolith A modular monolith is one deployment with strong internal module boundaries. Learn why it is the sweet spot for most teams and how modules actually enforce those walls.
- Microservices overview Microservices are independently deployable services that own their data. Learn what they buy you - team autonomy and independent scaling - and what they really cost.
- Monolith vs microservices How to choose between a monolith and microservices using team size, domain complexity and operational maturity. The rule: start monolith, extract services on real pain.
- The cost of distributed systems The network is not free: latency, partial failure, no distributed transactions, eventual consistency, harder debugging - and the 8 fallacies of distributed computing.
- What is Domain-Driven Design Domain-Driven Design explained for developers: shaping software around the business domain and its language, strategic vs tactical DDD, and when it is worth it.
- Ubiquitous language The ubiquitous language in Domain-Driven Design: one shared vocabulary between domain experts and code. How mismatched words cause bugs, with PHP examples.
- Bounded contexts A bounded context is a boundary where a model and its language stay consistent. See how the same word like Customer means different things in different contexts.
- Context mapping Context mapping in DDD: partnership, shared kernel, customer/supplier, conformist, anticorruption layer (ACL) and open host service, with a simple example map.
- Subdomains: core, supporting, generic DDD subdomains explained: core, supporting and generic. Learn where to invest your best design effort, and what to buy or simplify instead of building.
- Entities: identity that survives change Learn what an entity is in Domain-Driven Design: an object with identity that persists through change. Identity vs equality, with a PHP 8.4 example.
- Value objects: immutable, compared by value Learn what a value object is in Domain-Driven Design: immutable, self-validating, compared by value, with a PHP 8.4 readonly example.
- Aggregates and the aggregate root Learn what an aggregate and aggregate root are in Domain-Driven Design: one consistency boundary, one entry point that enforces invariants. PHP example.
- Domain events: recording what happened Learn what a domain event is in Domain-Driven Design: a past-tense record of what happened, raised by aggregates to decouple side effects. PHP example.
- Repositories: a collection of aggregates Learn the repository pattern in Domain-Driven Design: a collection-like interface that stores and retrieves aggregates, hiding the database. PHP example.
- Domain services and factories Learn domain services for logic that fits no single entity, and factories that build complex aggregates in a valid state. Clear PHP 8.4 examples in DDD.
- What is hexagonal architecture? Hexagonal architecture (ports and adapters) puts the domain in the center, isolated from the database, HTTP and the framework. A PHP beginner's guide.
- The domain at the center The dependency rule of hexagonal architecture: all dependencies point inward, and the domain knows nothing about the database, HTTP or the framework.
- Ports A port is an interface the domain defines: driven ports for what it needs (OrderRepository) and driving ports for what it offers. With a PHP 8.4 example.
- Adapters An adapter implements a port: a MysqlOrderRepository or a controller. Swap adapters without touching the domain. Ports and adapters explained in PHP.
- Driving vs driven adapters Primary/driving adapters call the app (HTTP, CLI, tests); secondary/driven adapters are called by the app (DB, mail, queue). The flow of control explained.
- Hexagonal vs onion vs clean architecture Hexagonal, onion and clean architecture are three names for one idea: dependencies point inward and the domain stays isolated. The differences and shared core.
- Vertical slice architecture Vertical slice architecture organizes code by feature, not by layer: a full slice from request to persistence. When it beats layered or hexagonal, honestly.
- The application layer What the application layer is: a thin layer of use cases that orchestrates the domain but holds no business rules, with one handler per action in PHP.
- Commands and queries (CQRS) Command-Query Separation and an intro to CQRS: commands change state and return nothing, queries read and never change state, with separate write and read models.
- DTOs and mapping What Data Transfer Objects are and why they matter: carrying data across boundaries, keeping Eloquent models and arrays out of the domain, with simple PHP mapping.
- Orchestrating the domain How a use case loads aggregates via a repository, calls domain methods and saves - wiring collaborators without holding business rules, with a worked PHP handler.
- Transactions and unit of work Why a use case is the natural transaction boundary: commit once at the end, the Unit of Work pattern, and when to dispatch domain events relative to the commit.
- CQRS in practice CQRS in practice: separate the write model from the read model, with a plain PHP example - and why CQRS does not require event sourcing or two databases.
- What is event-driven architecture? How publish/subscribe replaces direct calls between services, what a message broker does, and how events decouple senders from receivers in time and space.
- Events vs commands Events vs commands: a command is an intent one handler can reject; an event is a past-tense fact many can react to and cannot refuse. Learn the difference.
- Choreography vs orchestration Choreography vs orchestration: coordinate a multi-step process with services reacting to events, or a coordinator directing the steps. Trade-offs inside.
- Event sourcing Event sourcing stores the sequence of events as the source of truth instead of current state, and rebuilds state by replaying them. Benefits, costs, PHP example.
- Read models and CQRS Read models and CQRS: build query-optimized projections from an event stream. This is full CQRS - separate write and read models, rebuildable by replay.
- The saga pattern The two ways to run a saga - choreography and orchestration - plus compensating actions and why consistency across services is eventual, not instant.
- Structure a Laravel app by domain Structure a Laravel 11 project by domain (app/Billing, app/Catalog) instead of by type. A folder layout, the PSR-4 autoload note, and the coupling trap to avoid.
- Mapping DDD onto Laravel Mapping DDD onto Laravel 11: Eloquent as a persistence adapter behind a repository, the service container as wiring, and jobs and events for domain events.
- Keeping the domain framework-free Build a framework-free domain layer in Laravel: entities, value objects and use cases as plain PHP with no Illuminate imports. Why it pays off - and what it costs.
- A worked module end to end A worked Laravel module end to end: an Invoice aggregate, a Money value object, the repository pattern as a port with an Eloquent adapter, a use-case handler, and a controller.
- When Laravel's defaults are enough When to use DDD in Laravel and when Laravel's defaults win: for CRUD apps and small teams, fat models and controllers are fine. DDD earns its keep with real complexity.
- The anemic domain model The anemic domain model is an anti-pattern: entities that are bags of getters and setters with the logic in services. Why it defeats DDD, with PHP 8.4 before and after.
- When not to use DDD DDD and hexagonal architecture pay off only with real domain complexity. For CRUD, reporting or a tiny team they over-engineer the problem. How to judge, tied to YAGNI.
- Refactoring a monolith into modules Turn a big ball of mud into a modular monolith: find seams by bounded context, enforce boundaries, and extract modules incrementally. You rarely need a rewrite.
- Testing across boundaries The test pyramid for hexagonal architecture: fast unit tests on a framework-free domain, use-case tests with in-memory adapters, a few integration tests on real ones.
- Documenting architecture: ADRs and C4 Record decisions with Architecture Decision Records (context, decision, consequences) and communicate structure with the C4 model. Lightweight, durable docs.
- The strangler pattern The strangler fig pattern replaces a legacy system incrementally by routing slices of functionality to the new one until the old is gone. Safer than a big-bang rewrite.