Review of Sharp Architecture
понедельник, сентября 14, 2009 Joe Wilson
I've been using the open-source project Sharp Architecture for about 6 months now, and version 1.0 was recently released. It's a really great way to get rolling quickly on a project using ASP.NET MVC, Domain Driven Design (DDD), NHibernate, and Castle Windsor.
I won't go into the details about what Sharp Architecture does. I'll just cover what I like in the first version and what I hope makes it into future releases.
What I like
The Sharp Architecture framework uses inversion of control right out of the box with Castle Windsor and the Common Service Locator wrapping container calls. The MyProject.Core assembly holds your domain model and interfaces to your repositories. Implementations of those repositories are in MyProject.Data.
There is also a MyProject.ApplicationServices assembly for times when your controller logic starts to look heavier than it should or you prefer to push all your logic into an application layer so you can skim off the MVC UI for something else at some point (Silverlight? WCF?). I like this approach with very lightweight controllers and views for just this reason.
NHibernate Training Wheels
Billy McCafferty. the principal author on the project, is one of the gurus on NHibernate best practices . NHibernate is very powerful, but some tools, like Fluent NHibernate. which uses C# code to map your domain to your database instead of XML, are.well.kind of fluid.and still under construction.
I'm still new to NHibernate and very new to Fluent NHibernate, so I get tripped up often. It's nice to know that my solution is using best practices for tools where my footing is not as sure, like NHibernate session management.
Templates + Conventions
The Visual Studio solution and T4 templates inside Sharp Architecture are the things that makes it different from being just another reference implementation or architecture guidance. You can get a new, empty Sharp Architecture solution going in about 30 seconds with the Visual Studio solution template. The T4 templates help you add controllers and views built around conventions and the property names in your domain entity.
I used to be a big fan of code generation. It's nice to spit out a bunch of classes very quickly, but there really has to be a balance. If it gens too much code, is it all stuff you really need? If it only gens a little bit, did you need a code generator at all?
Sharp Architecture does a good job of giving you a jump start on stuff you will probably want or at least a place-holder for stuff you will want. It doesn't litter the solution with too much junk.
For instance, it doesn't generate a repository for your domain entity because you can use use the IRepository<MyDomainEntity> and Repository<MyDomainEntity> in the Sharp Architecture assemblies. It doesn't generate NHibernate mappings for your domain entity because the mapping conventions cover most cases. If you do need additional repository methods or have unconventional database mappings, it's easy to inherit from and override these. Sharp Architecture uses generics, base classes, and conventions to keep from needing a lot of code generation.
Documentation, Sample Code, Wiki, and Forum Support
This project is much better documented than most open-source projects. In addition to the "getting started" and 'using the framework" documents, there is a sample Northwind project that comes with the download files. Online, there is a wiki and a Google Group that is actively monitored if you need additional help.
I know real programmers only use Reflector for documentation. :> But don't underestimate the value of documentation for widespread adoption. You can have a great open source project that doesn't get very far if people don't know how to get up and running quickly and fully exploit the framework. That won't be a problem for Sharp Architecture.
Sharp Architecture libraries are chock full of all kinds of convenience methods and helpers. Want to write a database integration test using SQLite ? Just have your test class inherit from RepositoryTestsBase(). Want to hit the live database? Inherit from DatabaseRepositoryTestsBase(). Want to design by contract and check incoming parameters and return values easily? Look into the Check.Require() and Check.Ensure().
There are a ton of things like this that all of us have written before. Most developers I know walk around with a couple assemblies to make coding their next project easier. With Sharp Architecture, these are referenced in your solution right after File > New Project.
Everyone has their own preferred solution and folder
structure. The default project and folder organization in a new Sharp Architecture solution is pretty close to what I was already using and is simple for any developer to jump in and follow along.
This may not seem like a big deal because a good structure looks obvious in hindsight, but it's nice to not have to dig around for things. I've worked on solutions that have 20+ projects. Sharp Architecture goes the other way and you end up with about four projects in a normal MVC app.
What I would like to see in future releases
I don't have any strong objections to the design choices in Sharp Architecture. Most of the things here are more a matter of style/taste than anything.
Controllers back in MyProject.Web project
You can read Billy's view on putting the controllers in the web project. His main point is that controllers should be written and tested independent of the other assemblies so you don't succumb to temptation and do things like go straight to your repository from your controller instead of asking your IoC tool to give you the concrete repository instance.
That's fair. But my controllers don't do much besides call into my application services layer, render views, and redirect to other controller actions. I don't mind having a reference to the entire web project in my unit test project so I can test routes and the very little logic I have in my controllers.
In his article, Billy describes the pain of having done it the way I prefer. Maybe this is one of those lessons where you have to experience it yourself to internalize it. Like my dad telling me the stove was hot when I was a kid. >
MyProject.Infrastructure instead of MyProject.Data
Maybe I've looked at Code Camp Server or listened to Jeffery Palermo talk too much, but I lump data handling into a larger category of infrastructure concerns. Sharp Architecture's solution template gives you MyProject.Data, which holds the NHibernate mappings and conventions and the repository classes.
But I have other utility/infrastructure things I need to put somewhere, like logging, emailing, etc. I prefer having MyProject.Infrastructure with Data as a folder underneath it so I can throw all my infrastructure implementation code into that assembly. The interfaces for these guys still go in MyProject.Core, just like the repository interfaces.
More emphasis on MyProject.ApplicationServices
I prefer to have as little logic as possible in my views and controllers. I push as much as I can to an application layer so the UI can be replaced or added to with minimal impact. In Sharp Architecture, you've got MyProject.ApplicationServices for exactly that. There is one Northwind example that uses this layer, but in the other samples, the controllers are doing the application flow work.
I think it's better to have an application service passed into the controller's constructor so the controller doesn't need to know much except routing, views, redirects, the app service method to call, etc. I don't mind having these UI logic concerns in the controller, but anything beyond that needs to be in an application layer.
I've borrowed a metaphor from the SQL Server installer that talk about "surface area". I think of the MyProject.ApplicationServices layer as a wrapper around all the app logic. The methods in this layer are the surface area of my application, and they encapsulates all the implementation code my domain is dealing with. Calls into this layer can kick off multi-step processes, handle workflow, and usually have long, explicit method names. But this is the only part of my domain's surface area that is exposed externally.
The MVC web project is one client calling into this application layer, but there may be others someday on even medium-sized projects. If your app becomes more popular and you've followed this approach, you can add other clients that call into your application service layer like a WCF service, a system tray tool, etc. These guys may have their own specialized methods or may use something the web application was using. Either way, you are very intentional on the surface area you expose.
I think Sharp Architecture gets this right. I would just like to give it a little nudge to make it a point of emphasis.
I've used a lot of different frameworks, but Sharp Architecture comes closest to the way I want to work already. The templates and documentation put it well beyond a reference implementation, and you can work with a simplified solution sitting on top of a lot of abstracted complexity to get you productive right away.