The Truth as I See It: Part 2
Software has a half-life. This isn't really news; I'm hardly the first person to point out the phenomenon of code rot. But I would describe it a bit differently. Code rot is what happens when the core of your design is faulty -- when you have less-than-quality code at the heart. Maybe the person that wrote your first string handler, or Regex parser, or structured your data model really didn't know what they were doing.
There are plenty of ways to write bad code, regardless of language. Here's some examples of rotten code...
NotesDocument.ComputeWithForm (false, false)
@If(
@IsError(@DbLookup("" : "NoCache"; DbName; view; key; field)); "";
@DbLookup("" : "NoCache"; DbName; view; key; field)
)
for (int i=1; i<DocumentCollection.count; i++) {
Document curDoc = DocumentCollection.getNthDocument(i);
}
I believe there is a separate concept of code decay, where code expires not because it was anything less than brilliant when it was designed, but because the context in which it is run has changed, and it's ill-suited for that new environment. Mostly, this is about prior constraints being lifted, but sometimes it's about new constraints coming into the picture.
My favorite example of code decay is the formula engine in Notes. It was famously obtuse, buggy, and difficult to maintain for the better part of a decade, and one day Damien Katz got it into his crazy head to try to refactor it. He did, of course. And wonderfully so, and we've all been enriched by this, but when I first heard about it, I thought to myself "how is this kid going to refactor code that was designed and largely coded by Ray friggin' Ozzie!?!?!" It wasn't until after he told the tale that Ray dropped by and mentioned this original constraint: he was limited by the memory barrier that was still pervasive on workstation architectures at the time.
For me, reading that was a moment of staggering realization. Here was a situation where a self-professed C++ amateur could successfully refactor something written by "one of the top 5 programmers in the universe," because he was able to do drop a key constraint: that RAM was a rare and precious resource. The most amazing thing about it was what Damien was told before he set out on the project -- that none of the more experienced developers wanted to take on the job because they regarded it as too big a challenge precisely because the original code was so convoluted. Because he discarded the assumption of the original constraint, he was able to approach the task with fresh ideas, and it turned out to be achievable.
Allow me to offer what might be a more accessible code decay example for Domino developers. How many times have you seen this design pattern?
Why is this so common in the Domino world? Originally, people did this kind of design for two reasons: 1) because you couldn't show a view inside an open document -- your best option was to show responses underneath; and 2) because it was a performance advantage to have fewer large documents in an NSF instead of more small documents.
As of R5, point 1 was eliminated. You could use the Embedded View object in both a Notes client and on the web to display a view that was restricted to a contextually-selected subset. Yet developers stuck with the prior pattern largely due to concerns over the increased number of documents needed. As new versions were released and hardware performance continued to improve, the burden of large document counts in NSFs became less of a concern. Ultimately, that prior pattern became regarded as a bad approach, not because it wasn't good when it was originally done, but because the context for the platform had moved on.
Thus, we reach the theme of part 2: the need to refactor doesn't necessarily reflect the quality of code written in the first place. Often, it simply means the world has moved on, and your software must move along with it.
That's why I place such a high priority on maintainability. It doesn't matter how great a coder you are, or which choice of language you make, or how brilliant your underlying model is -- eventually your context will change and the approach you used before simply won't fit into that new situation. If you care about keeping a good system, you're going to have to invest in maintenance coding. It's like brushing your teeth or going to the gym -- just 'cause you have a winning smile or six-pack abs doesn't mean you get to stop working on it.
And so we reach an interesting paradox of software design: the faster your underlying support structure -- be it a platform, a language, a network or some hardware -- improves, the faster your code on top of it decays. Leaps forward on your platform result in dramatic points of decay. Composite apps are a great example of that. So are Xpages. The greatest apps designed on N/D 7 are already legacy code. (Side note: part of the job of a platform vendor should be to help you keep your code current more easily -- more on this in a later article.)
For this reason, I have come to think that all software engineering projects should include a code maintenance budget. It might cost you X dollars to build something initially, but that's not the end of the story. You should be spending at least 1/10th of that annually on continuing improvements to that code. Not because your code stinks and you constantly need to fix it, but because the world is in constant motion and your context is ever-shifting. (Incidentally, this has the nice side effect of making it easier to address new business needs as well.)
If you don't invest on a continual basis, the pattern of decay will eventually compel your users to demand a migration instead. Migrations are rarely about the target platform, far more often being about the investment in refactoring existing applications and processes. The same attention and expertise applied to the existing platform could often yield the same or better results, often for the same or less money. But who wants to pitch the idea of rewriting to the existing platform? There's nothing sexy about that. It doesn't sound innovative. It doesn't sound strategic. It simply sounds like you did a lousy job in the first place. And you did -- because you made the users suffer through decaying code while they were trying to get work done.
Migrations are the IT equivalent of getting a root canal or liposuction -- only necessary because you let yourself fall into a state of disrepair in the first place.
If you have designed for maintainability, then your continual investment will be successful. You will be able to swap out behavioral parts of your software, progressively reveal changes to your user audience, and easily identify bottlenecks in your ever-changing code. If you haven't designed for maintainability, then all your continual investment will be spent on trying to figure out what's already there and not break it.
Please share your thoughts and stay tuned for part 3 -- where we'll discuss how user experience can accelerate code decay.


Comments
-Devin.
Posted by Devin Olson At 09:49:08 AM On 07/24/2008 |
Posted by Tim Tripcony At 10:53:28 AM On 07/24/2008 |
Posted by Keith Brooks At 12:51:52 PM On 07/24/2008 |
Sometimes your VP of IT and your dentist/surgeon are golf buddies.
Not ALL migrations are the reflection of code rot - and I don't think this is what you're saying at all, I'm just trying to head off the l337ists...
But back on topic...
There's something to be said for weaponized development - that is, development that pretty much takes into consideration shifting needs, expansion of your environment, further adoption, and enhancements to the platform(s). This can be achieved through configuration-based coding of your applications: configurable workflow engines, expandable UIs, etc. Sure, it takes a little more up-front time for your first few (once you get it down, you should write it vanilla enough to allow porting to other projects with ease), but it pays off in the long run.
But this is why I like your article. Writing your applications so they can be configured won't get the job done indefinately... there will be code rot EVENTUALLY.
It's like bandaging a zombie bite - it'll stave off the infection for only so long before your shambling around using SharePoint and Exchange... (shudder).
Posted by Chris Toohey At 01:38:05 PM On 07/24/2008 |
*passes the spliff*
Posted by jonvon At 04:34:01 PM On 07/24/2008 |
Posted by Nathan T. Freeman At 04:48:35 PM On 07/24/2008 |
Sometimes, applications function well and should be left alone.
Rich Schwartz gave me a name to match a concept several years ago. The name is "Second System Syndrome" and it can be summed up with the statement "We're going to write the application, but this time we're going to do it right - knowing what we know now."
How many times have you seen that kind of project fail? These become the over thought, over engineered nightmare projects that are rebuilt to solve a problem that has changed in the time since the original.
Posted by Andrew Pollack At 08:18:50 PM On 07/24/2008 |
Posted by Tony Palmer At 08:59:51 PM On 07/24/2008 |
I didn't say that if a solution cost X, you should spend 5X to refactor it. That's platform migration. "Second System Syndrome" is the big, wad-it-up, shoot-it-all-at-once approach, and you're absolutely right -- that fails. It often fails spectacularly.
I said if you spent X, you should devote X/10/year to incremental improvements and what are basically regular workouts for your code. There's a big difference.
There's no application that "functions well and should be left alone." Not even yours. What was it you were bragging about doing with your code last weekend? Something about a single form to simplify some pieces that were already technically in place? Didn't you finish that product something like a year ago?
When was the last time you took NCT Search out for a run? Do you think you've learn nothing new about coding since your last build? Do you think there's been no changes in hardware, OS, database or network technology in the intervening years that would alter the way you do something inside it?
(Please note: not a word of this is to be critical of your software, which I find to be of exceptional caliber. It's actually because I find it to be high quality that I'm certain that if you looked again, you'd go "ah, well.... yeah, this could work better if I did X and Y and Z." I know you well enough to know that your mind has not stood still.)
Posted by Nathan T. Freeman At 10:06:06 PM On 07/24/2008 |
Code that doesn't need tweaking: The core code for a certain partner secure extranet has not needed modification in several (as in since the v5 days) years. The code that feeds the system has had changes (as it was planned to) to handle changes in the source data.
As far as Second Signal - Its never done. Its a core business. The last completion milestone was to make a useable site for end users. Automation was always in mind for the future. Revisions will be ongoing.
NCT Search -- Its probably 4 years overdue for a major re-fit. The core works great, but the peripheral stuff -- well its way outdated. It doesn't match whole new ways of using a tool like that. Its on my list for this fall.
Posted by Andrew Pollack At 10:18:34 PM On 07/24/2008 |
I don't know anything about the partner secure extranet you're referring to, but if it hasn't been modified since R5 and it's a web app, color me skeptical at the idea that it's in harmony with Web 2.0 design patterns and works well with mobile devices. Heck, even CSS has undergone a major revision since then.
Posted by Nathan T. Freeman At 06:45:34 AM On 07/25/2008 |
Posted by Andrew Pollack At 08:38:43 AM On 07/25/2008 |
That's a nice idea, but it's not very realistic in my experience. It's hard enough to get management to buy into a reasonable timeframe for a project. If you ask for 10% overhead for maintenance you'll get laughed out of the room. Or maybe I'm just a cynic.
Posted by Charles Robinson At 02:56:20 PM On 07/25/2008 |
Posted by Nathan T. Freeman At 04:41:11 PM On 07/25/2008 |
Now, from your perspective, Nathan -- working as you do from the consulting side on applications or on deliverable products that carry with them an expectation of long term maintenance, its relatively easy to justify a long term maintenance budget. Inside a company -- I doesn't play unless its a "critical" application.
Its like the outsourcing to low-wage development. You and I know that clients who go that route almost always fail. They fail because what they need is consulting and what they think they need is hourly development. You'll almost never convince them of this in a meeting. You can't tell them "well, you'll fail because you're not half the project manager you think you are, your specs suck, and you don't really know what you want." It doesn't go over well. You just have to wait for them fail and then come back to you complaining about the bad work they got. The truth will be that they got exactly the work they asked for. They'll never go down the road of understanding that they don't ask for the right things. Sad, but true.
Posted by Andrew Pollack At 08:19:10 PM On 07/25/2008 |
We could argue about whether decision makers understand this point until the cows come home. Obviously we agree that it's TRUE -- the issue is one of salesmanship. So let's figure out the people sales toolkit we can. Preferably something superior to, say, IBM's software marketing.
Posted by Nathan T. Freeman At 09:51:20 PM On 07/25/2008 |
Posted by Andrew Pollack At 12:29:55 PM On 07/26/2008 |
I'd like to get technical about your "matched table grid" example. There is a 3rd case where using fields on the original doc is still desired: indexing/search performance.
xPages helps to perform a JOIN of Notes data (as per your blog entry awhile back) but only for UI, and only for the web. But even with 8.5 there's still no way to quickly obtain an index of documents depending upon criteria in other linked documents.
E.g. If the rows in the grid are stored as separate docs, searching for "all employee docs where there are 3 or more Job Titles" is bulky to code and slow to execute.
But if you've stored the grid as fields in the employee docs themselves it's as simple as "@Elements(JobTitles) >= 3". And if you use a view you gain the performance advantage of Domino's incremental indexing updates moving forward. Then this approach becomes orders-of-magnitude faster than the separate-docs approach.
Of course, the separate-docs approach might be "fast enough" in some applications, and then it's definitely a great way to go.
Posted by Erik Brooks At 01:12:08 PM On 07/27/2008 |
Posted by Nathan T. Freeman At 02:06:42 PM On 07/27/2008 |
Posted by Charles Robinson At 08:52:15 AM On 07/28/2008 |