Developing software isn’t easy. No, I’m serious. It’s not. Every year that passes brings us more experience, and sometimes reality bites us real hard in the ‘rear.
For example, people do not always remain with a project until it completes. Often, people join a team for a summer, or for a year or two, then leave. That’s normal and expected. Of course, if the project is large, or the stay short, the code portion that was assigned to a particular individual may not be completed by the time he leaves. Can you manage to leave a team gracefully?
That’s an important question and I had to deal with the issue on both sides: myself leaving, and having someone on my team leaving. So, how do we ensure that the code left behind is in a usable state? There are three major aspects to it, as I understand it. One is code correctness, another is documentation, and the last one is the code completeness. Let us look at each in turn:
- Code Correctness: Not tested = Broken
When I first read Eckel’s essay on strong typing vs. strong testing , I thought he was pushing it a bit far by stating that if it’s not tested, it’s broken. Now I fully realize how right he was. A piece of code that’s insufficiently tested will literally wreck havoc in any project it is used.
The damn thing about code is the complexity of interactions that emerges from the combination of heterogeneous pieces of code, interactions that, even when every piece of code is essentially correct, are very hard to predict, even more so as the code base grows larger and larger. In school—I mean college or university—it is quite possible to retain a God’s eye view of your code because you work alone or with only one or two other people, and the largest projects you’ll have to deal with for homework is something like, maybe, say, 1500 or 2000 lines of code, which remains perfectly manageable for the average person.
This leaves you quite unprepared for real life. Because in real life, you’ll end up working on projects with tens, hundreds of thousand line of code, or even millions, written by many different individuals, and the God’s eye view becomes impossible—unless you’re some kind of god, which you likely aren’t.
The impossibility of maintaining the God’s eye view implies that you have to change radically the way you write software. You cannot assume that you control all interactions and can predict what will be asked from your code. From a controlled, sand-boxed, friendly environment, you move to an environment that is positively hostile to your code. Your code must behave correctly and be able to take sucker punches, that is, remain stable, in a correct state, regardless of how badly it is used—or abused. From good enough and seems to work, you’ll have to get to the next level, works every time because I wrote all possible tests to ensure the code correctness according to the specs I have for the code.
So when you leave, you make sure that you only leave code that have been thoroughly tested. Ideally, that code should come with its unit testing code and be ready for reuse. Parts of the code that are still in a WIP state should be clearly identified and isolated from the tested, stable code.
- Documentation: Insufficiently Documented Code = Useless Code
Another thing that can quite kill a piece of code is the lack of documentation. Not only must you chose nice names for your functions, classes, PODs, etc., not only must you comment the code to help who ever comes after you—and quite possibly a future you that forgot what the code is doing exactly—you must also provide detailed external documentation.
This external documentation is of course the very high level documentation that describes what your code does on a very high level. Does it require some special environment setup? What libraries does it expect? How does it manage data? What are the use-cases it should be used with? Things like describing how you must instantiate and initialize a given class before initiating this or that process. This documentation describes the behavioral aspects of your code, and will help an eventual user to make efficient use of your code in his project.
The minute details of how this file descriptor is used internally should be found it the internal documentation of the code (which may, or mayn’t be embedded in the source code itself). And, in many ways, is not as important as the external documentation because, if you’ve done your homework correctly, your code can be used as a black box and the user of the code will able concentrate on using your code rather than fixing it.
If your code is not or insufficiently documented, it will be much less attractive to other team members or to any prospective user. The perspective at having to look at tens of thousands lines of code to figure out what the code does and what it can be used for is, let us agree, a major turn off. The kind of turn off that will make people pick some other technology or write their own from scratch. If they do so, you will have thoroughly failed.
So, when you leave, you make sure that you leave sufficient documentation for your code to be reused by your team members.
- Completeness: Incomplete Code = Useless Code
If you just leave a bunch of spare parts in a ziplock bag behind, you have wasted everybody’s time, twice. First you’ll have wasted all your time and efforts because the code will be trashed as simply deemed unusable. Second, you’ll have wasted someone else‘s time because the code will simply have to be rewritten, setting the project back months, or worse.
So you must ensure that even though you were unable to complete your part of the project, you leave well documented, tested, and usable code behind so that whoever relays you can start as fast as possible and as far as possible, basically where you were when you left.
This implies that your code is modular and well tested and that is was well documented, both internally and externally, as we already discussed.
This also implies that you must be clear-sighted enough to realize that if there’s not enough time to complete your part of the project before you leave, you should stop adding stuff without testing and consolidate the code you have completed and tested in order to leave the project in a sequence point of sort, where your work is completed and another developer’s work can begin.
People do not always realize how extraordinarily expensive a bug can be. Even before the software is released, a bug can cost a fortune. First, of course, you pay the guy that first writes that part of the code that introduces a bug. Due to insufficient testing, the bug may be integrated into the main code body and be left there to sleep for months, causing hard to diagnose problems elsewhere in the code. Then eventually after having wasting many people’s time (because many developers fought that bug on their own in their part of the project) it is at last identified as a bug, isolated, maybe again at great cost, and then finally scheduled for fixing.
The fixing can take a while because not all bugs are shallow and you don’t necessarily have an infinite amount of eyeballs at your disposal. Because some guy neglected to test his code thoroughly, you waste precious time and resources to find a bug that might have been preventable entirely.
If the bug is released in the product, the consequences can be dire for the project and the company. Remember, more than year ago I told you about how avoidable was the Zune bug, why and how the bug should have been found, and how sometimes even simple testing strategies can help you get better, stronger code. I wonder if Microsoft did a study of the impact of this stupid bug on Zune-based revenues…
Again, as school does not prepare you for the real scale of the projects you will be working in, it does not prepare you for the real cost of your bugs either. In school, the consequences of a bug, even a serious one, are about nil. At worst, your code mostly works, and you’ll get most of your marks. Something like, hey, 7/10, good work, you’ll do better next time, ol’ champ.
That’s unfortunately not how it works in real life. In real life, carelessness can cost plenty of time and money, of course, but it can have really bad impacts. If only you get fired, at least that should be a lesson learnt… but what if it gets other people fired as well? What if your carelessness costs coworkers their jobs?