Browse in : |
All
> Topics
> Programming
All > Journals > CVu > 305 Any of these categories - All of these categories |
Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.
Title: Improve Code by Removing It
Author: Bob Schmidt
Date: 05 November 2018 17:40:00 +00:00 or Mon, 05 November 2018 17:40:00 +00:00
Summary: Pete Goodliffe takes a scalpel to unnecessary code.
Body:
We ascribe beauty to that which is simple;which has no superfluous parts;which exactly answers its end...
~ Ralph Waldo Emerson
Less is more. It’s a trite maxim, but sometimes it really is true.
Some of the most exciting improvements I remember making to code involved removing vast chunks of it. Let me tell you, it’s a good feeling.
A war story: As an Agile software development team, we’d been following the hallowed eXtreme Programming tenets, including YAGNI. That is, You Aren’t Gonna Need It: a caution to not write unnecessary code – even code you think is going to be needed in future versions. Don’t write it now if you don’t need it now. Wait until you do have a genuine need.
This sounds like eminently sensible advice. And we’d all bought in to it.
But human nature being what it is, we fell short in a few places. At one point, I observed that the product was taking too long to execute certain tasks – simple tasks that should have been near instantaneous. This was because they had been over-implemented, festooned with extra bells and whistles that were not required, and littered with hooks for later extension. None of these things were being used, but at the time they each had seemed sensible additions.
So I simplified the code, improved the product performance, and reduced the level of global code entropy by simply removing all of the offending ‘features’ from the codebase. Helpfully, my unit tests told me that I hadn’t broken anything else during the operation. A simple and thoroughly satisfying experience.
You can improve a system by adding new code. You can also improve a system by removing code.
Code indulgence
So why did all that unnecessary code get written? Why did one programmer feel the need to write extra code, and how did it get past review or the pairing process?
It was almost certainly the programmers’ indulging their own personal vices. Something like:
- It was a fun bit of extra code, and the programmer wanted to write it. (Hint: Write code because it adds value, not because it amuses you, or you’d enjoy trying to write it.)
- Someone thought it was a feature that would be needed in the future, so decided to code it now, whilst they thought about it. (Hint: That isn’t YAGNI. If you don’t need it right now, don’t write it right now.)
- But it was only a small thing; not a massive ‘extra’ feature. It was easier to just implement it now, rather than go back to the customer to see whether it was really required. (Hint: It always takes longer to write and to maintain extra code. And the customer is actually quite approachable. A small extra bit of code snowballs over time to a large piece of work that needs maintenance.)
- The programmer invented extra requirements that were not documented in the story that justified the extra feature. The requirement was actually bogus. (Hint: Programmers do not set system requirements; the customer does.)
Now, we had a well-understood lean development process, very good developers, and procedural checks in place to avoid this kind of thing.
And unnecessary extra code still snuck in.
That’s quite a surprise, isn’t it?
It’s not bad, it’s inevitable
Even if you can avoid adding unnecessary new features, dead pieces of code will still spring up naturally during your software development. Don’t be embarrassed about it! They come from a number of unavoidable accidental sources, including:
- Features are removed from an application’s user interface, but the backend support code is left in. It’s never called again. Instant code necrosis. Often it’s not removed “because we might need it in the future, and leaving it there isn’t going to hurt anyoneâ€.
- Data types or classes that are no longer being used tend to stay put in the project. It’s not easy to tell that you’re removing the last reference to a class when working in a separate part of the project. You can also render parts of a class obsolete: for example, reworking methods so a member variable is no longer needed.
- Legacy product features are rarely removed. Even if your users no longer want them and will never use them again, removing product features never looks good. It would put a dent in the awesome list of tick-box features. So we incur perpetual product testing overhead for features that will never be used again.
- The maintenance of code over its lifetime causes sections of a function to not be executable. Loops may never iterate because code added above them negates an invariant, or conditional code blocks are never entered. The older a codebase gets, the more of this we see. C helpfully provides the preprocessor as a rich mechanism for writing non-executable spaghetti.
- Wizard-generated UI code inserts hooks that are frequently never used. If a developer accidentally double-clicks on a control, the wizard adds backend code, but the programmer never goes anywhere near the implementation. It’s more work to remove these kinds of autogenerated code blocks than to simply ignore them and pretend that they don’t exist.
- Many function return values are never used. We all know that it’s morally reprehensible to ignore a function’s error code, and we would never do that, would we? But many functions are written to do something and return a result that someone might find useful. Or might not. It’s not an error code, just a small factoid. Why go through extra effort to calculate the return value, and write tests for it, if no one ever uses it?
- Much ‘debug’ code is necrotic. A lot of support code is not needed once the initial implementation has been completed. It is unsightly scaffolding that hides the beautiful architecture underneath. It’s not unusual to see reams of inactive diagnostic printouts and invariant checks, testing hook points, and the like, that will never be used again. They clutter up the code and make maintenance harder.
So what?
Does this really matter? Surely we should just accept that dead code is inevitable, and not worry about it too much if the project still works. What’s the cost of unnecessary code?
- It is undeniable that unnecessary code, like any other code, requires maintenance over time. It costs time and money.
- Extra code also makes it harder to learn the project, and requires extra understanding and navigating.
- Classes with one million methods that may, or may not, be used are impenetrable and only encourage sloppy use rather than careful programming.
- Even if you buy the fastest machine money can buy, and the best compiler toolchain, dead code will slow down your builds, making you less productive.
- It is harder to refactor, simplify, or optimise your program when it is bogged down by zombie code.
Dead code won’t kill you, but it will make your life harder than it needs to be. It gets in the way and slows you down.
Pete is a programmer who never stays at the same place in the software food chain. He has a passion for curry and doesn’t wear shoes.
Notes:
More fields may be available via dynamicdata ..