More thoughts on domain models
I wanted to write this down, because while "important" may overstate the case a bit, it occured to me that two separate threads of thought had converged into the same thing.
Thought number one I first heard at Jimmy Nilsson's software summit in Malmo. Mats Helander said this radical thing that floated like a lead balloon, at least in my mind ;-) He has elaborated greatly here. He said then that there should be no business logic in the domain layer. Of course he also meant this in the context of what a O/R mapping tool should provide. Translation, don't expect your mapping layer to implement your business logic. Makes sense. And, O/R tools make the manipultion of entities easier. In reality, the manipulation of entities is easy enough for generated logic to do. It's tedious to do by hand, and many people are happy with the "domain layer" that O/R tools assist in developing. Responding to his more recent comments I will probably take up later.
Thought number two was something that hung on from my blog about Clemens Vasters shot across the bows. If property setters and getters are weak toolage in the developers toolbox, what remains of the domain layer? In that blog, I said that that it was the assembling of business logic into a domain layer that remained of value. And that if this was done dynamically, it would be much more powerful.
Fast forward and combine these two ideas. You move from the idea of hand coded, statically typed domain objects containing state and behavior, to entities produced by generative techniques combined with dynamically constructed domain objects assembled for each use case, all dynamically typed. OK, that's a mouthful. So, one at at time.
- Statically typed domain objects - code you write and compile. It is code that has properties, methods and usually state. What's most important is that it lives as it was compiled, hence static.
- State - "Global Variables" that are only applicable within your class. Remember when global variables were evil? All the reasons given for not using global variables apply to class member variables, so by calling it state, you sound smarter but still have to worry about the same things. State is most often the data your class works with as a whole.
- Behavior - The code that does something in your class, usually manipulating the state (data)
- Entities - Things, nouns, data are all part of the term's definition. It usually refers to data though and is represented in a database as a set of closely related tables
- Generative techniques - Code that writes code! These techniques include the code generation of an O/R mapping tool, model driven developement tools, IDE tools like Resharper and Codesmith, and things you write for your own frameworks
- dynamically constructed - The statically typed domain object has all it's workings written in code and compiled in. With the use of delegates, events, and patterns like decorator, factory, visitor and memento, you can assemble the data and behavior "on the fly" as the object is put together.
Put it together and you have a persistent entity assembled into a domain object at runtime.
But in the end, you end up another "tool" to solve programming problems. Inversion of Control (IOC) is the name given to this approach I think. Unfortunately, it doesn't automatically answer the burning questions we all want answered, "how do I organize all this code?" I think the answer is probably something that would look like this: for any single thing I have to accomplish (perhaps use case), I want to see a simple solution. If my framework provides this, I can do much more complex things and still feel simple. OOAD, as envisioned with a clear simple one layer domain model, promised to deliver that simplified view, but I think it's clear that it doesn't scale up very well to large problems. The techniques I mention here and elsewhere along with many friends, can help scale up the complexity and perhaps hit a larger number of problems. AOP research has put more formalization on the process by helping to identify and isolate those things that do and don't make sense in a single object, but still apply code to problems at the right times. In the end, maybe AOP will be looked at as a framework building tool more so than a programming tool. And that is precisely what we need. OO offers good programming guidance, but framework guidance is really not a great strength. We keep trying to shoehorn problem domains into predetermined framework architectures, and we end up fighting the framework at every turn! If after all this time, we can't really say how to solve some really commonplace large problems without mountains of provisos, qualifiers and small print, perhaps we need to exand our view to look for new and better techniques.
It just feels like we must be using the wrong techniques if we always end up with the same problem when we are done.