[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-3885":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":25,"hasPages":23,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":47,"readmeContent":48,"aiSummary":49,"trendingCount":16,"starSnapshotCount":16,"syncStatus":50,"lastSyncTime":51,"discoverSource":52},3885,"domain-driven-hexagon","Sairyss\u002Fdomain-driven-hexagon","Sairyss","Learn Domain-Driven Design, software architecture, design patterns, best practices. Code examples included","",null,"TypeScript",14693,1556,199,3,0,1,10,66,4,83.18,"MIT License",false,"master",true,[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"architectural-patterns","architecture","backend","best-practices","clean-architecture","clean-code","ddd","design-patterns","development","domain-driven-design","hexagonal-architecture","javascript","nestjs","nodejs","onion-architecture","secure-by-design","solid-principles","system-design","typeorm","typescript","2026-06-12 04:00:19","# Domain-Driven Hexagon\n\n**Check out my other repositories**:\n\n- [Backend best practices](https:\u002F\u002Fgithub.com\u002FSairyss\u002Fbackend-best-practices) - Best practices, tools and guidelines for backend development.\n- [System Design Patterns](https:\u002F\u002Fgithub.com\u002FSairyss\u002Fsystem-design-patterns) - list of topics and resources related to distributed systems, system design, microservices, scalability and performance, etc.\n- [Full Stack starter template](https:\u002F\u002Fgithub.com\u002FSairyss\u002Ffullstack-starter-template) - template for full stack applications based on TypeScript, React, Vite, ChakraUI, tRPC, Fastify, Prisma, zod, etc.\n\n---\n\nThe main emphasis of this project is to provide recommendations on how to design software applications. This readme includes techniques, tools, best practices, architectural patterns and guidelines gathered from different sources.\n\nCode examples are written using [NodeJS](https:\u002F\u002Fnodejs.org\u002Fen\u002F), [TypeScript](https:\u002F\u002Fwww.typescriptlang.org\u002F), [NestJS](https:\u002F\u002Fdocs.nestjs.com\u002F) framework and [Slonik](https:\u002F\u002Fgithub.com\u002Fgajus\u002Fslonik) for the database access.\n\nPatterns and principles presented here are **framework\u002Flanguage agnostic**. Therefore, the above technologies can be easily replaced with any alternative. No matter what language or framework is used, any application can benefit from principles described below.\n\n**Note**: code examples are adapted to TypeScript and frameworks mentioned above. \u003Cbr\u002F>\n(Implementations in other languages will look differently)\n\n**Everything below is provided as a recommendation, not a rule**. Different projects have different requirements, so any pattern mentioned in this readme should be adjusted to project needs or even skipped entirely if it doesn't fit. In real world production applications, you will most likely only need a fraction of those patterns depending on your use cases. More info in [this](#general-recommendations-on-architectures-best-practices-design-patterns-and-principles) section.\n\n---\n\n- [Domain-Driven Hexagon](#domain-driven-hexagon)\n- [Architecture](#architecture)\n      - [Pros](#pros)\n      - [Cons](#cons)\n- [Diagram](#diagram)\n- [Modules](#modules)\n- [Application Core](#application-core)\n- [Application layer](#application-layer)\n  - [Application Services](#application-services)\n  - [Commands and Queries](#commands-and-queries)\n    - [Commands](#commands)\n    - [Queries](#queries)\n  - [Ports](#ports)\n- [Domain Layer](#domain-layer)\n  - [Entities](#entities)\n  - [Aggregates](#aggregates)\n  - [Domain Events](#domain-events)\n  - [Integration Events](#integration-events)\n  - [Domain Services](#domain-services)\n  - [Value objects](#value-objects)\n  - [Domain Invariants](#domain-invariants)\n    - [Replacing primitives with Value Objects](#replacing-primitives-with-value-objects)\n    - [Make illegal states unrepresentable](#make-illegal-states-unrepresentable)\n      - [Validation at compile time](#validation-at-compile-time)\n      - [Validation at runtime](#validation-at-runtime)\n    - [Guarding vs validating](#guarding-vs-validating)\n  - [Domain Errors](#domain-errors)\n  - [Using libraries inside Application's core](#using-libraries-inside-applications-core)\n- [Interface Adapters](#interface-adapters)\n  - [Controllers](#controllers)\n    - [Resolvers](#resolvers)\n  - [DTOs](#dtos)\n    - [Request DTOs](#request-dtos)\n    - [Response DTOs](#response-dtos)\n    - [Additional recommendations](#additional-recommendations)\n    - [Local DTOs](#local-dtos)\n- [Infrastructure layer](#infrastructure-layer)\n  - [Adapters](#adapters)\n  - [Repositories](#repositories)\n  - [Persistence models](#persistence-models)\n  - [Other things that can be a part of Infrastructure layer](#other-things-that-can-be-a-part-of-infrastructure-layer)\n- [Other recommendations](#other-recommendations)\n  - [General recommendations on architectures, best practices, design patterns and principles](#general-recommendations-on-architectures-best-practices-design-patterns-and-principles)\n  - [Recommendations for smaller APIs](#recommendations-for-smaller-apis)\n  - [Behavioral Testing](#behavioral-testing)\n  - [Folder and File Structure](#folder-and-file-structure)\n    - [File names](#file-names)\n  - [Enforcing architecture](#enforcing-architecture)\n  - [Prevent massive inheritance chains](#prevent-massive-inheritance-chains)\n- [Additional resources](#additional-resources)\n  - [Articles](#articles)\n  - [Websites](#websites)\n  - [Blogs](#blogs)\n  - [Videos](#videos)\n  - [Books](#books)\n\n# Architecture\n\nThis is an attempt to combine multiple architectural patterns and styles together, such as:\n\n- [Domain-Driven Design (DDD)](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDomain-driven_design)\n- [Hexagonal (Ports and Adapters) Architecture](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FHexagonal_architecture_(software))\n- [Secure by Design](https:\u002F\u002Fwww.manning.com\u002Fbooks\u002Fsecure-by-design)\n- [Clean Architecture](https:\u002F\u002Fblog.cleancoder.com\u002Funcle-bob\u002F2012\u002F08\u002F13\u002Fthe-clean-architecture.html)\n- [Onion Architecture](https:\u002F\u002Fherbertograca.com\u002F2017\u002F09\u002F21\u002Fonion-architecture\u002F)\n- [SOLID Principles](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSOLID)\n- [Software Design Patterns](https:\u002F\u002Frefactoring.guru\u002Fdesign-patterns\u002Fwhat-is-pattern)\n\nAnd many others (more links below in every chapter).\n\nBefore we begin, here are the PROS and CONS of using a complete architecture like this:\n\n#### Pros\n\n- Independent of external frameworks, technologies, databases, etc. Frameworks and external resources can be plugged\u002Funplugged with much less effort.\n- Easily testable and scalable.\n- More secure. Some security principles are baked in design itself.\n- The solution can be worked on and maintained by different teams, without stepping on each other's toes.\n- Easier to add new features. As the system grows over time, the difficulty in adding new features remains constant and relatively small.\n- If the solution is properly broken apart along [bounded context](https:\u002F\u002Fmartinfowler.com\u002Fbliki\u002FBoundedContext.html) lines, it becomes easy to convert pieces of it into microservices if needed.\n\n#### Cons\n\n- This is a sophisticated architecture which requires a firm understanding of quality software principles, such as SOLID, Clean\u002FHexagonal Architecture, Domain-Driven Design, etc. Any team implementing such a solution will almost certainly require an expert to drive the solution and keep it from evolving the wrong way and accumulating technical debt.\n\n- Some practices presented here are not recommended for small-medium sized applications with not a lot of business logic. There is added up-front complexity to support all those building blocks and layers, boilerplate code, abstractions, data mapping etc. Thus, implementing a complete architecture like this is generally ill-suited to simple [CRUD](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCreate,_read,_update_and_delete) applications and could over-complicate such solutions. Some principles which are described below can be used in smaller sized applications, but must be implemented only after analyzing and understanding all pros and cons.\n\n# Diagram\n\n![Domain-Driven Hexagon](assets\u002Fimages\u002FDomainDrivenHexagon.png)\n\u003Csup>Diagram is mostly based on [this one](https:\u002F\u002Fgithub.com\u002Fhgraca\u002Fexplicit-architecture-php#explicit-architecture-1) + others found online\u003C\u002Fsup>\n\nIn short, data flow looks like this (from left to right):\n\n- Request\u002FCLI command\u002Fevent is sent to the controller using plain DTO;\n- Controller parses this DTO, maps it to a Command\u002FQuery object format and passes it to an Application service;\n- Application service handles this Command\u002FQuery; it executes business logic using domain services and entities\u002Faggregates and uses the infrastructure layer through ports(interfaces);\n- Infrastructure layer maps data to a format that it needs, retrieves\u002Fpersists data from\u002Fto a database, uses adapters for other I\u002FO communications (like sending an event to an external broker or calling external APIs), maps data back to domain format and returns it back to Application service;\n- After the Application service finishes doing its job, it returns data\u002Fconfirmation back to Controllers;\n- Controllers return data back to the user (if application has presenters\u002Fviews, those are returned instead).\n\nEach layer is in charge of its own logic and has building blocks that usually should follow a [Single-responsibility principle](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSingle-responsibility_principle) when possible and when it makes sense (for example, using `Repositories` only for database access, using `Entities` for business logic, etc.).\n\n**Keep in mind** that different projects can have more or less steps\u002Flayers\u002Fbuilding blocks than described here. Add more if the application requires it, and skip some if the application is not that complex and doesn't need all that abstraction.\n\nGeneral recommendation for any project: analyze how big\u002Fcomplex the application will be, find a compromise and use as many layers\u002Fbuilding blocks as needed for the project and skip ones that may over-complicate things.\n\nMore in details on each step below.\n\n# Modules\n\nThis project's code examples use separation by modules (also called components). Each module's name should reflect an important concept from the Domain and have its own folder with a dedicated codebase. Each business use case inside that module gets its own folder to store most of the things it needs (this is also called _Vertical Slicing_). It's easier to work on things that change together if those things are gathered relatively close to each other. Think of a module as a \"box\" that groups together related business logic.\n\nUsing modules is a great way to [encapsulate](\u003Chttps:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FEncapsulation_(computer_programming)>) parts of highly [cohesive](\u003Chttps:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCohesion_(computer_science)>) business domain rules.\n\nTry to make every module independent and keep interactions between modules minimal. Think of each module as a mini application bounded by a single context. Consider module internals private and try to avoid direct imports between modules (like importing a class `import SomeClass from '..\u002FSomeOtherModule'`) since this creates [tight coupling](\u003Chttps:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCoupling_(computer_programming)>) and can turn your code into a [spaghetti](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSpaghetti_code) and application into a [big ball of mud](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FBig_ball_of_mud).\n\nFew advices to avoid coupling:\n\n- Try not to create dependencies between modules or use cases. Instead, move shared logic into a separate files and make both depend on that instead of depending on each other.\n- Modules can cooperate through a [mediator](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMediator_pattern#:~:text=In%20software%20engineering%2C%20the%20mediator,often%20consist%20of%20many%20classes.) or a public [facade](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFacade_pattern), hiding all private internals of the module to avoid its misuse, and giving public access only to certain pieces of functionality that meant to be public.\n- Alternatively modules can communicate with each other by using messages. For example, you can send commands using a commands bus or subscribe to events that other modules emit (more info on events and commands bus below).\n\nThis ensures [loose coupling](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FLoose_coupling), refactoring of a module internals can be done easier because outside world only depends on module's public interface, and if bounded contexts are defined and designed properly each module can be easily separated into a microservice if needed without touching any domain logic or major refactoring.\n\nKeep your modules small. You should be able to rewrite a module in a relatively short period of time. This applies not only to modules pattern, but to software development in general: objects, functions, microservices, processes, etc. Keep them small and composable. This is incredibly powerful in a constantly changing environments of software development, since when your requirements change, changing small modules is much easier than changing a big program. You can just delete a module and rewrite it from scratch in a matter of days. This idea is further described in this talk: [Greg Young - The art of destroying software](https:\u002F\u002Fyoutu.be\u002FEd94CfxgsCA).\n\nCode Examples:\n\n- Check [src\u002Fmodules](src\u002Fmodules) directory structure.\n- [src\u002Fmodules\u002Fuser\u002Fcommands](src\u002Fmodules\u002Fuser\u002Fcommands) - \"commands\" directory in a user module includes business use cases (commands) that a module can execute, each with its own Vertical Slice.\n\nRead more:\n\n- [Modular programming: Beyond the spaghetti mess](https:\u002F\u002Fwww.tiny.cloud\u002Fblog\u002Fmodular-programming-principle\u002F).\n- [What are Modules in Domain Driven Design?](https:\u002F\u002Fwww.culttt.com\u002F2014\u002F12\u002F10\u002Fmodules-domain-driven-design\u002F)\n- [How to Implement Vertical Slice Architecture](https:\u002F\u002Fgarywoodfine.com\u002Fimplementing-vertical-slice-architecture\u002F)\n\nEach module consists of layers described below.\n\n# Application Core\n\nThis is the core of the system which is built using [DDD building blocks](https:\u002F\u002Fdzone.com\u002Farticles\u002Fddd-part-ii-ddd-building-blocks):\n\n**Domain layer**:\n\n- Entities\n- Aggregates\n- Domain Services\n- Value Objects\n- Domain Errors\n\n**Application layer**:\n\n- Application Services\n- Commands and Queries\n- Ports\n\n**Note**: different implementations may have slightly different layer structures depending on applications needs. Also, more layers and building blocks may be added if needed.\n\n---\n\n# Application layer\n\n## Application Services\n\nApplication Services (also called \"Workflow Services\", \"Use Cases\", \"Interactors\", etc.) are used to orchestrate the steps required to fulfill the commands imposed by the client.\n\nApplication services:\n\n- Typically used to orchestrate how the outside world interacts with your application and performs tasks required by the end users;\n- Contain no domain-specific business logic;\n- Operate on scalar types, transforming them into Domain types. A scalar type can be considered any type that's unknown to the Domain Model. This includes primitive types and types that don't belong to the Domain;\n- Uses ports to declare dependencies on infrastructural services\u002Fadapters required to execute domain logic (ports are just interfaces, we will discuss this topic in details below);\n- Fetch domain `Entities`\u002F`Aggregates` (or anything else) from database\u002Fexternal APIs (through ports\u002Finterfaces, with concrete implementations injected by the [DI](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDependency_injection) library);\n- Execute domain logic on those `Entities`\u002F`Aggregates` (by invoking their methods);\n- In case of working with multiple `Entities`\u002F`Aggregates`, use a `Domain Service` to orchestrate them;\n- Execute other out-of-process communications through Ports (like event emits, sending emails, etc.);\n- Services can be used as a `Command`\u002F`Query` handlers;\n- Should not depend on other application services since it may cause problems (like cyclic dependencies);\n\nOne service per use case is considered a good practice.\n\n\u003Cdetails>\n\u003Csummary>What are \"Use Cases\"?\u003C\u002Fsummary>\n\n[wiki](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FUse_case):\n\n> In software and systems engineering, a use case is a list of actions or event steps typically defining the interactions between a role (known in the Unified Modeling Language as an actor) and a system to achieve a goal.\n\nUse cases are, simply said, list of actions required from an application.\n\n---\n\n\u003C\u002Fdetails>\n\nExample file: [create-user.service.ts](src\u002Fmodules\u002Fuser\u002Fcommands\u002Fcreate-user\u002Fcreate-user.service.ts)\n\nMore about services:\n\n- [Domain-Application-Infrastructure Services pattern](https:\u002F\u002Fbadia-kharroubi.gitbooks.io\u002Fmicroservices-architecture\u002Fcontent\u002Fpatterns\u002Ftactical-patterns\u002Fdomain-application-infrastructure-services-pattern.html)\n- [Services in DDD finally explained](https:\u002F\u002Fdeveloper20.com\u002Fservices-in-ddd-finally-explained\u002F)\n\n## Commands and Queries\n\nThis principle is called [Command–Query Separation(CQS)](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCommand%E2%80%93query_separation). When possible, methods should be separated into `Commands` (state-changing operations) and `Queries` (data-retrieval operations). To make a clear distinction between those two types of operations, input objects can be represented as `Commands` and `Queries`. Before DTO reaches the domain, it's converted into a `Command`\u002F`Query` object.\n\n### Commands\n\n`Command` is an object that signals user intent, for example `CreateUserCommand`. It describes a single action (but does not perform it).\n\n`Commands` are used for state-changing actions, like creating new user and saving it to the database. Create, Update and Delete operations are considered as state-changing.\n\nData retrieval is responsibility of `Queries`, so `Command` methods should not return business data.\n\nSome CQS purists may say that a `Command` shouldn't return anything at all. But you will need at least an ID of a created item to access it later. To achieve that you can let clients generate a [UUID](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FUniversally_unique_identifier) (more info here: [CQS versus server generated IDs](https:\u002F\u002Fblog.ploeh.dk\u002F2014\u002F08\u002F11\u002Fcqs-versus-server-generated-ids\u002F)).\n\nThough, violating this rule and returning some metadata, like `ID` of a created item, redirect link, confirmation message, status, or other metadata is a more practical approach than following dogmas.\n\n**Note**: `Command` is similar but not the same as described here: [Command Pattern](https:\u002F\u002Frefactoring.guru\u002Fdesign-patterns\u002Fcommand). There are multiple definitions across the internet with similar but slightly different implementations.\n\nTo execute a command you can use a `Command Bus` instead of importing a service directly. This will decouple a command Invoker from a Receiver, so you can send your commands from anywhere without creating coupling.\n\nAvoid command handlers executing other commands in this fashion: Command → Command. Instead, use events for that purpose, and execute next commands in a chain in an Event handler: Command → Event → Command.\n\nExample files:\n\n- [create-user.command.ts](src\u002Fmodules\u002Fuser\u002Fcommands\u002Fcreate-user\u002Fcreate-user.command.ts) - a command Object\n- [create-user.message.controller.ts](src\u002Fmodules\u002Fuser\u002Fcommands\u002Fcreate-user\u002Fcreate-user.message.controller.ts) - controller executes a command using a command bus. This decouples it from a command handler.\n- [create-user.service.ts](src\u002Fmodules\u002Fuser\u002Fcommands\u002Fcreate-user\u002Fcreate-user.service.ts) - a command handler.\n\nRead more:\n\n- [What is a command bus and why should you use it?](https:\u002F\u002Fbarryvanveen.nl\u002Fblog\u002F49-what-is-a-command-bus-and-why-should-you-use-it)\n- [Why You Should Avoid Command Handlers Calling Other Commands?](https:\u002F\u002Fwww.rahulpnath.com\u002Fblog\u002Favoid-commands-calling-commands\u002F)\n\n### Queries\n\n`Query` is similar to a `Command`. It belongs to a read model and signals user intent to find something and describes how to do it.\n\n`Query` is just a data retrieval operation and should not make any state changes (like writes to the database, files, third party APIs, etc.). For this reason, in read model we can bypass a domain and repository layers completely and query database directly from a query handler.\n\nSimilarly to Commands, Queries can use a `Query Bus` if needed. This way you can query anything from anywhere without importing classes directly and avoid coupling.\n\nExample files:\n\n- [find-users.query-handler.ts](src\u002Fmodules\u002Fuser\u002Fqueries\u002Ffind-users\u002Ffind-users.query-handler.ts) - a query handler. Notice how we query the database directly, without using domain objects or repositories (more info [here](https:\u002F\u002Fcodeopinion.com\u002Fshould-you-use-the-repository-pattern-with-cqrs-yes-and-no\u002F)).\n\n---\n\nBy enforcing `Command` and `Query` separation, the code becomes simpler to understand. One changes something, another just retrieves data.\n\nAlso, following CQS from the start will facilitate separating write and read models into different databases if someday in the future the need for it arises.\n\n**Note**: this repo uses [NestJS CQRS](https:\u002F\u002Fdocs.nestjs.com\u002Frecipes\u002Fcqrs) package that provides a command\u002Fquery bus.\n\nRead more about CQS and CQRS:\n\n- [Command Query Segregation](https:\u002F\u002Fkhalilstemmler.com\u002Farticles\u002Foop-design-principles\u002Fcommand-query-segregation\u002F).\n- [Exposing CQRS Through a RESTful API](https:\u002F\u002Fwww.infoq.com\u002Farticles\u002Frest-api-on-cqrs\u002F)\n- [What is the CQRS pattern?](https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Farchitecture\u002Fpatterns\u002Fcqrs)\n- [CQRS and REST: the perfect match](https:\u002F\u002Flostechies.com\u002Fjimmybogard\u002F2016\u002F06\u002F01\u002Fcqrs-and-rest-the-perfect-match\u002F)\n\n---\n\n## Ports\n\nPorts are interfaces that define contracts that should be implemented by adapters. For example, a port can abstract technology details (like what type of database is used to retrieve some data), and infrastructure layer can implement an adapter in order to execute some action more related to technology details rather than business logic. Ports act like [abstractions](\u003Chttps:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAbstraction_(computer_science)>) for technology details that business logic does not care about. Name \"port\" most actively is used in [Hexagonal Architecture](\u003Chttps:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FHexagonal_architecture_(software)>).\n\nIn Application Core **dependencies point inwards**. Outer layers can depend on inner layers, but inner layers never depend on outer layers. Application Core shouldn't depend on frameworks or access external resources directly. Any external calls to out-of-process resources\u002Fretrieval of data from remote processes should be done through `ports` (interfaces), with class implementations created somewhere in infrastructure layer and injected into application's core ([Dependency Injection](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDependency_injection) and [Dependency Inversion](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDependency_inversion_principle)). This makes business logic independent of technology, facilitates testing, allows to plug\u002Funplug\u002Fswap any external resources easily making application modular and [loosely coupled](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FLoose_coupling).\n\n- Ports are basically just interfaces that define what has to be done and don't care about how it's done.\n- Ports can be created to abstract side effects like I\u002FO operations and database access, technology details, invasive libraries, legacy code etc. from the Domain.\n- By abstracting side effects, you can test your application logic in isolation by [mocking](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMock_object) the implementation. This can be useful for [unit testing](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FUnit_testing).\n- Ports should be created to fit the Domain needs, not simply mimic the tools APIs.\n- Mock implementations can be passed to ports while testing. Mocking makes your tests faster and independent of the environment.\n- Abstraction provided by ports can be used to inject different implementations to a port if needed ([polymorphism](\u003Chttps:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPolymorphism_(computer_science)>)).\n- When designing ports, remember the [Interface segregation principle](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FInterface_segregation_principle). Split large interfaces into smaller ones when it makes sense, but also keep in mind to not overdo it when not necessary.\n- Ports can also help to delay decisions. The Domain layer can be implemented even before deciding what technologies (frameworks, databases etc.) will be used.\n\n**Note**: since most ports implementations are injected and executed in application service, Application Layer can be a good place to keep those ports. But there are times when the Domain Layer's business logic depends on executing some external resource, in such cases those ports can be put in a Domain Layer.\n\n**Note**: abusing ports\u002Finterfaces may lead to [unnecessary abstractions](https:\u002F\u002Fmortoray.com\u002F2014\u002F08\u002F01\u002Fthe-false-abstraction-antipattern\u002F) and overcomplicate your application. In a lot of cases it's totally fine to depend on a concrete implementation instead of abstracting it with an interface. Think carefully if you really need an abstraction before using it.\n\nExample files:\n\n- [repository.port.ts](src\u002Flibs\u002Fddd\u002Frepository.port.ts) - generic port for repositories\n- [user.repository.port.ts](src\u002Fmodules\u002Fuser\u002Fdatabase\u002Fuser.repository.port.ts) - a port for user repository\n- [find-users.query-handler.ts](src\u002Fmodules\u002Fuser\u002Fqueries\u002Ffind-users\u002Ffind-users.query-handler.ts) - notice how query handler depends on a port instead of concrete repository implementation, and an implementation is injected\n- [logger.port.ts](src\u002Flibs\u002Fports\u002Flogger.port.ts) - another example of a port for application logger\n\nRead more:\n\n- [A Color Coded Guide to Ports and Adapters](https:\u002F\u002F8thlight.com\u002Fblog\u002Fdamon-kelley\u002F2021\u002F05\u002F18\u002Fa-color-coded-guide-to-ports-and-adapters.html)\n\n---\n\n# Domain Layer\n\nThis layer contains the application's business rules.\n\nDomain should operate using domain objects described by [ubiquitous language](https:\u002F\u002Fmartinfowler.com\u002Fbliki\u002FUbiquitousLanguage.html). Most important domain building blocks are described below.\n\n- [Developing the ubiquitous language](https:\u002F\u002Fmedium.com\u002F@felipefreitasbatista\u002Fdeveloping-the-ubiquitous-language-1382b720bb8c)\n\n## Entities\n\nEntities are the core of the domain. They encapsulate Enterprise-wide business rules and attributes. An entity can be an object with properties and methods, or it can be a set of data structures and functions.\n\nEntities represent business models and express what properties a particular model has, what it can do, when and at what conditions it can do it. An example of business model can be a User, Product, Booking, Ticket, Wallet etc.\n\nEntities must always protect their [invariant](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FClass_invariant):\n\n> Domain entities should always be valid entities. There are a certain number of invariants for an object that should always be true. For example, an order item object always has to have a quantity that must be a positive integer, plus an article name and price. Therefore, invariants enforcement is the responsibility of the domain entities (especially of the aggregate root) and an entity object should not be able to exist without being valid.\n\nEntities:\n\n- Contain Domain business logic. Avoid having business logic in your services when possible, this leads to [Anemic Domain Model](https:\u002F\u002Fmartinfowler.com\u002Fbliki\u002FAnemicDomainModel.html) (Domain Services are an exception for business logic that can't be put in a single entity).\n- Have an identity that defines it and makes it distinguishable from others. Its identity is consistent during its life cycle.\n- Equality between two entities is determined by comparing their identificators (usually its `id` field).\n- Can contain other objects, such as other entities or value objects.\n- Are responsible for collecting all the understanding of state and how it changes in the same place.\n- Responsible for the coordination of operations on the objects it owns.\n- Know nothing about upper layers (services, controllers etc.).\n- Domain entities data should be modelled to accommodate business logic, not some database schema.\n- Entities must protect their invariants, try to avoid public setters - update state using methods and execute invariant validation on each update if needed (this can be a simple `validate()` method that checks if business rules are not violated by update).\n- Must be consistent on creation. Validate Entities and other domain objects on creation and throw an error on first failure. [Fail Fast](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFail-fast).\n- Avoid no-arg (empty) constructors, accept and validate all required properties in a constructor (or in a [factory method](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFactory_method_pattern) like `create()`).\n- For optional properties that require some complex setting up, [Fluent interface](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFluent_interface) and [Builder Pattern](https:\u002F\u002Frefactoring.guru\u002Fdesign-patterns\u002Fbuilder) can be used.\n- Make Entities partially immutable. Identify what properties shouldn't change after creation and make them `readonly` (for example `id` or `createdAt`).\n\n**Note**: A lot of people tend to create one module per entity, but this approach is not very good. Each module may have multiple entities. One thing to keep in mind is that putting entities in a single module requires those entities to have related business logic, don't group unrelated entities in one module.\n\nExample files:\n\n- [user.entity.ts](src\u002Fmodules\u002Fuser\u002Fdomain\u002Fuser.entity.ts)\n- [wallet.entity.ts](src\u002Fmodules\u002Fwallet\u002Fdomain\u002Fwallet.entity.ts)\n\nRead more:\n\n- [Domain Entity pattern](https:\u002F\u002Fbadia-kharroubi.gitbooks.io\u002Fmicroservices-architecture\u002Fcontent\u002Fpatterns\u002Ftactical-patterns\u002Fdomain-entity-pattern.html)\n- [Secure by design: Chapter 6 Ensuring integrity of state](https:\u002F\u002Flivebook.manning.com\u002Fbook\u002Fsecure-by-design\u002Fchapter-6\u002F)\n\n---\n\n## Aggregates\n\n[Aggregate](https:\u002F\u002Fmartinfowler.com\u002Fbliki\u002FDDD_Aggregate.html) is a cluster of domain objects that can be treated as a single unit. It encapsulates entities and value objects which conceptually belong together. It also contains a set of operations which those domain objects can be operated on.\n\n- Aggregates help to simplify the domain model by gathering multiple domain objects under a single abstraction.\n- Aggregates should not be influenced by the data model. Associations between domain objects are not the same as database relationships.\n- Aggregate root is an entity that contains other entities\u002Fvalue objects and all logic to operate them.\n- Aggregate root has global identity ([UUID \u002F GUID](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FUniversally_unique_identifier) \u002F primary key). Entities inside the aggregate boundary have local identities, unique only within the Aggregate.\n- Aggregate root is a gateway to entire aggregate. Any references from outside the aggregate should **only** go to the aggregate root.\n- Any operations on an aggregate must be [transactional operations](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDatabase_transaction). Either everything gets saved\u002Fupdated\u002Fdeleted or nothing.\n- Only Aggregate Roots can be obtained directly with database queries. Everything else must be done through traversal.\n- Similar to `Entities`, aggregates must protect their invariants through entire lifecycle. When a change to any object within the Aggregate boundary is committed, all invariants of the whole Aggregate must be satisfied. Simply said, all objects in an aggregate must be consistent, meaning that if one object inside an aggregate changes state, this shouldn't conflict with other domain objects inside this aggregate (this is called _Consistency Boundary_).\n- Objects within the Aggregate can reference other Aggregate roots via their globally unique identifier (id). Avoid holding a direct object reference.\n- Try to avoid aggregates that are too big, this can lead to performance and maintaining problems.\n- Aggregates can publish `Domain Events` (more on that below).\n\nAll of these rules just come from the idea of creating a boundary around Aggregates. The boundary simplifies business model, as it forces us to consider each relationship very carefully, and within a well-defined set of rules.\n\nIn summary, if you combine multiple related entities and value objects inside one root `Entity`, this root `Entity` becomes an `Aggregate Root`, and this cluster of related entities and value objects becomes an `Aggregate`.\n\nExample files:\n\n- [aggregate-root.base.ts](src\u002Flibs\u002Fddd\u002Faggregate-root.base.ts) - abstract base class.\n- [user.entity.ts](src\u002Fmodules\u002Fuser\u002Fdomain\u002Fuser.entity.ts) - aggregates are just entities that have to follow a set of specific rules described above.\n\nRead more:\n\n- [Understanding Aggregates in Domain-Driven Design](https:\u002F\u002Fdzone.com\u002Farticles\u002Fdomain-driven-design-aggregate)\n- [What Are Aggregates In Domain-Driven Design?](https:\u002F\u002Fwww.jamesmichaelhickey.com\u002Fdomain-driven-design-aggregates\u002F) \u003C- this is a series of multiple articles, don't forget to click \"Next article\" at the end.\n- [Effective Aggregate Design Part I: Modeling a Single Aggregate](https:\u002F\u002Fwww.dddcommunity.org\u002Fwp-content\u002Fuploads\u002Ffiles\u002Fpdf_articles\u002FVernon_2011_1.pdf)\n- [Effective Aggregate Design Part II: Making Aggregates Work Together](https:\u002F\u002Fwww.dddcommunity.org\u002Fwp-content\u002Fuploads\u002Ffiles\u002Fpdf_articles\u002FVernon_2011_2.pdf)\n\n---\n\n## Domain Events\n\nDomain Event indicates that something happened in a domain that you want other parts of the same domain (in-process) to be aware of. Domain events are just messages pushed to an in-memory Domain Event dispatcher.\n\nFor example, if a user buys something, you may want to:\n\n- Update his shopping cart;\n- Withdraw money from his wallet;\n- Create a new shipping order;\n- Perform other domain operations that are not a concern of an aggregate that executes a \"buy\" command.\n\nThe typical approach involves executing all this logic in a service that performs a \"buy\" operation. However, this creates coupling between different subdomains.\n\nAn alternative approach would be publishing a `Domain Event`. If executing a command related to one aggregate instance requires additional domain rules to be run on one or more additional aggregates, you can design and implement those side effects to be triggered by Domain Events. Propagation of state changes across multiple aggregates within the same domain model can be performed by subscribing to a concrete `Domain Event` and creating as many event handlers as needed. This prevents coupling between aggregates.\n\nDomain Events may be useful for creating an [audit log](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAudit_trail) to track all changes to important entities by saving each event to the database. Read more on why audit logs may be useful: [Why soft deletes are evil and what to do instead](https:\u002F\u002Fjameshalsall.co.uk\u002Fposts\u002Fwhy-soft-deletes-are-evil-and-what-to-do-instead).\n\nAll changes caused by Domain Events across multiple aggregates in a single process can be saved in a single database [transaction](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDatabase_transaction). This approach ensures consistency and integrity of your data. Wrapping an entire flow in a transaction or using patterns like [Unit of Work](https:\u002F\u002Fjava-design-patterns.com\u002Fpatterns\u002Funit-of-work\u002F) or similar can help with that.\n**Keep in mind** that abusing transactions can create bottlenecks when multiple users try to modify single record concurrently. Use it only when you can afford it, otherwise go for other approaches (like [eventual consistency](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FEventual_consistency)).\n\nThere are multiple ways on implementing an event bus for Domain Events, for example by using ideas from patterns like [Mediator](https:\u002F\u002Frefactoring.guru\u002Fdesign-patterns\u002Fmediator) or [Observer](https:\u002F\u002Frefactoring.guru\u002Fdesign-patterns\u002Fobserver).\n\nExamples:\n\n- [user-created.domain-event.ts](src\u002Fmodules\u002Fuser\u002Fdomain\u002Fevents\u002Fuser-created.domain-event.ts) - simple object that holds data related to published event.\n- [create-wallet-when-user-is-created.domain-event-handler.ts](src\u002Fmodules\u002Fwallet\u002Fapplication\u002Fevent-handlers\u002Fcreate-wallet-when-user-is-created.domain-event-handler.ts) - this is an example of Domain Event Handler that executes some actions when a domain event is raised (in this case, when user is created it also creates a wallet for that user).\n- [sql-repository.base.ts](src\u002Flibs\u002Fdb\u002Fsql-repository.base.ts) - repository publishes all domain events for execution when it persists changes to an aggregate.\n- [create-user.service.ts](src\u002Fmodules\u002Fuser\u002Fcommands\u002Fcreate-user\u002Fcreate-user.service.ts) - in a service we execute a global transaction to make sure all the changes done by Domain Events across the application are stored atomically (all or nothing).\n\nTo have a better understanding on domain events and implementation read this:\n\n- [Domain Event pattern](https:\u002F\u002Fbadia-kharroubi.gitbooks.io\u002Fmicroservices-architecture\u002Fcontent\u002Fpatterns\u002Ftactical-patterns\u002Fdomain-event-pattern.html)\n- [Domain events: design and implementation](https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fdotnet\u002Farchitecture\u002Fmicroservices\u002Fmicroservice-ddd-cqrs-patterns\u002Fdomain-events-design-implementation)\n\n**Additional notes**:\n\n- When using only events for complex workflows with a lot of steps, it will be hard to track everything that is happening across the application. One event may trigger another one, then another one, and so on. To track the entire workflow you'll have to go multiple places and search for an event handler for each step, which is hard to maintain. In this case, using a service\u002Forchestrator\u002Fmediator might be a preferred approach compared to only using events since you will have an entire workflow in one place. This might create some coupling, but is easier to maintain. Don't rely on events only, pick the right tool for the job.\n\n- In some cases you will not be able to save all changes done by your events to multiple aggregates in a single transaction. For example, if you are using microservices that span transaction between multiple services, or [Event Sourcing pattern](https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Farchitecture\u002Fpatterns\u002Fevent-sourcing) that has a single stream per aggregate. In this case saving events across multiple aggregates can be eventually consistent (for example by using [Sagas](https:\u002F\u002Fmicroservices.io\u002Fpatterns\u002Fdata\u002Fsaga.html) with compensating events or a [Process Manager](https:\u002F\u002Fwww.enterpriseintegrationpatterns.com\u002Fpatterns\u002Fmessaging\u002FProcessManager.html) or something similar).\n\n## Integration Events\n\nOut-of-process communications (calling microservices, external APIs) are called `Integration Events`. If sending a Domain Event to external process is needed then domain event handler should send an `Integration Event`.\n\nIntegration Events usually should be published only after all Domain Events finished executing and saving all changes to the database.\n\nTo handle integration events in microservices you may need an external message broker \u002F event bus like [RabbitMQ](https:\u002F\u002Fwww.rabbitmq.com\u002F) or [Kafka](https:\u002F\u002Fkafka.apache.org\u002F) together with patterns like [Transactional outbox](https:\u002F\u002Fmicroservices.io\u002Fpatterns\u002Fdata\u002Ftransactional-outbox.html), [Change Data Capture](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FChange_data_capture), [Sagas](https:\u002F\u002Fmicroservices.io\u002Fpatterns\u002Fdata\u002Fsaga.html) or a [Process Manager](https:\u002F\u002Fwww.enterpriseintegrationpatterns.com\u002Fpatterns\u002Fmessaging\u002FProcessManager.html) to maintain [eventual consistency](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FEventual_consistency).\n\nRead more:\n\n- [Domain Events vs. Integration Events in Domain-Driven Design and microservices architectures](https:\u002F\u002Fdevblogs.microsoft.com\u002Fcesardelatorre\u002Fdomain-events-vs-integration-events-in-domain-driven-design-and-microservices-architectures\u002F)\n\nFor integration events in distributed systems here are some patterns that may be useful:\n\n- [Saga distributed transactions](https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Farchitecture\u002Freference-architectures\u002Fsaga\u002Fsaga)\n- [Saga vs. Process Manager](https:\u002F\u002Fblog.devarchive.net\u002F2015\u002F11\u002Fsaga-vs-process-manager.html)\n- [The Outbox Pattern](https:\u002F\u002Fwww.kamilgrzybek.com\u002Fdesign\u002Fthe-outbox-pattern\u002F)\n- [Event Sourcing pattern](https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Farchitecture\u002Fpatterns\u002Fevent-sourcing)\n\n---\n\n## Domain Services\n\nEric Evans, Domain-Driven Design:\n\n> Domain services are used for \"a significant process or transformation in the domain that is not a natural responsibility of an ENTITY or VALUE OBJECT\"\n\n- Domain Service is a specific type of domain layer class that is used to execute domain logic that relies on two or more `Entities`.\n- Domain Services are used when putting the logic on a particular `Entity` would break encapsulation and require the `Entity` to know about things it really shouldn't be concerned with.\n- Domain services are very granular, while application services are a facade purposed with providing an API.\n- Domain services operate only on types belonging to the Domain. They contain meaningful concepts that can be found within the Ubiquitous Language. They hold operations that don't fit well into Value Objects or Entities.\n\n---\n\n## Value objects\n\nSome Attributes and behaviors can be moved out of the entity itself and put into `Value Objects`.\n\nValue Objects:\n\n- Have no identity. Equality is determined through structural property.\n- Are immutable.\n- Can be used as an attribute of `entities` and other `value objects`.\n- Explicitly defines and enforces important constraints (invariants).\n\nValue object shouldn’t be just a convenient grouping of attributes but should form a well-defined concept in the domain model. This is true even if it contains only one attribute. When modeled as a conceptual whole, it carries meaning when passed around, and it can uphold its constraints.\n\nImagine you have a `User` entity which needs to have an `address` of a user. Usually an address is simply a complex value that has no identity in the domain and is composed of multiple other values, like `country`, `street`, `postalCode` etc., so it can be modeled and treated as a `Value Object` with its own business logic.\n\n`Value object` isn’t just a data structure that holds values. It can also encapsulate logic associated with the concept it represents.\n\nExample files:\n\n- [address.value-object.ts](src\u002Fmodules\u002Fuser\u002Fdomain\u002Fvalue-objects\u002Faddress.value-object.ts)\n\nRead more about Value Objects:\n\n- [Martin Fowler blog](https:\u002F\u002Fmartinfowler.com\u002Fbliki\u002FValueObject.html)\n- [Value Objects to the rescue](https:\u002F\u002Fmedium.com\u002Fswlh\u002Fvalue-objects-to-the-rescue-28c563ad97c6).\n- [Value Object pattern](https:\u002F\u002Fbadia-kharroubi.gitbooks.io\u002Fmicroservices-architecture\u002Fcontent\u002Fpatterns\u002Ftactical-patterns\u002Fvalue-object-pattern.html)\n\n## Domain Invariants\n\nDomain [invariants](\u003Chttps:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FInvariant_(mathematics)#Invariants_in_computer_science>) are the policies and conditions that are always met for the Domain in particular context. Invariants determine what is possible or what is prohibited in the context.\n\nInvariants enforcement is the responsibility of domain objects (especially of the entities and aggregate roots).\n\nThere are a certain number of invariants for an object that should always be true. For example:\n\n- When sending money, amount must always be a positive integer, and there always must be a receiver credit card number in a correct format;\n- Client cannot purchase a product that is out of stock;\n- Client's wallet cannot have less than 0 balance;\n- etc.\n\nIf the business has some rules similar to described above, the domain object should not be able to exist without following those rules.\n\nBelow we will discuss some validation techniques for your domain objects.\n\nExample files:\n\n- [wallet.entity.ts](src\u002Fmodules\u002Fwallet\u002Fdomain\u002Fwallet.entity.ts) - notice `validate` method. This is a simplified example of enforcing a domain invariant.\n\nRead more:\n\n- [Design validations in the domain model layer](https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fdotnet\u002Farchitecture\u002Fmicroservices\u002Fmicroservice-ddd-cqrs-patterns\u002Fdomain-model-layer-validations)\n- [Why Domain Invariants are critical to build good software?](https:\u002F\u002Fno-kill-switch.ghost.io\u002Fwhy-domain-invariants-are-critical-to-build-good-software\u002F)\n\n### Replacing primitives with Value Objects\n\nMost of the code bases operate on primitive types – `strings`, `numbers` etc. In the Domain Model, this level of abstraction may be too low.\n\nSignificant business concepts can be expressed using specific types and classes. `Value Objects` can be used instead primitives to avoid [primitives obsession](https:\u002F\u002Frefactoring.guru\u002Fsmells\u002Fprimitive-obsession).\nSo, for example, `email` of type `string`:\n\n```typescript\nconst email: string = 'john@gmail.com';\n```\n\ncould be represented as a `Value Object` instead:\n\n```typescript\nexport class Email extends ValueObject\u003Cstring> {\n  constructor(value: string) {\n    super({ value });\n  }\n\n  get value(): string {\n    return this.props.value;\n  }\n}\n```\n\n```typescript\nconst email: Email = new Email('john@gmail.com');\n```\n\nNow the only way to make an `email` is to create a new instance of `Email` class first, this ensures it will be validated on creation and a wrong value won't get into `Entities`.\n\nAlso, an important behavior of the domain primitive is encapsulated in one place. By having the domain primitive own and control domain operations, you reduce the risk of bugs caused by lack of detailed domain knowledge of the concepts involved in the operation.\n\nCreating an object for primitive values may be cumbersome, but it somewhat forces a developer to study domain more in details instead of just throwing a primitive type without even thinking what that value represents in domain.\n\nUsing `Value Objects` for primitive types is also called a `domain primitive`. The concept and naming are proposed in the book [\"Secure by Design\"](https:\u002F\u002Fwww.manning.com\u002Fbooks\u002Fsecure-by-design).\n\nUsing `Value Objects` instead of primitives:\n\n- Makes code easier to understand by using ubiquitous language instead of just `string`.\n- Improves security by ensuring invariants of every property.\n- Encapsulates specific business rules associated with a value.\n\n`Value Object` can represent a typed value in domain (a _domain primitive_). The goal here is to encapsulate validations and business logic related only to the represented fields and make it impossible to pass around raw values by forcing a creation of valid `Value Objects` first. This object only accepts values which make sense in its context.\n\nIf every argument and return value of a method is valid by definition, you’ll have input and output validation in every single method in your codebase without any extra effort. This will make application more resilient to errors and will protect it from a whole class of bugs and security vulnerabilities caused by invalid input data.\n\n> Without domain primitives, the remaining code needs to take care of validation, formatting, comparing, and lots of other details. Entities represent long-lived objects with a distinguished identity, such as articles in a news feed, rooms in a hotel, and shopping carts in online sales. The functionality in a system often centers around changing the state of these objects: hotel rooms are booked, shopping cart contents are\n> paid for, and so on. Sooner or later the flow of control will be guided to some code representing these entities. And if all the data is transmitted as generic types such as int or String , responsibilities fall on the entity code to validate, compare, and format the data, among other tasks. The entity code will be burdened with a lot of\n> tasks, rather than focusing on the central business flow-of-state changes that it models. Using domain primitives can counteract the tendency for entities to grow overly complex.\n\nQuote from: [Secure by design: Chapter 5.3 Standing on the shoulders of domain primitives](https:\u002F\u002Flivebook.manning.com\u002Fbook\u002Fsecure-by-design\u002Fchapter-5\u002F96)\n\nAlso, an alternative for creating an object may be a [type alias](https:\u002F\u002Fwww.typescriptlang.org\u002Fdocs\u002Fhandbook\u002Fadvanced-types.html#type-aliases) (ideally using [nominal types](https:\u002F\u002Fbetterprogramming.pub\u002Fnominal-typescript-eee36e9432d2)) just to give this primitive a semantic meaning.\n\n**Warning**: Don't include Value Objects in objects that can be sent to other processes, like dtos, events, database models etc. Serialize them to primitive types first.\n\n**Note**: In languages like TypeScript, creating value objects for single values\u002Fprimitives adds some extra complexity and boilerplate code, since you need to access an underlying value by doing something like `email.value`. Also, it can have performance penalties due to creation of so many objects. This technique works best in languages like [Scala](https:\u002F\u002Fwww.scala-lang.org\u002F) with its [value classes](https:\u002F\u002Fdocs.scala-lang.org\u002Foverviews\u002Fcore\u002Fvalue-classes.html) that represents such classes as primitives at runtime, meaning that object `Email` will be represented as `String` at runtime.\n\n**Note**: if you are using nodejs, [Runtypes](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fruntypes) is a nice library that you can use instead of creating your own value objects for primitives.\n\n**Note**: Some people say that _primitive obsession_ is a code smell, some people consider making a class\u002Fobject for every primitive may be overengineering (unless you are using Scala with its value classes). For less complex and smaller projects it's definitely an overkill. For bigger projects, there are people who advocate for and against this approach. If you notice that creating a class for every primitive doesn't give you much benefit, create classes just for those primitives that have specific rules or behavior, or just validate only outside of domain using some validation framework. Here are some thoughts on this topic: [From Primitive Obsession to Domain Modelling - Over-engineering?](https:\u002F\u002Fblog.ploeh.dk\u002F2015\u002F01\u002F19\u002Ffrom-primitive-obsession-to-domain-modelling\u002F#7172fd9ca69c467e8123a20f43ea76c2).\n\nRecommended reading:\n\n- [Primitive Obsession — A Code Smell that Hurts People the Most](https:\u002F\u002Fmedium.com\u002Fthe-sixt-india-blog\u002Fprimitive-obsession-code-smell-that-hurt-people-the-most-5cbdd70496e9)\n- [Domain Primitives: what they are and how you can use them to make more secure software](https:\u002F\u002Ffreecontent.manning.com\u002Fdomain-primitives-what-they-are-and-how-you-can-use-them-to-make-more-secure-software\u002F)\n- [Value Objects Like a Pro](https:\u002F\u002Fmedium.com\u002F@nicolopigna\u002Fvalue-objects-like-a-pro-f1bfc1548c72)\n- [\"Secure by Design\" Chapter 5: Domain Primitives](https:\u002F\u002Flivebook.manning.com\u002Fbook\u002Fsecure-by-design\u002Fchapter-5\u002F) (a full chapter of the article above)\n\n### Make illegal states unrepresentable\n\nUse Value Objects\u002FDomain Primitives and Types ([Algebraic Data Types (ADT)](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAlgebraic_data_type)) to make illegal states impossible to represent in your program.\n\nSome people recommend using objects for every value:\n\nQuote from [John A De Goes](https:\u002F\u002Ftwitter.com\u002Fjdegoes):\n\n> Making illegal states unrepresentable is all about statically proving that all runtime values (without exception) correspond to valid objects in the business domain. The effect of this technique on eliminating meaningless runtime states is astounding and cannot be overstated.\n\nLet's distinguish two types of protection from illegal states: at **compile time** and at **runtime**.\n\n#### Validation at compile time\n\nTypes give useful semantic information to a developer. Good code should be easy to use correctly, and hard to use incorrectly. Types system can be a good help for that. It can prevent some nasty errors at compile time, so IDE will show type errors right away.\n\nThe simplest example may be using enums instead of constants, and use those enums as input type for something. When passing anything that is not intended the IDE will show a type error:\n\n```typescript\nexport enum UserRoles {\n  admin = 'admin',\n  moderator = 'moderator',\n  guest = 'guest',\n}\n\nconst userRole: UserRoles = 'some string'; \u002F\u002F \u003C-- error\n```\n\nOr, for example, imagine that business logic requires to have contact info of a person by either having `email`, or `phone`, or both. Both `email` and `phone` could be represented as optional, for example:\n\n```typescript\ninterface ContactInfo {\n  email?: Email;\n  phone?: Phone;\n}\n```\n\nBut what happens if both are not provided by a programmer? Business rule violated. Illegal state allowed.\n\nSolution: this could be presented as a [union type](https:\u002F\u002Fwww.typescriptlang.org\u002Fdocs\u002Fhandbook\u002Funions-and-intersections.html#union-types)\n\n```typescript\ntype ContactInfo = Email | Phone | [Email, Phone];\n```\n\nNow only either `Email`, or `Phone`, or both must be provided. If nothing is provided, the IDE will show a type error right away. Now business rule validation is moved from runtime to **compile time**, which makes the application more secure and gives a faster feedback when something is not used as intended.\n\nThis is called a _typestate pattern_.\n\n> The typestate pattern is an API design pattern that encodes information about an object’s run-time state in its compile-time type.\n\nRead more:\n\n- [Making illegal states unrepresentable](https:\u002F\u002Fv5.chriskrycho.com\u002Fjournal\u002Fmaking-illegal-states-unrepresentable-in-ts\u002F)\n- [Typestates Would Have Saved the Roman Republic](https:\u002F\u002Fblog.yoavlavi.com\u002Fstate-machines-would-have-saved-the-roman-republic\u002F)\n- [The Typestate Pattern](https:\u002F\u002Fcliffle.com\u002Fblog\u002Frust-typestate\u002F)\n- [Make illegal states unrepresentable — but how? The Typestate Pattern in Erlang](https:\u002F\u002Ferszcz.medium.com\u002Fmake-illegal-states-unrepresentable-but-how-the-typestate-pattern-in-erlang-16b37b090d9d)\n\n#### Validation at runtime\n\nData should not be trusted. There are a lot of cases when invalid data may end up in a domain. For example, if data comes from external API, database, or if it's just a programmer error.\n\nThings that can't be validated at compile time (like user input) are validated at runtime.\n\nFirst line of defense is validation of user input DTOs.\n\nSecond line of defense are Domain Objects. Entities and value objects have to protect their invariants. Having some validation rules here will protect their state from corruption. You can use techniques like [Design by contract](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDesign_by_contract) by defining preconditions in object constructors and checking postconditions and invariants before saving an object to the database.\n\nEnforcing self-validation of your domain objects will inform immediately when data is corrupted. Not validating domain objects allows them to be in an incorrect state, this leads to problems.\n\nBy combining compile and runtime validations, using objects instead of primitives, enforcing self-validation and invariants of your domain objects, using Design by contract, [Algebraic Data Types (ADT)](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAlgebraic_data_type) and typestate pattern, and other similar techniques, you can achieve an architecture where it's hard, or even impossible, to end up in illegal states, thus improving security and robustness of your application dramatically (at a cost of extra boilerplate code).\n\n**Recommended to read**:\n\n- [Backend Best Practices: Data Validation](https:\u002F\u002Fgithub.com\u002FSairyss\u002Fbackend-best-practices#data-validation)\n\n### Guarding vs validating\n\nYou may have noticed that we do validation in multiple places:\n\n1. First when user input is sent to our application. In our example we use DTO decorators: [create-user.request-dto.ts](src\u002Fmodules\u002Fuser\u002Fcommands\u002Fcreate-user\u002Fcreate-user.request.dto.ts).\n2. Second time in domain objects, for example: [address.value-object.ts](src\u002Fmodules\u002Fuser\u002Fdomain\u002Fvalue-objects\u002Faddress.value-object.ts).\n\nSo, why are we validating things twice? Let's call a second validation \"_guarding_\", and distinguish between guarding and validating:\n\n- Guarding is a failsafe mechanism. Domain layer views it as invariants to comply with always-valid domain model.\n- Validation is a filtration mechanism. Outside layers view them as input validation rules.\n\n> This difference leads to different treatment of violations of these business rules. An invariant violation in the domain model is an exceptional situation and should be met with throwing an exception. On the other hand, there’s nothing exceptional in external input being incorrect.\n\nThe input coming from the outside world should be filtered out before passing it further to the domain model. It’s the first line of defense against data inconsistency. At this stage, any incorrect data is denied with corresponding error messages.\nOnce the filtration has confirmed that the incoming data is valid it's passed to a domain. When the data enters the always-valid domain boundary, it's assumed to be valid and any violation of this assumption means that you’ve introduced a bug.\nGuards help to reveal those bugs. They are the failsafe mechanism, the last line of defense that ensures data in the always-valid boundary is indeed valid. Guards comply with the [Fail Fast principle](https:\u002F\u002Fenterprisecraftsmanship.com\u002Fposts\u002Ffail-fast-principle) by throwing runtime exceptions.\n\nDomain classes should always guard themselves against becoming invalid.\n\nFor preventing null\u002Fundefined values, empty objects and arrays, incorrect input length etc. a library of [guards](\u003Chttps:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGuard_(computer_science)>) can be created.\n\nExample file: [guard.ts](src\u002Flibs\u002Fguard.ts)\n\n**Keep in mind** that not all validations\u002Fguarding can be done in a single domain object, it should validate only rules shared by all contexts. There are cases when validation may be different depending on a context, or one field may involve another field, or even a different entity. Handle those cases accordingly.\n\nRead more:\n\n- [Refactoring: Guard Clauses](https:\u002F\u002Fmedium.com\u002Fbetter-programming\u002Frefactoring-guard-clauses-2ceeaa1a9da)\n- [Always-Valid Domain Model](https:\u002F\u002Fenterprisecraftsmanship.com\u002Fposts\u002Falways-valid-domain-model\u002F)\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>Note\u003C\u002Fb>: Using validation library instead of custom guards\u003C\u002Fsummary>\n\nInstead of using custom _guards_ you could use an external validation library, but it's not a good practice to tie domain to external libraries and is not usually recommended.\n\nAlthough exceptions can be made if needed, especially for very specific validation libraries that validate only one thing (like specific IDs, for example bitcoin wallet address). Tying only one or just few `Value Objects` to such a specific library won't cause any harm. Unlike general purpose validation libraries which will be tied to domain everywhere, and it will be troublesome to change it in every `Value Object` in case when old library is no longer maintained, contains critical bugs or is compromised by hackers etc.\n\nThough, it's fine to do full sanity checks using validation framework or library **outside** the domain (for example [class-validator](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fclass-validator) decorators in `DTOs`), and do only some basic checks (guarding) inside of domain objects (besides business rules), like checking for `null` or `undefined`, checking length, matching against simple regexp etc. to check if value makes sense and for extra security.\n\n\u003Cdetails>\n\u003Csummary>Note about using regexp\u003C\u002Fsummary>\n\nBe careful with custom regexp validations for things like validating `email`, only use custom regexp for some very simple rules and, if possible, let validation library do its job on more difficult ones to avoid problems in case your regexp is not good enough.\n\nAlso, keep in mind that custom regexp that does same type of validation that is already done by validation library outside of domain may create conflicts between your regexp and the one used by a validation library.\n\nFor example, value can be accepted as valid by a validation library, but `Value Object` may throw an error because custom regexp is not good enough (validating `email` is more complex than just copy - pasting a regular expression found in google. Though, it can be validated by a simple rule that is true all the time and won't cause any conflicts, like every `email` must contain an `@`). Try finding and validating only patterns that won't cause conflicts.\n\n---\n\n\u003C\u002Fdetails>\n\nAlthough there are other strategies on how to do validation inside domain, like passing validation schema as a dependency when creating new `Value Object`, but this creates extra complexity.\n\nEither to use external library\u002Fframework for validation inside domain or not is a tradeoff, analyze all the pros and cons and choose what is more appropriate for current application.\n\nFor some projects, especially smaller ones, it might be easier and more appropriate to just use validation library\u002Fframework.\n\n\u003C\u002Fdetails>\n\n## Domain Errors\n\nApplication's core and domain layers shouldn't throw HTTP exceptions or statuses since it shouldn't know in what context it's used, since it can be used by anything: HTTP controller, Microservice event handler, Command Line Interface etc. A better approach is to create custom error classes with appropriate error codes.\n\nExceptions are for exceptional situations. Complex domains usually have a lot of errors that are not exceptional, but a part of a business logic (like \"seat already booked, choose another one\"). Those errors may need special handling. In those cases returning explicit error types can be a better approach than throwing.\n\nReturning an error instead of throwing explicitly shows a type of each exception that a method can return so you can handle it accordingly. It can make an error handling and tracing easier.\n\nTo help with that you can create an [Algebraic Data Types (ADT)](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAlgebraic_data_type) for your errors and use some kind of Result object type with a Success or a Failure condition (a [monad](\u003Chttps:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMonad_(functional_programming)>) like [Either](https:\u002F\u002Ftypelevel.org\u002Fcats\u002Fdatatypes\u002Feither.html) from functional languages similar to Haskell or Scala). Unlike throwing exceptions, this approach allows defining types (ADTs) for every error and will let you see and handle them explicitly instead of using `try\u002Fcatch` and avoid throwing exceptions that are invisible at compile time. For example:\n\n```typescript\n\u002F\u002F User errors:\nclass UserError extends Error {\n  \u002F* ... *\u002F\n}\n\nclass UserAlreadyExistsError extends UserError {\n  \u002F* ... *\u002F\n}\n\nclass IncorrectUserAddressError extends UserError {\n  \u002F* ... *\u002F\n}\n\n\u002F\u002F ... other user errors\n```\n\n```typescript\n\u002F\u002F Sum type for user errors\ntype CreateUserError = UserAlreadyExistsError | IncorrectUserAddressError;\n\nfunction createUser(\n  command: CreateUserCommand,\n): Result\u003CUserEntity, CreateUserError> {\n  \u002F\u002F ^ explicitly showing what function returns\n  if (await userRepo.exists(command.email)) {\n    return Err(new UserAlreadyExistsError()); \u002F\u002F \u003C- returning an Error\n  }\n  if (!validate(command.address)) {\n    return Err(new IncorrectUserAddressError());\n  }\n  \u002F\u002F else\n  const user = UserEntity.create(command);\n  await this.userRepo.save(user);\n  return Ok(user);\n}\n```\n\nThis approach gives us a fixed set of expected error types, so we can decide what to do with each:\n\n```typescript\n\u002F* in HTTP context we want to convert each error to an \nerror with a corresponding HTTP status code: 409, 400 or 500 *\u002F\nconst result = await this.commandBus.execute(command);\nreturn match(result, {\n  Ok: (id: string) => new IdResponse(id),\n  Err: (error: Error) => {\n    if (error instanceof UserAlreadyExistsError)\n      throw new ConflictHttpException(error.message);\n    if (error instanceof IncorrectUserAddressError)\n      throw new BadRequestException(error.message);\n    throw error;\n  },\n});\n```\n\nThrowing makes errors invisible for the consumer of your functions\u002Fmethods (until those errors happen at runtime, or until you dig deeply into the source code and find them). This means those errors are less likely to be handled properly.\n\nReturning errors instead of throwing them adds some extra boilerplate code, but can make your application robust and secure since errors are now explicitly documented and visible as return types. You decide what to do with each error: propagate it further, transform it, add extra metadata, or try to recover from it (for example, by retrying the operation).\n\n**Warning**: Some errors\u002Fexceptions are non-recoverable and should be thrown, not returned. If you return technical Exceptions (like connection failed, process out of memory, etc.), It may cause some security issues and goes against [Fail-fast](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFail-fast) principle. Instead of terminating a program flow immediately and logging the error, returning an exception continues program execution and allows it to run in an incorrect state, which may lead to more unexpected errors, so it's generally better to throw an Exception in those cases rather than returning it. Analyze if the error is \"likely recoverable\" or \"likely unrecoverable\". If an error is most likely a recoverable error, it's a great candidate for using it in a Result object. If an error is most likely unrecoverable, throw it.\n\nLibraries you can use:\n\n- [oxide.ts](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Foxide.ts) - this is a nice npm package if you want to use a Result object\n- [@badrap\u002Fresult](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@badrap\u002Fresult) - alternative\n\nExample files:\n\n- [user.errors.ts](src\u002Fmodules\u002Fuser\u002Fdomain\u002Fuser.errors.ts) - user errors\n- [create-user.service.ts](src\u002Fmodules\u002Fuser\u002Fcommands\u002Fcreate-user\u002Fcreate-user.service.ts) - notice how `Err(new UserAlreadyExistsError())` is returned instead of throwing it.\n- [create-user.http.controller.ts](src\u002Fmodules\u002Fuser\u002Fcommands\u002Fcreate-user\u002Fcreate-user.http.controller.ts) - in a user http controller we match an error and decide what to do with it. If an error is `UserAlreadyExistsError` we throw a `Conflict Exception` which a user will receive as `409 - Conflict`. If an error is unknown we just throw it and our framework will return it to the user as `500 - Internal Server Error`.\n- [create-user.cli.controller.ts](src\u002Fmodules\u002Fuser\u002Fcommands\u002Fcreate-user\u002Fcreate-user.cli.controller.ts) - in a CLI controller we don't care about returning a correct status code so we just `.unwrap()` a result, which will just throw in case of an error.\n- [exceptions](src\u002Flibs\u002Fexceptions) folder contains some generic app exceptions (not domain specific)\n\nRead more:\n\n- [Flexible Error Handling w\u002F the Result Class](https:\u002F\u002Fkhalilstemmler.com\u002Farticles\u002Fenterprise-typescript-nodejs\u002Fhandling-errors-result-class\u002F)\n- [Advanced error handling techniques](https:\u002F\u002Fenterprisecraftsmanship.com\u002Fposts\u002Fadvanced-error-handling-techniques\u002F)\n- [\"Se","Domain-Driven Hexagon 是一个专注于教授领域驱动设计、软件架构、设计模式和最佳实践的项目。它通过提供基于NodeJS、TypeScript及NestJS框架编写的代码示例，深入讲解了六边形架构（也称为端口与适配器架构）、实体、聚合、值对象等核心概念和技术特点。尽管示例采用特定技术栈实现，但该项目强调的原则和模式是语言\u002F框架无关的，因此适用于任何希望构建可维护、可扩展且安全的应用程序的场景，尤其是对于那些需要遵循领域驱动设计理念来解决复杂业务逻辑问题的情况。",2,"2026-06-11 02:56:55","top_language"]