In this issue of
MSDN Magazine, we focus our attention on topics related to best practices in software design. This theme is a personal favorite, because good design practices are ubiquitous across all sub-specialties of software development. We have a compelling lineup, with topics ranging from acceptance testing and IronRuby to presentation patterns in WPF—and even an overview of the "Oslo" platform.
The article of greatest interest to me, however, is Dave Laribee's "An Introduction to Domain-Driven Design." I have been a subscriber to and practitioner of domain-driven design (DDD) thinking since I read Eric Evans' book of the same name about four years ago and have grown in this way of thinking with minimal problems. I believe that this has been largely due to the complementary relationship between domain-driven design, the rich domain model pattern, and test-driven development.
But when it comes to building software, there is no silver bullet. I watch technologies such as Windows Workflow Foundation (WF) and Windows Communication Foundation (WCF) continue to evolve; I see the continued shift toward service orientation. And I can't help but wonder whether my staunch adherence to certain practices and heuristics has caused me to recreate a few wheels of my own and subsequently undermine one of the goals of good software design—creating a more maintainable system.
Let's take the insurance problem domain that Dave references in his article. I, too, once worked in this industry and built what I considered to be a rather elegant framework for validating policy configurations and calculating projections known as illustrations. I created my domain model from the outside in using a test-driven approach, mapped my model to a database using a popular object-relational mapper, and projected my model onto multiple presentation layers. As I continued to refactor my domain model, I noticed a couple of things. First, all of the logic (and all of the tests) that I had built began to resemble something I had seen before. And in fact, when I stepped back and looked at my domain model, I realized that I had essentially written my own forward-chaining rules engine.
Keeping in mind that the most maintainable code is code that you don't have to maintain, consider how policy illustrations are calculated. The company's actual calculation logic was created by actuarial scientists using a functional, generally symbolic language such as APL or Mathematica. This logic was then translated into our object-oriented domain model. As I'm sure you can deduce, a great many bugs found during regression testing were introduced in this translation.
In light of my own experience, I wonder what my application would have looked like had I refactored my validation logic into a rules engine and taken a more polyglot-based approach for calculating. Would my application have still been "domain-driven"? Or can DDD philosophy be separated from its more frequent, object-oriented implementations?
I've been reviewing my old code recently, looking to see where my understanding of DDD principles has been biased by my OO coding skills and then refactoring appropriate pieces of the application to more suitable paradigms. What I've concluded thus far is that domain-driven thinking is still an essential part of designing software. (In fact, certain elements of DDD become more meaningful in a multi-paradigm design.) In the end, my experience has been a validation of the fact that the domain must drive the design—even when it challenges what is comfortable for us as developers.
Thanks to the following Microsoft technical experts for their help with this issue: Surupa Biswas, Mike Calligaro, John Gossman, Tim Heuer, Ed Katibah, Gaurav Khanna, Ravi Krishnamurthy, Mike Magruder, Rick Molloy, Dave Murray, Michael Puleio, Bob Schmidt, Don Smith, and Matt Winkler.