Anemic Domain Model

737 views
Skip to first unread message

George Dinwiddie

unread,
Apr 9, 2015, 6:40:14 AM4/9/15
to clean-code...@googlegroups.com
Hello craftsmen,

I keep running into a pattern in clients' code that I consider a severe
anti-pattern. It's what Martin Fowler calls an Anemic Domain Model.
Essentially it divides the ostensibly object-oriented code into Service
objects and Domain objects. The Domain object methods are only getters
and setters. They are essentially data-only. The Service objects get
data out of Domain objects, perform operations, and put them into the
same or a different Domain object.

<sigh/>

I ask here because I feel this is an audience who understands that this
is not the most effective OO technique. Apparently, though, there are a
significant set of programmers who think this pattern is to be admired,
and work hard to achieve this separation between data and code. Perhaps
you've seen this.

My question is, can anyone explain to me why someone would choose such a
pattern? What would make this pattern attractive to
otherwise-intelligent programmers? I'm really puzzled.

- George

--
----------------------------------------------------------------------
* George Dinwiddie * http://blog.gdinwiddie.com
Software Development http://www.idiacomputing.com
Consultant and Coach http://www.agilemaryland.org
----------------------------------------------------------------------

Caio Fernando Bertoldi Paes de Andrade

unread,
Apr 9, 2015, 9:15:09 AM4/9/15
to clean-code...@googlegroups.com
George,

I’m sorry but I hear a lot of rhetoric and no logic or practical wisdom. I’m familiar with the concept of Anemic Domain, but I question myself whether it’s really an anti-pattern.

Computing has had the same input-processing-output model since Von Neumann. Any program is essentially a function that takes primitive data as input and outputs transformed primitive data. Structured programming gave us a way to organize our big function into many small ones that cooperate. Object orientation gave us a better way to organize those small functions, grouping them into objects. We also got better polymorphism, due to the pointer-to-funcion management into objects.

Those features are nice but not mandatory. There are systems written in OO languages made out of mostly functions (Service objects) that are very readable and maintainable. In fact, the Usecase objects we talk about in CleanArchitecture are pretty much Service objects. The Rich Domain can emerge from those Service objects as refactorings of the duplicate rules in them and from the need to have shared rules or concepts between Services. This often happens as the application grows and matures, but it’s not a rule. I can have no shared logic whatsoever between Usecases, hence my code is Anemic but also highly decoupled, readable and maintainable.

I think that by this point it’s clear that the anemic code is not the anti-pattern here. Code duplication is. High coupling between UI, logic and database is. The symptoms can be felt inside the Service objects, but thinking that the Service objects themselves are the anti-pattern is a too shortsighted analysis. If the focus is on pushing logic out of Services, the duplication and high coupling will move to models or controllers or helpers or anywhere, and the problem continues. The real antidote for that is SOLID and unit tests and clean code.

So I think Anemic Domain is a concept too abstract to be considered an anti-pattern. Service-like objects play a central role in the architecture of applications. The real anti-patterns are of a different nature. I hope this is clear enough and I apologize for this email being so big. :-)

Caio
> --
> The only way to go fast is to go well.
> --- You received this message because you are subscribed to the Google Groups "Clean Code Discussion" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discu...@googlegroups.com.
> To post to this group, send email to clean-code...@googlegroups.com.
> Visit this group at http://groups.google.com/group/clean-code-discussion.

Jo Van Eyck

unread,
Apr 9, 2015, 10:20:05 AM4/9/15
to clean-code...@googlegroups.com
George,

I've been facing this exact same issue at my current project for months now
I find it quite shocking that many programmers that use an OO language today still don't understand core OO concepts like keeping state and behaviour that changes this state together.
Nothing screams "not OO" more than an object ripping out another object's internals, performing some calculation and then stuffing the result back into the original object. Goodbye encapsulation.

I haven't been able to convince all of my colleagues of this point up until now, so I'm eagerly anticipating answers on this thread :)

Mathias Verraes has a relevant post on this topic: http://verraes.net/2014/09/objects-as-contracts-for-behaviour/

- Jo Van Eyck

George Dinwiddie

unread,
Apr 9, 2015, 11:12:22 AM4/9/15
to clean-code...@googlegroups.com
Hi, Caio,

I'll agree with you that an Anemic Domain is not THE problem, but it is,
in general, an anti-pattern because it, in general, generate problems of
high coupling, low cohesion, and duplication. In systems of size, the
Transaction Script pattern quickly becomes inadequate and the Domain
Model pattern becomes much more robust. This is described well in Martin
Fowler's Patterns of Enterprise Application Architecture.

Anemic Domain is not the analysis technique. It's merely the name of a
pattern where the Transaction Script pattern is being followed with a
slight nod toward Domain Model.

I know that you can find places where Transaction Script is a perfectly
suited pattern. My question is why people prefer it such that they hold
onto it in spite of the presence of coupling, cohesion, and duplication
issues. Like Martin Fowler, I tend to shift to the Domain Model pattern
quite early, avoiding heavy refactoring after the issues become
widespread. I'm trying to understand the mindset of those who shift
late, or never quite make the shift.

- George

Colin Williams

unread,
Apr 9, 2015, 9:58:00 PM4/9/15
to clean-code...@googlegroups.com
My experience with the Anemic Domain is that it violates the principle "code that changes together should live together." More concretely, in an anemic domain, if I want to make a change to the Domain object, I find I have to make a similar change in the Service object. This makes the code more difficult to maintain, and introduces the possibility of bugs related to mismatched structure.

Caio may be right, although I haven't seen this architecture work in practice. I'm not too invested in the idea of data encapsulation being king, but I greatly dislike designs that require a large number of places to change because of a minor adjustment to the data model.
>> To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discussion+unsub...@googlegroups.com.

George Dinwiddie

unread,
Apr 9, 2015, 10:10:42 PM4/9/15
to clean-code...@googlegroups.com
Colin,

On 4/9/15 9:58 PM, Colin Williams wrote:
> My experience with the Anemic Domain is that it violates the principle
> "code that changes together should live together." More concretely, in
> an anemic domain, if I want to make a change to the Domain object, I
> find I have to make a similar change in the Service object. This makes
> the code more difficult to maintain, and introduces the possibility of
> bugs related to mismatched structure.

I agree. Even in C code, I kept the data and code in the same file. The
encapsulation may have just been in my mind, but it helped a lot.

Thanks for your comments. I'm still puzzled why someone would prefer
this pattern.

- George
> clean-code-discu...@googlegroups.com <javascript:>.
> >> To post to this group, send email to
> clean-code...@googlegroups.com <javascript:>.
> <http://groups.google.com/group/clean-code-discussion>.
> >
>
> --
>
> ----------------------------------------------------------------------
> * George Dinwiddie * http://blog.gdinwiddie.com
> Software Development http://www.idiacomputing.com
> Consultant and Coach http://www.agilemaryland.org
>
> ----------------------------------------------------------------------
>
> --
> The only way to go fast is to go well.
> ---
> You received this message because you are subscribed to the Google
> Groups "Clean Code Discussion" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to clean-code-discu...@googlegroups.com
> <mailto:clean-code-discu...@googlegroups.com>.
> To post to this group, send email to
> clean-code...@googlegroups.com
> <mailto:clean-code...@googlegroups.com>.

Sebastian Gozin

unread,
Apr 10, 2015, 9:06:52 AM4/10/15
to clean-code...@googlegroups.com
I can visualize the anemic domain model.
I am no longer sure I can do the same for the rich domain model.

So,
I have a purchase order request. What kind of API do I give it to?

My mind has an interactor but that looks closer to a transaction script than a domain object. So when do I encounter the domain object?
>      >> To post to this group, send email to
>     clean-code...@googlegroups.com <javascript:>.
>      >> Visit this group at
>     http://groups.google.com/group/clean-code-discussion
>     <http://groups.google.com/group/clean-code-discussion>.
>      >
>
>     --
>
>     ----------------------------------------------------------------------
>         * George Dinwiddie * http://blog.gdinwiddie.com
>         Software Development http://www.idiacomputing.com
>         Consultant and Coach http://www.agilemaryland.org
>
>     ----------------------------------------------------------------------
>
> --
> The only way to go fast is to go well.
> ---
> You received this message because you are subscribed to the Google
> Groups "Clean Code Discussion" group.
> To unsubscribe from this group and stop receiving emails from it, send

DEG

unread,
Apr 10, 2015, 11:23:31 AM4/10/15
to clean-code...@googlegroups.com

Since this is also something that I encounter frequently and have a strong opinion about, i thought I’d share it.

 

I am addressing an anemic domain model here. Not a persistence model, a model just there for the orm and that can only be accessed from inside the persistence layer.

Which is what i think a anemic domain model boils down to in most applications. But i'll get to that.

I had a lot of time on the train so this got to be a rather long post.

 

So let’s get started.

 

Is it OO?

-----------

 

To me it is most definitely not OO since the inner state of an object is exposed but no behavior is exposed. This violates the basic idea of OO and the Tell-don't ask principle. ( I do follow the OO definition from Alan Kay, which is explained  here ) To me an anemic domain model is just using mutable data structures with the logic on how to change the data elsewhere. Worst case: spread out over the system.

 

See Chapter 6 of Clean Code :  "Why do so many developers automatically add getters and setters to their objects?"

There is a difference between Objects and data structures. Use what is needed when appropriate. When i talk about a domain model if talk about Objects with behavior. Data structures i prefer to be immutable  by the way.

 

Is it bad?

-----------

 

I do consider it a bad practice.  Not because it is not OO (although why do it in an OO language?). It is bad because it violates encapsulation. Even in procedural programming in C we have encapsulation.

 

Instead of having the domain objects having expose behavior, they expose their inner state. Which means that everything that has access to the domain object can modify it state. Regardless of any logic or invariants that may exist. So the Service may mutate the state of the "domain" objects, hopefully correctly. Unfortunately everything else can also change the state of the objects since it are "domain" objects and they are central to the application. Because everyone can access it, there is no encapsulation. So it is also very easy for bugs to sneak in. Or to do a quick fix. The larger the system gets, the more developers that are on the team, the bigger a problem this gets.

 

It also violates the single responsibility principle. Since the domain object is not responsible for the data it contains. That logic is spread out over the system. In an anemic domain model i assume that we can agree that ideally there should only be one service object that contains the logic and controls the state of the domain object for a given use case. But the problem is that it is very easy to have other services modify the "domain" object. Which eventually always happens. This results in really fragile code.

 

Why do people do it?

----------------------------------

 

I think because it is just procedural programming which is more natural at first than OO. Most developers i encounter who do this, don't do it out of conviction. They do it simply because that is how they have always done it. They often don't know the alternative and haven't really thought about it.

Another reason is that it is easier to do at first. Simply code your logic and mutate some state.

 

It think is also easy to go ‘fast’ if you can access anything from anywhere. You can change whatever you want wherever you want it. Which at first might seem less complicated than being constrained by objects not wanting to expose their state.

 

In practice the "domain" model often just serves as an input for the orm. So it is more of a persistence model than a domain model. But unfortunately a model that everyone can change. Something not everyone has a problem with.

 

 

Response to earlier posts

------------------------------

In response to the blog post from Mathias Verraes, i completely agree with it. ;-)

 

In response to the remarks from Caio.

 

The problem is not that there exist service objects. Gateways and application services are indeed service objects. But that the domain object hold no logic and are only there to sore the state. State that is mutable by anyone. A transaction script is focussed highly on the database. No layers, no model. Just simple logic and data changes. A domain model should not care or know about the database.

 

In response to George

 

The encapsulation is not just in your mind in C. As uncle bob likes to emphasise: "In C we had perfect encapsulation" :-)

 

My standard example

-----------------------------

In order to explain my point i usually use the classic example of buying a paper from a paper boy. Though it is probably overkill, i thought i include it here as well. Although it will make this post very long, it may help someone who stumbles upon this thread to clarify what i'm talking about :) Of course there is also the risk that people start to over analyse this example code. Please don't :-) The code is just some pseudo code with a minimum design. I’ve left out the constructors, getters and setters etc... But hopefully it does the job of explaining what i mean. 

 

The anemic model way:

......................................

   /********************

   //The model

   

    class Wallet {

        private Money money;

 

        public Money take(double price) {

        //With logic if money is available

        }

    }

 

    class Customer {

        private Wallet wallet;

        private Paper paper;

 

        //With getters and setters

    }

 

    class PaperBoy {

        private Wallet wallet;

        private Stack<Paper> papers;

        private double unitPriceOfPaper;

 

         //With getters and setters

    }

 

   /********************

   //The gateway

    class ApplicationService {

 

        private BuyPaperService service;

        private Dao dao;

 

        public void buyPaper(Long customerId, Long paperBoyId) {

            Customer customer = dao.getCustomer(customerId);

            PaperBoy paperBoy = dao.getPaperBoy(paperBoyId);

            service.buyPaper(customer, paperBoy);

        }

    }

   

/********************

   //The services

 

//The service with the logic

//Note the law of demeter violations/ train wrecks

    class BuyPaperService {

 

        void buyPaper(Customer customer, PaperBoy paperBoy) {

            Paper paper = paperBoy.getPapers().pop();

            double unitPriceOfPaper = paperBoy.getUnitPriceOfPaper();

 

            //Seriously? anyone can just take my wallet and take what they want?

            Money moneyForPaper = customer.getWallet().getMoney().remove(unitPriceOfPaper);

            customer.setPaper(paper);

            paperBoy.getWallet().getMoney().add(moneyForPaper);

        }

 

    }

   

    //Some other Service that hides between all the other services in the application        

    class BadService {

 

        void losePapers( PaperBoy paperBoy) {

            paperBoy.setPapers(null);

            //Nullpointers bound to happen.

        }

 

        void takeTheirWallet(Customer customer, PaperBoy paperBoy) {

            final Wallet walletCustomer = customer.getWallet();

            final Wallet fakeWallet = new Wallet();

 

            //They just replaced my wallet!

            customer.setWallet(fakeWallet);

            final Wallet walletPaperBoy = paperBoy.getWallet();

            paperBoy.setWallet(fakeWallet);

           

            //They both have lost their wallets

            //And the now both have the same wallet!!           

           

            partyTimeForMe(walletCustomer,walletPaperBoy);

        }

 

        void buyPaperFromEvilPaperBoy(Customer customer, PaperBoy paperBoy) {

            customer.getWallet().getMoney().remove(1000000); 

            customer.setPaper(null);            

        }

       

       

    }

 

 

Of course the bad service should not exist. The problem is that it is easy for stuff like this to do exist. Working with the code above you would need to look to everything that accesses the data members of the model and check if it is correct. You would also always need to know the state the object is currently in. The logic can easily be spread out over multiple services.  So you need to know in which sequence which state changes were made and if the object is still in the correct state. If a bad Service made the paperboy lose all its papers and the BuyPaperService then buys a paper...

Or if the paperboy and customer have the same wallet...

 

Why make it so difficult?  It should just not be possible to do these things. Fight cognitive overload.

The only one who may handle the papers is the paper boy. The only one who may handle a wallet is the owner of the wallet.

 

 

My preferred way

.............................

/********************        

//The model

class Customer {

        private Wallet wallet;

        private Paper paper;

 

        void buyPaper(PaperBoy paperBoy){

            double price = paperBoy.getUnitPriceOfPaper();

            if(priceToHigh(price)) throw new RuntimeException("i don't want to pay that much");

            Money amount = wallet.take(price);

            this.paper  = paperBoy.buyPaper(amount);

        }

 

    }

 

    class PaperBoy {

        private Wallet wallet;

        private Stack<Paper> papers;

        private double unitPriceOfPaper;

 

        Paper buyPaper(Money money){

            if(money.isEqualTo(unitPriceOfPaper))

                return papers.pop();

            else

            if(money.isLargersThan(unitPriceOfPaper))

                throw new RuntimeException("You paid To Much. No change available");

            else

                throw new RuntimeException("You paid To little. More money is required");

        }

    }

 

/********************

//The gateway

 

    class ApplicationService {

 

        private BuyPaperService service;

        private Dao dao;

 

        public void buyPaper(Long customerId, Long paperBoyId) {

            Customer customer = dao.getCustomer(customerId);

            PaperBoy paperBoy = dao.getPaperBoy(paperBoyId);

            customer.buyPaper(paperBoy);

        }

    }

  

   //There are no service with the logic.

  

  

The scenarios from the bas service are no longer possible.

You can’t  lose your papers outside of the PaperBoy class because only the paperboy has acces to its papers.

You can’t just take and replace someones wallet. Only the owner has acces to it.

You can’t just take whatever money you want. They will take their own money and give it to you when they want to.

 

If there is a bug in buying a paper, you know exactly where to look. It can’t be anywhere else. By encapsulating the data you have control over who modifies it.

     

To summarize

------------------

 

To me this is all about encapsulation. Not encapsulating your state makes it easier to modify state and just do whatever you want. Which is one of the reasons why this is so popular I think. But it has the big side effect that you lose control over who changes what and what state your “objects” are in. You need to chase down the logic to make sure it is not misused. Thats how big balls of mud are created IMO.

 

Fight cognitive overload! Keep it simple. Encapsulate data so you it doesn't change behind your back :-)

And if you are using an OO language, use OO :D


There.

I feel a lot better now i got this of my chest :-)


Regards,

Guido

 

 




----
Dit bericht (inclusief de bijlagen) kan vertrouwelijk zijn. Als u dit bericht ten onrechte hebt ontvangen, wordt u verzocht de afzender te informeren en het bericht te wissen. Het is niet toegestaan om dit bericht, geheel of gedeeltelijk, zonder toestemming te gebruiken of te verspreiden. Continuum Consulting NV sluit elke aansprakelijkheid uit wanneer informatie in deze e-mail niet correct, onvolledig of het niet tijdig overkomt, evenals indien er schade ontstaat ten gevolge van deze e-mail. Continuum Consulting NV garandeert niet dat het bericht vrij kan zijn van onderschepping of manipulatie daarvan door derden of computerprogramma’s die worden gebruikt voor elektronische berichten en het overbrengen van virussen.

Message has been deleted

George Dinwiddie

unread,
Apr 10, 2015, 12:23:33 PM4/10/15
to clean-code...@googlegroups.com
Thanks, Guido,

I really like your cognitive overload explanation, and I hadn't even
thought about the security aspects of a rogue service.

- George

On 4/10/15 4:30 AM, DEG wrote:
> Since this is also something that I encounter frequently and have a
> strong opinion about, i thought I’d share it.
>
> I am addressing an anemic domain model here. Not a persistence model, a
> model just there for the orm and that can only be accessed from inside
> the persistence layer.
>
> Which is what i think a anemic domain model boils down to in most
> applications. But i'll get to that.
>
> I had a lot of time on the train so this got to be a rather long post.
>
> So let’s get started.
>
> Is it OO?
>
> -----------
>
> To me it is most definitely not OO since the inner state of an object is
> exposed but no behavior is exposed. This violates the basic idea of OO
> and the Tell-don't ask principle. ( I do follow the OO definition from
> Alan Kay, which is explained here
> <http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay_oop_en> )
> To me an anemic domain model is just using mutable data structures with
> the logic on how to change the data elsewhere. Worst case: spread out
> over the system.
>
> See Chapter 6 of Clean Code :"Why do so many developers automatically
> add getters and setters to their objects?"
>
> There is a difference between Objects and data structures. Use what is
> needed when appropriate. When i talk about a domain model if talk about
> Objects with behavior. Data structures i prefer to be immutableby the way.
>
> Is it bad?
>
> -----------
>
> I do consider it a bad practice.Not because it is not OO (although why
> over multiple services.So you need to know in which sequence which state
> changes were made and if the object is still in the correct state. If a
> bad Service made the paperboy lose all its papers and the
> BuyPaperService then buys a paper...
>
> Or if the paperboy and customer have the same wallet...
>
> Why make it so difficult?It should just not be possible to do these
> things. Fight cognitive overload.
>
> The only one who may handle the papers is the paper boy. The only one
> who may handle a wallet is the owner of the wallet.
>
> My preferred way
>
> .............................
>
> /********************
>
> //The model
>
> class Customer {
>
> private Wallet wallet;
>
> private Paper paper;
>
> void buyPaper(PaperBoy paperBoy){
>
> double price = paperBoy.getUnitPriceOfPaper();
>
> if(priceToHigh(price)) throw new RuntimeException("i don't want to pay
> that much");
>
> Money amount = wallet.take(price);
>
> this.paper= paperBoy.buyPaper(amount);
>
> }
>
> }
>
> class PaperBoy {
>
> private Wallet wallet;
>
> private Stack<Paper> papers;
>
> private double unitPriceOfPaper;
>
> Paper buyPaper(Money money){
>
> if(money.isEqualTo(unitPriceOfPaper))
>
> return papers.pop();
>
> else
>
> if(money.isLargersThan(unitPriceOfPaper))
>
> throw new RuntimeException("You paid To Much. No change available");
>
> else
>
> throw new RuntimeException("You paid To little. More money is required");
>
> }
>
> }
>
> /********************
>
> //The gateway
>
> class ApplicationService {
>
> private BuyPaperService service;
>
> private Dao dao;
>
> public void buyPaper(Long customerId, Long paperBoyId) {
>
> Customer customer = dao.getCustomer(customerId);
>
> PaperBoy paperBoy = dao.getPaperBoy(paperBoyId);
>
> customer.buyPaper(paperBoy);
>
> }
>
> }
>
> //There are no service with the logic.
>
> The scenarios from the bas service are no longer possible.
>
> You can’tlose your papers outside of the PaperBoy class because only the

George Dinwiddie

unread,
Apr 10, 2015, 12:29:09 PM4/10/15
to clean-code...@googlegroups.com
Sebastian,

On 4/10/15 9:06 AM, Sebastian Gozin wrote:
> I can visualize the anemic domain model.
> I am no longer sure I can do the same for the rich domain model.
>
> So,
> I have a purchase order request. What kind of API do I give it to?

I find that ATDD & TDD helps me discover the API that's suitable. The
API should fit the needs of the client. Tests give me another client,
and therefore help me generalize the API appropriately.

I don't know the functionality you have in mind, but just guessing...

If a PurchaseOrderRequest gives me a filled purchase order, I might want

PurchaseOrderRequest request = new PurchaseOrderRequest();
request.addItem(itemToPurchase);
PurchaseOrder po = request.submit(requestorCredentials);

>
> My mind has an interactor but that looks closer to a transaction script
> than a domain object. So when do I encounter the domain object?

I don't understand what you mean by this.

- George

Sebastian Gozin

unread,
Apr 10, 2015, 3:13:22 PM4/10/15
to clean-code...@googlegroups.com
George,

Thank you, that is actually very interesting.

About the interactor.
It's more or less the place where I would have put the code you gave as an example.

But I believe the code you wrote is the transaction script (a short one). And the domain component is the PurchaseOrderRequest.
If I had written that code I probably would've written the stuff dealing with the requestor credentials in that same place instead of behind PurchaseOrderRequest.submit(creds).
I also would have passed the request instance to a repository.Something like repository.save(request)

I think what I'm describing here is close to what you're talking about in the OP.
Something like:

void submit(PurchaseOrderRequest request, Credentials creds) {
    // test credentials
    def order = new PurchaseOrder()
    // copy stuff from request to order
    repository.save(order)
}

Though perhaps not quite.
I have an event payload in the form of the PurchaseOrderRequest.
I have a record held in a persistent collection in the form of the PurchaseOrder.

So where is the domain?
It's not the event payload.
It's not the PurchaseOrder.
It's not the transaction script.

But could it be hidden in the transaction script?
Those questions have been gnawing at me for a while now.

And...

I lost my train of thought and am feeling a bit overwhelmed trying to reason about it all at this late hour.
So forgive me for rambling and not being terribly useful to the conversation.

I feel like I'm learning something though.
So, thank you.

- Sebastian

George Dinwiddie

unread,
Apr 10, 2015, 5:51:16 PM4/10/15
to clean-code...@googlegroups.com
Sebastian,

On 4/10/15 3:13 PM, Sebastian Gozin wrote:
> George,
>
> Thank you, that is actually very interesting.
>
> About the interactor.
> It's more or less the place where I would have put the code you gave as
> an example.
>
> But I believe the code you wrote is the transaction script (a short
> one). And the domain component is the PurchaseOrderRequest.
> If I had written that code I probably would've written the stuff dealing
> with the requestor credentials in that same place instead of behind
> PurchaseOrderRequest.submit(creds).
> I also would have passed the request instance to a repository.Something
> like repository.save(request)
>
> I think what I'm describing here is close to what you're talking about
> in the OP.
> Something like:
>
> void submit(PurchaseOrderRequest request, Credentials creds) {
> // test credentials
> def order = new PurchaseOrder()
> // copy stuff from request to order
> repository.save(order)
> }

Where does this submit() method live? Why should it know what fields
PurchaseOrder needs from the request? When you add a field to
PurchaseOrder, how many places do you have to change? I would more
likely say

order = new PurchaseOrder(request)

and let the order and request agree on their common ground.

>
> Though perhaps not quite.
> I have an event payload in the form of the PurchaseOrderRequest.
> I have a record held in a persistent collection in the form of the
> PurchaseOrder.
>
> So where is the domain?
> It's not the event payload.
> It's not the PurchaseOrder.
> It's not the transaction script.
>
> But could it be hidden in the transaction script?
> Those questions have been gnawing at me for a while now.

In your example, I don't think you have a true domain. You have bags of
data that are manipulated by others.

>
> And...
>
> I lost my train of thought and am feeling a bit overwhelmed trying to
> reason about it all at this late hour.
> So forgive me for rambling and not being terribly useful to the
> conversation.
>
> I feel like I'm learning something though.
> So, thank you.

You're welcome. It would be good to flesh out the hypothetical context a
bit more. It's hard for me to know what I'd do with so little
understanding of the business needs, and I'm wary that we are filling in
the details differently in our minds.

- George

>
> - Sebastian
>
>
> On Friday, April 10, 2015 at 6:29:09 PM UTC+2, George Dinwiddie wrote:
>
> Sebastian,
>
> On 4/10/15 9:06 AM, Sebastian Gozin wrote:
> > I can visualize the anemic domain model.
> > I am no longer sure I can do the same for the rich domain model.
> >
> > So,
> > I have a purchase order request. What kind of API do I give it to?
>
> I find that ATDD & TDD helps me discover the API that's suitable. The
> API should fit the needs of the client. Tests give me another client,
> and therefore help me generalize the API appropriately.
>
> I don't know the functionality you have in mind, but just guessing...
>
> If a PurchaseOrderRequest gives me a filled purchase order, I might
> want
>
> PurchaseOrderRequest request = new PurchaseOrderRequest();
> request.addItem(itemToPurchase);
> PurchaseOrder po = request.submit(requestorCredentials);
>
> >
> > My mind has an interactor but that looks closer to a transaction
> script
> > than a domain object. So when do I encounter the domain object?
>
> I don't understand what you mean by this.
>
> - George

[snip]

Philip Schwarz

unread,
Apr 11, 2015, 6:44:18 PM4/11/15
to clean-code...@googlegroups.com
Hi George,

>can anyone explain to me why someone would choose such a 
pattern?

Here are some excerpts from Implementing DDD, in which Vaughn Vernon tells us why he thinks anaemia happens:

"So if an Anemic Domain Model is the sickly outcome of a poorly executed design effort, why do so many use it while thinking that their model is experiencing fine health? Certainly it does reflect a procedural programming mentality, but I don’t think that’s the primary reason. A good portion of our industry is made up of sample code followers, which isn’t bad as long as the samples are quality ones. Often, however, sample code is purposely focused on demonstrating some concept or application programming interface (API) feature in the simplest possible way, without concern for good design principles. Yet oversimplified sample code, which usually demonstrates with a lot of getters and setters, is copied every day without a second thought about design."

"There is another, older influence. The ancient history of Microsoft’s Visual Basic had much to do with where we are today...What I am talking about is the influence of properties and property sheets, both backed by property getters and setters that were made so popular by the original Visual Basic forms designer...The Java Bean standard was originally specified to assist in the creation of visual programming tools for Java...like Visual Basic’s. Soon almost every framework and library jumped on the JavaBean bandwagon. This included much of the Java SDK/JDK as well as libraries such as the popular Hibernate. Specific to our DDD concerns, Hibernate was introduced to persist domain models. The trend continued as the .NET platform reached us...."

"Most, if not all, of the Web frameworks also function solely on the JavaBean standard. If you want your Java objects to be able to populate your Web pages, the Java objects had better support the JavaBean specification. If you want your HTML forms to populate a Java object when submitted to the server side, your Java form object had better support the JavaBean specification. Just about every framework on the market today requires, and therefore promotes, the use of public properties on simple objects. Most developers can’t help but be influenced by all the anemic classes all over their enterprises. Admit it. You’ve been bitten by it, haven’t you? As a result, we have a situation that might be best labeled anemia everywhere."

Philip

Philip Schwarz

unread,
Apr 11, 2015, 6:53:19 PM4/11/15
to clean-code...@googlegroups.com
George,

In "Real World Java EE Patterns-Rethinking Best Practices" Adam Bien reminds new generations of the bitterness of EJB in J2EE, and of the procedural code and anaemic domain models it
resulted in, and while he admits that the anaemic domain model is still prevalent, he says that there is no good reason for that. He says that with Java EE and JPA, the current best practice is rich domain models and the anaemic domain model is an anti-pattern, though he does qualify that with "at least in more ambitious projects" ;-) 

The 'Rethinking' part of his title comes from the fact that he revisits now outdated J2EE patterns in the light of Java EE.

One of the patterns he rethinks is the J2EE Core Patterns' Business Object: http://www.corej2eepatterns.com/Patterns2ndEd/BusinessObject.htm 

A couple of extracts from the 'Problem' section:

"The vast majority of Java EE applications are built in a procedural way without a reason. The business logic is decomposed into tasks and resources, which are mapped into Controls and anemic, persistent entities. Such a procedural approach works surprisingly well until type-specific behavior for domain objects must be realized." 
...
"All the shortcomings mentioned here are caused by the lack of object orientation in the persistence layer of most J2EE and Java EE applications."

A single opening extract from the 'Solution' section:

"The solution is surprisingly simple: Model your application with real objects and don't care about the persistence at the beginning. Real objects imply cohesive classes with encapsulated state, related behaviour, and inheritance. Just put business logic into the domain objects and use inheritance where appropriate. JPA turns out to be really flexible for mapping rich domain objects into relational tables. The more complex is the logic you have to realize, the less viable is the development of applications in a procedural way with anemic domain objects."

And finally, here is the 'Rethinking' section:

"The outdated J2EE CMP persistence didn't supported inheritance or polymorphic queries, so the anemic domain object approach was the only viable solution. The J2EE patterns were designed to mitigate such restrictions. Although alternative solutions, such as JDO or Hibernate, support inheritance, the situation did not improve. Due to the implementation of outdated patterns, most of the domain objects in production are still anemic -- without any reasonable explanation.
 
With the ubiquity of JPA, it's time to rethink the way complex logic is developed. Persistence is a cross-cutting concern and should not have any impact on design or, in particular, on the amount of logic residing in domain objects. Only the remaining cross-cutting and, often, procedural logic should be implemented in a Control. You should have a good reason to split the state and behaviour into separate layers.

Rich domain objects have become a best practice and the anemic domain model (http://www.martinfowler.com/bliki/AnemicDomainModel.html) is an anti-pattern, at least in more ambitious projects."

Philip

On Thursday, 9 April 2015 11:40:14 UTC+1, George Dinwiddie wrote:

Philip Schwarz

unread,
Apr 11, 2015, 7:45:51 PM4/11/15
to clean-code...@googlegroups.com
Chris Richardson wrote a great book back in 2006: POJOs in Action.

Relevant sections:

1.2.1 Using an objet-oriented design.

2.2 Decision 1: organizing business logic.
2.2.1 Using a procedural design
2.2.2 Using an object-oriented design 

Chapter 3 Using the Domain Model pattern

Chapter 9 Using the Transaction Script pattern

Here are a couple of sections from chapter 9:

9.1.2 Benefits and drawbacks of the Transaction Script pattern
The Transaction Script pattern has the following benefits and drawbacks.

Easy to use
One of the most appealing aspects of the Transaction Script pattern is that it is
easy to apply because you don’t need to have OO design skills. You just have to
write a transaction script method to handle each request. Similarly, to implement
a new business logic feature you typically have to add some code to an existing
transaction script. In comparison, to use the Domain Model pattern you must
have object-design skills and know how to identify classes and assign responsibilities
to them.

Can use full range of SQL features
Another benefit of the Transaction Script pattern is that it can sometimes improve
performance significantly because transaction scripts can access the database
using the full range of SQL features. An application can use SQL to efficiently
query the database in ways that are not supported by persistence frameworks such
as JDO and Hibernate. This can be especially important when you’re working with
a legacy schema. In addition, SQL’s ability to perform bulk updates and deletions
is far superior to those capabilities provided by some persistence frameworks. As a
result, it’s not uncommon to implement some parts of an application using the
Transaction Script pattern and SQL.

Code can be difficult to understand and maintain
The simplicity of this pattern is a double-edged sword. Because you do not have to
do any OO design, all of the business logic is concentrated in the transaction
scripts. This can make the code difficult to understand and maintain, especially if
the business logic is complex. This is made worse by the fact that transaction
script-based business must explicitly load and save data, whereas in a domain
model-based design, many objects are automatically loaded by navigation and
changes are automatically written back to the database.

Cost of maintaining handwritten SQL
Another problem with using the Transaction Script pattern is that you have to write
all of the SQL yourself. While this gives you a lot of control and makes your SQL
available for inspection by the DBAs, it can be difficult and tedious to maintain
large amounts of SQL. It is quite common for one small change to a table definition
to cause you to update multiple SQL statements and DAOs. For example, if you add
a column to the RESTAURANT table, then in addition to changing the Restaurant-
DAO you might need to change the PendingOrderDAO because it executes a SQL statement
involving the RESTAURANT table. There are ways of designing the DAO
classes that reduces this problem, but they do not prevent it altogether.

Lack of portability of SQL
The problem with developing and maintaining SQL is made even worse by the differences
between the SQL dialects supported by the various databases. For example,
some databases (such as Oracle) have sequences to generate unique IDs,
whereas other databases (such as HSQLDB) have identity columns. Consequently,
developing a JDBC application that supports multiple databases is extremely challenging.
This can be a problem even if your application is only deployed on a single
database because you might want to write tests that use an in-memory database
such as HSQLDB.
You could use a persistence framework to avoid these problems. JDO and
Hibernate insulate the application from the differences between the various databases
and will even generate the DDL that defines the schema from the O/R mapping.
In this kind of design, the persistent classes would mirror the database
schema rather than implementing a domain model and would not contain any
business logic. Of course, this option would only work if an application accessed
the database in ways that are supported by the persistence framework, which is
often not the case if you are using the Transaction Script pattern. Moreover, if the
application can use a persistence framework, then it is not clear why you would
not want to go further and implement a complete domain model.

9.1.3 When to use the Transaction Script pattern
As you have just seen, business logic organized using the Transaction Script pattern
can be hard to maintain because it is procedural and typically uses handwritten
SQL to access the database. However, there are four main situations where the
Transaction Script pattern is the best choice.

The application must use SQL directly
One common reason to use the Transaction Script pattern is if the application
must execute SQL directly because it needs to access the database in ways that are
not efficiently supported by the persistence framework. However, it is important
to keep in mind that persistence frameworks are constantly improving. JDO and
Hibernate have powerful query languages and they both support SQL queries,
which means that you can implement more of your business logic with the
Domain Model pattern. In addition, Hibernate 3.0 and EJB 3 support bulk
updates and deletes, which reduces the need to use SQL. As a result, the need to
directly use SQL directly is diminishing

A persistence framework is unavailable
It can also make sense to use the Transaction Script pattern if the application cannot
use a persistence framework. Budget issues and preference of the architect or
developers are just two reasons why you’d want to take this approach. In this case,
the developers must use SQL directly to access the database. In principle, you
could write JDBC code to persist a domain model, but this is usually impractical if
the domain model is complex.

The business logic is very simple
You might consider using the Transaction Script pattern if the business logic is
very simple and developing a domain model is not worthwhile. For example, if
the application just queries a database and displays the data, then it could very
well be a candidate for the Transaction Script pattern.

The development team doesn’t have OO design skills
Developing a domain model requires the development team to have OO design
skills, which is not always the case. It is better to succeed with a procedural transaction
script-based design rather than fail with a domain model.

Philip

On Thursday, 9 April 2015 11:40:14 UTC+1, George Dinwiddie wrote:

Philip Schwarz

unread,
Apr 11, 2015, 8:03:20 PM4/11/15
to clean-code...@googlegroups.com
Chris Richardson, author of POJOs in action, also gave this great presentation: Improving application design with a rich domain model (springone 2007).

He also has this video of the demo he gave during the talk: Refactoring to an object-oriented design 

Philip

On Thursday, 9 April 2015 11:40:14 UTC+1, George Dinwiddie wrote:

Philip Schwarz

unread,
Apr 12, 2015, 3:18:13 AM4/12/15
to clean-code...@googlegroups.com, caio...@icloud.com
Hi Caio,

in  Object-Oriented Analysis and Design with ApplicationsGrady Booch says the following about Algorithmic decomposition and OO decomposition

Algorithmic Decomposition: Most of us have been formally trained in the dogma of top-down structured design, and so we approach decomposition as a simple matter of algorithmic decomposition, wherein each module in the system denotes a major step in some overall process. 
... 
Object-Oriented Decomposition: We suggest that there is an alternate decomposition possible for the same problem. ...Because our decomposition is based on objects and not algorithms, we call this an object-oriented decomposition. 
... 
Algorithmic versus Object-Oriented Decomposition: Which is the right way to decompose a complex system—by algorithms or by objects? 
Actually, this is a trick question because the right answer is that both views are important: The algorithmic view highlights the ordering of events, and the object-oriented view emphasizes the agents that either cause action or are the subjects on which these operations act. 

However, the fact remains that we cannot construct a complex system in both ways simultaneously, for they are completely orthogonal views. We must start decomposing a system either by algorithms or by objects and then use the resulting structure as the framework for expressing the other perspective

Langdon suggests that this orthogonality has been studied since ancient times. As he states, “C. H. Waddington has noted that the duality of views can be traced back to the ancient Greeks. A passive view was proposed by Democritus, who asserted that the world was composed of matter called atoms.Democritus’ view places things at the center of focus. On the other hand, the classical spokesman for the active view is Heraclitus, who emphasized the notion of process”. Our experience leads us to apply the object-oriented view first because this approach is better at helping us organize the inherent complexity of software systems, just as it helped us to describe the organized complexity of complex systems as diverse as computers, plants, galaxies, and large social institutions. 
... object-oriented decomposition has a number of highly significant advantages over algorithmic decomposition. Object-oriented decompositionyields smaller systems through the reuse of common mechanisms, thus providing an important economy of expression. Object-oriented systems are also more resilient to change and thus better able to evolve over time because their design is based on stable intermediate forms. Indeed, object-oriented decomposition greatly reduces the risk of building complex software systems because they are designed to evolve incrementally from smaller systems in which we already have confidence. Furthermore, object-oriented decomposition directly addresses the inherent complexity of software by helping us make intelligent decisions regarding the separation of concerns in a large state space. 
... 
Certainly, many good engineers have developed and deployed countless useful software systems using structured design techniquesHowever, there are limits to the amount of complexity we can handle using only algorithmic decomposition; thus we must turn to object-oriented decomposition. 
...Structured programming appears to fall apart when applications exceed 100,000 lines or so of code” 


Philip

> To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discussion+unsub...@googlegroups.com.

Philip Schwarz

unread,
Apr 12, 2015, 3:31:49 AM4/12/15
to clean-code...@googlegroups.com, caio...@icloud.com
Caio,

can I take the opportunity to reiterate the deficiencies of functional decomposition and the advantages of OO  decomposition by quoting excerpts from Object Thinking (by David West), a brilliant book (IMHO) which contrasts behavioural OO with other variants, and explains the advantages of the former over the latter. 

The rest of this post is a long series of excerpts from "Object Thinking" (not necessarily in the same order as in the book): 

Object-oriented ideas and principles are poorly understood 

...Why does Alan Kay say the object revolution has yet to occur? ...[because] software developers tend to be so focused on what and how that they forget to explore questions of why. 

...Thirty plus years have passed since Alan Kay coined the term object-oriented...The ubiquity of object terminology does not mean, however, that everyone has mastered object thinking. Nor does the popularity of Java. Nor does the de facto standardization of object modeling embodied in UML. 

...An argument can be made that the contemporary mainstream understanding of objects is but a pale shadow of the original idea. Further, it can be argued that the mainstream understanding of objects is, in practice, antithetical to the original intent. 

...Thinking like a computer is the prevailing mental habit of traditional developers...begin by thinking what a computer has to do first and write that down; then think about what the computer has to do next, and continue that way until you have described the last thing the computer must do (David Parnas)...Object thinking focuses our attention on the problem space rather than the solution space. Object thinkers take the advice of Plato, Parnas, Fred Brooks, Christopher Alexander, and many others by letting the problem define its own solution...they are not thinking about the structure of a computer program; they are talking about finding the naturally occurring divisions and classifications ("natural joints") in the problem space. This is essential because the naturally occurring modules in a problem space are not isomorphic (exhibiting fitness between context and solution) with the modules discovered and defined when you are thinking about the design of a computer program. But they can be. 
Thinking like an object will lead to a greater degree of isomorphism between objects found in the problem space (the enterprise domain) and those in the solution space (the computer program) than thinking like a computer. Isomorphism of the modules (objects) in problem and solution space is a desirable, in fact essential, quality for software...the leading advocates of "behavioural objects", Kent Beck and Ward Cunningham invented the CRC card approach to finding and defining objects, the most popular of the "behavioural methods" 

...Plato suggests three things: decomposition is hard (and anyone really good at it deserves adoration), any decomposition that does not lead to the discovery of things that can be recombined—composed—is counterproductive, and the separation of one thing into two should occur at “natural joints.” By implication, if you decompose along natura joints—and only if you do so—you end up with objects that can be recombined into other structures. Also by implication, the natural joints occur in the domain, and “bad carving” results if you attempt to use the wrong “knife”—the wrong decomposition criterion...Decomposition is accomplished by applying abstraction—the “knife” used to carve our domain into discrete objects...Traditional computer scientists and software engineers have used data (attributes) or functions (algorithms) to decompose complex domains into modules that could be combined to create software applications. This parallels Edsger Wybe Dijkstra’s notion that “a computer program equals data structures plus algorithms.” 

...The fact that a computer program consists of data and functions does not mean that the nonsoftware world is so composed. Using either data or function as our abstraction knife is exactly the imposition of artificial criteria on the real world—with the predictable result of “bad carving.” The use of neither data nor function as your decomposition abstraction leads to the discovery of natural jointsDavid Parnas pointed this out in his famous paper “On Decomposition” (http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf). 

...Parnas' paper examined two conceptual abstractions for decomposing complex systems for the purposes of developing software. One was top-down functional decomposition, the approach that was gaining widespread acceptance under the label "structured design"Functional decomposition is based on an attempt to model the performance of the computer and software and to translate the requirements of the domain problem into those computer-based constructs. 
Parnas offered an alternative approach called "design decision hiding" [self: hiding of decisions which are difficult or changeable], in which the problem or problem domain is modeled and decomposed without consideration of how the component parts of that domain or problem would be implemented. He was able to show that his alternative led to simpler, easier to read, easier to maintain, and more composable software modules than functional decomposition. Unfortunately his advice was essentially ignored as the juggernaut of structured development came to dominate, at least officially, the manner in which software was conceived and implemented.

...Parnas, like Plato, suggests that you should decompose a complex thing along naturally occurring lines, what Parnas calls “design 
decisions.” 
...Both data and function are poor choices for being a decomposition toolParnas’s predictions have consistently been demonstrated as the industry blithely ignored his advice and used functional decomposition as the primary tool in program and system design for 30 years (40 if you recognize that most object development also uses functionality as an implicit decomposition criterion ). Using data as the decomposition abstraction leads to a different set of problems. Primary among these is complexity arising from the explosion in total data entities required to model a given domain and the immense costs incurred when the data model requires modification. 
What criterion should be used instead of data or functions? Behavior! ...Behavior is the key to finding the natural joints in the real world. This means, fortunately, that most of our work has already been done for us. Software developers simply must listen to domain experts. If the domain expert has at hand a name (noun) for something, there is a good chance that that something is a viable, naturally carved, object. ...Only when we are confident that our understanding of the domain and of its decomposition into objects mirrors that of the user and the natural structure of that domain should we begin to worry about how we are going to employ that understanding to create software artifacts. 

... If we “think in Java,” don’t we “think like objects” instead of engaging in the kind of “computerthink” discussed by Parnas? Unfortunately, no...Although you can implement object thinking in any programming language, knowing an “OO” language is not sufficient to engender object thinking...Languages such as Java and object-modeling tools such as UML effectively define an object as the encapsulation of data structures and algorithms. According to this kind of definition, an object is nothing more than a very tiny COBOL program... A COBOL program is the encapsulation of data structures (data division) and algorithms that operate on those data structures (procedure division)...developers tend to perpetuate old thinking habits, albeit sometimes to a lesser degree. 

...It’s useful to generalize Parnas’s observation to accommodate datacentric development and development in nonprocedural languages 
such as Prolog and Lisp. The essence of thinking like a computer is thinking in terms of the means of problem solution. You view every development problem through the lens of the means you intend to use to solve that problem. In datacentric development, the means of solution consists of relations and relationships; for Prolog and LISP, a set of propositions or state declarations. 
...The generalization being made here is a variant of the adage, “If your only tool is a hammer, every problem looks like a nail.” 
Following Parnas, I’m suggesting that software development has been distorted and that all the problems noted by Parnas persist because “our only tool is a computer, so every problem looks like a virtual machine.”... 

Philip

On Thursday, 9 April 2015 14:15:09 UTC+1, Caio Fernando Bertoldi Paes de Andrade wrote:
> To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discussion+unsub...@googlegroups.com.

Philip Schwarz

unread,
Apr 12, 2015, 4:10:19 AM4/12/15
to clean-code...@googlegroups.com

I love Fowler's pseudoscientific graphs. This is from Patterns of Enterprise Application Architecture --> Part 1: The Narratives --> Chapter 1. Layering --> Chapter 2. Organizing Domain Logic --> Making a Choice

Fowler says: Your problem, of course, is to figure out where on that x axis your application lies. The good news is that I can say that you should use a Domain Model whenever the complexity of your domain logic is greater than 7.42. The bad news is that nobody knows how to measure the complexity of domain logic. In practice, then, all you can do is find some experienced people who can do an initial analysis of the requirements and make a judgment call.

Fowler also says: "the better the team is, the more I’m inclined to use a Domain Model"

Philip

On Thursday, 9 April 2015 11:40:14 UTC+1, George Dinwiddie wrote:

Philip Schwarz

unread,
Apr 12, 2015, 4:43:16 AM4/12/15
to clean-code...@googlegroups.com, caio...@icloud.com
Caio,

In his book, Object Oriented Software ConstructionBertrand Meyer introduced a set of complementary properties, which taken collectively, cover (in his opinion) the most important requirements on a modular design method. The properties are 5 criteria, 5 rules, and 5 principles (ignore for now the fact that three in are in blue):

About ten years ago I put together some slides capturing Meyer's opinion of functional decomposition, as expressed in his book. Here are the slides:

Philip




On Thursday, 9 April 2015 14:15:09 UTC+1, Caio Fernando Bertoldi Paes de Andrade wrote:
> To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discussion+unsub...@googlegroups.com.

Philip Schwarz

unread,
Apr 12, 2015, 4:49:54 AM4/12/15
to clean-code...@googlegroups.com, caio...@icloud.com
Caio,

One of Bertrand Meyer's criticisms of functional decomposition is 'Premature Ordering'. Here is my summary of the criticism in the form of bullet 
points: 
  • premature emphasis on temporal constraints
  • each refinement expands a piece of the abstract structure…into a more detailed CONTROL architecture, …specifying the order in which various functions will be executed.
  • such ordering constraints become essential properties of the system architecture… but they too are subject to change.
  • freezing ordering relations at the earliest stages of design is not reasonable
  • with top-down design, you must specify the order of the executing operations… before you have had a chance to understand properly what the operations will do.
See below for my summary of how David Parnas puts the problem in http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf : 

Parnas says that the effectiveness of a modularization is dependent upon the criteria used in dividing the system into modules. He takes a 
sample system and decomposes it, first using the 'conventional method' (conventional at that time), and then using a new, unconventional one. 

The conventional method was the one meant by all proponents of modular programming (at that time). The criterion for modular composition was 
to make each step in the processing a module. One might say that to get the first decomposition one makes a flowchart. 

In the unconventional method, the criterion used for modular decomposition is information hiding: every module is characterized by its knowledge of a design decision, which it hides from all others. The module's interface or definition is chosen to reveal as little as possible about its inner workings. 

Parnas then compares the two decompositions and shows that the unconventional one has distinct advantages for the goals of flexibility, comprehensibility and shorter development time. He finds that the order in time in which processing is expected to take place should not be used in making the decomposition into modules. Parnas draws the following conclusions: It is almost always incorrect to begin the decomposition of a system into modules on the basis of a flowchartWe propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others. 

Philip


On Thursday, 9 April 2015 14:15:09 UTC+1, Caio Fernando Bertoldi Paes de Andrade wrote:
> To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discussion+unsub...@googlegroups.com.

Philip Schwarz

unread,
Apr 12, 2015, 5:16:50 AM4/12/15
to clean-code...@googlegroups.com, caio...@icloud.com
Caio,

in 2013, David West, author of Object Thinking, presented 'OOP is Dead' at the BBC: https://vimeo.com/77415896.

Here is an extract from a comment West made in a thread discussing the talk:

a major theme of the video is the fact that objects were "ruined and made irrelevant" because they fell into the hands of programmers (including Alan Kay) and objects have little, if any, value as a programming concept.  Because all the arguments about objects occurred in the context of programming they focused on things that really don't matter much, like single versus multiple inheritance, dot notation versus explicit messages for getting and setting or invoking methods; class hierarchies, friends, even the idea of a class.

In the early 90s when OO programming as ascendant - destined to be the "next COBOL" in popularity - thousands of existence proofs showed that programs could be written in Smalltalk in a third of the time, with an order of magnitude fewer lines of code, less complexity of the code, etc. etc.  The problem was that none of these unquestionable results had anything to do with the programming language.  95% of the results were attributable to design.

Objects lead to more accurate understandings of complex domains and better and simpler designs, which when implemented are extraordinarily simple - the programming tends to become trivial.

The rant against java - and the fact that if you decide to create a class - the class structure demands a main() with, usually, typed instance variables, and subroutines for each method.  Without being given the opportunity to reflect or find alternatives, programmers are forced into thinking about their programs, and their objects, as tiny instances of the 1950s model of program architecture called a "Program Structure Chart" with its master control module, afferent, efferent, and transform modules (all subtroutines) called at the discretion of the master control module.  This causes all kinds of conflict - conflict exceeded only by trying to force fit object software into a relational database.  You can have the most elegant of solutions and design for an implementation only to find yourself unable to express it directly and easily in Java.

Philip

On Thursday, 9 April 2015 14:15:09 UTC+1, Caio Fernando Bertoldi Paes de Andrade wrote:
> To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discussion+unsub...@googlegroups.com.

Luis Cordova

unread,
Apr 13, 2015, 12:21:12 AM4/13/15
to clean-code...@googlegroups.com, caio...@icloud.com
thanks for this thread man, learning a lot

To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discu...@googlegroups.com.

vivek poddar

unread,
Apr 13, 2015, 5:14:43 AM4/13/15
to clean-code...@googlegroups.com

Hi, I am a newbie and seriously there a lot of things going over my head. Can anyone please summarise the discussion for someone like me to get some take home advice.

Thanks!

Robert Martin

unread,
Apr 13, 2015, 9:29:41 AM4/13/15
to clean-code...@googlegroups.com
Why are domain models so often anemic?

Simple answer: They start with databases.

When we start with a database, we are starting with data structures that have no behavior. Our thought processes are related to how _data_ should be represented, and not how _behavior_ should be represented.

This causes us to create elegant sets of interconnected data structures that represent the persistent state of the system. It does _not_ cause us to create elegant sets of interconnected behaviors that represent the _function_ of the system.

This is unfortunate because the reason we program computers is to make them _behave_. Programming is the art of describing behavior to a machine.

Solution:

When designing systems _ignore_ the database for as long as possible. Think of the database as nothing more than an IO device — a detail to be deferred. Don’t work on the data model first.

Design the objects in your system from the point of view of their behavior. Create relationships between objects that facilitate that behavior. Ignore persistence. Ignore SQL. Ignore all the details that are more related to the IO device than to system function.

Then, when you have the behavior working, with lots of tests passing — when you have a nice domain model that describes the _behavior_ of the system. _Then_, create a decoupled back-end that manages to extract the relevant data from the domain model, and persist it.

You will find that the domain model that describes behavior will differ significantly from the data model that you actually manage to store in a database. And that’s a good thing.

Guido Dechamps

unread,
Apr 14, 2015, 9:42:40 AM4/14/15
to clean-code...@googlegroups.com
The fact that many large companies, and definitely banks, always want to start with the database design up front doesn't help. It then takes an extra effort from the developers not to let the database/data structure dictate the model. Although i'm personally convinced that the database is a detail that should be addressed as late as possible, it is very hard to convince the customer, or other developers of this. I usually do succeed in letting my domain model be the center of the application, hiding all of the persistency concerns. But i've never been able to postpone the database by more than a few sprints. Which was quite the accomplishment. :)

The combination of the facts that

a) a lot of companies are DBA heavy and want their relational DB schema defined a.s.a.p.
b) the anemic domain model is the tool of preference of most developers that i encounter
c) a lot of internet resources claim that the anemic domain model is not bad.

has led me to believe that i'm fighting a losing the battle against the anemic domain model. It is just everywhere and most people don't have a problem with it.

Apart from the fact that i consider it bad design, in my experience it also leads to hard to maintain software. I've only seen it "work" on very small applications. In the many large applications i saw it used, it has always resulted in a big ball of mud with the database taking center stage.

Alas we keep on using it, and it doesn't look like this will change any time soon :(

George Dinwiddie

unread,
Apr 14, 2015, 9:52:39 AM4/14/15
to clean-code...@googlegroups.com
Guido,

On 4/14/15 9:42 AM, Guido Dechamps wrote:
> The fact that many large companies, and definitely banks, always want to
> start with the database design up front doesn't help. It then takes an
> extra effort from the developers not to let the database/data structure
> dictate the model. Although i'm personally convinced that the database
> is a detail that should be addressed as late as possible, it is very
> hard to convince the customer, or other developers of this. I usually do
> succeed in letting my domain model be the center of the application,
> hiding all of the persistency concerns. But i've never been able to
> postpone the database by more than a few sprints. Which was quite the
> accomplishment. :)

I've worked on legacy code where the DB schema was well established (and
was a good representation of the data hierarchy), but was able to avoid
tying my domain model to the schema. To do this, I used a Data Access
abstraction.

I drove my code development using TDD, and let that drive out the API I
needed for data access. Then I would drive the development of the Data
Access Objects I needed to connect that abstraction with the existing
database. I've needed to join as many as seven tables to do this, but it
was much better than any machine driven object-relational mapping.

Caio Fernando Paes de Andrade

unread,
Apr 18, 2015, 10:58:42 AM4/18/15
to clean-code...@googlegroups.com
Thanks for all this information, Philip. I guess my understanding of the concept of an Anemic Model was incomplete.

I agree with you and the references on the core issues and problems, and also on the solutions.

This whole discussion, the amount of text written about this, and the amount of excerpts you posted here to make your point force me to be critical about one thing, though:

The name Anemic Model is a very poor name for this issue.

Just like Mocks and Test Doubles, maybe we are bound to keep using the name Anemic Model, but for me a better (cleaner ;) nomenclature would clearly be Data-Centric Model, Function-Centric Model and Behaviour-Centric Model.

Thanks again for your time finding this info and texts.

Caio
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discu...@googlegroups.com.

Philip Schwarz

unread,
Apr 19, 2015, 12:43:23 PM4/19/15
to clean-code...@googlegroups.com, caio...@icloud.com

>The real antidote for that is SOLID and unit tests and clean code. 

Speaking of SOLID, I just bumped into this: The Anaemic Domain Model is no Anti-Pattern, it’s a SOLID design. I don't think the author is trolling because the blog is hosted by http://blog.inf.ed.ac.uk/ which is the University of Edinburg's School of Informatics.

Philip.

Philip Schwarz

unread,
Apr 19, 2015, 1:25:44 PM4/19/15
to clean-code...@googlegroups.com
Hi Guido,

>c) a lot of internet resources claim that the anemic domain model is not bad. 

If you find the time, then I wouldn't mind some links.

Thanks.

Philip

Philip Schwarz

unread,
Apr 19, 2015, 1:34:02 PM4/19/15
to clean-code...@googlegroups.com, caio...@icloud.com

Note to self: 

Philip

Philip Schwarz

unread,
Apr 19, 2015, 1:53:54 PM4/19/15
to clean-code...@googlegroups.com
>When designing systems _ignore_ the database for as long as possible. 
Related: your 2012 post, NO DB

Philip

Guido Dechamps

unread,
Apr 21, 2015, 5:31:12 AM4/21/15
to clean-code...@googlegroups.com
@Philip Schwarz

Simple googeling on Anemic domain model (ADM) is sufficient to find what i mean.

A couple of examples.

Th post you already mentioned in this thread:
https://blog.inf.ed.ac.uk/sapm/2014/02/04/the-anaemic-domain-model-is-no-anti-pattern-its-a-solid-design/
I'm not so sure that is meant as a joke. But i must confess, i didn't really bother to read it

A post on why the ADM is an anti pattern:
http://blog.decayingcode.com/post/anti-pattern-anemic-domain-model
but then also read all the comments to see how prevalent the idea is.

Gregy Young's post:
http://codebetter.com/gregyoung/2009/07/15/the-anemic-domain-model-pattern/

Although definetely an advocate of DDD Greg states that for very simple domains and a not highly functional team, the anemic domain model might be the best.
"Said bluntly, 90% of teams in the Microsoft world should be looking at building anemic domain models "


The problem resulting from posts like this is that, even if the post were not intended too, they are often used by developers as an excuse for using the ADM.
The posts are seen as the proof that it is just a matter of opinion if the ADM is good or bad.
Or as one technical lead put it "It is just a matter of taste. Like putting on a red or blue shirt"

The arguments i encounter usually go as follows:
    "If it is hard, why do it? The AMD works for us."
    "Look here, we have a post from an authority that says that it is ok to do use the anemic domain model."
    "It is just a matter of opinion. The ADM is just as valid as the domain model."

Which brings me back to the original question: Why is the ADM used so often?
Next to the reasons already offered in this thread i would like to add:
    
    The why and when the ADM is bad is not well understood.
    Plain old laziness. It is easier to just map the data to the ADM and change whatever you want on the ADM.

I'm afraid we can not easily change the second one.
But in order to address the first one we can perhaps make some additional blog posts on the ADM that answers the traditionally voiced pro arguments that can always be found in the comments to the above mentioned posts.
It can only help...

As said before i encounter this all the time and i'm starting to feel like Don Quichot.

Rodrigo Baron

unread,
Apr 22, 2015, 10:30:51 AM4/22/15
to clean-code...@googlegroups.com
My 50 cents about it,

a intentional Anemic Model is known as Persistence Model (only to represent data). They have no direct relationship, you can create a mapping between your persistence model and the related domain models.

"can anyone explain to me why someone would choose such a pattern?"

You are tryng make reusable components, you know what the component should do (Domain Model) but don't know from where fetch/persist data (Repository/Gateway) and how are the data structure (Persistence Model).

I think Repository/Gateway can solve the problem about "how are the data structure" too. But if have an object that represents exactly the data structure I'm using at the moment, makes maintenance much more easier / more clean^^ ...



--
The only way to go fast is to go well.
---
You received this message because you are subscribed to the Google Groups "Clean Code Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discu...@googlegroups.com.

To post to this group, send email to clean-code...@googlegroups.com.
Visit this group at http://groups.google.com/group/clean-code-discussion.



--
Regards,
Rodrigo Baron.
Reply all
Reply to author
Forward
0 new messages