Bad experiences scar us - forcing us to learn for our own
survival. This evolutionary theory can also be applied to software. If you don’t
learn from your mistakes, you’ll soon be on this guy’s plate:
So when creating web apps, what have my survival instincts
really taught me?
They’ve taught me that almost nothing applies universally. Since
I generally create larger-scale web apps, this article applies primarily to
that context. Even in this context, though, trade-off benefits will vary for
specific circumstances.
They’ve also taught me to isolate the domain, keep the web
layer thin and listen to the wise words of people of like Uncle Bob, Udi Dahan
& Eric Evans. They’ve even taught me (via Udi Dahan) to “justify why the
simplest possible thing isn’t enough” – so expect lots of that too.
In this series of blog posts - reflecting my current
thinking - I will be showing:
1. The
“Architecture” (clarify the quotes the later)
2. My
unit testing strategy
3. A
few other preferred patterns
What Does it Look Like?
First, when I talk about architecture, I apply it generally
and mean any component of the system as a whole – not just the domain. This
contradicts Uncle Bob and may be wrong, but I couldn’t think of another phrase
that would be understood that encompassed domain and delivery mechanism(s).
One Model In One Model Out & Endpoint-specific Models
A recent addition I picked up is the OMIOMO (one model in
one model out) convention from fubumvc – each action receives a request or
input model and returns a view model (or some other model).
By making these models specific to each action, they are
very simple data structures – keeping cognitive load to a minimum. It also
saves you from having shared view models that introduce bugs when they change
for one view and cause another to break.
Endpoint-specific models facilitate the Endpoint Testing
Pattern – discussed in part 2.
Endpoints Talk to Domain Services in DTO Language
Transfer of information between endpoints/controllers and
domain services is through simple DTO data structures.
Here’s an example:
Endpoint using a query service
public CreateBookViewModel Get(CreateBookLinkModel model)
{
IEnumerable<GenreDto> genres = genreRetriever.GetAllOrderedByName();
return new CreateBookViewModel(genres);
}
Implementation of query service
public IEnumerable<GenreDto> GetAllOrderedByName()
{
var genres = session
.Query<Genre>()
.OrderBy(g => g.Name);
return genres.Select(g => new GenreDto {Id = g.Id, Name = g.Name});
}
public bool CanFindGenreWith(string id)
{
return session.Query<Genre>().Count(g => g.Id == id) > 0;
}
Why Bother with DTOs?
Critically, the use of DTOs protects the domain and your
application – the contract between your application and domain is a lightweight
data structure. With this loose contract, the domain model is free to evolve –
and when you’re applying DDD, with the need to refactor often and sometimes aggressively
– your domain model has no outside concerns to worry about.
When you do apply domain refactorings, as long as you still
meet the contract – the DTO – your application remains unaffected.
I won’t explain the business value of DDD.
Why Separate Services to Query and Command?
A philosophy in CQRS is to separate reads and writes for architectural
flexibility. At the heart it is a simple pattern. Generally it appears to be
used when reads and writes have a separate data model – but in my case, the domain
data model is hidden – so it could be the same or different – we have the
flexibility. But what about the cost……
Isn’t Hiding Your Data Access Bad?
In some
cases – yes. But for my example, I’d argue – no….domain isolation is worth it.
It is a very thin layer, two mouse clicks away and one interface agreement.
Data access needs to know domain entities and the underlying data model – to gain
the benefits of DDD we don’t want to expose that to the application layers.
I think a thin layer of domain service implementations (not
interfaces) that take a dependency on the data access is ok. Some people put
them in a separate project, some people chuck it all in the controller – I like
this middle ground.
Data access is a tricky, context-specific beast that this is
probably the least prescriptive of my ideals.
Using this pattern and RavenDb also gives rise to a good
strategy for comprehensive testing of data access – you’ll see that in part 2
as well.
An Example From the Wild
You start out with a synchronous N-Tier application, but your
domain model rapidly evolves – with the DTOs being passed between boundaries
this is no more difficult than necessary because the domain is isolated.
Suddenly you have multiple bounded contexts, sharing aspects
of what once was a single domain entity - so you want to switch to an
asynchronous messaging based architecture. As long as you have a separate
service for queries and commands, with your data model hidden, you can focus
totally on the domain and its contract to the outside world – DTOs.
For those thinking this doesn’t happen – it is the exact
situation I am in with the contract I am working on, and appears not uncommon
from what I hear elsewhere. If the application followed these principles,
changes would be isolated to the domain and we’d only have to worry about
meeting service interface criteria – unfortunately there are swathes of
inter-twined spaghetti code all through the application and domain that
are affected – there’s your business value, son.
So…..
Cowboys have their opinion, those in ivory towers voice
quite another. But experience and practice are crucial in finding out what really
works and the contexts in which the arguments put forward by each are
favourable.
Reflecting on experiences, using personal projects to test
assumptions and try new ideas is a great way to get closer to that firm-footing
of reality. If you keep doing the same – you’ll keep getting the same. I was
pretty bored of those domain entity model binding issues and domain refactorings
causing crippling breakages in my web layer - so here’s a small conceptual
step, less destined for failure.
Also when you write posts like these, you force yourself to
double-check blog posts and podcasts – just to make sure you correctly
understood the topic. This reinforces what you’ve learnt, also saving you from
any false assumptions you may be carrying on your sleeve.
Tune in for part 2.
Related Shizz
Martin Fowler, CQRS - http://martinfowler.com/bliki/CQRS.html
Uncle Bob, Web Architecture - http://www.cleancoders.com/codecast/clean-code-episode-7/show
AND http://skillsmatter.com/podcast/design-architecture/uncle-bob-web-architecture
Udi Dahan talk on SOA - http://skillsmatter.com/podcast/open-source-dot-net/qa-with-udi-dahan


Hi, Just wanted to say I enjoyed your post. I'm looking forward to the rest of the current series.
ReplyDelete