The boundary is not arbitrary or artificial. The boundary comes back to the reasons we were actually creating a domain model in the first place. it seems what Oren is actually arguing against is not whether “advances in ORMs” have changed things but that he questions the isolation at all. The whole point of the separation is to remove such details from our thinking when we deal with the domain and to make explicit the boundaries around the domain and the contracts of those boundaries.
As I understand Greg’s interpretation of my points, I agree. For quite a few needs, there is no need to create an explicit boundary between the persistence medium and the code. Transparent lazy loading and persistence by reachability allow us to hand the entire problem to the infrastructure. The two things that we have to worry about it controlling the fetch paths and making sure that we aren’t doing stupid things like calling the database in a loop.
Those things are the responsibilities of the controllers layer (not necessarily an MVC controller, by the way, I am talking about the highest level in the app that isn’t actually about presentation concerns).
If we take Oren’s advice, we can store our data anywhere … so long as it looks and acts like a database. If that is not the case then oops we have to either
- Make it look and act like a full database
- Scrap our code that treated it as such and go back to the explicit route.
Just to be clear on this point … He has baked in fetch paths, full criteria, and ordering into his Query objects so any new implementation would also have to support all of those things.Tell me how do you do this when you are getting your data now from an explicit service?
Well, duh! Of course they would need that. We need to be able to do that to be able to execute business logic. Going back to the example that I gave in the previous post, “Add Product” and “Charge Order” have drastically different data requirements, how are you going to handle that without having support for fetch paths?
The last statement there is quite telling, I think. I thought that my previous post made it clear that I am advocating doing this inside a service boundary. The problem that Greg is trying to state doesn’t exist since you don’t do that across a service boundary.
Its not just about YAGNI its about risk management. We make the decision early (Port/Adapter) that will allow us to delay other decisions. It also costs us next to nothing up front to allow for our change later. YAGNI should never be used without thought of risk management, we should always be able to quantify our initial cost, the probability of change, and the cost of the change in the future.
I call bull on that. Saying that it using an adapter cost “next to nothing” is wrong and misleading. Leaving aside the problems of trying to expose the advance functionality that you need aside, it also doesn’t work. A good example would be using a repository using NHibernate, which take part in a Unit of Work and uses persistence by reachability and auto flush on dirty.
Chances are, the developers aren’t even aware that they are taking advantage of all of that. Trying to switch that with a web service based repository introduce quite a lot of friction to the mix. I know, I was there, and I saw what it did.
That is leaving aside things like how do you expose concurrency violations or transaction deadlocks using different persistence options. You need to control that, and an adapter is generally either a very leaky abstract or a huge effort to write, and it is still leaky. Worse, using an adapter, you are forced to go with the lowest common denominator for features. Of course you would want to isolate that, you are working at a level so low you might as well be writing things to the disk without the benefit of even a file system. That doesn’t mean that this is the smart choice.
Trying to abstract things away unless you have a firm requirement is just about the definition of YAGNI. And handwaving effort required to build this sort of infrastructure doesn’t really make it go away.
Yes, the approach that I am advocating makes a lot of assumptions. If you remove any of them, the approach that I am advocating is invalid. But when the assumptions are valid (inside a service boundary, using a database, using a smart persistence framework), not making use of that is… stealing from your client.
Arguments against my approach should be made in the context that I am establishing it.
Let me point out a large failure in logic here. You assume an impedance mismatch with a relational database that results in a much higher cost of getting the children with the parents. If I am using other mechanisms like say storing the ShoppingCart as a document in CouchDb that the cost will be nearly identical whether I bring back only the Cart or the Items.
Again, I am talking about something in context. Taking it out of context make the argument invalid. I am going to stop here, because I don’t think that there is any value in parallel monologues. Arguments against the approach that I suggesting should be made in the context that I am outlying my suggestion, not outside it.