Defending my project architecture
Today in a meeting we had a big debate about project architecture, anemic domain models, SOA, and other kinds of good stuff. Seeing that I was in the minority arguing against lots of really smart people I should answer the call and defend my ideas. :)
The question that started the discussion was, “Does SOA lead to the anemic domain model anti-pattern?” This issue has been debated in the altdotnet forums recently.
First, a little about the architecture of my project. We are writing a Windows Forms app that talks to a middle-tier using WCF and then saves to a SQL Server database. Our layers go something like this:
User Interface (controllers, views)
Service Agent (helps controllers talk to web services)
—- service boundary —-
WCF services
Business Logic
Data Access (LINQ to SQL)
————————–
SQL Server
LINQ to SQL generates all of our entity objects and these entity objects are used on both sides to the wire. Our web services are not exposed to the public and our Winforms client is the only app consuming them.
Here are the issues that people have with this:
Sharing the entity objects on both sides of the wire violates SOA tenets because it introduces tight coupling between server and client.
Sharing the entity objects on both sides does violate SOA tenets. But in our case, what we’re doing is not SOA! Wikipedia defines SOA as:
Service-Oriented Architecture (SOA) is a software architecture where functionality is grouped around business processes and packaged as interoperable services. SOA also describes IT infrastructure which allows different applications to exchange data with one another as they participate in business processes.
Notice the part about applications exchanging data with one another. We are not exposing our web services to anyone other than our client. We have total control of both sides of the wire. Just because I’m using web services in my app does not mean that we have a service oriented architecture! So why should I create different entity objects for each side of the wire along with DTOs and translation classes? What benefit does that give me?
Sure, sometimes you add properties to entity objects just to help you display something in a grid. And sometimes you have properties on an entity that you will never need on the client side. And theoretically there is a situation where you may want your entity object on the client to be structured differently than they are on the server for some reason. But are any of these good reasons to create new layers and create more code that I have to maintain?
I’ve worked on projects that have had separate entities for the client and server (with DTOs and translation in between). This was quite painful. Every time I had to add a new entity object with corresponding services and UI screens, I had to add 13 files to the project. 13 files!! This was before I even wrote any unit tests. I spent more time writing plumbing than anything else.
One day when I was working said project I picked up what looked like an easy bug. I had to add 2 fields to a database table and then add them to a screen. No fancy logic, no validation. It took me 20 minutes! All I was doing as was adding two properties to a screen! These types of things should be easy.
On my current project, things go much faster. I can drag my database tables onto the LINQ to SQL designer and immediately I have my entity objects created and I can load and save them to the database. I can immediately go and start writing code that has business value. I have to create 4 fewer classes for each entity now (no client entity, no DTOs, no translation code). I’m not hand-writing my entities and mapping files because these are generated for me. Sure, they’re not true POCO entities (although you can do this with LINQ to SQL if you don’t want to use the generated code), but I don’t think that it’s worth throwing away the generated code just so that I can write my own POCO entities (read: plumbing).
There are some cases where we still need DTOs to load and save data in complex situations, but we don’t spend the time doing it until we need to.
Like I said before, all of my web services are only consumed by our client. If another application or someone outside of my team wanted to consume my services, I would create a new service and use DTOs and translation so that I don’t tightly couple my domain model with outside consumers. Now I’m doing true SOA! But I don’t spend the time doing all of the extra work until I need to do it.
Because LINQ to SQL generates our entity objects and we use these throughout the app, we don’t have a rich domain model and our entity objects map one-to-one with database tables.
Sure, I admit that having entity objects map one-to-one with database tables isn’t always “ideal”, and LINQ to SQL doesn’t handle many-to-many relationships that well. But honestly, it’s not that bad. This doesn’t always sit well with the Domain Driven Design crowd, who say that you should start by creating your business objects and that the primary focus should be on the domain and domain logic. Certainly these are good concepts, and I’m not saying that DDD is a bad idea at all. If we were using NHibernate instead of LINQ to SQL we could make our business objects more like business objects and less like database tables.
My point is this — there are situations where Domain Driven Design is good (complex domain designs). But keep in mind that the goal is to deliver a working piece of software (that is testable and maintainable and all that). No one will care that your business layer is super-elegant if you don’t get done on time. In that case, my “good enough” business layer trumps the more elegant business layer that took longer to develop (in fact, I’d guess that with DDD you would still have the majority of your business objects map one-to-one with database tables anyway). Remember, the architecture is not the deliverable.
The business objects do not have any behavior in them, all of that is in the business logic layer (the anemic domain model anti-pattern), and this is not good object-oriented design.
Yes, the fact that my business objects don’t have the logic in them is an example of the anemic domain model pattern. You got me on this one. But really, how bad is this? Sure, you don’t know to look for GetOrdersForCustomer() in the CustomerLogic class or the OrderLogic class. But what’s the worst that can happen? Someone writes the code to fetch this stuff twice?
While I would love to have the business logic encapsulated in my business objects, I also don’t want to send all of the validation rules and server logic over to the client, and I don’t want to switch to DTOs and client entities just to resolve this problem. So I’ll live with the anemic domain model for now. Honestly, most of the complaints I’ve heard is that it’s annoying to have the logic in separate classes, but I haven’t heard anyone say that it flat out doesn’t work.
In summary…
Remember, what is our goal — to deliver a piece of software on time, that meets the business needs, and is maintainable. On my current project, we delivered on time (our first release was done a month ahead of time), we were able to spend more time writing code that meets a business need (vs. writing plumbing), and our code is quite maintainable in my opinion (18 different developers have worked on it, and we just wrote our 3000th unit test today). Obviously, I cannot take most of the credit for this because the people writing the code are the main reason for the success. But I like to think that the architecture that we’re using helped us do it.
Discuss!
Wow, missed out on that discussion….. I’m with ya Jon – in this particular case, I think that the model being used helped get the project complete on time, however it can be said that future developers on the project could end up getting lost in the forest, even if it is a small one.
In the attempt to analyze and nitpick and say “what hurt, and what can we do better”, it gets easy to criticize. Let me express my congratulations for a successful first release, and many more to come. You’re right – success and business value trumps “ideal design” any day.
On the anemic domain…
I have found this topic very interesting to study over the past few months, and I’ve found a lot of people doing the anemic domain successfully. But for me, it all comes back to what is tried and true, and what I value.
Object oriented principles offer all kinds of benefits that naturally lead you into “the pit of success” (I hate that phrase, but it seemed fitting). More importantly, writing good classes alleviates the most important problem with software: complexity.
As McConnell says “design is a wicked problem” … a delicate balance of forces that are in opposition. My only goal in providing feedback is to spark dialog and creativity to these hard design questions – so we can get better at what we do.
To be honest though, this discussion would be better sitting at a round table with a beer in hand :) Let me know when and where.
>> Sure, sometimes you add properties to entity objects just to help you display something in a grid. And sometimes you have properties on an entity that you will never need on the client side. And theoretically there is a situation where you may want your entity object on the client to be structured differently than they are on the server for some reason. But are any of these good reasons to create new layers and create more code that I have to maintain?
I would ask, why should your domain entities care about presentation concerns? And why should your presentation objects care about domain logic? These are orthognal concerns. So in an effort to keep the system MORE maintainable these orthogonal concerns should be kept… well, separate. (see: Separation of Concerns)
>> On my current project, things go much faster. I can drag my database tables onto the LINQ to SQL designer and immediately I have my entity objects created and I can load and save them to the database. I can immediately go and start writing code that has business value.
Drag-n-dropping of tables to generate entities is very typical in data-centric approaches. But, does “time savings” gained by mapping your entities directly from the persistence mechanism really mean you’re delivering more business value? Does your database really model the way the business works, or more importantly, the way the business wants to work? How much value is lost in missed opportunities because you’ve now artificially tied yourself to a sub-optimal, relationally constrained, model… a model that does not translate well to object oriented code?
We need to forget about the database for a bit and instead work with the domain experts to come up with a shared understanding of how to model the domain. That model will of course be wrong, but by working with the domain experts to continually refine our the model we can eventually get closer and closer to a true representation of how the business works… meaning we can more accurately deliver the value the business really needs.
Of course, what I’m talking about is nothing new. I’m just rehashing many of the ideas promoted by DDD, as you’ve mentioned.
You’ve said that DDD makes sense when dealing with complex domain models. And knowing what I do about your particular project, I’d say it is a complex domain. And the point of DDD is not just to create a “super-elegant business layer” – it is to build a well understood model of a complex business domain, allowing you to deliver more value. The point is to allow you to focus on the core competencies of the business… the things that make the business unique, b/c thats is where real value will be found.
As to the question of the Anemic Domain Anti-Pattern – sometimes just passing around bit-buckets makes sense… but when dealing with complex domains, why not do what OO was designed to and try to model the domain and encapsulate the complexity? We need to get back to our OO fundamentals.
First, I don’t think anyone was trying to skewer the architecture of your project! Your successes speak to themselves, and you certainly shouldn’t feel a need to defend your choices.
Secondly, all this discussion is absolutely healthy. We need a pragmatic mindset when choosing our approaches to these sorts of problems — and it’s absolutely not black and white or a simple decision in most all our projects.
Speed to market, maintainability, flexibility, clarity. Nice things to think about, often hard to bundle all together at once.
FWIW, I think the success of your project is testiment enough to the validity of the approaches you took.
Oh, I’m enjoying working on this architecture MUCH more than on some of the past projects. I think that our time to deliver was drastically reduced, and that we’ve accomplished more work for the client in the same amount of time than we could have hoped for in a “pure” architecture. If the DDD zealots want to burn me at the stake for heresy, then so be it.
On the other hand, I see things that ARE accomplishable, or that just rub me the wrong way personally. In the past three projects, I’ve never liked the fact that all our business knowledge seems to reside outside the entities, which to me are the only logical place for that knowledge to be. In my mind, the Client class should the end-all authority on all “Client-y” things.
Persistence ignorance? Who cares? It’s a goal, sure, but not one to sacrifice the rest of your project for. On my first project for Quick I saw it pay off, big time, when they switched from Oracle to SQL Server over the weekend, and I didn’t even notice on Monday morning. That’s awesome… it’s also the only time I’ve ever seen it happen in 15+ years of doing this stuff. Very cool, but it’s like Haley’s comet… you MIGHT live to see it pay off once in your life… maybe.
I’m fine with Linq to Sql entities not being persistence-ignorant, so long as I’m doing my work in the other half of the partial class. It’s not “pure”, but I can pretend that the other half of the class isn’t there, and go about my business. It’s not perfect, but it’ll do for now. I’d much rather have some sophisticated mapping like NHibernate, but not until it is as easy to maintain as Linq to Sql is now. Maybe the Entity Framework will get us there, maybe not, we’ll just see when it’s released I guess.
So yes, I see all the points, and they’re all valid. In a world with an unlimited budget and timeline I would absolutely opt for the architecturally correct way of doing things. We don’t live in that perfect world of endless green fields, though. Our fields are brown, and customers want results NOW.
@Steve Harman,
>> I would ask, why should your domain entities care about presentation concerns? And why should your presentation objects care about domain logic? These are orthognal concerns. So in an effort to keep the system MORE maintainable these orthogonal concerns should be kept… well, separate. (see: Separation of Concerns)
I agree, but is it worth the time to create separate entities, DTOs, and translators to fix this problem? You could say this about a web app too (that’s not using web services), but you wouldn’t make separate entity objects in that case.
About DDD… I think this is a good example of what Alexei was saying when he said that everything depends on the business situation. Because if we were doing our current project from the ground up, you’re exactly right, we have a very complex domain model and DDD would be the correct way to go. In our case, we were stuck with a database structure and had to live with it, so I think the way that we did it made sense (LINQ to SQL somewhat constrained us vs. what we could do with NHibernate).
In an attempt to analyze and nitpick and say “what hurt, and what can we do better”, it gets easy to criticize. Let me express my congratulations for a successful first release, and many more to come. You’re right — success and business value trumps “ideal design” any day.
On the anemic domain…
I have found this topic very interesting to study over the past few months, and I’ve found a lot of people doing the anemic domain successfully. But for me, it all comes back to what is tried and true, and what I value.
Object oriented principles offer all kinds of benefits that naturally lead you into “the pit of success” (I hate that phrase, but it seemed fitting). More importantly, writing good classes alleviates the most important problem with software: complexity.
As McConnell says “design is a wicked problem” … a delicate balance of forces that are in opposition. My only goal in providing feedback is to spark dialog and creativity to these hard design questions – so we can get better at what we do.
To be honest though, this discussion would be better sitting at a round table with a beer in hand :) Let me know when and where.
Let me start by saying that I in no way feel you need to “defend your project architecture”… no one was or is attacking it. We (and by “we” I might just mean “I”) am only trying to discuss some of the pains felt when working with said architecture.
The point is to keep improving. And we do that by uncovering a pain point and then addressing and alleviating it. Then we lower our pain threshold just a little more, find the next pain point, and work to alleviate it, continuing ad nauseam.
Rather than taking those bits of feedback as an attack, look at them for what they are – real people giving real feedback about what caused them pain. Then address those pains and move forward. The goal is perfection – but we can only hope to get there through continuous improvement. :)
@Steve Harman,
No offense taken. I’m always up for a good debate and I’m always open to changing things. I just wanted to say my side of the story.
Just came across your post here. I want to reinforce many of the decisions you’ve made here because we are beginning to make similar decisions. After being in the trenches for a few years with a highly abstracted model, we are now moving to a singular model. The practical costs of a highly abstracted model are just too high in many cases when you actually have to do the work and aren’t just commenting in blog posts. I will say that we are moving away from an anemic model however and moving as much entity self-awareness logic into our partial classes as we can. If business logic needs to exist that crosses entity boundaries, then we’ll spin up new service classes to handle those integrations. Also, if we need a class that doesn’t map well to a data table, we simply create it – almost all of our grids map to custom classes this way that are fed from stored procedures. The point is that the DDD zealots don’t address much of the pain that real development incurs from having to create tons of new files just to get a new piece of information onto the screen, or the maintenance nightmare of having to edit a ton of files just to do something really simple. Almost every change to the database actually DOES require a change all the way through an app vertically. Why else would you be changing the data model? It’s very rare that the dba’s need to totally re-work something just because they want to and not for a change driven by business need. I totally agree with the Haley’s comet comment. DDD causes all developers to incur at least a 15% increase in ALL development cost just to handle 5% of the scenarios that really benefit from it. I feel it’s a more pragmatic approach to leverage the fact that most of your domain really does indeed map closely to your data model. In the few cases where it doesn’t, make custom classes and use procs. Don’t hold one pattern back by forcing all scenarios to go through the same pattern. If you have a rare case where your most common pattern doesn’t fit, just divorce it. As long as your entity interfaces look similar, everyone will be happy.