Who Can Help Me? started life towards the end of 2009, after myself, Howard, James, and a host of other amazing ex-colleagues worked together on www.fancydressoutfitters.co.uk. We’d built the client-facing site using S#arp Arch and a bunch of other open source tools, and wanted to put together a vastly simplified sample app demonstrating how we did it. And so, we build Who Can Help Me? and put it out there for the community to play with.
Despite not originally being intended as a S#arp Arch demo, it was adopted as one. Which gave rise to the question: what do we do with it for S#arp Arch 2.0? When we built it, we wanted to demonstrate the architecture and toolset we used for an enterprise-level e-commerce site. We didn’t go out of our way to demonstrate any specific patterns, and we made no effort to demonstrate many of the nice features offered by the different tools we used. After some back and forth between the team we decided that things have moved on in the last 2 years, and whilst we are all still proud of the e-commerce site it was based on, WCHM is not representative of the way we choose to build websites today.
In addition, those who follow Ayende’s blog may have noticed his recent code review on WCHM. He raised some valid issues with the code, and fortunately there are several upcoming SA 2.0 features that will help me address them. So here’s the hit list for how WCHM 1.9.6 will go not only to 2.0, but also to being a true Sharp Architecture sample app.
Firstly, relevant points from Ayende’s review:
The mapping sucks
The pattern we adopted when writing our controllers is as follows:
- Receive request.
- Make request to tasks layer (aka application services); get domain entities returned.
- Use mapper to map entities to view models.
- Return view result, passing view model.
This looks extremely simple on paper, and for the most part it is. However it has a few issues:
- It can get messy quickly, especially if your view requires several disparate pieces of data – in this case, the controller makes multiple calls to the tasks layer to retrieve the required data, which is then passed into a mapper. Often this mapper will use other mappers to map collections or child view models.
- It is, as Ayende pointed out, a breeding ground for SELECT N+1 issues.
S#arp Arch 2.0 has a solution to this problem in the form of the Enhanced Query Object approach. So, to populate a view model we no longer make calls into the tasks layer. Instead we use a query object which retrieves all necessary data. Because the EQO talks directly to the NHibernate session we can bypass the layers of abstraction that Ayende derides in his posts, replacing it with LINQ/Criteria/HQL/named queries/whatever else we think is the right fit for the problem.
Too many specifications
There are quite a few specifications in the domain layer. They fit nicely into two categories:
- Specifications that just shouldn’t be there at all. This covers ProfileByIdSpecification and CategoryByIdSpecification. Simply put, these shouldn’t exist. Instead, the FindOne method on the relevent repository should be used, which simply passes through to the Session.Get<T> method.
- Specifications that aren’t really specifications. Unfortunately, this covers the remainder of the specifications. The problem is, a specification is really intended for codifying a business rule – so an OverdueInvoiceSpecification would capture what it means for an invoice to be overdue. When you look at it in that way, it’s pretty obvious that TagByNameSpecification (for example) is not codifying any business rule and as such has no place in the domain layer.
Unfortunately this means I’ll be deleting all the existing specifications. Hopefully I’ll be able to come up with a good example or two to replace them with.
Now, onto a few of my own points:
Anaemic Domain Model
Anaemic Domain Model (Wikipedia, Fowler) normally – and in my opinion, somewhat unfairly – gets labelled as an anti-pattern. It actually made a lot of sense in the original application, because in fact there was no domain logic to speak of. However, since Sharp Arch has all the DDD terms baked in, WCHM needs to do more than pay lip service to these, so I’ll be doing my best to improve this.
No obviously identified aggregate roots
Following on from the previous point – the code in WCHM doesn’t follow the DDD practice of accessing entities via aggregate roots only, so this will be another thing to improve.
Replace existing Tasks with Commands
WCHM currently uses a traditional tasks layer, with the different methods grouped up into a few different application services – CategoryTasks, ProfileTasks, etc. As described above, the query methods will be pulled out of these tasks and moved into queries that will be homed alongside the controllers. The remaining methods will be separated into commands, which will remain in the Tasks layer.
Merge Web.Controllers and Web
As detailed in Geoff’s Introductory post in this series, we’re merging controllers back into the main web project, and renaming to Presentation.
In reading this, you might think that I’m saying WCHM is a steaming pile of something unpleasant. Nothing could be further from the truth – www.fancydressoutfitters.co.uk is a project that I’m proud to have been part of, and WCHM is an extension of that. The site has been running with no significant unplanned downtime for nearly 2 years now, from a project that went from nothing to live in just ten 2 week sprints.
However, I hate it when code I’ve written is allowed to stagnate – like most of us, I look back on code I’ve written and think about all the ways it could be better. I hope that there will never be a day when I look back on one- or two-year old code and realise I’ve learned nothing since it was written. In the meantime, I’d appreciate any feedback people have on WCHM and this post.
Following on from Geoff’s first post in this series, this post details the move from two repositories (Sharp-Architecture and Sharp-Architecture-Contrib) to the current set up, including how we’ve restructured the repositories themselves and included a common build system across everything.
We’ve moved all the SA repositories into a single GitHub organisation, separated samples into their own repositories, brought the repository structures in line with one another, and implemented a common build system shared by the solution in each repository.
Until the end of last year, Sharp Arch consisted of two repositories. We had Sharp-Architecture, which contained SA itself and the Northwind sample app, and Sharp-Architecture-Contrib, which was pretty much what it said on the tin. The master versions of these repositories lived in Billy’s GitHub account.
When we started talking about Sharp Arch 2.0, Billy had already taken a step back from the project. Who Can Help Me? had been adopted as a second sample application (with the master version living in my GitHub account), and we had big plans for both Sharp Arch itself and the sample apps we provide for it. As a result, we made a few decisions:
- We’d bring all of the Sharp Architecture repositories under one roof so that it was obvious what was “official” Sharp Arch and what wasn’t
- We’d provide each sample app – including Northwind – in it’s own repository, rather than having a single massive repository containing SA core and all of it’s samples.
- We’d adopt a common structure for all our repositories, so that people know what to expect when getting into each one.
- We’d provide a common way of building all of the projects, so that we didn’t need something specific in each repository.
Step 1. Sharp Architecture organisation on GitHub
This was the easy bit; as you probably already know if you’re a Sharp Arch user, we’ve created a new GitHub organisation that our repositories can call home. It’s at https://github.com/sharparchitecture/ and at time of writing, contains the following repositories:
The core Sharp Arch projects. This currently has a master branch, which is the source of the current release (1.9.6), and a develop branch which contains the restructured work in progress version.
An all-new, 2.0 repository containing code for the different persistence options we’re providing for Sharp Arch 2.0. Because it’s new for 2.0, the master branch of this repository contains the code that’s aligned with the develop branch in the main Sharp-Architecture repo. Apologies if this is somewhat confusing.
As with the core repo, the master branch contains the source of the current release and the develop branch contains the Contrib project that will support SA 2.0.
Common build system for the Sharp Architecture solutions – see below for more information.
The original SA sample app. As before, master contains the code that goes along with the current SA release, and develop will be updated to use SA 2.0.
Sharp Arch’s second sample app. As before, master contains the code that goes along with the current SA release, and develop will be updated to use SA 2.0.
A new kid on the block, this will eventually contain the reference project structure that is used to generate the Templify package for SA. At the moment, our Templify package is built from the Northwind sample, but we are intending to change this as part of the 2.0 release.
Another newbie – this is a new sample application that differs from Northwind and Who Can Help Me? in that it doesn’t intend to be a real world example of how to use SA to build an app. Instead, it will contain a series of examples of different things that can be done with SA. “Recipies” that you might find in the cookbook could include the different ways of setting up NHibernate (Automapping, Fluent and traditional HBM mapping), using SA with WCF, usage scenarios for LinqRepository and the Specification pattern and so on. Our hope is that over time, this will become the main reference for “how do I…” questions.
Step 2. Repository structure
We decided to standardise on the repository structure used in WCHM. At the top level, it contains the following folders:
Build scripts for the project – see below for more details
Git submodule used to pull the common build bits and pieces from Sharp-Architecture-Build.
Contains any common files used across multiple projects. In practice, this is normally a CommonAssemblyInfo.cs file, which holds the assembly attributes shared across all projects in solution, and an AssemblyVersion.cs which is automatically updated by the build process to ensure that assemblies get a version number that matches the TeamCity build number.
Pretty much what it sounds like – external libraries that are used by the solution. These are normally organised into subfolders for each dependency, in order to make it crystal clear which assemblies are part of which dependency – for example, the NHibernate folder contains the core NHibernate.dll, Iesi.Collections and other supporting bits.
Installers for anything you need to set up locally in order to use some or all of the solution. For example, it helps to have the T4Toolbox installed to work with the T4 templates that are currently part of SA, so the installer for this is included in the RequiredPackages folder of the Sharp-Architecture repository.
Home for the projects that make up the solution. As you’d expect, each project is in it’s own subfolder, and the solution file sits here as well.
As mentioned above we felt that a common structure for the repositories is important. Not only does it mean that you know what to expect when getting into each repository, it also facilitates the next major step – the creation of a common build system for all of the projects.
Step 3. Common Build System
Up until 2.0, Sharp Arch has relied on a Nant build script for build and packaging. This has served well so far, but with the changes we’ve made in the way our repositories are structured, the time was right for a change.
The build system we now have consists of two parts:
- A set of common MSBuild targets and tasks that encapsulate steps within the build process – for example, building a solution, running unit tests, or packaging source files. These files live in the Sharp-Architecture-Build repository, and each repository contains a submodule that pulls this into the BuildSystem folder.
- A script that is specific to each repository and invokes the correct tasks from the common build project, with the correct parameters for the project. This script, along with some batch files that can be used to run it, exists in the Build folder of each repository.
Using this set up, and with the knowledge that each repository is structured in the same way, it’s simple to assemble the correct tasks to build and package any of the solutions from the Sharp Architecture repositories. For example, the process to build the Sharp Architecture core solution consists of the following steps:
- Clean (remove any files from the Drops folder that are about to be recreated by this build)
- Update the common assembly version number file that’s shared by all projects.
- Build the solution
- Run the MSpec unit tests
- Merge the assemblies together
- Package the assembly and source files.
If you compare this with the build process for Northwind – which, given it’s a sample app rather than the framework itself, you might expect to be somewhat different – you’ll see the following steps:
- Update the common assembly version number file that’s shared by all projects.
- Build the solution
- Run the NUnit unit tests
- Package the assembly and source files.
Clearly the bulk of the steps are actually the same as those required by the core Sharp Arch solution, hence the reason for encapsulating each of these steps in it’s own target so that it can be easily consumed as needed.
This system does, unfortunately, add some complexity to the process of getting source from GitHub and building locally. Once you’ve done a git clone of any of the repositories, it’s then necessary to run two additional commands against your clone.
- git submodule init initialises the submodule
- git submodule update updates the submodule with the files from the correct commit of the Sharp-Architecture-Build repository.
Anything that raises the barrier to getting started with Sharp Architecture is clearly not a good thing, so we’re still looking at ways in which this process can be improved.
Once the submodule is up to date, the files in the Build subfolder can then be used to build and package the solution. These scripts are also used for our CI builds, and when used with TeamCity they ensure that the assemblies created and packaged by each build are correctly version stamped with the build number, and that the packages created by the build process are published as build artefacts.
As we continue working towards 2.0, it’s likely that we’ll evolve what I’ve described here but it’s unlikely to change radically. We’ll probably move to using NuGet instead of the old fashioned way of pulling in external dependencies, which may affect how we use the ReferencedAssemblies folders in each repository. And we’re also not entirely happy with the additional complexity that using Git Submodules adds to the mix, so we’re still thinking of ways to improve this. In addition, we’ll be making some additions to automatically create and publish the Templify and NuGet packages for Sharp Architecture.
As always, we welcome all suggestions, feedback and pull requests so please get involved and help us make Sharp Architecture something you want to use in your projects.