ASP.Net MVC Principles – Part 1
Our clients often ask us to explain the architecture decisions behind the ASP.Net MVC principles in our standard application template. We’ve had these discussions a number of times and felt it would make a great blog series. Here we start with our first part of a planned four-part series describing our MVC project template.
We have the opportunity to review, maintain, and build a lot of projects. On each of these projects the quality and complexity of the code we are given to work with varies greatly. We’ve learned how to be successful in all these situations, but a favorite scenario for our team is the “greenfield” project – a brand new project or rebuild of an older project. On greenfield projects targeting the Microsoft stack we use our BHW MVC project template, designed in accordance with our ASP.Net MVC Principles.
As a consulting company we have to tailor our approach to match our client’s desire, capability, and technology investment. Installing a Laravel project into an ASP.Net WebForms shop generally isn’t a good idea, but when the right situation presents itself, BHW often advocates the use of our standard Microsoft application template.
We’ve built our MS app template over the last three years, making changes from lessons learned in projects of all sizes. Our decisions about specific modules favor technologies that we feel make us the most productive without sacrificing run-time performance, security, or increasing the cost of maintenance. There are trade-offs with every choice, but as you’ll see below we are big fans of modular, loosely-coupled systems. If you don’t like something, change it out.
First off, we’re big fans of community-driven, open source code. Yes we’ve worked on projects that cannot link any non-Microsoft assembly, must approve every third-party dependency, etc. Those projects can be fun too, but when we have the flexibility to include open-source solutions we always do (this is a fantastic financial benefit for our clients as well). You have to carefully review the open source license requirements, but that’s for a different article…
We’d like to thank the people who have worked on the open source projects we include in our template. They have truly made a fantastic contribution to the quality of development and code on the Microsoft MVC stack. Our ASP.Net MVC principles have been heavily influenced by Jeremy Miller and his excellent work on FubuMVC as well as the IoC container, StructureMap. Thanks also goes out to Jimmy Bogard and his contributions to AutoMapper as well as his great discussions around MVC. In the past we used the Castle team’s excellent Windsor IoC and Validation frameworks. Thanks too to the NHibernate team. We don’t often have the chance to use their data layer now, but there was a time when it was involved in many of our projects.
ASP.Net MVC Principles
We’ve built our app template on the following guiding principles of object oriented design:
- SOLID – an acronym describing five separate object oriented design principles:
- Single responsibility – design classes with a single responsibility. This is most often seen in business logic and integration code. We’ve all opened a class that includes “the kitchen sink”. We’ve all felt the worry of making changes in that code, with no idea what impact we may unintentionally have. Designing classes with a single responsibility makes them smaller, easier to test, and increases their ability to be reused elsewhere.
- Open-closed – classes should be open to extension but closed to modification. This concept solves a problem that is easy to demonstrate in systems with code reuse. If I change a class to meet my needs, what did I just do to everyone else who uses the same class? Modification can change the correctness of other parts of a system where extension is localized to the new code being added.
- Liskov substitution – “objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program”. Wikipedia also references “Design by Contract” as an example of Liskov substitution. You can argue for polymorphism here as well, but we’re bigger fans of substituting concrete classes using interface contracts as you’ll see below.
- Interface Segregation – “many client-specific interfaces are better than one general-purpose interface”, Robert C. Martin. We’ve already mentioned we like loosely-coupled systems, and interface segregation is a great explanation why. A large interface creates many dependencies in the client code as well as dependencies in the concrete classes that chose to implement it. Think to the last time you were writing a concrete class for an interface and found yourself copy-pasting “no-op”, “return null”, and “throw NotImplementedException” methods to complete the interface contract requirements. Callers of your new interface may very well expect these methods to work, since they are part of the interface, and they will be surprised at run-time when they don’t.
- Dependency Inversion – “depend upon abstractions of a class, not the concrete class itself”, Robert C. Martin. Most people know that Computer Scientists love abstraction layers, and Inversion of Control (IoC) containers give us an easy factory pattern for implementing this principle. As you’ll see soon, this one principle is at the core of our template.
- DRY – do not repeat yourself, frequently coupled with “convention over configuration”. A favorite saying of Rubyists. Remember the last time you worked with a WCF configuration file, or maybe implemented a new log4net appender? XML tags start to blur together – “wait am I editing the client or server binding”? Once you got it working I bet you copied it over and over to every project where you needed it, dreading having to open the editor to fiddle with an interface name change. Luckily Microsoft copied was heavily inspired by Ruby on Rails, adopting many of the concepts behind routes, view rendering, etc. If you come from Java you have similar EJB configuration horror stories. Configuration is error prone and time consuming. Why not build our decisions into the framework as defaults and manage only the exceptions?
- Aspect Oriented Programming (AOP) – Caching, Logging, and Security are the most often quoted examples of AOP. With AOP you can wrap a proxy around every class, intercepting method calls to do useful things. Quick add function execution timing to every method in our address validation interface! We need to cache every call to our lookup data! Log the security principle’s name, method, and input values on every admin function! With AOP all of these needs can be as simple as a few lines of code and a change to the IoC… Encapsulate what changes – this is the principle of compartmentalizing areas of the code that are likely to change or be extended later. At BHW, many times we start building a system and the client doesn’t yet know which payment processor, address validator, map provider, control, or business algorithm will be in the final build. In these scenarios it is useful to use the techniques here to encapsulate the area impacted by this decision so that later when a decision is reached we have a smaller, localized change to make.
- Defensive Programming – This is the practice of checking our input parameters and output parameters for expected values, typically checking against nulls. You can argue it makes code less readable, but we think it’s better to check all our inputs than to simply “let if fail”. By checking inputs we can give better error messages when our code receives a null parameter or unexpected value. A better error message, even from a thrown exception, saves time that our developer doesn’t spend digging though a stack-trace for a Null Reference exception that could have originated in multiple places.
That’s the end of part one. In part two we’ll cover how these object oriented design patterns are mirrored in our ASP.Net MVC principles. We’ll also go into more detail about the BHW application template.
Do you need an expert in web development? With a team of web development specialists covering a wide range of skill sets and backgrounds, The BHW Group is prepared to help your company make the transformations needed to remain competitive in today’s high-tech marketplace.