Readable maintainable code? Use DDD TDD CQRS IoC

Back in 1994 when I was 14 my parents asked me if I want a video player or a computer. So I got a PC, 286, 12 MHz, EGA graphics with 16 bloody colours. Everybody was playing Doom except me. After completing all sorts of 16 coloured games distributed on faulty 3.5” diskettes, I became bored. A friend of mine installed Turbo Pascal on my machine, and I was started. Later I learned C/C++, Java, wrote couple of university projects in it, and at last C#/.NET - a language and a platform of my choice.

When I started working, I realized that most companies were doing waterfall development - develop something quickly to make deadline and budget happy. Then support it for couple of years, pray for no requirement changes, if there are requirement changes, hack it somehow to make it work, then hack it even more, and then don’t touch it otherwise you break it for good. I realized I want to do some other way of development - the way which is compatible with requirement changes and safe refactoring so you don’t have to hack but maintain the code nice and tidy over the years. I learned that a way to achieve it is to use TDD/DDD/design principles & patterns/agile/CQRS/IoC/DI and other magic shortcuts in my development process. So how do these shortcuts solve issues?

With TDD every path of the code has a unit test, if you use database you would have integration tests for DB queries. This set of tests ensures safe refactoring as if you refactor some code because of requirement change or to achieve better readability, you run those tests to ensure you didn’t break anything. Next, TDD forces you to design your code to be easily testable breaking it into smaller units, so it forces you to design your code better. And at last, these tests serve as an up to date documentation of the usage of the code. Of course, you should write your code in a readable way, extract blocks of code into private methods with a descriptive name, etc, but still those tests give you an additional understanding of the usage as you can see test setup and test assertions. This is important when developers on the project come and go through out the years, newcomers can have much better understanding of the code base.

DDD. Let’s suppose you need to design an application for some non-trivial business/domain. Basically any kind of design will try to model somehow business/domain entities. You usually talk to business people who are speaking about business entities, their relationships and operations with them, etc. With relational database first approach, you think first about which data your entities should hold, you create DB tables and you ensure that data are persisted into tables, be it via O/R mapper, manually with SQL statements embedded in a code or stored procedures, etc. This database first approach forces you to think first about data, database and SQL without regard to operations/behaviours of entities. With domain first approach, you think first about operations/behaviours of entities, which force you to design entities and their relationships in accordance with these operations. Applying DDD to your domain design brings structure and rules, all state changes/updates must happen via a domain method of aggregate root entities (DDD concept) instead of ad hoc updates of any non-aggregate root entities. If you persist your domain into relational database, at any point you can generate your entire database SQL create script from your manually written domain entity classes via libraries like NHibernate/Fluent NHibernate which auto maps domain entities into DB tables, so you don’t have to deal with SQL / table / table relationships creation.

Applying SOLID design principles among other things ensures your classes are not huge and complicated (break such classes into more smaller simple classes) which simplifies unit tests, your concrete classes are not dependent on another concrete classes but rather their interface abstractions (dependency inversion) so you can stub/mock these abstracted services via some mocking library like Rhino Mocks for unit testing.

Applying design patterns when reasonable and suitable ensures better readability and understanding of a code. Design problems which fit some design pattern should implement it instead of a custom solution which nobody understands except the author. When a service is implemented as singleton, or is factory, or is using state pattern, it immediately says what it is.

Agile development with Scrum process helps implementing and delivering new set of features every couple of weeks, usually two weeks. These couple of weeks is called a sprint. At the beginning of each sprint, you plan with your team new stories/tasks representing new application features for the sprint. You plan only enough work to be realistically completed within the sprint. No more three weeks overnights before unrealistic deadlines. Of course, business layer needs to support this kind of agile development approach.

CQRS ensures that implementation of commands (a code which modifies state/updates DB) and queries (which does not modify state/update DB) is independent. The advantage of this approach is that a developer might safely reuse queries or change their order as they do not modify the state. The opposite approach is to mix queries and updates, but this usually leads to a spaghetti not-reusable code.

IoC/DI - Inversion of control/dependency injection patterns are about removing dependencies. Your concrete classes are not dependent on other concrete classes but rather their interface abstractions. This helps unit testing as you can stub/mock these abstractions so you can test your class methods in complete isolation. In the application in some IoC framework (e.g. Castle Windsor) you configure concrete implementations of abstract services and IoC framework is then used to instantiate these concrete implementations with injected concrete implementations of dependent abstractions.

When you start a new project, you have couple of options how to support these technologies. You can start from scratch, develop the support on your own, or take it from another similar project, or use a library for it. As I could not find any suitable library, I decided to develop my own instead of writing it again and again for every new project. So, CoreDdd library was born containing support for mentioned technologies. From CoreDdd tutorial you can learn how to start developing .NET applications using TDD/DDD/CQRS/IoC. You are expected to understand OO programming, be able to use Visual Studio development environment, and optionally Resharper Visual Studio plugin which speeds up development and refactoring.



About Me

Martin Havlišta is DDD TDD .NET/C# software developer, author of CoreDdd library, interested in modelling complex domains and implementing them using DDD and TDD.

Comments