Skip to main content

Posts

Showing posts with the label Domain Driven Design

Type Aliases in C#: Bringing F#-style readability to your C# code

As I like to to program not only in C# but also F#, there are some paradigms and features in F# that influence my C# coding style. One of those features is F# type abbreviations that make complex type signatures more understandable and expressive. Since C#12, you have a similar feature available in C#: type aliases using the using directive. But although this option already exists for some time, I don’t see many C# developers use it. But I’ll hope that this blog post can help to change this and increase adoption… What are Type Aliases? Type aliases allow you to create shorthand names for existing types, making your code more readable and self-documenting. Instead of repeatedly writing complex generic types or lengthy class names, you can define a meaningful alias that captures the intent of your data structure. The F# connection In F#, type abbreviations have been a feature for years: These abbreviations don't create new types—they're simply aliases that make the ...

Don’t talk about non-functional requirements, talk about quality attributes

When discussing software development, terms shape our perception and priorities. One such discussion revolves around the terminology used for requirements that go beyond direct functionalities. Traditionally, when talking about architectural needs, I used to call them non-functional requirements (NFRs). However, I switched recently to a  more fitting term—quality attributes—as it may better emphasize their importance and value.    Generated by AI Let me explain why this more than just a semantic change but a strategic enhancement… What are non-functional requirements? Before I explain my reasoning, let me shortly define what non-functional requirements are: Non-functional requirements (NFRs), also known as quality attributes, refer to criteria that judge the operation of a system rather than specific behaviors or functions. These requirements define the overall qualities and characteristics that the system must possess, ensuring it meets user needs and performs ...

Loading aggregates with EF Core

In Domain-Driven Design (DDD), an aggregate is a cluster of domain objects that are treated as a single unit for the purpose of data changes. The aggregate has a root and a boundary: Aggregate Root : This is a single, specific entity that acts as the primary point of interaction. It guarantees the consistency of changes being made within the aggregate by controlling access to its components. The aggregate root enforces all business rules and invariants within the aggregate boundary. Boundary : The boundary defines what is inside the aggregate and what is not. It includes the aggregate root and other entities or value objects that are controlled by the root. Changes to entities or value objects within the boundary must go through the aggregate root to ensure consistency. An example of an aggregate is an Order (which is the Aggregate root) together with OrderItems (entities inside the Aggregate). The primary function of an aggregate is to ensure data consist...

Understanding Pure Domain Modelling: Bridging the Gap Between Existing Systems and the Real Domain

Domain modelling plays a crucial role in the way that I design systems to reflect the business's needs and processes. However, I experienced there is often a disconnect between the idealistic view of domain modelling and the practical reality faced by domain experts. One key issue is that domain experts tend to start from their existing systems rather than describing the 'real' domain. In this post I want to talk about pure domain modelling as a way to overcome the bias that domain experts have when explaining their needs. The domain expert bias When domain experts contribute to domain modelling, they frequently start from the perspective of the existing systems they are familiar with. These systems, whether they are legacy products, databases, or other technological solutions, shape their understanding and descriptions of the domain. While this approach has its advantages, it also introduces several challenges: Bias Towards Existing Systems: Domain experts may de...

The importance of the ubiquitous language

We all know that the hardest thing in software development is naming things . Domain Driven Design tries to tackle this by focusing on the 'ubiquitous language'. The "ubiquitous language" refers to a shared language that is used by all team members, including domain experts, developers, and stakeholders, to discuss the domain and the software being developed. This language is designed to bridge the communication gap between technical and non-technical team members, ensuring that everyone has a clear understanding of the domain concepts and requirements. The ubiquitous language consists of domain-specific terms and concepts that are defined collaboratively and consistently used across all artifacts of the software development process, including code, documentation, and discussions. By using a common language, DDD aims to reduce misunderstandings and ambiguities, leading to more effective collaboration and better software designs. The best way to emphasize the imp...

Applying the smart constructor pattern in C#

In Domain-Driven Design (DDD), domain invariants are fundamental principles or rules that must always hold true within a specific domain. These invariants define constraints or conditions that govern the behavior and state of the entities, value objects, and aggregates within the domain. They emphasize the Always-valid rule: Your domain model should always be in a valid state. By using invariants, your domain model guarantees that it cannot represent illegal states. These invariants define the domain class: that class is what it is because of them. Therefore, you can’t possibly violate these invariants. If you do so, the domain class would simply cease being the thing you expect it to be; it’d become something else. As Greg Young explains it: A unicorn without a horn is a horse, not a unicorn. There are multiple ways to protect those invariants. Using value objects and taking advantage of the type system are a great help here. However not all invariants can be enf...

Understanding the DDD Whirlpool Process for Effective Domain Modeling

In the world of software development, aligning the software solution with the real-world problem it aims to solve is crucial for success. One powerful approach to achieving this alignment is Domain-Driven Design (DDD). At the heart of DDD lies the DDD Whirlpool process , a collaborative and iterative approach that enables teams to model the core domain effectively. The goal of the whirlpool process is to describe a way on how to iterate on the design of your domain model. The gist of this approach is to keep challenging the model.  Start by harvesting a few reference scenarios(through Event Storming or any other technique you like). Use these scenarios to create multiple possible models and quickly iterate over them. Once you end up with a workable model, you can start prototyping your model in code. Introduce another scenario into the mix and see how it impacts your current model. Keep repeating this process during the full development lifecycle.

Units of measure in C#

Yesterday I talked about the 'units of measure' feature in F# . This allows you to associate a unit of measure to a type and allows the compiler to help you avoid providing the wrong input. Unfortunately in C#, a similar feature does not exist but we can let the type system help us by creating 'Value Objects'. What are Value Objects? Value objects are probably best known in the context of Domain Driven Design where they are one of the tactical patterns. They allow you to encapsulate (domain) logic in a type and should always be in  a valid state. Eric Evans uses the following example to describe them: When a child is drawing, he cares about the color of the marker he chooses, and he may care about the sharpness of the tip. But if there are two markers of the same color and shape, he probably won’t care which one he uses. If a marker is lost and replaced by another of the same color from a new pack, he can resume his work unconcerned about the switch. Value Ob...

Service decomposition and service design

Finding the boundaries of your system and decompose it into multiple services sounds easy, but it certainly isn’t. If you are interested in this topic, check out the blog series by Vadim Samokhin: Why you should split the monolith Wrong way of defining service boundaries What characteristics my services should possess How to define service boundaries Remark: After writing this post, I noticed that Vadim created a blog post linking to the series above and included also some other related posts.

Domain Driven Design–The first 15 years

If you are into DDD and you want to have a heads up what happened in the DDD community since the release of the “ blue book ” by Eric Evans, Domain Driven Design – The first 15 years is a must read. Fifteen years after the publication of "Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, DDD is gaining more adoption than ever. To celebrate the anniversary, we've asked prominent authors in the software design world to contribute old and new essays.   The book was released in 2015 so maybe it becomes time for another update, but until that happens you can read this edition.

Saying goodbye to the Monolith - The one Entity abstraction

 In most systems I encounter there is a strong focus on "Entities". We try to model everything in this "Entity" abstraction where one "Entity" is typically mapped to one table. Every piece of data that is related to this "Entity" is encapsulated in this object. This could sound fine from a OO perspective but can bring us on a path where we get too much coupling and information from multiple domains get encapsulated in the same object. A first step in the right direction is to focus on the difference between related entities and child entities . Could some parts of the data move to a child entity or even a value object? A second step is to identity your bounded contexts and start to split your entity across the boundaries of these contexts. This means you will typically not end up with one entity but many entities each containing a subset of the data. Let's take a look at an example... Imagine that we have a Product entity. If we try to split ...

Domain Driven Design–Structuring your applications

There are a lot of options out there on how you should structure your DDD projects. Although DDD gives you a clear explanation of the different building blocks, it doesn’t prescribe any particular project setup or structure. So this leaves it up to you (and everyone else) to create a structure that works for you. A possible setup I used before can be found below: It is inspired on the blog articles below: Applied Domain-Driven Design (DDD), Part 1 - Basics Applied Domain-Driven Design (DDD), Part 2 - Domain events Applied Domain-Driven Design (DDD), Part 3 - Specification Pattern Applied Domain-Driven Design (DDD), Part 4 - Infrastructure Applied Domain-Driven Design (DDD), Part 5 - Domain Service Applied Domain-Driven Design (DDD), Part 6 - Application Services Applied Domain-Driven Design (DDD), Part 7 - Read Model Services Applied Domain-Driven Design (DDD), My Top 5 Best Practices Applied Domain-Driven Design (DDD), Event Logging & Sourcing For Auditing ...

DDD–Strongly typed Ids

One of the core principles of DDD is the usage of value objects to avoid “primitive obsession”. "Primitives" refer to the built-in types in C#,  int , string,guid etc. "Primitive obsession" refers to over-using these types to represent domain concepts that aren't a perfect fit. Some examples are a HouseNumber that is represented by an int or an EmailAddress that is represented by a string. This concept not only makes sense for your value objects but is also valuable for your Entity and AggregateRoot id’s. A ProductId should not be interchangeable with an OrderId. Creating a valueobject for every Id type is not that hard but remains cumbersome. Let’s introduce StronglyTypedId as a solution. From the website : StronglyTypedId makes creating strongly-typed IDs as easy as adding an attribute! No more accidentally passing arguments in the wrong order to methods - StronglyTypedId uses Roslyn-powered build-time code generation to generate the boilerplate ...

Domain Driven Design–3 rules to help you get started

I recently started a new project where we are using the DDD principles to build our software. As most of my team members are new to DDD, I noticed some obvious mistakes. Here are some rules that can help you avoid the same mistakes… Rule #1: Your domain should be modelled first When you start a new project spend enough time on the domain before introducing a frontend and a database. Try to identify your bounded contexts, what are your entities? What can be a good aggregate? Which domain events are needed? This allows you to really focus on the domain itself and explore it in depth. This is also a perfect time to introduce TDD(Test Driven Development) in your team. Rule #2: Your domain should reflect your business logic not your database If you start with Rule #1 you are already on the correct path. In too much cases I see that the domain is immediately setup in such a way that it works with the ORM tool the team has chosen. If the ORM needs getters and setters, they are adde...

Domain Driven Design–Get rid of your anemic domain model

Although most developers have heard about Domain Driven Design, most applications I encounter today are the traditional ‘layered cake’ with an anemic domain model . I have to admit that even a lot of applications I’ve helped building the last years are still using this approach. Why? 2 reasons; Lack of DDD knowledge in the teams. Most developers ‘know’ the tactical DDD patterns but are not aware of the strategic DDD patterns. What makes it even worse is that even the tactical patterns like the repository pattern are wrongly applied. Getting a team up to speed with DDD takes time, time that we unfortunately not always have in ‘fixed price, fixed time, fixed scope’ projects. Another reason to go for the ‘product not project’ approach. Lack of access to Domain experts.   Good domain modelling can only work if the necessary expertise is around to help you find the correct ubiquitous language, identify bounded contexts and create a shared understanding of the business. T...