arch:adm

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
arch:adm [2021/10/18 10:35] – [V. Anemic Domain represents developers’ view of OOP] khdzhambongtenkearch:adm [2026/08/29 07:59] (current) – external edit 127.0.0.1
Line 16: Line 16:
  
 Why despite its high propagation, some high figures in software engineering like Martin Fowler [2] still consider ADM as being anti-pattern? Well, there are multiple reasons: Why despite its high propagation, some high figures in software engineering like Martin Fowler [2] still consider ADM as being anti-pattern? Well, there are multiple reasons:
-      * ADM violates the **encapsulation** and **abstraction** principles of OOP, since the models contain only data and not logic associated with operating those data (except for some getters and setters). + 
-      * In the context of model/database mapping, ADM is prone to difficulties, especially when the model will evolve and become more complex. +  * ADM violates the **encapsulation** and **abstraction** principles of OOP, since the models contain only data and not logic associated with operating those data (except for some getters and setters). 
-      * ADM transforms domain models into mere domain data carriers. +  * In the context of model/database mapping, ADM is prone to difficulties, especially when the model will evolve and become more complex. 
-      * ADM is a failed attempt to use object-oriented programming, that ended on procedural programming.+  * ADM transforms domain models into mere domain data carriers. 
 +  * ADM is a failed attempt to use object-oriented programming, that ended on **procedural programming**. 
 All those reasons seem good enough for developers to avoid this anti-pattern, right? Well, not exactly. In the next few sections, we will consider the good aspects of ADM and why software engineers still use it. All those reasons seem good enough for developers to avoid this anti-pattern, right? Well, not exactly. In the next few sections, we will consider the good aspects of ADM and why software engineers still use it.
  
Line 38: Line 40:
 In ADM, we observe **highly cohesive, loosely coupled** components which communicate via abstract interfaces. Those components are composed via dependency injection allowing for trivial mocking of dependencies. Therefore, scenario construction is made easier during automated test. In RDM, this process is more complicated to construct since tight coupling proliferates, making ADMs’ automated tests more maintainable. For illustration, let’s consider the following Reach Domain Model: In ADM, we observe **highly cohesive, loosely coupled** components which communicate via abstract interfaces. Those components are composed via dependency injection allowing for trivial mocking of dependencies. Therefore, scenario construction is made easier during automated test. In RDM, this process is more complicated to construct since tight coupling proliferates, making ADMs’ automated tests more maintainable. For illustration, let’s consider the following Reach Domain Model:
  
-{{ :arch:reach_domaon_model.jpg?600 |}}+[[arch:_detail:arch:reach_domaon_model.jpg|]]
  
-Suppose we ought to write unit tests on the //IsItemPurchasable(Item item)// method. The domain rules requires that the customer has enough funds and is in an allowed shipping region for that specific item for an item to be purchasable. Let’s consider a test checking the scenario when a customer has sufficient funds but is not in an allowed shipping region for that specific item (meaning the item is not purchasable). In accordance with the RDM this test shall be written as follow: +Suppose we ought to write unit tests on the //IsItemPurchasable(Item item)// method. The domain rules requires that the customer has enough funds and is in an allowed shipping region of that specific product for an item to be purchasable. Let’s consider a test checking the scenario when a customer has sufficient funds but is not in an allowed shipping region of that specific product (meaning the item is not purchasable). In accordance with the RDM this test shall be written as follow:
-      * construct a //Customer// and an //Item//, +
-      * configure that customer to have enough funds, +
-      * configure the customer region to be outside the allowed shipping regions for that item, +
-      * at the end, we need to assert that //customer.IsItemPurchasable(item)// returned value is false.+
  
-However, the //IsItemPurchasable// method is directly dependent on the implementation of the //ShipsToRegion// method of the Item domain model. Any change in the domain logic in Item will change the result of the test. This is not the desired behavior, as the test should only be testing the customer’s //IsItemPurchasable// method logic. This bad behavior is the result of tight coupling and result on difficult code testability, which is familiar while using RDM. This simple example used few methods and already we see difficulties being draws. Imagine this same RDM with dozens of tightly coupled domain models. Testing in this case becomes a nightmare.+  * construct a //Customer// and an //Item//, 
 +  * configure that customer to have enough funds, 
 +  * configure the customer region to be outside the allowed shipping regions for that item, 
 +  * at the end, we need to assert that //customer.IsItemPurchasable(item)// returned value is false. 
 + 
 +However, the //IsItemPurchasable// method is directly dependent on the implementation of the //ShipsToRegion// method of the //Item// domain model. Any change in the domain logic in Item will change the result of the test. This is not the desired behavior, as the test should only be testing the customer’s //IsItemPurchasable// method logic. This bad behavior is the result of tight coupling and result on difficult code testability, which is familiar while using RDM. This simple example used few methods and already we see difficulties being drawn. Imagine this same RDM with dozens of tightly coupled domain models. Testing in this case becomes a nightmare.
  
 On the other hand, ADM requires us to: On the other hand, ADM requires us to:
-      * express the //IsItemPurchasable// logic within a separate service, which loosely depend on an abstract interface (the //ShipsToRegion// method of //IItemShippingRegionService//), + 
-      * provide a stubbed, mock implementation of //IItemShippingRegionService// for this test, which will always return false in the //ShipsToRegion// method.+  * express the //IsItemPurchasable// logic within a separate service, which loosely depend on an abstract interface (the //ShipsToRegion// method of //IItemShippingRegionService//), 
 +  * provide a stubbed, mock implementation of //IItemShippingRegionService// for this test, which will always return false in the //ShipsToRegion// method.
  
 ===== V. Anemic Domain represents developers’ view of OOP ===== ===== V. Anemic Domain represents developers’ view of OOP =====
Line 56: Line 60:
 Within the software engineering community, there is a long discussion going on about what logic can be implemented within a domain model to interact with itself. The problem is that if implementing RDM, we quickly enter a situation where we must write a logic like this: //Order.Save(order)//. However, if you think a bit about this command, it does not make sense. Should the //Order// model know how to save itself? Let's say we introduce a repository for that purpose. Can Order add order lines within the repository? it seems not to make sense, and it is because it does not. A //User// adds //Product// to //Order//, can we do //User.AddOrderLineToOrder()//? That starts to look strange! What if we wrote //OrderService.AddOrderLine()//? Now it makes sense! What we draw from this little experiment is that in OOP, encapsulation consists in putting business logic on models where the logic will need to access the model's internal state. If we need to access //Order.OrderLines// collection, we put //Order.AddOrderLine()// on Order. This way class's internal state doesn't get exposed. Within the software engineering community, there is a long discussion going on about what logic can be implemented within a domain model to interact with itself. The problem is that if implementing RDM, we quickly enter a situation where we must write a logic like this: //Order.Save(order)//. However, if you think a bit about this command, it does not make sense. Should the //Order// model know how to save itself? Let's say we introduce a repository for that purpose. Can Order add order lines within the repository? it seems not to make sense, and it is because it does not. A //User// adds //Product// to //Order//, can we do //User.AddOrderLineToOrder()//? That starts to look strange! What if we wrote //OrderService.AddOrderLine()//? Now it makes sense! What we draw from this little experiment is that in OOP, encapsulation consists in putting business logic on models where the logic will need to access the model's internal state. If we need to access //Order.OrderLines// collection, we put //Order.AddOrderLine()// on Order. This way class's internal state doesn't get exposed.
  
-    This is exactly how most software engineers understand OOP. If it is needed to perform some operations on a set of objects or persist those objects, it seems more logical to have a separate service performing those operations, rather than having the objects performing those operations on themselves.+This is exactly how most software engineers understand OOP. If it is needed to perform some operations on a set of objects or persist those objects, it seems more logical to have a separate service performing those operations, rather than having the objects performing those operations on themselves.
  
 ===== VI. Procedural programming is easier to catch ===== ===== VI. Procedural programming is easier to catch =====
  
-    One of the arguments mentioned by the detractors of ADM is that “ADM is a failed attempt to use object-oriented programming, that ended on procedural programming”. Well, that is not false. However, what those detractors usually fail to grasp is the complexity of pure OOP, implemented in a RDM approach. New software engineers tend to learn coding by copying codes provided to them on internet resources. On those resources, nearly all examples are presented in a procedural manner. Models are constructed separately, and they store most of the time only data. The logic is presented in a separate service layer. If RDM is so good, why do most examples on the internet (and sometimes books) are written in a procedural manner? The answer is simple - for readability and understandability. RDM by itself is complex to grasp, especially if you are a new developer.+One of the arguments mentioned by the detractors of ADM is that //“ADM is a failed attempt to use object-oriented programming, that ended on procedural programming”//. Well, that is not false. However, what those detractors usually fail to grasp is the complexity of pure OOP, implemented in a RDM approach. New software engineers tend to learn coding by copying codes provided to them on internet resources. On those resources, nearly all examples are presented in a procedural manner. Models are constructed separately, and they store most of the time only data. The logic is presented in a separate service layer. If RDM is so good, why do most examples on the internet (and sometimes books) are written in a procedural manner? The answer is simple - for readability and understandability. RDM by itself is complex to grasp, especially if you are a new developer.
  
 ===== Conclusion ===== ===== Conclusion =====
-    In this essay, we took a quick look into the notion of design patterns, then we made a critical analysis of the so called Anemic Domain Model (ADM). We assessed why it is being labelled as an “anti-pattern” by some. After that, we considered the good aspects of ADM and why people still use it. Despite its multiple cons, I personally consider ADM to be a great approach in software design. It helps build applications with domain models that follow the SOLID principles. Three scenarios when ADM is preferable: 
-      * When working in presence of a ORM library to operate data with the persistence layer. 
-      * When the system’s business logic implies strong coupling between models. 
-      * When testability is important, but we want to spend minimal time modifying / refactoring tests in each new model modification. 
  
 +In this essay, we took a quick look into the notion of design patterns, then we made a critical analysis of the so called Anemic Domain Model (ADM). We assessed why it is being labelled as an “anti-pattern” by some. After that, we considered the good aspects of ADM and why people still use it. Despite its multiple cons, I personally consider ADM to be a great approach in software design. It helps build applications with domain models that follow the SOLID principles. Three scenarios when ADM is preferable:
  
-===== References =====+  * When working in presence of a ORM library to operate data with the persistence layer. 
 +  * When the system’s business logic implies strong coupling between models. 
 +  * When testability is important, but we want to spend minimal time modifying / refactoring tests in each new model modification.
  
-  - https://martinfowler.com/bliki/DomainDrivenDesign.html +===== References =====
-  - https://martinfowler.com/bliki/AnemicDomainModel.html +
-  - https://blog.codecentric.de/en/2019/10/ddd-vs-anemic-domain-models/ +
-  - https://blog.inf.ed.ac.uk/sapm/2014/02/04/the-anaemic-domain-model-is-no-anti-pattern-its-a-solid-design/ +
-  - https://medium.com/oceanize-geeks/the-active-record-and-data-mappers-of-orm-pattern-eefb8262b7bb+
  
 +  - [[https://martinfowler.com/bliki/DomainDrivenDesign.html|https://martinfowler.com/bliki/DomainDrivenDesign.html]]
 +  - [[https://martinfowler.com/bliki/AnemicDomainModel.html|https://martinfowler.com/bliki/AnemicDomainModel.html]]
 +  - [[https://blog.codecentric.de/en/2019/10/ddd-vs-anemic-domain-models/|https://blog.codecentric.de/en/2019/10/ddd-vs-anemic-domain-models/]]
 +  - [[https://blog.inf.ed.ac.uk/sapm/2014/02/04/the-anaemic-domain-model-is-no-anti-pattern-its-a-solid-design/|https://blog.inf.ed.ac.uk/sapm/2014/02/04/the-anaemic-domain-model-is-no-anti-pattern-its-a-solid-design/]]
 +  - [[https://medium.com/oceanize-geeks/the-active-record-and-data-mappers-of-orm-pattern-eefb8262b7bb|https://medium.com/oceanize-geeks/the-active-record-and-data-mappers-of-orm-pattern-eefb8262b7bb]]
  • arch/adm.1634553321.txt.gz
  • Last modified: 2026/08/29 07:59
  • (external edit)