Search code examples
phpoopdnsdatabase-abstraction

How To Handle Communication Between the Domain and Database Layers?


I am fairly new to using separate layers for the business logic (Domain) and database access logic, but in the course of working things out I've come across a problem to which I still feel I haven't found a great solution.

Clarification My existing solution uses Data Mappers to deal with the database interactions directly. However, as I've further investigated this issue many people have suggested that the Domain layer should not directly communicate with nor contain the Data Mappers that actually perform the database interaction. This is why I placed the Repository objects between the Domain and the necessary Data Mappers but this doesn't feel quite natural or correct. So the real question is what layer naturally exists to handle communication between the Domain and the Data Mappers? Any examples of how to structure it would be appreciated.

For example:

  • How do I properly handle retrieving a collection of domain objects within the context of another domain object?
  • How do I force the insertion of a single domain object or collection of objects based on an action performed against another object. The case I'm facing currently is that when a Person is attached to a Campaign, then I need to insert all of the Events that need to be executed for that Person for that Campaign.

Solution

  • Gabriel, this is called the "impedance matching problem." There are many solutions around, from heavyweight ones like J2EE entity beans to Ruby ActiveRecord to simply coding a hand connection.

    Update

    Okay, well, its hard to see exactly how to attack this without a lot more information, but here's the basic approach.

    Any of these sorts of architectural issues are driven by non-functional requirements like performance; in addition, there is a correctness issue here, in that you want to make sure updates are done in the correct order. So, you're going to need to think about the workload, which is to say the pattern of usage in real-world application. With that in mind, you basically have a couple of issues: first, the base data types in your application may not map correctly to the data base (eg, what's a VARCHAR property represented as in your code?), and second your domain model may not map cleanly to your database model.

    What you would like is to have the database and the dmain model work out so that one instance of a domain object is exactly a row of a table in your database model; in large-scale applications you can rarely do this because of either performance constraints or constraints imposed by a pre-existing database model.

    Now, if you completely control your database model, it simplifies things somewhat, because then you can make your database model more closely resemble the domain. This might mean the database model is somewhat denormalized, but if so, you can (depending on your database) handle that with views, or just not have a completely normalized database. Normalization is a useful theoretical construct, but that doesn't mean you can't relax it in a real system.

    If you don't completely control your database model, then you need a layer of objects that make the mapping. You've got a bunch of options to choose from in implementing that: you can build views or denormalized tables in the database, you can build intermediate objects, or you can do some of both, or even have several steps of both (ie, an intermediate object that accesses a denormalizaed table.)

    At that point, though, you run into issues with "don't repeat yourself" and "do the simplest thing that will possibly work." Think about what is most likely to change? Your domain model? If you've got a strong domain model, that's less likely --- the business changes relatively rarely. The exact representation of data in the database? A little more common. Or, most commonly, the exact patterns of use (like discovering a need to handle concurrent updates.) So, when you think about that, what do you need to do to make it as easy as possible to deal with the most common changes.

    I realize this isn't giving you very precise instructions, but I don't think we can offer precise instructions without knowing a whole lot about your applicaiton. But then I also kind of get the impression you're wondering about what the "right" way of handling this would be, while you are already working with something that more or less does the job. So, I'd end up by asking "what are you unhappy with now?" and "How would you like to solve that?"