As a product manager at patterns & practices, I got to write a lot more code than most people would expect from a product manager. However the nature of the job and the team meant that it was basically all prototypes and samples. So after over 3 years, it's very exciting to be working as a solution architect in Microsoft's Solutions Development Centre where I am able to get my hands dirty with real enterprise projects again. And for the first time in ages, I get to experience something most of you do every day: finding out what it's like to use patterns & practices deliverables on "real world" projects.
Our team has just started work on a large customer project, and for the last two weeks my key task has been to establish the baseline architecture, which basically involves trying out design approaches and establishing repeatable patterns through implementing just a couple of use-cases end-to-end. So now I wanted to share how we are using patterns & practices deliverables on this project and what the experience feels like from outside of Building 5. Keep in mind that we are still in the early stages of this project and we may yet revisit any number of design decisions as we implement more features and get more test feedback - but hopefully these first impressions are still interesting, and I'll try to keep you updated on what changes as the project progresses.
I'm sure it will come as no surprise that we're making extensive use of patterns & practices deliverables on the project, although to be perfectly honest I didn't expect to be using so much at these early stages - it just happened that we kept running into requirements where they proved helpful. Here's a quick rundown of what we've used where in the baseline:
- The baseline currently consists of two WCF-based services. The project structure and key service interface classes were generated using the Web Service Software Factory, and the overall architecture corresponds very closely to that described in the factory documentation. We didn't use the Service Factory to generate any of the data access components, since the SDC already has its own toolset for this purpose (in fact, the p&p Data Access Guidance Package was inspired by the SDC's solution)
- Exception shielding is implemented at the service interface using the Enterprise Library WCF Exception Shielding Behaviour, which provides an entry point into the Exception Handling Application Block and Logging Application Block.
- Cross-cutting concerns are able to be injected at the boundary of the business logic and resource access layers using the Enterprise Library Policy Injection Application Block. Handlers used at the business layer will likely include validation, instrumentation and authorisation. At the data access layer the key requirement is to map SQL Server error codes to .NET exceptions (see below)
- The Enterprise Library Exception Handling Application Block is a nice solution for systematically wrapping or replacing one exception type with another - but it can't be used out-of-the-box to wrap a SqlException with different custom exceptions based on the included error code. To get around this, I used the Application Block Software Factory to create a new Exception Handler class that lets you configure different wrapping exception types for different error codes. I'll publish more details on this and share the code over the next few days.
- The data access code (generated from the SDC's component generator) uses the Enterprise Library Data Access Application Block for managing database connections and calling stored procedures.
- To save me writing about 5 lines of code, I used the Enterprise Library Cryptography Application Block for calling hashing algorithms without dealing with pesky byte arrays
- Various aspects of the security model were inspired from guidance in the Web Services Security guide.
So that's what we've used. But what was the experience like? OK I realise I'm not entirely impartial, but here are a few thoughts from the first couple of weeks of work:
- I'm only using any of this stuff because it works. As soon as it starts to cause more trouble than it solves it will be out the door. But so far, I've been very impressed by how much I've been able to achieve with so little custom code.
- The Web Service Software Factory was awesome in setting up the initial layering for the services (although I do think some of the projects it generates could be merged together), and in most cases it saved me needing to hack configuration files by hand. However once I had the basic structure set up (with a very minimalist service contract) I found that I wasn't really using anything in the factory except for snippets to add new operations to the service contracts. While I'm very interested in where the team is going with the upcoming "modelling edition" of the factory, at this stage of the project I don't think having pretty DSL diagrams of my service contracts and service interactions will make my job any easier.
- Even though I have always insisted that any Enterprise Library customers who want control over their own destiny should compile and strong-name the code themselves rather than rely on the pre-signed binaries, at this stage of the project I can't justify the effort to do this - although this may change.
- The Policy Injection Application Block is way cool in keeping code clean and consistent. However a couple of times it's confused me by throwing meaningless NullReferenceExceptions when the blocks it uses aren't configured properly.
- I was never a big fan of the Exception Handling Application Block, since it required writing a silly piece of boilerplate exception handling logic in every method. But with the Policy Injection Application Block and/or the WCF Exception Shielding Behaviour, this block is surprisingly useful 🙂
- When you create a new policy with the Exception Handling Application Block, the default post-handling action is NotifyRethrow, meaning the original exception will be returned back to the application. I've been stung by this about 4 times already, where I've configured policies that modify the exception, but the modified exception never gets thrown. If you don't change the post-handling action to ThrowNewException this won't work.
- Given the choice of controlling block behaviour through configuration or attributes, I've been opting for the latter wherever possible (and unfortunately it's not possible all that often). I like being able to control things declaratively, but managing configuration files is already becoming painful - especially when you have multiple services and unit test projects, each with their own configuration files.
- The Application Block Software Factory rocks! I built a new exception handler, complete with design-time, in about 3 hours. I would have no hope of doing this the old-fashioned way, even with generous copying-and-pasting from the Enterprise Library code base.
I'd be interested in hearing whether I'm still looking at p&p through rose-coloured glasses, and to hear how your experiences are different to mine. Also I know that Don, Grigori and the gang will be watching, so this is still a great forum to influence the direction that these deliverables go in the future.