I’m going to depart from the ongoing series on The Project and review a book I finished last week. That book is Applying Domain-Driven Design and Patterns by Jimmy Nilsson.
Upon hearing of the book, but before reading it, I thought that this is the book I should’ve read before beginning work on The Project. Some criticisms of Domain-Driven Design by Eric Evans are correct: while very interesting and technically sound, the Evans tome does not help you in specifying implementation guidelines.
This is where Nilsson steps in. The first chapter had me thrilled, as Nilsson touched on several problems, like OR/M mapping, lazy loading, and load graphs, problems which I had struggled with and overcame on The Project.
It also contained a rather crisp description of the Impedance Mismatch. It really demonstrated just how radically different OO and relational models really are. I didn’t consider the problem that drastic until reading about it in this book.
Test-driven development was also introduced in the first few chapters, and with quite enough detail. Nilsson explicitly states if a code snippet will flat-out not compile, and mentions this is SOP for TDD.
Nilsson also does something I like a lot: discuss several solutions to the problem. This mirrors the real world, where there isn’t one way to get the job done. You can guess why I liked this approach (see the four-part series on Domain-Driven Reports).
Another problem I encountered, and that was handled early in the book, was essentially how to specify parameters to methods in a Repository. Nilsson outlines three solutions:
- Filter within Domain Model: in memory, and Nilsson points out as impractical
- Filtering in Database with Huge Parameter Lists: this is what I did for The Project, with a bunch of optional parameters
- Query Objects: very intriguing, but thinking back to The Project, probably impractical to write a bunch of reflective code to translate between domain model member names and database column names
Regarding TDD: I did use NUnit on The Project, but I did not write tests before writing the code. Furthermore, I did not develop in a Persistent Ignorant way: when testing Dynamic Enumerations and my Repositories, I tested with either MS Access or SQL Server behind the scenes. Looking back, I think TDD and in-memory fake Repositories would have worked really great here.
The first section on domain-driven design brought me one of the parts I was looking forward to most: implementation of Repositories. I was made to wait, however, as the initial sketches and code were of interfaces and in-memory fake implementations.
When he finally got down to it, I was a little disappointed that he decided to introduce Unit of Work and Identity Maps before introducing NHibernate. It threw me off, thinking that Nilsson would wave his hands at the two patterns. A better approach would’ve been to introduce NHibernate first and then mention that NHibernate utilizes those the patterns. I was left thinking that a prospective developer on Nilsson’s example project would be left to implement the patterns themselves, or at least defer to yet another open source download.
Indeed, Nilsson talks about a fake implementation of a IWorkspace, which uses two levels of Identity Maps. Unit of Work is not mentioned, and code is not presented. This is an instance in which I would have benefited from having been “drag[ged] through the details”.
Another part that had me cheering was Nilsson’s discussion on the physical view of the architecture of the book-long example. This raised another issue I completely avoided during The Project: concurrency control. The Project had only SQL Server-supported concurrency control: if two users tried to edit the same equipment at the same exact second, or a user was logged in more than once and both logins tried to add new equipment at the same exact second.
That was it. So if two users loaded the same equipment, user A could make a change, save, and user B could make a change, save, and thus overwrite user A’s changes. Classic race condition. Truth-be-told, the situation outlined above is unlikely at best, and I definitely wouldn’t've received enough time to implement locking with no application server.
Had I even made an attempt at it, I probably would’ve tried to indicate that a row in the correct tables for an asset was “locked” on the client side, but that opens an entire can of worms such as: what if the user loses network connection to the server and the lock is never released? How do we implement time-outs with no permission to run executables on the server?
Nilsson’s sometimes-unreadable treatment of domain rules raises yet another instance where I went wrong on The Project: for most validation, I had single methods in the Application Layer that constructed error strings and passed them back up to the UI Layer in an event. I completely missed the boat on collections of rules and rules themselves as objects.
The introduction to NHibernate was welcome, though perhaps misplaced in the flow of the book. Whether I could have utilized this popular OR/M is debatable. At the time of the start of The Project, I was highly naive regarding the Impedance Mismatch. Much of the benefits of NHibernate would have been lost on me because I didn’t fully understand the problem to start with. I was even unaware that my manual implementation of one-column-per-class-attribute was the standard way most developer approach the problem. However I think I would try to put a tool such as Hibernate into action on a future project.
I thoroughly enjoyed most of the UI chapter. The section on “Test-Driving a Web Form” was difficult to read in parts, but that is probably because it is a difficult topic. Overall, though, I think Ingemar Lundberg did a fine job presenting it. I saw echoes of the very approach I took of flattening all the data the UI needs and sending it over as a “dumb” Data Transfer Object. I learned that outright flattening may not be needed in all circumstances.
The section on “Mapping and Wrapping” by Mats Helander was the best section in this chapter. Helander also did a great job in the section in the Appendix entitled “Object-Oriented Data Model, Smart Service Layer, and Documents.” I found echoes of my senior design project in the document-oriented separation of clients and server. The Smart Service Layer also reminded me of my own extensibility roadmap I wrote for The Project that detailed how future developers could migrate to an ASP.NET front-end.
There were some sections of the book, though, that leave more to be desired. Most of these sections, though, were written by guest authors:
- Claudio Perrone’s section on mocks and stubs: I get the stubs, but the mocks are explained using NMock. For readers without NMock experience, like me, this section is kind of a fly-by-faith section.
- Erik Dornenburg’s section on Inversion of Control and Dependency Injection: I followed the section until the Registry Pattern was brought up but highly muddled due to a poor code example. I am still looking for an outside-tool-agnostic explanation of the Registry Pattern. Oddly enough, my lack of understanding of Registry didn’t affect my understanding of the Service Locator. I also found the Inversion of Control section to be a little hand-wavey.
- Aleksandar Seovic’s section on Aspect-Oriented Programming: again, an outside-tool-agnostic example would’ve been much more illuminating for me.
- Ingemar Lundberg’s section on Pragmatism and the Non-traditional Approach: arguably the worst section in the book, not because of the topic but because of the way it was explained. Not quite sure what was said.
The first point at which I found myself disagreeing with Nilsson is in his section “Reconstituting an Entity from Persistence: How to Set Values from the Outside” where he proceeds to use reflection to set an OrderNumber field of a reconstituted Order object. He then factors this logic out into a Repository helper.
I think this is overkill. I understand that OrderNumber is private and unsettable by client code, because that is an accurate model of reality. Reflection, though, seems like a side-step at best to the problem. It is as if we are guarding against members of our own team from attempting malicious behavior by altering the OrderNumber field. Now, I was the only guy on The Project, so I may not appreciate this concern. But save that concern, I think making this field private and then engaging in reflection acrobatics might border on a distraction.
Nilsson also attempts to hook in a small amount of UI consideration into the initial example, though I think this was a little misguided. I had to postpone disbelief when I saw his UI code work with what looked like domain objects. Since in the UI chapter, he backs off on this approach, I think this section was better left for that chapter as possibly the “wrong” way of approaching the problem.
Overall, this is a very good book to complement Evans’ masterpiece because it provides the details that Evans defers to the situation.