Programming for Maintenance

Code Complete defines Maintainability as “The ease with which you can modify a software system to change or add capabilities, improve performance, or correct defects.”

I’ve been thinking for awhile now about this post and I’ve been unsure of exactly what needs to be here.  I know I’ve done a lot of maintenance work.  It’s inevitable.  You name the field and chances are we’ve developed something for it.  A lot of the software we develop we do so because there just isn’t commercial off the shelf (COTS) software for the business process.  COTS is for the broad market.  So customers come to us when COTS doesn’t meet their needs.

Which gets us to maintenance.  We try the best we can but in any software application there will be bugs.  It is inevitable, it is a fact of life.  Unless you are just writing a “Hello World” program there will be people who use your product in ways you didn’t expect.  We have had clients who take the application we’ve written for them and walk away.  Not because they’re unhappy but because the cost to fix every single bug and add in every feature they want can often be prohibitive.  They’re happy where the app is and that’s good enough.

Most clients stay with us for a maintenance tail.  They prioritize the bugs they want fixed and features they want added and budget accordingly.  We want happy clients, it’s that simple.  The happier they are with us the more work they bring to us.  This is common across all businesses, whether you’re a dry-cleaner or doing software services, a happy client is good.

So in software services how do you make a client happy?  In my experience it’s been minimizing maintenance tail costs.  But how do you do this?  I’m going to try and sum up where I have noticed problems.  I could reprint Code Complete here and say, “There, that’s how you do it” but that would be meaningless.  The point of this post is to focus on a few key points.

1.  The obvious:  Requirements, requirements, requirements.
As much as possible try to impress upon your clients the importance of requirements.  The more requirements analysis and design that is done up front before even beginning development the cheaper the maintenance tail.  It’s fact the earlier you find a problem the cheaper it is to fix. (Code Complete, Table 3-1, Average Cost of Fixing Defects Based on When They’re Introduced and Detected)

The biggest problem with this?  Most of the time clients don’t know what they want.  That’s right, they come to us and say, “Well, I want an application that does this.”  But what does that mean?  Does this need to mirror an existing business process?  Is it something completely new?  Do you have an idea of how the process should flow?  Do you know where you get your data and where it should go?  What kind of reporting are you going to need? (Customers never know that last one)

A lot of time we end up building up an existing business process in order to understand what needs to be developed for the application.  That’s okay.  I can accept that business analysis may be a part of the job.  So this is key:  (most of the time)  Clients don’t know what they want.  They will usually have a generally vague idea but you will have to help them.  Try to come up with a basic set of requirements.  Next, at a minimum, whip out Visio (there are better products out there but Visio is probably the most common) and throw together a few pages of the app.  Put together some sort of flow.  Help them bring their vision to reality.  Only then will they really begin to understand their own requirements and process.  Only then will they see what’s there and what’s missing.  Most clients can’t envision software.  They’re paying money for something that is completely virtual and just can’t see the final product.

Now, this is all well and good.  The problem is that a lot of clients don’t want to spend several weeks (or longer) designing the app, they want to get moving on it.  This leads to iterative development.  It’s more expensive.  But done properly I’ve still had happy clients.  Prioritize parts of the application.  Model a couple of those pages, build it, move on.  You will have problems.  I had one client who missed telling us about a key part of data for the app.  The ERD we had didn’t support this new data so we had to build out some new tables and fix everything.  This was after we’d done requirements and modeled the pages.  It wasn’t until the app was in beta that he went, “Oh, and you need to put this in there.”

2.  Naming Conventions: Use it, love it
This is going to sound stupid but one of the biggest problems I’ve had coming in to maintain an app I didn’t design or build is naming conventions.  Even if the names are consistent and meaningful, when there is no standard across an application where multiple developers have been working on it, it takes way too long to understand everything.  I’m not saying that your company should enact a strict naming convention company wide.  That would be nice but it’s not reality.  Your project lead, however, should.  Even if you’re working under different project leads you need to adapt.  This is especially true in this polyglot world of development.  At one time I was working on a PHP project, a java project and a C# project.  Each has their own naming conventions.  Yes, it took longer when I had to switch projects to re-orient myself but that in and of itself is the nature of polyglot programming.  I know that when someone comes behind me to maintain the app (and in a lot of cases it’s even me) it is a hell of a lot easier to get going on maintenance when there is some sort of naming convention across the app.

So what do I mean by naming conventions?  Method names, event and delegate names, variable names.  If it takes a name there needs to be a standard.  Whether it’s public, private, static, constant, an enum or class, there needs to be a standard.  The only place I haven’t seen a need for naming conventions is internal to methods.  If the app is coded right and adhering to basic OOP methodology variables internal to a method shouldn’t be around that long.  They still should be meaningful but I don’t care if you want to put an underscore in front of your internal variables or not.  I don’t care if you want to capitalize them or not.  Anytime I have to walk through from class to method to class to method to delegate to method there better be some sort of convention.  Otherwise it costs the client money.  There will always be some sort of spin-up when entering maintenance.  Just try and minimize it.

So you’ve got your requirements and naming conventions, what’s next?

3.  OOP, if you use it, use it
The biggest trouble I’ve had, excepting those mentioned above, are projects where developers seemed to take a procedural approach to OOP.  God classes and methods (functions?), poor use of inheritance and virtually no use of interfaces.  This makes maintenance tough.  I have to admit I myself was bit lacking in this area out of college.  Sure I took an OOP class, sure I had the theory but applying the theory is wholly different then having the theory.  And I’m not the only one.  It seems one of the universal constants having new engineers on my team fresh out of college is that they can’t apply OOP.  This often also applies to self-taught programmers who many times don’t even have the theory.

I want a black box (Code Complete, Encapsulate Implementation Details, Information Hiding).  When I step into a method during troubleshooting I want to only go into that method once.  There after I want to trust that the method works as intended.  I want a method to only do one thing and not affect parts outside of itself.  If I have a login control it should only be doing login.  I want a class to default all properties (getters/setters) to private.  I don’t want those variables being changed outside the class unless they need to be.  I want interfaces(Code Complete, Form Consistent Abstractions).  It seems like this is the least understood by programmers straight out of college.  So often new engineers like to inherit and override.  Obviously this has it’s time and place.  But think if this really is needed or if you just need to create an interface (Code Complete, Inherit-When Inheritance Simplifies the Design).

I digress, I’m starting to write out Code Complete.  If nothing else, use and apply Code Complete, 5.3 Design Building Blocks: Heuristics.

So how to fix this?  If you have an engineer on your team that you’re not familiar with do a code review.  Assign him a task and take a look at his code.  I don’t think I carry the title Senior Software Engineer because I such a great programmer.  Really I barely consider myself adequate.  I have seen a lot of code, written a lot myself, I lead teams pretty well as a project lead and clients like to work with me.  If you’re leading a project remember the code of the engineers underneath you is your responsibility.  Yeah, you might ruffle some feathers.  We programmers take our code personally.  We’re proud of it.  No different than an architect whose proud of a house he’s built or a chef whose proud of his food.

4.  Stay up-to-date
I won’t harp on this long because I’ve said this before.  Programmers use what’s available to them.  I love LINQ, but I know LINQ because I read about it before it was even released publicly.  I can do a lot of stuff easier with LINQ.  I love WPF, but I know WPF because I read about it before it was even released publicly.  I can do a lot of stuff easier with WPF then I could with WinForms.  If you don’t stay current there’s a good chance you’ll jump into a project where it’s using something you don’t understand.

5.  Code to maintain
I suppose this is really the heart of the issue.  What the hell does this mean?  Any adequate programmer should be able to jump into a piece of code and start working on bugs and adding features.  I’m not saying there won’t be a spin-up.  Of course there is going to be some spin-up.  But try and minimize that.  When most people are working on code they’re not thinking that in a year or more someone is going to have to come behind them and read the same code trying to figure out what they were doing.  But they should be.

Finally, I want happy clients.  That means minimizing maintenance.  There will always be maintenance, it’s inevitable.  But when I can jump into the maintenance tail of an project faster, fix bugs faster, implement new features faster than clients are happier and my job is easier.  And I like it when my job is easier.  It will always be challenging but I prefer challenging and fun to challenging and a pain in my ass.

I could keep going.  Someone could write a book on the subject (yeah, I know, Code Complete).  This post is just intended to hit a few top issues I’ve seen when maintaining code. YMMV.  You may have seen other issues that top this list.  Tell me about them.  Post a comment.

Later,
Brian

Comment (1)

  1. Tyler Coles

    Regarding requirements gathering: I would go so far as to say that frequent iterative development/prototyping is the only way to develop. No one ever knows what they want an application to do. If you’re lucky you know “what do I want it to do right now?” which can change on a day to day basis anyway. This isn’t a fault; it’s the nature of the game. If you make the iterations frequent enough, you minimize “lost” effort if the client wants to change direction mid-stream. But I wouldn’t even call it lost effort. It’s effort that was spent to discover the true needs of the application.

    I’m also convinced that automated testing (unit- and functional-tests) is the most important piece to make a site maintainable. Especially in large applications, maintainers need to be free to make changes without worrying about breaking a component that has an unknown dependency on the piece being changed. With good automated tests, I should know right away that I broke something and I’ll know right away when I’ve fixed it. This might even point out inherent design flaws.

    To take that one step further: an application without automated tests is already broken, you just don’t know it yet. Unit tests don’t stop you from writing buggy code (or buggy unit tests) but they do give you the freedom to make changes. Even better, writing unit tests will point out how terrible your OO design is. You can’t unit test procedural code. You can’t unit test code that is tightly coupled with other components. I’m not saying development ought to be Test Driven, more like Test Assisted, but I definitely feel like developing without tests is negligent engineering.

Leave a Reply