Don’t ever, ever build domain objects that can’t…

…run without the database — Active Record implementations like Trade trade = new Trade(“tradeId”) where the constructor immediately reaches into the database to grab the rest of its properties.  One of the reasons that I won’t use the Entity Framework by choice is the lazy fetch implementation:  invoice.Items.Load().  I understand their reasoning for doing this, but it totally screws up unit testing.


…run without a configuration file — Extra stuff that has to be copied around and valid for the code to work


…run without needing half of the rest of the application — “Trade trade = new Trade(“tradeId”, tradeRepository)” is no bueno


…be at least partially set up in a few lines of code — An ObjectMother can help tremendously.  Yeah, an ObjectMother is often times deoderant, but still…


 


 


and just for any Java folks that might have stumbled into this accidentally.


…run without some sort of heavyweight container*


But Jeremy, I just needed to “Git ‘R Done!” and I don’t have time to worry about ivory tower things like separation of concerns!  Careful design *is* pragmatic.  Keeping service and infrastructure concerns out of your domain objects should help in the “Git ‘R Done” category, because:




  1. Your business logic lives in the domain objects.  It’s more efficient and safer to be able to work on domain logic without other services getting in the way.  I want to write and read code that works with domain concepts.  I want to work on one thing at a time, and in this case that one thing is domain logic.  More signal and less noise makes it easier to verify the business logic code by inspection, which is good considering that that code is very likely to change.


  2. Much of the rest of the system reacts to and interacts with your domain objects.  When I’m working with a controller class or a repository class I want to develop and test those things without incurring a heavy tax from setting up connected domain objects with whatever container.

 


 


*Of course, the great thing about being in .Net is that the Java guys bump into most of the problems first since they’re always a year or two ahead.  Just pay attention to what causes the Java community pain and avoid it when some clown tries to introduce the pain into .Net. 


 

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Featured, Ranting. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://colinjack.blogspot.com/ Colin Jack
  • http://colinjack.blogspot.com/ Colin Jack

    Agree on most of this, really good post.

    Having said that you will find lots of people who do seem to have their domain depend on infrastructure (see http://tech.groups.yahoo.com/group/domaindrivendesign) but I don’t advocate it. Thats why I completely avoid DI in my domain classes, if I do NEED a dependency from the domain to infrastructure (or a repository) I use a ServiceLocator/Registry approach and plan to try to remove the dependency as soon as I can.

    There are situations where you do have to access infrastructure along with doing domain work, for those situations I use a THIN layer above the domain layer to handle talking to the things that we don’t want the domain to be dependent on (infrastructure and other domain models being two examples). I call that layer the coordination layer (http://colinjack.blogspot.com/2007/02/domain-coordination-layer.html), its basically SERVICE classes that depend on other domains/infrastructure and that I thus want to keep out of the main domain assemblies. Not perfect but it isn’t too bad.

    I’m not completely sold on the generic “create the assocation from the one end” answer, that sometimes works and sometimes doesn’t. Order to Customer, fine. But thats not going to work in all cases and designing associations to make them easier for your ORM to manage isn’t going to result in a great domain model either.

    On the ease of setup, your right but equally the domain enforces constraints and even if that makes testing harder it still needs to be done. If your Order needs to have three things passed to its constructor, for example, then thats the way it should be designed and your ObjectMother should take care of it for the tests. I do think that testing gets harder with a domain model (especially when the domain objects have lifecycle/states). However most of the time the tests use the domain objects in a way that isn’t the way applications will use it (e.g. create a Client in state X, put an Order in state Y onto it, try to transition the the Order to Active….). I’d say Eric Evans makes good points in this post: http://tech.groups.yahoo.com/group/domaindrivendesign/message/5683

    I also think state based testing of the domain is the way to go.

    @Tobias – That is exactly what we do.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    Bil,

    All I really meant is the ability to execute and unit test the business logic with the database turned off. Unit testing for one, and higher reuse potential for a second reason.

    The side argument was whether or not Invoice(id, IInvoiceRepository) was good enough. Me coming down on the side of this not being that great and unnecessary and others saying it was perfectly fine and necessary.

  • http://weblogs.asp.net/bsimser Bil Simser

    Something is bugging me about this post. “Don’t ever build domain objects that can’t run without the database”. I like to think I live in a PI world when it comes to my domain objects. After all, if I don’t have a database behind my domain objects, it let’s me question why they exist. Let me turn that around. If I have a domain object that’s tied to getting it’s data from a database, I would consider that a smell that my “domain object” really is just a data container or something. To me, domain objects are defined by behavior not data.

    Personally I build out entities based on requirements and tests. At some point we need to get collections of them so that’s what aggregate roots are for and eventually a repository or service that will abstract away persistence from my entities. Grant you, if I’m using NHibernate I end up tweaking my entities so they can work with the mapper (default constructor, virtual, ids, etc.) but it’s a small price to pay to simply say CustomerRepository.Save(customer) and doesn’t require me to have some crappy infrastructure call inside my customer (like customer.Save or customer.Load). To me, ActiveRecord is for apps where I don’t care about the domain but then for those type of beasts I would do the simplest thing possible until the customer needed some business rules around it.

    Maybe I don’t get it, but I don’t agree building domain objects that can’t operate without a database. That’s not my domains job. Or did I miss something here?

  • Gerry Lowe

    Joe

    I don’t agree with Jeremy re. the need to remove repo knowledge from your business (domain) objects. I think lots of business rules/logic often requires access to the “context” within which the BOs operate (e.g. get some related objects from the repo, get the current datetime, send an email etc).

    I think it’s fine for each BO to be able to access this “context”, provided it does so through clean interfaces which can be easily stubbed/mocked when testing the business logic in isolation.

    So, for example, the root superclass of all your BOs could hold a Context object, which itself could hold any interfaces you desire (data mapping/nhibernate, sending email etc). These dependencies can be set up appropriately depending on whether you’re unit testing etc.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    Joe,

    Wouldn’t that particular case be better to do by modeling a “to-1″ relationship from Order to Customer and getting that data like:

    IOrderRepository.FindByCustomerForDataRange(customer, dateRange)

    Or using some sort of query object as the arg.

    In that particular case I don’t think I would have a navigable relationship from Customer to Order.

  • Joe

    Jeremy

    Do you think you might be able to set up a quick example to demonstrate this? I just don’t see a way around some instances such as “Customer.LoadOrdersForDataRange” where i need to access data dynamically.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    Joe,

    It’s really not that hard to avoid needing a connection to the db for any reason in your domain classes. If you need lazy loading from parent to child, just use a virtual proxy or a ghost in place of the child.

    I don’t want Trade to know about ITradeRepository either.

  • Joe

    “run without needing half of the rest of the application — “Trade trade = new Trade(“tradeId”, tradeRepository)” is no bueno”

    How do you design to avoid that? Is it as simple as substituting tradeRepository for ITradeRepository and passing in a “dummy” implementation, or do you have a way of designing your domain objects so they never need to access data from a repository?

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @jdn,

    Gotcha. It’s all about the feedback cycle for me. Small, fine-grained unit tests on the domain objects that are probably mostly state-based. Then interaction based unit tests on the controller/presenters (and maybe views). Then integration tests with the partial stack. My philosophy/theory is that it’s cheaper to eliminate as many problems as possible with unit tests before moving on to bigger integration tests — but you always do do the integration tests.

    @Evan,

    Agreed. AR in Ruby is a different ballgame. Part of it though is how easy they made it to set up test data with Fixture’s. I’m wondering though if some of the “we don’t need no stinkin’ referential integrity” attitude coming from the RoR camp is related to the negative consequences of tying their domain model so tightly to a database schema.

  • http://www.evanhoff.com/ Evan

    I can sum up your griefs with a single principle..

    the Domain Separation Principle

    And let’s remember that we are only talking about the statically typed world. ActiveRecord in a dynamically typed language (ie..Ruby) is a whole other ballgame.

    ;-)

  • http://www.e-Crescendo.com jdn

    Jeremy:

    No, I’m fine with all that. I’m doing a POCO/nHibernate project right now, and have separate Domain tests from Persistence tests and whatnot.

    I’m just wondering at what point you ‘glue’ the concerns together.

    If my presenter calls into my persistence, there’s a dependency there (even if you DI it all out, you can’t completely divorce all implementation details out of the interface….it has to do something).

    I could ‘pass-through’ the Domain layer (which I prefer), but that just moves the dependency around.

    Which is a fact of life of course. But you can’t have pure separation of concerns, at least as far as I can see, since the pieces have to connect at some point in order to do anything (in the same way that the best way to make a SQL server secure is to disconnect the network cable, disconnect the keyboard, heck, power it off…you just can’t use it then).

    Then again, I think ultimately the integration tests are the most important, since I’m a data guy, so what do I know .

  • http://blogger.forgottenskies.com Steve Gentile

    Thanks for the responses. I do test the dao layer right now by some code I wrote that will attach/detach an sql express database file, run the test, etc…

    I do try to run those in a different set of test than the others. But it’s good to hear that is what others are doing – I’ve always wondered if it ok to do :)

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    jdn,

    I think you might be misunderstanding the issue. I don’t see any problem with the UI Controller/Presenter’s calling directly into the service layer or even the persistence layer in simpler applications. The underlying goal is just to have domain objects (or Model objects in the UI) that are simple to set up.

    The root issue is that I’ve found that there’s a very strong corollary from the ease or difficulty of domain object setup and productivity when working with a legacy system. The harder it is to set up test cases, the slower that development goes.

    That doesn’t entirely rule out Active Record approaches by the way. *I* don’t care for AR personally, but you can still do it in such a way that you don’t sacrifice testability by coupling too tightly to the db. You just have to leave yourself a pathway that allows you to construct the objects in a completely disconnected mode without the database or web service or active directory or whatever hanging around.

    Simply ask yourself these questions:

    * Can I test my business logic in isolation from persistence and the UI?

    * Can I test the View behavior without the persistence?

    * Can I test the persistence in isolation from the UI?

    * Can I test from the service layer down?

  • http://www.e-Crescendo.com jdn

    How do you save your domain objects from the Presentation layer without calling the Persistence layer directly?

    Seems like there are many different ways to layer, and each has significant drawbacks.

  • Gerry Lowe

    Steve

    Pushing the separation of concerns a little further should solve your problem.

    You’re right, you want to test your mapping files. You can do this simply by pushing your objects through the nhibernate session api, and verifying that you get the correct results (new/updated/deleted rows in database, correct business objects returned by nhibernate query). Call these “persistence unit tests”.

    But this type of functionality (and test) should be entirely separate from your business logic. So business objects which need to access the database should do so via an api which you can easily stub/mock. Your stub/mock will behave however you desire. Call these “business logic unit tests”.

    So – business logic can be tested without a database, but you can be confident that things will behave correctly when the code is integrated, due to your persistence tests.

    Gerry.

  • Tobias

    @Steve: I’m working with NHibernate for quite a while now. I have two different levels of tests for my domain objects. One that tests the domain objects persistence behaviour (mapping), and one that tests everything else. The persistence tests run directly against the database, which even with hundreds of tests still runs fast enough. The other tests just care about business logic and dont’ need a database at all, if you follow Jeremy’s advice.

    The DAO / DAL classes are also tested directly against a database. When testing stuff that depends on the DAO / DAL layer, I simply mock IDal or whatever interfaces are used.

    To make the tests, that run against the database, fast and independent of external configuration or external database servers, I use an embedded FireBird DB with auto generating the database schema.

  • http://blogger.forgottenskies.com Steve Gentile

    I agree and have a question:

    My domain objects don’t call the database. I have a Dao layer.

    ie. TradeDao, which has a TradeDao.GetById()… and returns a Trade object.

    In this case, the GetById of TradeDao uses a IDao GetById.

    TradeDao is inherently dependent on the database – although I could mock out the IDao and return a pre-filled Trade object without going to the database. Does that follow separation of concerns?

    At the same time, I’d want to validate my mapping files (I use NHibernate), and calls are actually getting data from the data base. How is this test to happen?

    At some point in time I want to validate calls are correct. ie. in some of my save() calls with NHibernate I’ve discovered mapping file errors in my tests that have helped me uncover the problem.

    Good stuff though, I agree and want to work toward separation of concerns as much as possible.

  • http://blog.magenic.com/blogs/aarone Aaron Erickson

    You know, I agree with you.

    For years, I didn’t do this, and leaving testability aside for a second – found that lack of seperation of concerns simply cluttered up the design.

    The amazing thing is that once you get in the habit of seperating concerns, it really isn’t any more work to do so. Trust me – I am as “get-r-done” as anyone, and I use IoC in every current project I am involved with, if for no other reason, I want to be able to attach my framework of choice to my business logic down the road, and I don’t want a lot of crud around that would make that painful.