You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

The clean architecture principle can be followed quite nicely in the model. Below is a simple example of the clean architecture in studio.

Example

In this small example a person is able to rent a house. In the domain layer we define the entities and attributes for Person and for House. There exists a 1:n relation between them, as a person might rent multiple houses. A person has a salary, and based on that his or her maximum rent is calculated.

Everything defined so far does not say anything about how we get this information, or how it is presented to the end user or persisted in a database. This domain and business rule is part of the Domain Layer.

 

 

 

 

 

 

 

 

We now create the use case that a person looks at available houses, chooses one and starts renting it. The flow starts with a page that shows all houses that a person can rent, based on his or her maximum rent (which is determined by the salary). After a choice has been made, the flow continues to store the information in the database, and shows a thank you page. This flow describes a use case, and is part of the Application Layer.

You might wonder why the sub-flow for the database is referenced here in the application layer. Storing something in the database should be part of the Interface Layer. While we indicate here when information should be stored, we do not indicate any specifics of where to store the information or how to save it exactly. We just indicate the moment when information should be saved. For the first version, the sub-flow might be completely empty (a mock-flow).

 

 

 

 

 

 

 

The service that stores the updated rental information in the database is part of the interface layer. The database could actually be behind a web service, when the service is of type AQ_WebServiceClient.

As this service is placed in a sub-flow, we can simply change out this manner of persisting with a complete different one. This would not affect the application or domain layer. If the service would have been placed directly in the flow for renting a house (see Application Layer), then all use cases in which data is stored need updating when the persistence manner changes.

You might place the StoreInDatabase flow in a library, together with all other persistence flows. If you have a second library with the same flows for a different type of persistence, you could simple swap out the library for one-another and do not have to make any changes to the rest of application in order to store the information somewhere else. This is in essence similar to dependency injection, but requires you to adhere to a strict naming of the re-usable flows, and any element in the library for it to work, and is not often done in practice.

 

 

 

 

Frequent Scenarios

There are certain scenarios that you will frequently encounter on a project. We want to highlight 4 of those scenarios in the context of the clean architecture. They are shown on the schematic to the right.

Application to Domain (1)

You will always have this transition when creating an application with some sort of flow in it that displays pages to the end user. As in the example above, the flow determines how a use case of the application works, and uses the domain layer. If you have a Blueriq as a Service (BaaS), then this might skip the applications layer.

Persistence of data (2)

Data needs to be read from or written to a database. This usually happens at the start or the end of the flow, respectively. The service in the interface layer reads and writes to the database. The translation to the internal format is done by the applications layer, and in studio can be seen in the data-mapping. The mapping translates information from the domain layer into a format that is suitable for the database and stores it; and vice versa.

Calling a web service (3)

There often is a need to communicate with an external system or party. This communication is frequently handled with REST or SOAP services. As there is a contract for a web service, you need to adhere to it. the information located in the domain layer needs to be translated into a format that fits this contract.

Showing data to customer facing applications (4)

The flow in the application layer describes the use case, but the user interface is responsible for showing the information to the end user. So, actions from the end user (pushing a button) trigger behavior in the use case. The use case is unaware of what kind of user interface is used (MVC, XSLT, command line...)

 

 

The need for decoupling

The clean architecture works well for any programming language. Once the domain layer is defined, the application layer can build on that. The internals of the domain layer are placed in methods, and the methods can be used in the application layer. A method in above example could be registerNewRenter(Person person) of the House class. What exactly is happening inside that method is hidden from the application layer. Only when the footprint of the method changes does this have impact on all classes in the application layer that use the method. Luckily do footprints of methods change much less frequently than the internals of the method.

In Blueriq is everything included in an interaction module. This means that your flow has access to each and every element in the domain of the domain layer. This is in principle correct, and adheres to the dependency rule of the clean architecture. What this however implies, is that changing any element of the domain layer may have an impact on the application or interface layer. This was not your intention however, as you also expose internals to the higher layer. In any object oriented programming language, you expose a method or interface to another class, but not the inner working of the method. In Blueriq there are no methods, meaning that all internals are exposed, and can be seen as method or interface. Even though this adheres to the dependency rule, this is much more than intended or needed. As a result, before changing any small thing an impact analysis needs to be performed. This can be achieved by using the dependencies in studio. Having to do this for every element is however a tedious job, and mistakes are bound to happen. This leads to:

  • Additional work to check for the impact of every change
  • People being scared to make changes
  • A preference for creating new attributes above reusing/refactoring old ones, cluttering the domain
  • An overflow of elements in studio, which reduces the working speed and increased the mental load

It would be great however if you can know for sure what elements can be changed without any impact on the higher layers, and which ones should be changed with care after an impact analysis. What we essentially want to achieve is that only a small set of elements has this dependency (you can also say that it is coupled), and you can quickly and easily change all other elements. This small set of elements can be regarded as the method footprint if you think of it as code. This leads to

  • Quicker development
  • Better test-ability
  • Confident business engineers

Thinking of the original layered structure, you might add an additional layer to visualize this idea in Blueriq, which might not be needed in programming languages. On the right side, we call this new layer Commons. In this layer you place anything that should be shared between the interfaces and applications layer and the domain layer. This could include

  • Attributes that are used as function parameters
  • Web service contracts
  • AQ_StartProject input
  • ...

Although the dependency rule allows dependencies between interface/applications and domain, we now only allow dependencies between interfaces/applications and commons. This way, it is possible to change the internals of the domain layer without having impact on the outer layers.

You might also just regard the Commons layer as part of the Domain layer, as method names in code are also part of the domain layer.

When a layer boundary is crossed, then this is a good opportunity for decoupling. There actually might also be a need for decoupling when staying in the same layer. For example, lets say a calculation for the maximum lease amount of a car is dependent on the risk score of a customer. Both of these numbers are part of the domain layer. You may however want to decouple each calculation so that all internals of a single calculation may be refactored and maintained easily, and are not 'in the way' when working at other parts of the application. So, to summarize, the application of decoupling can be split up into two categories:

  1. Decoupling to prevent layers blend into each other.
  2. Decoupling to expose functions within the same layer.

The next section of this guide describes concrete patterns of how this can be achieved: 4. Decoupling

  • No labels