Tom Hollander's blog

patterns, practices and pontification

The Seven Deadly Sins of Reusable Asset Development

The Seven Deadly Sins of Reusable Asset Development

  • Comments 8

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:

  1. No real strategy at all - every application is written more or less independently, and any code reuse is ad-hoc
  2. Building and maintaining a complete code library or development framework in-house
  3. Using a code library or development framework built by a solutions provider company
  4. 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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?

  • Hi Tom,

    Some of your assertions I agree with.

    One you didn't mention was that a great deal of solutions aim to solve non-standard requirements. i.e. there are way too many types of customer requirements - hence way too many frameworks and solutions that can't be re-used with high effect (and bloat the solution domain). They are also way to context specific and hard to learn another customers requirements which they fit well.

    A lot of this would be easier if requirements were standardised, with standard solutions if you get my drift. Then framework applicability and reuse would increase dramatically, becuase there would be a common understanding of common requirements and appropriate solutions.

    The other point is that any given framework (or other high level abstraction i.e. a DSL) is typically not suitable for adaptation to another slightly different use (unless that use in on teh same axis as orginal DSL, i.e. a specialisation or generalisation of it), and adapting or hacking to fit that different use becomes more trouble to maintain than its worth. Again, this is a side-effect of non-standard custom requirements.

    One of the biggest problems customers face in the real world is assessing any given framework will apply to them.  In order to do this, many feel like they have to own a deep understanding of it, and they need an exact match between their unique customer requirements and those covered by the framework. Doing this easily is the largest challenge with selecting a framework, and to be fair, most organisations don't have the time or budget to invest in that exercise (not that it wouldn't pay off, but more becuase it's easier to take a 'not built here' position so they can tackle the intellectual challenge themselves). Resulting in of course rolling their own one-off solution or half-baked attempt at a reusable framework - which suffers the problems you point out in the first point.

  • This will be printed and posted on my cube with all the other good advice on it that nobody follows.  Well said Tom, keep it coming!

  • You've been kicked (a good thing) - Trackback from DotNetKicks.com

  • This feels very much like a list of sins for Big Design Up Front frameworks.  I think if this list were written from an Agile perspective, it might look completely different..  Thoughts?

    Evan

  • Jezz - it almost sounds like you're suggesting we use something like a Software Factory! :-) Of course I agree that these are valuable and can simplify many aspects as reuse by packaging related resuable assets together and being explicit about what requirements they do and don't address. However I still believe that the potential pitfalls listed here can apply to almost any resuable asset type, including software factories (which are really a context-specific combination of all of the asset types mentioned in my post).

    Evan - I'm not sure I agree. If you set out to build a business application using agile techniques, then any frameworks or other reusable assets would need to fall out of the user stories, and as such many of the risks I've listed shoudn't occur. However if you set out to specifically build a resuable asset, even if using agile techniques for planning and developing, I believe it's possible to fall into these traps. Ultimately most of these issues are a function of the requirements and priorities, and if these aren't thought through well it doesn't really matter what process is followed to actually build the thing.

  • Evan/Tom

    I don't think software development methodology makes any more of a difference than the language when it comes to good/bad - success/failure.  

    Projects/frameworks written with Agile/RUP/ERUP/Scrum/Waterfall have all had successful outcomes and complete failures.  Just as projects/frameworks written in VB/C#/Fortran/C++/Java/COBOL/RPG have all had successful outcomes and complete failures.  

    If our community focused more on doing things right, and being pragmatic about it, rather than trying to find the golden methodology/language that will solve all there problems or be the solution to 90% of there problems, maybe we would have so many pointless debates about which is better and why and so many shops that have the horse blinders on and won't even consider other options.  All methodologies, all languages have there pros and cons.  Use the right tools for the right jobs.

  • Making sure that eveyone in the team / organisation knows what is available can be a major hurdle. You can spend forever creating the perfect comms layer but if no-one else knows youve done it, youve wasted your time. I sometimes find myself creating code to perform a particular task only to find out later that theres already a  method in the .net framework that would have done the same thing for me. The same applies.

  • I think number 7 is a big hurdle for a lot of people too...especially when it comes to naming your classes; things like CarImpl?  WTF?  It's either a Car or it's not a Car.  If you want to talk about it generically call it a Car (abstract or root) or ICar (interface); if you want to talk about it specifically, call it a Saturn, or a Ford - but these stupid Impl classes I see floating around in some frameworks is just asinine.  Oh wait, I probably shouldn't use the word 'asinine' - sorry Tom; let me just hit my KeyImpl a few times on my InputDeviceImpl and remove those...

    Anyway, unnecessary declarative programing... why have all your objects config file driven and all this extra fat in your config file if there's not a chance in a heck that you're ever going to need that type of flexibility.  It's hard to maintain, much harder to debug, and harder to develop new features against.  It's like the UIP or WF - great/outstanding framework - if you need that level of flexibility and scalability - but if you don't need it why are you adding extra complexity?  Martin Fowler has a few words for those of you answering with 'we might need it someday' - 'Speculative Generalities'.  But then unfortunately a lot of developers just add it because it's there, it's considered trendy, and 'they can' - that's even worse than speculative generalities - that's outright amateur.

Page 1 of 1 (8 items)