Thursday, October 22, 2009

Sample Application with White,WPF,TDD and DDD

I'm currently thinking about what we could do better on a next project avoiding some technical issues that we have had in our latest project. Some of the issues were

  1. The Passive View implementation for our Win-Form client was too costly. The design of it wasn't intuitive and straight forward at all.
  2. The Passive View implementation didn't allow us to unit-test the UI. Even we were able to test the presenters we still couldn't test the event- and data binding automatically .
  3. Our initial plan to do acceptance- and integrationtesting with TestComplete failed. No tests have ever been written with TestComplete.
  4. Our testing-suite runs too slow. The whole suite was too slow and even running one single test took too much time.
  5. We struggled with Aggregates and domain logic leaked sometimes into the presentation layers.
  6. The application is too slow. This was caused due the fact that we couldn't react appropriately when we were forced to move our 2-tier implementation to a 3-tier implementation.
I've recently written a sample application to find answers to some of those problems. You can download the application from this site (Click 'Save file to your PC' at the end of the site).

I'm going to explain my thoughts in detail maybe later, but the most interesting points in the sample application are:
  • WPF+White: White allows testing the UI right from inside the unit-test runner. Following some basic principals it allows to script the UI right from the c#-code. But I used White just to Unit-Test the UI and to write some basic integration tests. I don't believe that one should use White to do more than that otherwise he might get some serious maintenance issues. For details see OrderExploration.Test\UnitTest\Ui and OrderExploration.Test\Integration
  • Acceptance-Testing: I think acceptance-testing frameworks are a weak point of the .net-world. Either they require a lot of infrastructure (like wiki's) or they can't be used by "none technical's". NBehave is useless because it can't be used by "none technical's" and it doesn't produce readable code at all (That statement is maybe wrong with Version 0.4, but I didn't check). FitNess is far too complicated for a small project like the sample application. I tried StoryTeller as well, but there is not a lot of documentation available yet, so I gave up. So why not using pure old nunit-tests if there are no "none technical's"? For details see OrderExploration.Test\Acceptance
  • Persistence-Ignorance: There is just one test that hits the database (see OrderExploration.Test\Integration). All other tests (UI, unit und acceptance) run against stubs.
  • Test-Setups: To setup Unit- Acceptance- and Integrationtest differently I used SetupFixtures (I didn't know them before!). Lookout for classes with name "SetupFixture"
  • CQS (Command-Query Seperation) inspired by a Ian Cooper: I tried to separate querying data (mainly for displaying on view) and commanding (mainly for updating on aggregates). I'm not sure if I really got it right! For an example see method DataService.GetOrders() that queries data right from the database and see OrderService.Submit() that writes changes through the aggregate to the database.
  • Aggregates: See the class Order that defines an Aggregate-Root. I tried to build an expressive aggregate by separating the aggregate from its persisted structure (see class OrderRow) and its displayed structure (see class OrderDetailData). If there is an interest I would like to discuss that decision later. For now see method Order.AddTag() and think about: 1.) If the class Order were directly bound to the UI, how would you handle the fact that the user can add/remove tags several time but just the last state should be persisted and logged in the history. 2.) If the class Order were persisted directly, how would you handle the fact that tags are persisted as strings? (see Order.Tags in the database-scheme)
  • and StructureMap and AutoMapper ... of course!
  • White is cool and helps to (Unit)-test UI
  • Persistence Ignorance can be implemented and helps to make Unit-/UI-/Acceptance tests much faster
  • CQS (Command-Query-Separation), ViewModels, DomainModel and PersistenceModel add another layer of indirection that can help to solve tricky problems quite easly. However, these indirections can be a huge overkill for simple applications. I have no doubts that it's worth to have ViewModels (including all kind of MVP,MVC) but I'm not sure when it's worth to separate DomainModel and PersistenceModel. In the sample application, DDD (e.g Repository-Pattern) helped me to answer that question per Aggregate. In the sample application the Aggregate Order has a separated DomainModel and PersistenceModel. For the other Aggregates DomainModel and PersistenceModel are the same. Any thoughts about that?