ERNI Technology Post No. 42 - Keep your domain driven design in order with structure 101

Innovation is the heart of a company, the reason for its growth and the main factor for maintaining the lead over its competitors. For companies depending on complex software systems, a design approach that harmoniously reflects current innovation and facilitates the integration of further new features is essential. That is why Domain Driven Design has evolved over many years and plays an important part in complex software systems. The reason is simple: Domain Driven Design puts the focus on the company’s domain knowledge and separates it from other software modules like graphical user interface, databases and other infrastructural modules, which allows ongoing innovation to be efficiently embedded into the software system.

On the other hand software systems get increasingly complex and keeping the software architecture in order becomes a challenge. That is why tools like Structure101 gain more and more importance primarily for analyzing existing code structure but also for designing new software architecture.

To ensure a quick understanding of Domain Driven Design, the first part of this article gives an insight into its key elements. The second part outlines the capabilities of the Structure101 software, and in the last part a practical example demonstrates what distinguishes Structure101 in large and complex software projects.

Domain Driven Design is not a novelty, is it?

Domain Driven Design has evolved over two decades but has been increasingly crystallized during the last few years, particularly by Eric Evans in his book [3]. The essential idea behind Domain Driven Design is to focus on the domain in which a software system is operating. This might be the audiological domain with a hearing instrument manufacturer or the flight booking domain of an airline, etc. The best way to accomplish this is to make software a reflection of the domain. As a very first step the domain has to be expressed as a model. Therefore the software specialists (architects and developers) and the domain experts need to work together to create a domain model. In doing so, it is important that these two parties use a common language (in this context called “ubiquitous language”) which reflects the domain aspects and becomes a link for overcoming the differences in communication style between software specialists and domain experts.

For the domain model the following basic patterns are proposed [3]:

  • Entities have a unique identity within the domain and a clearly defined life cycle. These are the core objects of the domain.
  • Value objects do not have an identity of their own; they express the state of other objects.
  • Services represent procedures and processes of the domain which are not covered by entities. They handle operations which do not contain any state.

The domain model is the basis for the following design which uses the classical layering that provides loose coupling to the layers above and has only references to the layers below, as shown in Figure 1. The top layer is the presentation layer, which represents the information display and receives user entries and commands. Below this is the application layer, which describes and coordinates business processes and delegates to the domain layer as well as the infrastructure layer. The next layer is the domain layer, the core of Domain Driven Design where the domain model exists. The domain layer delegates the persistency of its entities to the infrastructure layer. The bottom layer is called the infrastructure layer; it contains common technical services such as data persistency or communication with other systems.

Figure 1: Domain Driven Design layering and domain encapsulation

Other key elements of Domain Driven Design are the three managing objects which systematically handle the domain objects (entities and value objects) [3]:

  • Aggregatesencapsulate the domain objects, which are connected with each other. An aggregate contains only one entity object as a root object, which is the only entry point for the aggregate. Various domain objects that are connected with the root object are local and it is not allowed to have references from outside to these objects nor to have references from inside the aggregate to the outside, as indicated with the red arrow in Figure 1.
  • FactoriesAggregates as well as entities can contain complex structures of networked objects which cannot be composed simply. Therefore the use of factories is highly recommended in order to encapsulate the creation of aggregates and entities. Factories only exist within the domain and do not have access to the infrastructure layer.
  • RepositoriesThe purpose of using repositories is to encapsulate all the logic needed to obtain object references. The domain objects will not have to deal with the infrastructure to get the required references to other objects of the domain; they will just get them from the repository. Accordingly, the model is regaining its clarity and focus.

There is a relationship between factory and repository. They are both patterns of model-driven design and help manage the life cycle of the domain objects. While the factory is concerned with the creation of objects, the repository takes care of already existing objects by either caching objects locally or retrieving them from persistent storage.

Now you should have a basic understanding of Domain Driven Design especially as you might already be familiar with certain key elements. You may have noticed that Domain Driven Design follows numerous design rules which are a challenge to handle particularly in the case of complex software systems. Let us find out how Structure101 can counteract that.

Why do I need a tool like Structure101? I know all about the structure of our software system …

This might be true of smaller software projects but with growing complexity of software systems, it becomes increasingly challenging to keep an overview of the software structure and its architecture. In the worst case, the real code structure drifts away from what the software architect intends it to be. At this point, a tool like Structure101 provides relief for various languages (.NET, Java, C/C++, scripting, etc.) as it exactly reflects the code of your software. It helps you understand the actual structure of your code as opposed to what you think it is.

Figure 2: Structure101 architecture diagram showing dependencies of a selected module

One of the most valuable properties of Structure101 is the fact that it expresses your code in a layered manner, which means you can have a look from the top and go down into the fine details of class granularity.

Another valuable property of Structure101 is that doing so is a simple procedure. You can create an architecture diagram, as shown in Figure 2, directly from your code and obtain an overview of your current code reflection [2]. You can immediately identify dependencies that do not comply with the design rules you have agreed upon. In Figure 2, a violation is indicated with the blue arrow from the domain layer to the presentation layer. One of the basic principles in Structure101 is that components (“cells”) should only depend on components on lower levels and not on components on the same or higher levels. But sometimes a top-down dependency structure is too simple to capture the intent of an architecture. In this case using “Overrides” enables you to override the default layering of a diagram so that you can allow a specific dependency between a cell and a neighboring cell on the same level. The opposite is also possible by enforcing a stricter layering, for instance if it is intended for one layer only to use the next layer down but not any layers below that.

Architecture diagrams are a suitable communication means: they can be used to point out existing architecture violations to team members but also to communicate a target architecture. Keeping the Structure101 model of your software architecture in a central, easily accessible location ensures that the team can work on the basis of the current architecture, which helps prevent further violations of your code.

As opposed to an architecture diagram, Structure101 offers, among others, a structural diagram with a composite perspective as shown in Figure 3, where tangles can be efficiently identified as indicated with the red box.

An architecture diagram as shown in Figure 2 can be interactively edited towards the desired architecture. It allows the definition of numerous rules for keeping the software in order and in the desired shape. This improves the code base structure and architecture and speeds up development.

After this basic introduction to the Structure101 software, a practical example will give you a good impression of the Structure101 capabilities.

What if assembly-based architecture verification cannot handle your architectural structure?

There are tools (.NET reflector, ArchiCop) that analyze the dependencies on the assembly level, which means on the level of built code. That works fine for numerous applications but could cause problems with more complex software systems where the dependencies on the assembly level do not reflect all dependencies in the software system. In that case, it is advisable to use architecture verification software (Structure101, NDepend, TFS Ultimate Layer diagrams) working with code reflection. The following example should shed more light on this.

Figure 3: Composite view showing a tangle

In larger and more complex software systems it makes sense to build up the software using modules, as shown in Figure 4. Let us assume that a large company manufactures an electronic product delivered with user software and that it has a production line as well as a huge R&D department. For all three of these stakeholders, a dedicated software is required: for operating the product (user software), for calibrating and testing the product during the production process, and for verifying and validating the product quality at the end of the development process.

In this case it would not be wise to build up separate software for each of these stakeholders as the customer software most likely contains a lot of business logic and a domain model that can be reused by the production and R&D software. It would be more reasonable to build up a modular software platform as shown in Figure 4, where the user software represents the core and the production as well as R&D software modules are dependent on it and contain extended functionalities. Such an architecture enables customized deployments according to the functionalities required.

Figure 4: Modular software system with variable deployments

In order to avoid additional complexity, it makes sense to group similar functionality modules into subsystems, which results in separate subsystem assemblies of the user platform, production platform and R&D platform with identical namespaces. Here, architecture rules need to assure that there are only dependencies from an outer platform to its neighboring inner platform but not in the opposite direction as indicated by the striped arrows in Figure 4. In that case the assembly-based dependency verification is not sufficient. At this point Structure101 is a suitable tool for setting up and verifying the rules.

Conclusion

We have seen that Domain Driven Design is still an up-to-date design approach that has established itself over several years with regard to complex software systems. Nonetheless it is a challenge to maintain the software architecture with the numerous architecture rules of Domain Driven Design in a dynamic development environment.

From my point of view, Structure101 is a perfect tool for reducing complexity and keeping the target software architecture in order. Its easy usage and intuitive, user-friendly handling allow the source code to be efficiently reflected and optimized towards the desired architecture. Integrating the established architecture rules into the continuous integration verification process helps maintain the architecture enormously and makes life much easier for a software architect working in a team with dozens of software developers. Besides, it is a great communication tool for referring to architecture violations as well as communicating the target architecture to the team members. That is why I can highly recommend it.

References

[1] Domain Driven Design Quickly: http://www.infoq.com/minibooks/domain-driven-design-quickly

[2] Structure101: http://structure101.com/

[3] Domain Driven Design: Tackling Complexity in the Heart of Software, Eric J. Evans

posted on 19.03.2013
Categories: 
by: Stefan Odermatt