Title Image

Don Xml's Grok This

The home of Don Demsak
Welcome to Don Xml's Grok This Sign in | Help
in Search

This Blog

Syndication

Site Sponsors

DonXml's All Things Techie

Reality Blogging – Test Driven Development with Domain Driven Design – Part 1

Over on the discussion group asked the group their opinions on how they go about driving their domain driven design implementation using test driven development.  Rather then just answering him there, where only the domain driven design folks will see it, I thought it might be better to not only answer the question, but go one further and let developers into my thought process when developing an application.  As luck had it, I have just started a brand new project that will eventually get released as an open source project (I actually started the code the day Scott sent out his email).  So, instead of me just starting to code and eventually releasing it to the public to continue its development, I thought it might be a very good learning opportunity, on a couple different levels.

The project I have started is related to the stuff I’ve been talking about.  I’m looking to create a controlled vocabulary object model built around the PRISM Controlled Vocabulary spec.  The object model represents controlled vocabularies, but should also be serialized and deserialized to the PRISM CV XML format.  Since PRISM’s CV spec version 1.3 relies heavily on the , simple .Net XML serialization will not work, so I’m going to have to roll my own serialization (which might also be a good thing to learn about).  I’m going to use the CV spec as the user requirements for the domain driven design.  Because I want to appeal to as many .Net developers as I can, I’m going to stick with .Net 1.1 and use C# as my language (but the language shouldn’t really matter).

I’m definitely not a DDD or TDD purist, nor do I think it is a good idea for anyone to just adopt a practice without adding some of their own style.  I just use what works for me.  It might not be 100% according to the rules, but that is fine with me.  What I want developers to see is that it is alright to “bend the rules” a little and not get intimidated by purists who that think everything should be done just as the technique was written.  But I’m also not infallible, so I’d also like to see some of the “experts” jump in and help correct some of things I might be doing wrong (hey, I like to learn from the experts, too).  Think of this as one big code camp chalk talk session.

The take aways for this series of blog posts should be:

  1. Learn one way to use test driven development with Visual Studio 2003.
  2. Experience domain driven design in action, with Visual Studio 2003.
  3. Feel the pain of developing using public standards that have poorly written specs (which is the majority of them).

If you want to play along at home I’m going to take a snapshot of the solution every time I make a post.  The code will be from the end of that currently development cycle.  You can download the first code drop here.  There isn’t much code there, but it is a pretty good starting point for this experiment.  If you are new to TDD, download and installed  and .  If you don’t know , buy the book, and/or download the Patterns Summary.  Here is how I got to this point:

  1. I always create a blank solution first.  This project is going to be called the Controlled Vocabulary Exchange, so the solution is named CVExSolution.
  2. Added a C# Class Library called CVLib and set the default namespace to CvExchange, although I’m not totally happy with having the library name and the prefix namespace different.  But CvExchange feels like the correct default namespace, so something is going to have to change here before I finish this project.
  3. Added a C# Class Library called CVLib.UnitTests which will be our test fixture for the CVLib.  I then add references to NUnit Framework and the CVLib.
  4. In the CVLib project, delete the Class1.cs file.
  5. Add a folder called ControlledVocabulary.  This is where the main CV domain objects will be contained.
  6. Add a folder called Messages.  This is where I’ll put the classes that represent the message version of the domain objects (the classes that look like the XML structure).
  7. Looking at the spec, the classes that jump out at me are Synonym, SynonyCollection, Taxon, TaxonCollection, Vocabulary and VocabularyCollection, so I create files for them.  Each one of these class will be public, but the constructors will be internal unless I find a reason to change it.  I always try to start as narrow of exposure as possible.
  8. Taxon seems to be the hub of the domain, so I create a TaxonRepository class in the root folder, which will use the Repository pattern.
  9. I start to build out the Taxon class, starting with the properties.  I always make my properties readonly at first and later make then read/write if need be.  The Taxon class maps to the Descriptor element in the spec and represents an entry in the vocabulary.  A Taxon contains collections of broader terms, narrower terms, related terms and synonyms, so I create properties for them using the collection classes.  Each property has a matching private field.  I add the prefix of an underscore to the property name for the field name.
  10. While writing the code for the narrower terms I realize that it is really a collection of taxons.  Hmm, we seem to have 2 different words, taxon and terms, for the same thing.  I like term better then taxon, since it seems more descriptive.  I go back into the code and change Taxon to Term.
  11. Reviewing the comments for Descriptor I noticed that there are 2 different types of Descriptors, one that contain the actual definition and another that is just a reference to the real one (a pointer).  At first I want to create an enum to handle this property, but in thinking about it, maybe we need a base class and an inheriting class (Term being the class that inherits the base class).  What is the base class?  Hmm, is it really just a uri?  I’m not sure, so I create a class called TermLink (the link to the term) and have that inherit from System.Uri.  At the moment I’m not sure if I should skip the TermLink class and just have Term inherit from Uri, but something tells me that I may need to modify the behavior of Uri, or add some additional info, so we will go with my instincts and can easily change it later if need be.
  12. I create a single internal constructor for TermLink that takes a string, and pass that into the base Uri constructor.  For all domain objects, I always make the constructors internal.  If I later decide they need to be public or protected, I open them up at that time.
  13. The Descriptor element contains a Label element which contains the human readable label for the term.  I create a Text property in the Term class to hold this info and make it a string type.
  14. The Descriptor element contains a Code element which is the machine readable version of the Label element and is the unique identifier within a vocabulary.  I create an Id property to hold this information.  It looks like it should be a string type, so I use string, for now.
  15. The Definition element is also part of the Descriptor, so I need to add a property for that.  I’ll keep the same name and make it a string type.  I will have to change this eventually, since the spec has 2 types of definitions, one of pure text, and another that can contain markup.  They recommend using XHTML, but is that a must or just a may rule.  I’ll have to research that, thus, dropping back to string for now.
  16. Although the spec doesn’t explicitly mention carry a link to the vocabulary for each term, it seems like something that will be needed, so I add a ParentVocabulary property with a type of Vocabulary.  I don’t think a term can be contained in more then one vocabulary.  At least not with the exact same defintion, so I think we are good with just using a Vocabulary and not a VocabularyCollection.
  17. I’m done with the properties, for now, so off to take a look at the constructor.  What do I need to create a complete Term.  I need its Id, Text, Definition, and the parent vocabulary.  Hmm, I need to pass into the base constructor a string that represents the uri.  Well, the parent vocabulary should have the base Uri for the terms in the vocabulary.
  18. So I have to go over to the Vocabulary class and add a BaseUri property (with its matching private field).  I might as well create a constructor too, for the Vocabulary, that passes in the base uri.
  19. Go back to the and complete the constructor by adding a constructor for the base class.  I combine the string version of the parent vocabulary’s base uri property with the Id passed in to the Term’s constructor.
  20. I can now create a new vocabulary and also create a term for that vocabulary.  But now I need to let the outside world in.  So I go over to the TermRepository.
  21. I add a using clause for CvExchange.ControlledVocabulary and leave the default public constructor.
  22. Add a public method called CreateVocabulary that returns a Vocabulary type.  Since a vocabulary requires a uri, this method has one parameter, a string that will become the Uri.  I could have them pass in a Uri, so I might need to add an overloaded version of this method, but for now, I will leave it.
  23. In the new method, take the string uri and convert it to a type of Uri.  Then return a new Vocabulary using the Uri.  We need to add some exception handling here, but I’ll do that later, once I create some domain specific exceptions.
  24. Now off to create the first test.
  25. Delete the auto generated Class1.cs file and create our first test class, TermRepositoryTests.  
  26. Create a test method called CreateVocabulary that will call the Repository’s method of the same name.
  27. Check to make sure that the return isn’t null.

That’s all the time I had to play with this new project.  Wonder what will happen in the next part of this series. 

Published Thursday, December 15, 2005 11:58 AM by donxml

Comments

Dru said:

Excellent Post
December 15, 2005 2:48 PM

Scott Bellware said:

> Now off to create the first test.

Whoa, dude. You just added a mess of classes and you're only just getting around to adding a test?
December 16, 2005 2:55 AM

Toby Henderson said:

Good post mate.

"24. Now off to create the first test."

Sorry to inform you but you're doing TAD (Test After Development).
In TDD the first thing you should do is create a test, compile it and run the test, before even writing your first class. I'm learning TDD at the moment and struggling with the change in my development style which is very similar to way you are doing things currently. I'm lucky to have a good tutor but even he says it takes a while before you are able to change your perspective.

Enough babbling. This series is a brilliant idea, this is real sharing of you're ideas, style and code.
Like the meaty content too.

Looking forward to seeing how this turns out for you.

All the best

Toby
December 16, 2005 6:13 AM

Don Demsak said:

Toby - Yep, I know my TDD style does not conform to standard TDD. That is my point, use it to fit your style. Bend the rules, but don't break them. In my style, developing the tests are the most important thing, not if I do it before or after the code. But, I know it bugs some TDD folks. I want people to mention where they seem problems/issues, so keep it up! This is the best way for others to learn.

Scott - Yep, one test, so far. Most of the other classes are all stubs built with template code. But keep commenting, it is important for the others to learn.

December 16, 2005 9:36 AM

Scott Bellware said:

Don,

By your own description of your process and by your own admission of the stuff you do, it's really hard to say that you’re doing “Test-Driven Development” – unless you want to define TDD the way MSDN recently defined TDD, but you might then be open to the same public scorn that caused Microsoft to recant and admit that the author of their guidance docs really never did any TDD and never really understood the depth and thus the point of TDD. If I were a traditional waterfall developer consistently following the process that you’ve laid out, I don’t see how the process would teach me anything about contemporary software design rather than simply reinforce my beliefs about traditional, waterfall design. For example, I might never learn the subtleties of why classes produced under the influence of TDD would have few internal constructors ;-)

The basic cost of entry for TDD is mere test-first programming. That’s the basics. After spending some time doing test-first programming, the imperatives for creating code that is more amenable to test begin to fundamentally change your notions of software design in ways that likely can’t be predicted until engaging in the practices.

I don’t look at what you’re doing as a TDD style, but it’s early yet. It appears at this point that you might be borrowing the TDD moniker to lend credibility to waterfall development by dialectic association – like saying that death is a particular style of life. You certainly could say that, but it wouldn’t really say anything about the way you engage in living, which is what I’d expect to learn in reading about a particular style of life.

I don’t see the differences here as merely stylistic, I think you’re following the tried and true design-up-front habits that you’ve got while potentially only using TDD for buzzword compliance reasons. This is the beef that I’ve got with a heck of a lot of Microsoft-oriented developers. TDD isn’t something that developers understand merely by reading about it – it’s a practice whose value emerges from practice.

Maybe it’s just that the example you’ve chosen isn’t terribly amenable to test-first process. Then again, if that were so, it points to the need to set the starting point somewhere in the system other than at the inter-system messaging format. You’ve got code to write, assembly and disassembly classes for DTO classes, that to me is a more logical starting point to approach the model from a TDD perspective. Start at something that requires programmatic validation – otherwise, you’re not doing much more than doing something that a class designer can do. And if you’re starting at the class designer, you’re potentially engaging in the exact same issues that caused Microsoft to embarrass itself over its opportunistic definition of TDD.

It’s perfectly reasonable to do automated testing with NUnit and not be doing TDD. On the other hand, there’s not much to be gained by doing waterfall and calling it TDD – if that’s in fact what’s happening. Like I said – it’s still early in your example and you’re starting from DTO classes like the XML-infected XML dude that you are. Personally, I wouldn’t expect to see a data transformer built under TDD start with the definition of behavioristically uninteresting stuff like a DTO. Those things are already defined in some industry schema. I personally don’t see any value in representing them in code at this point in the development unless you’re planning on immediately putting them under test. However, putting the assembler objects under test is behavioristically interesting and would lead necessarily to the implementation of the DTO’s, and to the DTO’s own tests.

Ultimately, what you’re calling an issue of style, I’m calling out as spin. If you’re not doing TDD, just be OK with that and do what you do the way that you’re comfortable doing it. If you’re earnestly interested in understanding the potential depth of software design paradigm shift inherent in TDD, then I don’t see how you’re gonna get there by avoiding the mere basics of the practice in test-first programming. There isn’t a path to TDD’s inherent software designs that don’t go through test-first programming, unless perhaps you’re counting on grace and divine intervention in your design practice, which I suppose isn’t really TDD either :)
December 16, 2005 11:26 AM

Don Demsak said:

Scott - You are 100% correct, so far. I've found that starting off a new project using pure TDD just doesn't feel right. Writing that first test and having it fail until I get the beginnings of the object model up and running doesn't sit right with me. So, I do test after development, but just for the first test. Once you have the beginnings of the obejct model, and the first test written, things are more TDD, because that first test starts to beg for additional tests, and that is when you start writing the additional tests before the actual code.
December 16, 2005 12:16 PM

Scott Bellware said:

TDD's adoptability has never been about whether or how well it sits with developers. It's upside down and backward to waterfall development - it should be uncomfortable to traditional developers much in the way that the navigation charts for the Nina , Pinta, and Santa Maria are to the Flat Earth Society. The criteria for beginning to engage in TDD practices in earnest isn't how much instant gratification or comfort comes from it.

There's a whole lot to be learned about *why* TDD is the way it is and ultimately how it delivers increasing value through numerous careful and subtle structural optimizations over an entire system by trying TDD in earnest.
December 16, 2005 4:14 PM

Grant said:

It's a shame I can't filter out the subset of comments mired down in the usual zealotry. Oddly enough, I read your semantic caveat about your interpretation and then was able to keep my knickers untwisted about this or that definition. I enjoyed reading your step by step and hope you won't get mired down in silly dogmatic detours--the content and substance part is interesting, I know the difference between TxD and TyD, this isn't a referendum on that.
December 18, 2005 12:09 PM

Don Demsak said:

I'm continuing with this, just taking my time. I know that most folks don't read my site everyday, so giving time between posts is actually a good thing.
December 18, 2005 5:23 PM
Anonymous comments are disabled

About donxml

I’m an independent consultant, specializing in .Net solutions architecture, based out of New Jersey who also doubles as an evangelist for XML, Domain Driven Design, enterprise architecture and .Net. I do not work for Microsoft, the W3C or any other big company that you may know of (at least not yet). I’ve been an indie for over ten years, and although I’ve been tempted a couple times to take a job with companies like Microsoft, I’ve haven’t found something better than my current situation. I work mostly with the large pharmaceuticals that are based here in New Jersey, and usually find myself on long term contracts. Definitely not the prototypical indie consultant, but it lets me dedicate time to my non-income generating activities like the developer community stuff, plus financing open source projects like XPathmania and MVP-XML. If you would like to talk to me about doing some contract work, just contact me via the contact page. My rates vary widely, depending on lots of different variables, but mostly distance from Jersey, and type of work. Plus, I’ve been known to donate some of my code for various projects.
Powered by Community Server, by Telligent Systems