The other day a customer asked me to give them some advice on building or acquiring a development framework. As it turns out, I've spent most of the last seven years either building or using reusable code assets of various kinds, so I happily agreed. And since I've still looking for directions to take my blog since leaving p&p, I thought I'd share some of this with you too!
First, a quick comment on terminology. I generally avoid the work framework since it tends to mean many different things to different people. Still it isn't necessary to get hung up on what is and isn't a framework, as this discussion is really about reusable code assets in general. But while we're on the topic, here's the taxonomy I normally use when thinking about reusable code:
- Platform libraries, such as the .NET Framework or WSE
- Reusable components, such as the Logging Application Block. These encapsulate useful functionality, but don't prescribe an architecture
- Application frameworks, such as the Composite UI Application Block. These tend to enforce layering and responsibilities for a specific architectural style
- Code generation, as is used in p&p's software factories. Generated code may automate any of the above, and sometimes provides a good alternative to components or frameworks since the variability is dealt with at design-time, resulting in simpler run-time code.
Code reuse is of course a very good thing - provided it is managed well. A good reuse strategy will lower development time and cost and result in applications that are more consistent, of higher quality and easier to maintain. Unfortunately implementing a good reuse strategy is easier said than done. Over the course of the last ten or so years I've seen a number of different strategies in use at customers, including:
- No real strategy at all - every application is written more or less independently, and any code reuse is ad-hoc
- Building and maintaining a complete code library or development framework in-house
- Using a code library or development framework built by a solutions provider company
- Using a free library or framework (such as patterns & practices or open source) and extending or customising where necessary.
All of these strategies are in use by some customers today, and all can make sense under some circumstances. However the general trend has been to move through this list in order, and more and more people are gravitating towards number 4.
But whether you are building your own framework, evaluating one that already exists, or extending one, there are a number of common pitfalls I've seen people fall into. Here are the main offenders:
- Not harvesting from proven practices. While this may seem obvious, it's probably the most common mistake I've seen. Attempting to build a reusable code asset before you fully understand the problem or the solution is not going to work well. By far the best way of achieving this is to have one or more applications that had these requirements and solutions that work (even if they are not yet reusable). Having one such application should be the minimum bar, having two is better as it makes it easier to determine a more generalised solution. Building an application and a reusable framework at the same time can work, however in my experience it is much riskier than harvesting code from a finished solution.
- Solutions that are more complex than the problem. Reusable code attempts to mitigate problems that can occur if applications are built from the ground up. Sometimes there are very legitimate concerns about where this will lead, however before introducing a framework (especially if you plan on building it in-house), make sure it doesn't cause more problems than it solves. The cost of building, maintaining and training people on a reusable asset can be sizable, and while in many cases it is the right strategy, make sure you pick your fights carefully.
- Custom solutions to generic problems. There are many development challenges that affect almost every application on a platform, regardless of your industry or application's requirements. While these challenges tend to be addressed in the base platform eventually, there can be a considerable period where some other kind of reuse strategy is required. For challenges that are clearly generic (such as logging, caching, enforcing MVC patterns, etc), it is almost never a good idea to build your own solutions from scratch as someone else has probably done most of the work already. Even if your organisation does have unique requirements (such as the need to log in a proprietary format), it is generally possible (and better) to extend an existing solution.
- Diverging too far from the base platform. As mentioned above, each new release of a platform such as .NET will tend to address challenges that previously required custom code. While this doesn't mean you shouldn't use higher-level reusable assets while the challenges exist, you should be very careful not to stray too far from the platform's approaches as this can lead to major migration headaches. A good example is the configuration system in Enterprise Library 1.x, which was build from scratch rather than leveraging System.Configuration. While we had good reasons to do this at the time, it caused major pain when we migrated to .NET Framework 2.0's System.Configuration as it addressed many of the same challenges in a different way.
- Lock-in to a single company or architectural approach. No matter how attractive a pre-existing offering is, there's a very good chance that it won't be the best option for your organisation in 3 or 5 years. It's a good idea to think of an exit strategy for any given framework before you get hooked on it. In particular you should be very careful before adopting any solution that imposes requirements on other applications it communicates with, such as using custom wire formats for messaging. Wherever possible, the use of the framework should be invisible outside of the application's boundaries, and any external communication should be standards-based.
- Not considering ongoing maintenance and support costs. Building and maintaining any large body of code is expensive. While reusable code is theoretically more cost effective, as it gets used across multiple applications, many organisations fail to consider the ongoing cost before starting an in-house framework. Sometimes the benefit will indeed outweigh the cost, but I've seen many examples where this hasn't been the case. As mentioned above, for generic problems there are a number of great free solutions available, and keeping in-house development to the parts that are genuinely unique to your organisation is a great way of lowering ongoing costs.
- Not focusing on usability, documentation and training. As I pointed out in an earlier rant, it doesn't matter how functional or architecturally beautiful something is if nobody is able to figure out how to use it. While this applies to almost everything in life, I've found this problem to be particularly common in the area of reusable code assets. The very premise of reuse is that the code will be used by someone other than the guy that wrote it, and that the more people reuse it the better the results. But there's no way this is going to work unless the end developer understands the value, knows how to use it, and believes it will make his or her job easier.
Of course this is just my opinion based on my own set of experiences. Do you agree with my list of deadly sins? Do you have anything else to add to the list? What do you think is the key to a successful code reuse strategy?