AVOID Entity Services by Focusing on Capabilities

Entity Services are services that are centered around an Entity. For example, a CustomerService or a ProductService. Most times these services focus on data and CRUD operations. These services can cause low cohesion and in turn cause high coupling. Instead, focus on capabilities of services, the data encapsulated and owned by the service. Focusing on capabilities will increase cohesion and lower coupling.

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.

Entity Services

I believe that the default way that systems are built and designed today in 2021 is still revolving around large data models. This can be illustrated by a question on Reddit, which was asking if a microservices architecture where each table represented its own microservices was the best approach.

The answer is no. Absolutely not.

I don’t blame the user for posting this question. There is so much content around creating CRUD apps that it’s not really surprising. Also, when creating a large monolith, having a large schema is also typical. So the idea to split a large monolith and schema into microservices, would seem like you would create services around tables/data.

Also, I would guess most developers relate Entities to tables. This is likely because of ORMs like Entity Framework.

Data Centric

For my example throughout this post, I’m going to use the concept of a product in a warehouse.

Entity Services

This entity has a few different properties that would probably be managed by CRUD. If you’re talking about an HTTP API, it would probably follow a CRUD to HTTP Methods.

For example, if you wanted to create a product you would call:

POST /products

Or if you wanted to update a product you would call the route:

PUT /products/{Sku:Guid}

These are the typical examples you’ll find in blogs/tutorials/videos.

If you’re looking at an API, it would contain just CRUD type methods:

Capabilities

The alternative is to focus on the capabilities of your service. Instead of grouping your entities by their data, rather group them by the capabilities they provide that relate to each other.

A service is the authority of a set of business capabilities.

If you look at the entity, which properties relate to each other? What are the actions users would take in order that would change those properties?

If the quantity on hand of a product is changing, why is that? What would a user be doing that would change the QuantityOnHand?

Does the QuantityOnHand have any relation to the cost? Would QuantityOnHand ever change at the same time as the price?

Likely not.

If you decompose the capabilities that you need to expose to users, they are driven by commands/actions/tasks. What are the things users are trying to do?

Entity Services

Moving away from CRUD and exposing explicit capabilities will then expose which capabilities are concerned with what pieces of data.

The QuantityOnHand is affected by shipping and receiving products. The capabilities of shipping and receiving products belong to the warehouse.

The Name, Description, Price, and Cost have nothing to do with shipping and receiving products. So why are the other properties on the product entity?

Entity Services

If you do this to the other properties, you will realize that the capabilities define the data they own. Group related capabilities together into their own service/boundary, then you will realize that you do not have a single entity, but multiple concepts of the same entity that reside in multiple services.

Entity Services

The concept of a product now lives in multiple different boundaries/services. They all share the common SKU, but each service owns a set of capabilities. Behind those capabilities are the relevant data it owns.

Focusing on capabilities will increase cohesion and reduce coupling. Coupling is reduced because of increasing cohesion. You do not need to call other services to get/change data because you have the required data within a service for the capabilities that it owns.

Links

Follow @CodeOpinion on Twitter

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Aggregate (Root) Design: Behavior & Data

How do you persist your Aggregate using Entity Framework? Using a Repository to get/set your Aggregate Root? I see a lot of examples that bend over backward to make their Entities expose behaviors while try to encapsulate data. It doesn’t need to be difficult. And if you’re not using an ORM, what’s a way that you can capture the changes made by the Aggregate Root so that you can persist them writing SQL?

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.

Entity Framework

The most common examples I see are creating an Aggregate using Entity Framework entities. In the very simplest of use-cases, I think it can work. However, I’ve watched/read enough content that makes me shake my head about the hoops people will jump through to make their data persistence model also be their domain model. This is often because they are trying to hide the actual data or conform to how EF needs the entity to behave.

They don’t need to be the same object.

Your domain model is about exposing behaviors and encapsulating data.

If you’re not exposing data from an aggregate, meaning there’s no way for callers/consumers to get data from it (think CQRS), then you can encapsulate your data model inside your aggregate root. Your data model at that point is your Entity Framework entities. Your aggregate root is your aggregate.

Separate Aggregate & Data

This is very simple but allows you to use EF exactly how it’s intended and create an Aggregate Root that simply exposes behaviors and encapsulate your data model (EF).

First, let’s start with our Entity Framework Entities, which are basically now just our data model. They contain no behavior. Simply a data model used for persistence.

Next, all of our behavior goes into a separate class that takes the ShoppingCart as a parameter in the ctor. We’ll manipulate this data model in all of our behavior methods. We don’t ever expose the data model to any outside caller/consumer.

Finally, we use a repository to Get and Save a ShopingCartDomain.

There are a lot of opinions about Repositories. My opinion is they should be for constructing and saving your behavior only aggregate. This generally means you’ll only ever have 2 methods: Get() and Save()

The repository will get the data using Entity Framework, then construct a new instance of our Aggregate and pass in the data model.

Aggregates (Root) without an ORM

If you’re not using an ORM like Entity Framework, but still want to create a domain with behavior then the ultimate problem is change tracking. With an ORM, it’s doing the change tracking of knowing which properties on your entities changed that it needs to persist to your database.

This is what needs to be implemented (change tracking) if you’re not using an ORM.

To do so, I like to implement this using events to represent state changes.

In our behavior methods, we’re recording and keeping track of them in the _events member. We’re also taking a parameter that represents the data model of the current state that our repository will build us.

When we want to save our state changes, our repository will iterate through the events, then have the appropriate SQL statements for them.

Expose Behavior and Encapsulate Data

If you’re doing all sorts of odd things to make your ORM be a data model that also contains behaviors, just separate the two. If you’re not using an ORM, it doesn’t mean you can’t create aggregates. Use events as a method of change tracking and implement the SQL statements for each event that represents a state change.

Links

Clean up your Domain Model with Event Sourcing

Follow @CodeOpinion on Twitter

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Write Stable Code using Coupling Metrics

Are you tired of changing one part of a system, only to have another part break? Write stable code! Writing stable code can seem impossible. Trying to keep things from breaking can be a nightmare if you’re unaware of how your system is coupled. Understanding Afferent & Efferent coupling can guide you into insights about your software architecture & design.

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.

Coupling

To illustrate coupling, I’m going to talk about it at a project/package/boundary level. You could also think of these diagrams at a class level as well, however I think looking at it from a higher level such as project/packages of your system is a better place to start.

Write Stable Code using Coupling Metrics

Each blue box in the above diagram represents a boundary/project within the system. The direction of the arrows is to illustrate the coupling required from one boundary to another.

Shipping is dependent on Sales
Billing is dependent on Sales
Sales is dependent on CRM

Afferent Coupling (Ca)

Who depends on you? Afferent coupling (denoted by Ca) is a metric that indicates the total number of other projects/boundaries that are dependent upon it.

So from the viewpoint of the Sales boundary, it has an Afferent Coupling of 2. Shipping and Billing are both dependent upon Sales.

From a .NET solution, this would be represented by project references. When you take the viewpoint of a particular project in a solution, what other projects reference it? The number of other projects that reference your project is the total of Afferent Coupling (Ca).

Afferent Coupling: Who depends on You?

Efferent Coupling (Ce)

Who do you depend on? Efferent coupling (denoted by Ce) is another metric that is the verse of Afferent Coupling. It is the total number of projects that a given project depends on.

From the viewpoint of the Sales project/boundary, it has an Efferent Coupling (Ce) of 1. It depends on the CRM project/boundary.

From a .NET solution, this would represent all the references you have to other projects for a given project.

Efferent coupling: Who do you depend on?

Coupling Metrics

If we count all the Afferent (Ca) and Efferent (Ce) coupling in the entire diagram, we get the following counts.

Write Stable Code using Coupling Metrics

If you were to do this with your solution/system, what could you derive from this data? How could you use this to better understand your system overall and the possible issues with it?

Having a high Afferent Coupling (Ca) will generally cause you pain when you make a non-compatible change. Meaning, if you make a change to a project that is used by a lot of other projects, you have a high risk of causing issues with all those other projects. You’ll know this if you make a change and break other parts of your system.

Having a high Efferent Coupling (Ce) will generally cause you pain when you need to change it. Because it’s so dependent on so many other projects/ boundaries, it’s can be difficult to change. Having a lot of dependencies could mean that it’s simply doing too much or that you actually have misaligned boundaries.

Instability

Instability another metric that is a ratio.

I = Ce / (Ce + Ca)

This metric is a ratio between 0 and 1. With 0 meaning it’s totally stable and 1 meaning it’s unstable.

Note: Having a high ratio of instability isn’t unreasonable depending on the context of the project.

Here’s the calculated instability ratio for each project/boundary.

Write Stable Code using Coupling Metrics

CRM has an Instability of 0. Meaning it’s stable. And this makes sense because it has no dependencies. Nothing can affect it. In other words, no changes to any other projects can affect it. However, since it has a high Ca, changes to it can affect other parts of the system. We need to be cautious of change.

Billing & Shipping have Instability of 1. If sales changes in a way that is not handled by Billing, it can make it unstable. This isn’t inherently bad because we need to realize that it’s relative to the Ce for those projects. Having a dependency on 1 project is much different than having 10 dependencies. Also, we can change these projects freely and we will not affect any other projects.

Sales has a combination of both Ca and Ce. While these numbers are low, if you’re in a situation where a project has a high number of both Ca and Ce, it may be cause for concern in your design. This would be the center point of your diagram. It can be affected by many projects, and change to it can affect many projects. Not an ideal scenario.

Coupling Metrics

Use coupling metrics of Afferent Coupling (Ca), Efferent Coupling (Ce), and Instability (I) as a way to review your system and your design goals. Let metrics guide your decision making in refactoring where needed.

Follow @CodeOpinion on Twitter

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.