Friday, November 9, 2018

Clean Architecture

Clean Architecture

Hexagonal Architecture

Hexagonal Architecture

Onion Architecture

Onion Architecture

Application Service Layer


What is the job of the Application Layer?

The Application Layer of a Domain Driven Design application acts as a public API to the application. The Application layer will accept requests from the outside world and return responses in an appropriate manner.
The Application Layer is important because it acts as an agnostic barrier between the outside world and your application. Your application should not care where a request comes from.
The Application Layer also acts as a conductor by pulling in the services it requires to satisfy a request or send a response. This might mean sending Commands into a Command Bus, or running a query on a Repository.

How do you implement the Application Layer?

I’m by no means an expert in this area of application development, but it seems to me that there are basically two methods for implementing the Application layer.

Application Services

The first method is to use Application Services. An Application Service is basically just a class with methods for the various tasks your application can perform.
For example, you might have the following IdentityApplicationService:
class IdentityApplicationService  
{  
/**  
* Register a new user  
*  
* @param string $email  
* @param string $username  
* @param string $password  
* @return User  
*/  
public function register($email, $username, $password)  
{  
// register a new user  
}  
}  
The register() method on this Application Service would accept the raw strings from the request and use the internal RegisterUserService to create a new User object.
The Application Service would be injected with the various services it requires to complete the task. Application Service would generally separated by functional area of the application and would group together related methods.

Command Bus

Alternatively you have the Command Bus approach. A Command Bus accepts a Command object and delegates it to a Command Handler.
For example, you might have a RegisterUserCommand that is sent to the Command Bus and delegated to a RegisterUserHandler.
The RegisterUserHandler would be able to handle the process for registering a new user in the application.

What are the differences between Application Services and The Command Bus?

There are many differences between Application Services and The Command Bus and both have their positives and negatives.
Firstly, Application Services tend to be more complicated than using a Command Bus. This is because grouping together many related tasks means you end up with a large class that requires a number of dependencies and has a lot of responsibility.
Using a Command Bus is far more simpler because each Command has a single Command Handler. Each Handler only needs to be concerned with satisfying a single Command, and so your code ends up much closer to The Single Responsibility Principle.
However on the other hand, using a Command Bus can be more complicated than using an Application Service in some situations. A Command Bus should not return a value after a Command has been handled.
For example, if you were creating a new resource in your application, you would not be returned the id of the new resource so you could redirect the user to it’s view page.
Now arguably, this is probably only going to make using a Command Bus more difficult if you are trying to use a Command Bus for the wrong job. If you face this situation, you should probably use an Application Service.
However testing A Command Bus is more difficult because it’s harder to test code when there is no return value from the method call. I’m still trying to get my head around this one.
When you begin writing The Application Layer of your application, you don’t need to choose either Application Services or a Command Bus. You can very easily use one type of implementation for certain functionality of your application and another for other aspects. It’s about choosing the right tool for the job, and not trying to fit a square peg in a round hole.

Services

We can define services as processes that perform certain tasks. Employees and evolved from Service Oriented Architecture or Remote Procedure Call . Generic tasks or actions that are not associated with a single determined single object instance, so the most common tendency is to create static methods on the entity or aggregate . This practice is not considered optimal because it does not follow the principles of development and greatly complicates testing, and it is considered bad practice to access repositories within the aggregates or entitiesin the domain model. The need to include static methods in the domain model is a good indicator to create a service .

Application Services

  • Direct client of Domain Services and domain model.
  • Use cases of the application that coordinates and orchestrates the requests to the business logic and repositories.
  • Coordinates the responsibilities of the domain model and domain services.
  • Hosted in Application Layer .

Domain Services

  • Contains the logic / business rules .
  • Transform one domain object to another.
  • Calculate the value by entering objects from the domain model.
  • They can access repositories.
  • Hosted in Domain Layer .
In order to follow the development principles , we will declare interfaces for each Service. 
The services are not a silver bullet , if we use them in excess extracting all the logic of application or domain in services, we can cause an Anemic Domain Model . It must be determined and correctly decided if an entity / aggregate method should be included in the domain model or create a service following Single Responsibility Principle at all times .
In general, the implementations of the services are hosted in the infrastructure layer , although sometimes when we have a single implementation they can be hosted in the same layer where the interface is declared.

Infrastructure Layer

The Infrastructure Layer
The Infrastructure Layer is made up of all the technical details of how our application is implemented.

For example, most applications require a database and so the code that interacts with the database would sit in the Infrastructure Layer.

Domain Driven applications should rely on interfaces and not implementations. This means we would rely on a Mailer interface, but we would use a MailGunMailer implementation that implements the interface we require.

So far we’ve covered the following sections of the Infrastructure layer:

Creating a Mailer Infrastructure Service
Creating and testing Doctrine Repositories

Domain Model Layer

What is the Domain Model in Domain Driven Design?

If you have been following along with my Building Cribbb series you will probably already be aware of the fact that Domain Driven Design has a lot of terminology.

To understand Domain Driven Design, you really need to understand the terminology. However, I often find that terminology in the absence of real world context is not only difficult to understand, but almost impossible to apply and reap the benefits of.

Domain Model is a term you will hear a lot in Domain Driven Design. I think Domain Model is one of the most obvious examples of terminology that means absolutely nothing unless you understand the context in which it applies.

In today’s article we’re going to be looking at what Domain Model actually means, why it is important and how to use it within the context of your development projects.

The Domain is the problem
Domain Driven Design is predicated around the idea of solving the problems organisations face through code. This is achieved by focusing the investment of resources into the heart of the business logic of the application.

The domain therefore is, the world of the business. Whenever you hear the phrase “Domain Driven Design”, you should think of it as “Business Problem Driven Design”.

The domain is the world of the business you are working with and the problems they want to solve. This will typically involve rules, processes and existing systems that need to be integrated as part of your solution.

The domain is the ideas, knowledge and data of the problem you are trying to solve. Most businesses will have terms that have specific meaning within the context of their organisation. They will also likely have metrics, goals and objectives that are unique to their business.

All of the knowledge around the company and how it operates will form the domain of your Domain Driven Designed project.

The Model is your solution
The Model of an Domain Driven Designed project is your solution to the problem.

The Model usually represents an aspect of reality or something of interest. The Model is also often a simplification of the bigger picture and so the important aspects of the solution are concentrated on whilst everything else is ignored.

This means your Model should be focused knowledge around a specific problem that is simplified and structured to provide a solution.

The Domain Model
So if the Domain is the world of the business, and the Model is your solution, what is the Domain Model?

The Domain Model is your organised and structured knowledge of the problem. The Domain Model should represent the vocabulary and key concepts of the problem domain and it should identify the relationships among all of the entities within the scope of the domain.

The Domain Model itself could be a diagram, code examples or even written documentation of the problem. The important thing is, the Domain Model should be accessible and understandable by everyone who is involved with the project.

The Domain Model should also define the vocabulary around the project and should act as a communication tool for everyone involved. The Ubiquitous Language is an extremely important concept in Domain Driven Design and so it should be directly derived from the Domain Model.

One of the downfalls of many software development projects is the misunderstanding of terms, objectives and proposed solutions that are scoped at the beginning of development.

The Domain Model should act as a clear depiction of the problem that is being solved and the proposed solution. It is extremely important that all stakeholders of the project contribute to the Domain Model so that everyone understands the key concepts and definitions of the vocabulary of the project and how the problem is being tackled and solved.

Why is the Domain Model important?
So the Domain is the world of the business, the Model is your solution and the Domain Model is the structured knowledge of the problem.

Why is this important to Domain Driven Design? Well, I think there are three reasons why a Domain Model is important.

The Domain Model and the heart of the design shape each other
The code that you write should be intimately linked to the model of the problem you are solving. Anyone on the team should be able to look at your code and understand how it applies to the problem you are solving.

When developers deviate from the model, they write code that is built around their mental model of the problem. The code that you write should be directly derived from the agreed Domain Model to ensure that your solution meets the requirements of the business.

The Domain Model is the backbone of the language used by all team members
Every single person on the project team should use the Ubiquitous Language. This means that technical and non-technical people have a common language to communicate so there is no loss of understanding between parties.

The Ubiquitous Language should be directly derived from the Domain Model and so without a Domain Model you don’t have a Ubiquitous Language.

Without a Ubiquitous Language you will start to feel the friction of communication and the loss of understanding between technical and non-technical members of the team. If the code that is written starts to deviate away from the requirements of the business experts, the end solution won’t satisfy the goals of the project.

The Domain Model is distilled knowledge
The Domain Model should be the outcome of an iterative discovering process where everyone on the team meets to discuss the problem you are facing and how it should be solved.

This early collaboration between domain experts and the development team is critical to the success of the project.

The Domain Model should capture how you think about the project and all of the distilled knowledge that has been derived from those collaboration sessions.

Whenever a decision needs to be made during the course of the project everyone should refer to the Domain Model to look for the answer or to try to iteratively evolve the design to discover a hidden truth that has not previously been exposed.

How do you arrive at a Domain Model?
Arriving at a Domain Model is an iterative approach that attempts to discover the real problem that is faced and the correct solution that is required.

It’s important to focus a Domain Model on one important problem. Trying to capture the entire scope of a business inside of a single Domain Model will be far too overcomplicated and most likely contradictive as concepts and ideas move around the organisation.

The problem should be mapped out through talking to business experts to discover the problems they face. This should form the conceptual problem that you are looking to tackle.

Business experts won’t talk in the terms of technical solutions, and so it is your job to correctly interpret their problems into technical solutions.

During this process the important aspects of the problem should be picked out from the language and given concrete definitions to form the Ubiquitous Language.

It doesn’t really matter whether the Domain Model is created in code, as a diagram or in prose. However there should be a tight feedback loop where everyone on the project discusses the proposed Domain Model to get closer to the solution. This is an iterative approach that will likely encompass code, diagrams and prose to really understand the problem and to discover the correct solution.

What is an example of a Domain Model?
It’s difficult to show an example of a Domain Model as it should really be taken from a real world business problem.

However, for the benefit of this article, lets pretend we have the following business problem we need to solve:

A business wants to create software to manage it’s projects
Projects are derived from a product roadmap
The project is picked due to certain criteria
The project is assigned to a project manager
The project manager organises the team
The sprint is planned
The 6 steps that I’ve outlined above is the manually process that managers at a fictitious organisation walk through to assign tasks to employees. This is the Domain because it is solely focused on the world of the business.

The Model is focused on this one aspect of project management within the scope of the bigger organisation. In large organisations there are probably numerous ways that work is chosen and allocated to teams of employees. However in order to stay on track, we only care about this one, structured problem.

The Domain Model should take the Domain and the Model to form a a conceptual solution to the problem.

For example, we can see that we will probably need entities for Roadmap, Project Managers, Employees, Team and Sprint.

We will need a way of selecting projects from some kind of persistence storage.

We will need a way of capturing the business logic of Criteria to make decisions of priority based upon what is important to the business.

And finally we will need a way of planning a sprint and allocating times and resources to ensure that the work is completed.

I’m sure if this was a real world problem we would need to explore the concept of assigning projects in much greater detail, but hopefully you see what I’m getting at.

Conclusion
The Domain Model is the important starting point when taking on a Domain Driven Design project. Domain Driven Design is all about solving the problems of an organisation, and so the Domain Model is all about understanding and interpreting the important aspects of a given problem.

The Domain Model represents the Ubiquitous Language of the project, the important concepts and the relationships between those concepts.

The Domain Model should also be used as a way to validate as to whether everyone on the team understands the problem. A Domain Model will focus attention on a specific problem and it will define the vocabulary and the context of the important things that need to be considered.

Arriving at a solid Domain Model for a given problem is an iterative approach of collaboration between the business experts and the technical team. It should act as a source of truth for the project and it is a living document as the project progresses.

Strategies for Integrating Bounded Contexts

Strategies for Integrating Bounded Contexts
Over the last couple of weeks we have looked at a couple of important topics in the world of Domain Driven Design.
First we looked at what are Domain Models and why are they so important to Domain Driven Design. A Domain Model is the focused knowledge around a specific problem to the business.
Next we looked at Bounded Contexts and how they fit into the Context Map of an entire organisation. A Bounded Context is the boundary around a specific Domain Model, whereas a Context Map is the global view of how each individual Bounded Context fits into the bigger picture.
The vast majority of all Domain Driven Design applications will have multiple Bounded Contexts. This could mean integration with third-party services, but it is also often the case that you need to integrate with existing legacy applications or simply other models of the same application.
There are many technical ways to integrate Bounded Contexts, third-party services and legacy applications.
However, choosing the correct integration pattern is extremely important because it will have a big impact on the design of your application and the future of your project as a whole.
In today’s article we’re going to at the strategies for integrating Bounded Contexts in a Domain Driven Design application, the pros and cons of each and how to come to a decision of which to choose for your project.

Recap of Domain Models and Bounded Contexts

Before I jump into talking about the integration strategies, first we’ll do a quick recap of Domain Models and Bounded Contexts.
A Domain Model is the focused knowledge around a particular problem. This includes the Entities, Value Objects and relationships between the things of importance that are specific to that particular problem.
A Bounded Context is the boundary around a Domain Model. The language, names of objects and ideas within the Bounded Context should form a unified model of the problem at hand. The Bounded Context shields the internal model from the complexity of the outside world. Each Bounded Context should have an internal model that is clearly understood by all members of the team. This is important because in most organisations, certain terms will have different meanings across departments or areas of the business.
And Finally the Context Map is the global view of how each Bounded Context fits together within the application or organisation. This bigger picture view of the problem ensures that the goal of the application is not lost in the focused details of each Bounded Context. It’s better to have a true internal model for each Bounded Context with a layer of translation, rather than having monolithic objects that try to fill the role of different, often conflicting jobs.

The reality of software projects

In an ideal world, every software project would start with a blank slate, a clean git repository and no legacy headaches.
However, in the real world, these types of projects are very rare.
The vast majority of all non-trivial application development projects will require multiple Bounded Contexts.
When working with an existing organisation, it is usually the case that you will be required to integrate with legacy applications or third-party services.
It is therefore your job to integrate these legacy applications and third-party systems with the new project you are working on.
The problem with these types of integrations is, there are an unlimited number of situations you can find yourself in. For example, you could find yourself at the mercy of a third-party service, or perhaps you are responsible for providing an interface to an existing legacy system.
There are a number of different integration strategies that I will discuss in this article. Each strategy has it positives and negatives.
Choosing the correct integration strategy for your particular situation is extremely important because it’s going to have a major impact on the design of your application and it’s future development path.

A simple example of translation

Before we jump into discussing the integration strategies, first I will explain a simple example so we’re all on the same page as to why this is important.
Imagine that we’ve been brought into an existing offline retailer as Consultants to create a new online Ecommerce website for the company.
The company has been trading on the high street for a number of years now and so it already has existing stock management, distribution and financial systems.
Our assignment is to create an Ecommerce website that can interface with the company’s existing systems to provide a seamless new channel for sales.
Our new development project is clearly a new Bounded Context within the scope of the Context Map of the Organisation as a whole. We aren’t going to be extending any of the current systems, but we must consume and return data from each of the existing systems in order to make the new channel seamlessly integrate into the current architecture.
We will need to be able to request data from the stock management system in order to know what should be made available to purchase online.
We will also need to send data to the distribution and financial systems so orders are processed correctly and the company’s accountancy liabilities are dealt with.
If this was a real life situation, we would probably have to interface with a whole load of other existing systems and third-party services. However, hopefully you can see the requirement for being able to integrate with existing systems through a layer of translation.
Whilst in a theoretical idea world, it would be wonderful if Ecommerce sales, stock management, distribution and finances were all part of a single unified model. However, the complexity of such a system would quickly get out of control.
Instead we need to find ways of integrating through a layer of translation. The following are 7 ways of doing just that.

Shared Kernel

The first integration strategy is to use a Shared Kernel, where a part of the Domain Model is shared between different teams working on the same application.
The Shared Kernel integration strategy is beneficial because it reduces the amount of duplicated code and the overhead of translation layers.
However a Shared Kernel will only work if all of the development teams work to share and communicate the requirements of the shared code. This means that the design of the Shared Kernel can’t evolve as quickly as other aspects of the application, and any changes must be agreed upon by members of each development team.
Each development team will also have to take equal responsibility for maintaining unit tests that ensure the functionality of the Shared Kernel remains consistent.
When there is a shared requirement of a certain aspect of the application, and relatively high levels of communication and low levels of political unrest, the Shared Kernel integration strategy can be easier to implement than many of the other integration strategies we will look at in this article.
An example of using a Shared Kernel in our Ecommerce analogy might be that the Customer Model is shared between the Transaction team and the Online Marketing team.
The Transaction team requires the Customer Model to associate transactions and request payments, whereas the online marketing team requires the Customer Model to send marketing information to stimulate new purchases and keep the customer informed of new products and offers.
Instead of both teams writing their own Customer Model and translating back and forth, they could have a shared Customer Model that they both rely on to satisfy their requirements. This means that the teams need to agree on the specification of the Customer Model, and any future changes must be signed off by both teams.

Customer / Supplier

A common relationship between two software applications is where a downstream application requires data from an upstream application, but the upstream application is not dependent on the downstream application.
This relationship can play out in a number of different ways.
Firstly the downstream team can be at the mercy of the upstream team if the upstream team make changes without thinking about the requirements of the downstream team.
Alternatively the upstream team can feel restricted on the design and implementation of their application if the downstream team has control over how their application evolves.
The downstream team is dependent on the upstream team, but the upstream team is not responsible for the deliverables of the downstream team. In order to make this situation work, the two teams need to have a formal relationship where the requirements of the downstream team are considered, as would occur in any Customer / Supplier relationship.
This means future development priorities, tasks and requests need to be agreed upon by members of both teams.
Both teams should also agree upon a series of Acceptance tests that will ensure the interface of the boundary remains consistent. This means the upstream team can evolve their application as long as the interface remains consistent, and the downstream team can be assured that they won’t wake up one day to find their application broken because of the upstream team’s changes.
The Customer / Supplier relationship works best when both teams’ goals are aligned or they both report to the same layer of management. When the goals of the two teams are not aligned, the relationship will often break down.
An example of the Customer / Supplier relationship from our Ecommerce analogy could be where a separate Analysis application must take data from the Ecommerce application in order to generate customer recommendations and predict new trends.
The Analysis application is in a different Bounded Context because it is likely to be written in a different programming language and use very different tools and persistent storage than that of the Ecommerce application.
The Analysis application is relying on the Ecommerce application to send data of the transactions, customer profiles and tracking events in order to run the analysis.
The two teams should agree upon on the type, format and method of the data and how it should be transferred downstream. If both teams are aligned in increasing the success and profitability of the company as a whole, this relationship is more likely to work.

Conformist

When the relationship between the Customer and the Supplier is not mutually aligned, the downstream team can end up in a situation where it is at the mercy of the upstream team.
This can occur in the same company where each team reports to a very different layer of management with different goals, or where the Supplier has many small Customers and so each individual Customer is not particularly important to the Supplier.
This means that the upstream team has no motivation to provide any kind of priority or even consistency to the downstream team. The downstream team just has to accept the fact that they cannot rely on the upstream team and a consistent interface at the boundary of the relationship.
If the value of the upstream application is critically important to the downstream application, the only way to continue is to adhere to the whims of the upstream team.
This will mean that the upstream team will be completely in control of the integration of the two applications and so the downstream will have to just make it work.
This will cause the downstream team to have a deep dependency on the upstream team and so any future development will be constrained by the situation.
An example of the Conformist relationship in our Ecommerce analogy could be where we rely on a third-party delivery service to send packages to our customers. In order to update our customers on the location of their progress we need to request updates from the third-party delivery service.
However, we are only one of thousands of customers of the delivery service, and so they have no motivation to provide the data we require. The delivery service is also free to change their API at any point, potentially breaking our integration.
In this situation we are completely at the mercy of the delivery service and so we have to take responsibility for accepting their data and the interface they provide for requesting it. If the interface changes, it is our responsible to conform to those changes and evolve our integration to meet those requirements.

Anti-Corruption Layer

When working with existing legacy applications or third-party services, the integration requirements can often be complex. Whilst it might initially seem easier to avoid the integration all together, if the other system is critically important, there is probably more value in the integration.
Integrating other systems is difficult because the other model can leak through the integration and begin to affect the new system’s own model. By adapting to the existing systems too much, we can end up with a new system that has an inconsistent or unsuitable model to solve it’s own problem.
In order to prevent the model from an external system leaking internally to a new system, we need a way to translate the data between the two models. This will often mean ensuring the context of how the data is interpreted is consistent in the new model, but also preventing unnecessary data from leaking through the integration.
To achieve this we need to create an isolating layer that can communicate with the existing interfaces of the legacy and third-party systems, and then translate that back forth between our internal model as requests come and go.
An example of using an Anti-Corruption Layer in our Ecommerce analogy could be linking an existing customer loyalty scheme from the offline retail system with a customer loyalty scheme for our new online retail system.
If an existing offline customer has an existing loyalty balance with the retailer and she starts to shop online, those two systems should know about each other so the customer does not lose out on benefits or discounts.
However the two systems are likely going to have different models and different supporting data that is not relevant between the two systems.
In order to keep the two systems consistent we can set up Web Hooks (What are Webhooks?) that will send a request whenever the customer loyalty balance is updated on one side of the relationship.
When a request is sent or received, it will travel through the Anti-Corruption Layer to be translated into the appropriate form for the receiving application. This means data can flow between the two systems without having to change the existing offline system and without having to conform the new system to the model of the existing system.

Open Host

When your application will need to integrate with another system, you will typically provide a layer of translation to make this integration easier.
However when your application needs to integrate with many other existing systems, having all of these layers of translation can start to become unwieldily.
Instead of providing one off translation layers for each integration, instead provide a set of Services that can be consumed by any other Bounded Context.
By providing your application as a series of Services you reduce the overhead required to maintain multiple layers of translation.
These Services are likely to evolve as new functionality is created internally, or requested from external consumers. However for one off integration requirements, a single layer of translation will be better than compromising the generic Service interface.
An example of using the Open Host strategy in our Ecommerce application could be providing data about the customers and transaction as a series of Services.
Many of the existing applications inside the company will likely need to request data from our application in order to fulfil orders or restock products, and so instead of providing layers of translation for each system, we can provide a set of Services to reduce this overhead.

Published Language

Integrating the model from an external system into a new system is difficult because you don’t want your new system to be influenced by the design of the external system.
The external system’s model is likely going to be incompatible with your internal model and so accepting their model as a data exchange language can mean your model is dependent and influenced by the external system.
Instead of relying on the model as a data exchange language, we should use common published languages such as JSON or XML that allow data to be translated between different systems using a common format.
An example of using a Published Language in our Ecommerce analogy could be updating an Messaging application whenever a new transaction occurs. The Messaging application will send emails to the customer to notify them of product updates, discounts and related products.
We can ensure that the data is compatible with the Messaging application by sending details of the request as JSON or XML. By sending the data as a common format we aren’t forcing the Messaging system to conform to our internal model or make compromises in how they design their internal application.

Separate Ways

In many situations, integration can be more costly than it is worth. This could be due a Conformist situation, or perhaps the other team is just too difficult to work with.
If the functionality or data between the two system is not inherently linked, just because it is related, does not mean that it should be integrated.
Instead of trying to force an integration, allowing two systems to go their Separate Ways is another attractive option.
An example of Separate Ways in our Ecommerce analogy could be that of reporting financial statistic to the retailer’s existing finance department. The finance department uses an archaic system that would take a long time to integrate with our new ecommerce application.
The Financial liabilities of the company need to be reported weekly, monthly, quarterly and yearly. Investing time to build integration between the two systems for real-time reporting is superfluous to our needs.
Instead we can simply ensure that financial reports can be exported in the required format. This means the two systems don’t need to be integrated at all and so we lose the overhead of trying to make the integration work.

Conclusion

It’s almost inevitable that you will need to integrate with existing applications, third-party services or multiple Bounded Context in any non-trivial application.
Many different types of companies around the world can reap huge productivity benefits from integrating new and existing systems within their organisation.
Understanding the common patterns around integration will be a huge asset when you are tasked to integrate two very different systems.
Integration is also something important to keep in mind when developing a totally new application. By providing your application as a series of services, you will make any future integration requirements with your application a whole lot easier!
The power of software is really magnified when distributed systems can be integrated and leveraged as a whole. Understanding how to integrate applications under different circumstances is very valuable knowledge to possess.