This is the second part (of n) in my look into Alan’s example implementation of having a project that doesn’t use a repository. As a reminder, the goal is not CQRS, or DDD, but to see how applications can be built that do data access san repositories.
Show Me Ze Codez
The code for the (maybe first?) alternative implementation can be found here:
In the root folder, there’s a src2 folder, with Alan’s original implementation in the src folder. The areas of interest are the Model project, the PeopleSearchController, the PersonRegistrationController, and the Owin startup class.
The biggest change from Alan’s implementation is that abstraction is done at a different level. While Alan’s implementation tries to hide EF and provide a consistent data access “layer” to execute all queries, this implementation abstracts at the query level. The queries are the abstraction in this case, and it is up to us to provide an implementation for each query. This prevents the need for a common data access layer for all queries, and query implementations are free to use whatever makes sense. If there is value in having a generic data abstraction for the majority of queries, we can implement reusable functionality (though personally, I find myself doing that very rarely). If some query needs more raw control, I might use dapper and execute it using that. If I then find the query is best served by connecting to a web service, it’s again just one place where that needs to happen – the query implementation. I have control over each query independently. The uniform data layer leaky abstraction no longer exists. For reuse, we could implement a reusable library. Or go crazy nuts with reflection and generics. Or do runtime codegen. Or do any the magical thing we want. But all of that is hidden from client code via simple query abstractions. And when something doesn’t work and a different approach is needed, the effect of that change can be limited a lot more than with the same data access strategy across everything.
You Said Commands, I See Only Queries
I called both RegisterPerson (I really don’t like the term “Create Person”!) and GetPeopleByFirstName queries. Shouldn’t the first one be a command? Sure, it can. Semantics. The query objects are merely wrapping SQL queries – one an update query, and the other a select query. This is a crud app. Call it a command if you like :)
Where’s the Domain?
What is a domain? The core of the application that encapsulates business logic? The application in question doesn’t really have that. Alan’s “domain” had a single data structure called Person with maximum coupling and zero cohesion. It’s used across all “layers” providing (and enforcing) a single “view” of a Person. The alternative implementation does away with a pseudo domain. Instead it has a viewmodel to represent the result of the GetPeopleByFirstName query. Until I face complexity, I’d rather not introduce complexity.
What About Testability?
The application code (in this case, controllers) are dependent on query object interfaces. For the queries themselves, for the simple implementation, I’ve made the implementations take a hard dependency on the context. In my experience, unless there’s a great many of them, since they’re wrapping db operations, an integration test for the query object implementation tends to be accurate. Unless a database provides an “in memory” mode, I’ve often found in memory pseudo implementations behave differently to the real thing. If there are many though, and this becomes an issue, it would be fairly trivial to wrap the context in an interface, and have unit tests around that. The query implementations take a hard dependency on the underlying mechanism, and so will the test. The query object interfaces, and the client code that uses them would remain agnostic.
But Your Library Depends on EF
Yes. But you’ll notice it’s limited to the EF implementation and the boot function. Could easily have been implementation specific libraries.
Why So Much MVC
Wanted to show an application. And was too lazy to create from empty.
There’s No Structure, Layers
That’s kind of the point. Query implementations can use shared libraries, or not. They don’t have to. If reusable infrastructure is actually useful, it’ll get reused. If it’s only there coz of “architecting”, then it should get ignored. Darwinism, wild wild west, whatever.
I Need Transactions, Multi Steps, MOAR Logic!!
Context per user request can go a long way. Implicit transaction scopes may be done in a number of ways. For more complex things, I’d look at application services, perhaps a core domain, possibly in memory messaging. We’re going more into DDD and CQRS here. One thing we should always remember is that creating and maintaining a domain model is expensive. It should only be done in high value high complexity situations. Not everything needs a domain model. And I don’t care what “best practices” astronauts tell you. Eric’s blue book covers this quite clearly.
This Doesn’t Follow the GoF Command Pattern
No, it doesn’t. The query parameter values are passed in the method call. An alternative could be to have the query objects take in values in the constructor and the Execute methods take in the abstraction. A template method pattern similar to Alan’s can come in handy here, but if I were implementing this, I’d probably have the client code injected with a context abstraction, and pass that explicitly to execute. I’d shy away from creating a generic data access facility abstracting EF. It might look like a good idea, but it brings in a lot of connascence. Perhaps I’ll cover this in a future post if there’s interest.
You Use a Container…YUK!!
Last Words for Today
This implementation is quite simple, and the approach is useful in a lot of scenarios. Obviously, it won’t work in every case, and certain scenarios may need to extend the approach, or use something else. This implementation is strictly about CRUD scenarios and basic query object usage. [Possibly] more to follow.