Over the last week there’s been some really interesting discussion about the idea of an ‘Anemic Domain Model’ for some reason including rethinking the usage of DAOs. I find it a pretty strange concern, if you want me to be honest. I’m not sure I follow the logic of reorganizing tiers of your domain model just to satisfy this notion that every object MUST have logic in them. Here’s some background, most of this discussion refers to
this thread on TheServerSide which raises concern over having thin domain objects that are passed into DAOs for persistence instead of knowing how to persist themselves (ActiveRecord pattern, btw). The funny thing is the very first reply sums everything up pretty well by bringing up the analogy of a Cake (your anemic bean), an Oven (your persistence mechanism) and a Baker (which he says is the controller, I’ll get to that). In his scenario he asks the question, does a cake know how to bake itself? Of course not. I have a slightly different take on this example, though.
You have a bakery, it’s a service, which provides cakes, as well as cookies and bread and what not. Components that make up the bakery, like the refrigerator, the oven, the display case, the baker, are each part of different tiers that, when composed together into the bakery, provide services to return cakes, cookies, bread, etc. Lets look at that oven/persistence tier. What exactly is wrong with putting persistence code into it’s own tier now? Doesn’t that assist in making clean, cohesive components? If I put that logic into the Cake object, isn’t that muddying up the logic of the cake a bit? Personally I find the DAO approach to fit nicely into an organized persistence tier off my applications. And, of course, ColdSpring will assist in building that bakery. Just as a side note, in the TSS thread the consensus was quickly reached that the DAO example was a pretty bad choice. So what was the issue again? Oh yeah the thin business objects.
This is an argument that has been going on in the Java world for a while now. It’s against using transfer objects, because they don’t actually have any real business logic in them, so they’re not a real objects. I guess it could be said that this is contrary to the basic ideas of object oriented design, ok I guess Martin Fowler can say that. Rod Johnson, the creator of Spring, also warns against writing objects that only contain methods to expose their data, as they are not actual objects. But lets look at this. This is a Java issue. Java has no lightweight typed objects. C# solves this by providing an excellent Struct implementation which is really a lightweight typed class. So when you ask for the ‘name’ you get a String back. Quite different from Java’s alternative, various types of Maps, which all return Objects back, so casting is necessary. For many purposes, using a bean is a better alternative to a map, because getters return data in the correct type (this is addressed with generics in java 5). But wait a second. ColdFusion. Don’t we have a Struct? Of course we do. Any we are dynamically typed, so the casting issues are not a problem. So if transfer objects are such a problem, why not use Structs, right?
But wait. I don’t think we’ve really looked at the issues here. There’s more to consider. Typing IS an issue. We need to validate types when putting data INTO transfer objects, we want numbers to be numbers, not strings, just for a simple example of why, consider this. We pass a struct into a gateway object to retrieve all users of typeID=6, our where clause looks like this: WHERE user.typeID = #myStruct.type#. But some wily hacker comes along and figures out how to set that value to ‘truncate table user’. Whoa, hold on! That’s like uh, SUPER BAD! Certainly having a numeric type enforced on that data could have really helped here (any yeah I know, queryparam could help, but that’s not my point). I could have also built a validate method in either the TO or validator object which could have been used by some service object before even attempting to send the TO to the DAO. The point is that even though beans / TOs have little logic in them, their use is a part of a bigger picture, which makes up business logic. I have a novel idea that beans and transfer objects are actually part of architectures which represent logic by design. Isn’t that a huge part of OOP anyway? Complex logic is often represented by the interactions of the objects that make up our domain model. Some of those objects are going to make up our Persistence tier. Some of them are going to make up our Service tier. Some of them are going to be Domain Objects and represent our primary business (we sell books, so we have book objects). And some of those objects may very well be lightweight objects, but they assist in clear separation of our logic, they assist in typing and data validation, they may model forms from our view tier, etc, etc. Are they second class citizens on our domain, no way! Embrace the Bean!