Defining Useful Coding Practices?
markmcb writes "A NASA engineer recently wrote about his disappointment that despite having well-documented coding practices, 'clever' solutions still made the code he has to maintain hard to follow. This got me thinking about the overhead spent at my own company regarding our code. We too have best practices that are documented, but most seem to focus on the basics, e.g., comments, modularity, etc. While those things are good, they don't directly ensure that quality, maintainable code is written. As the author points out, an elegant one-liner coupled with a comment from a few revisions ago makes for a good headache. I'm curious what experience others have had with this, and if you've seen manageable practices that ultimately offer a lot of value to the next programmer down the line who will have to maintain the code."
In my company i am the sole/lead/only developer, and as such i have my own defined best practices and i follow them adamantly, that said i have written clever couplets of code that "just work" they are commented from here to the nines yet 4-6 months and 3 projects later when it comes time to look at reviewing for a possible update in the project i can sometimes look at it and have to spend extra time to follow the elegant code around to get it "loaded" back into my head to see what i did. i think that so long as programs are written by humans who can sometimes look at it sometimes as an art form there should always be an "elegant code" overhead coefficient worked into every project update.
A person whose code I regularly inherit seems to hate functions. He just writes subs with no parameters and uses global variables to pass information to and from them. It's awesome...
The thing is, though, that that sort of programming used to fetch the highest dollar. This was back in the days when computers only had 2K of memory and you had to use overlay programming. 45 seconds is always a significant amount of time.
I remember porting a piece of date validation code from an old WANG computer. At the heart of the algorithm was the computation 3113-1881 (or something like that). I ported everything straight over, and... it didn't work. I ran through the code manually, and... it made no sense. 3113-1881 is 1232. I went back to the WANG computer and typed in PRINT 3112-1881, and suddenly the algorithm became clear. On the WANG, 3113-1881 was 1231.9999, which made a perfect mask for a numeric date.
When our name is on the back of your car, we're behind you all the way!
If you're going to be maintaining it, you'd better damn well look over more than just the immediate code. Look at the declaration, instead of assuming what it is. There are too many pieces of code where people asume the type of a variable, "fix" the code, and make things worse.
3 most important rules
ctags is your friend. Even the laziest f*** can learn how to use it in a minute or two.
If you can't use ctags and/or fgrep effectively, you shouldn't be touching c code. You're simply not qualified.
Mod parent up! I think that comments should tell you 'what', as well as 'why', in cases where 'what' isn't synonymous with 'how'. When changing existing code, I like to know what the original author's intent was, so I can tell if certain aspects of the existing behaviour are coincidental side effects of how the code was written, or deliberate choices by the author.
A "hotshot" programmer will aggressively abstract. A mediocre programmer -- one who keeps his nose to the grindstone and is ever mindful of deadlines -- is more likely to "inline" constants (i.e. not abstract them at all) or even repetitive blocks of code. When ccde and constants are "inline", code is much easier to read because you're not constantly looking up in other files what the abstractions are.
Supposedly, both abstraction and locality aid maintenance.
The truly master programmer balances abstraction with locality. And takes into account who will be maintaining and the expected lifespand of the code. If the code is to be retired in two years, why bother abstracting? The general rule of thumb is that abstracted code has to be utilized six times in order to make the investment worthwhile.
When it comes to abstraction, the master programmer abides by the words of the Federation President, "Let us redefine progress to mean that just because we can do a thing, it does not necessarily mean we must do that thing."
Exactly! Mod this please. Anyone who has any knowledge of pointers will look at that loop and know what it is doing right away. The only exception is if you never learned pointers and just used the library function calls. That's what you get when you initially teach people such an abstracted high-level language (e.g., mega overhead JAVA). If you aren't going to use huge lists, there is no reason to include the overhead of the STL library (or any other); just form your own linked list (as done in the example)! Saves RAM, CPU and typing time. Also, it's 100% easier to prove correct mathematically (on paper). Try doing that with verbose library calls!
Who stays at the same coding job for 5 years? If you're actually good at your work, you will be getting offers from other companies that include large raises long before then.
Um, maybe someone who actually cares about doing quality work and improving the business? When I look at a resume with a bunch of 2 year stints at various companies, I will immediately think, "Great, here's a jackass code-jockey who will wander in, piss all over my group's code, and then leave as soon as someone else offers him an extra $1.50/hour. Pass."
That said, I also believe in rewarding quality work, so if you're doing well for me, you'll get those raises without needing to jump ship. But perhaps I'm a rarity in business these days...
Simple, clever doesn't pay the bills, reliable and maintainable do. It's a cost benefit analysis: if that clever one-liner saves many man-hours of work, then probably a good idea. If it saves you two or three lines of code and all of an addition 45 seconds, probably not worth the blow to maintainability and readability.
I view it as a premature optimization issue. It's very rare indeed that you save much time in writing code by doing something cute or clever; usually it's a matter of trying to do something slickly to save cpu time or memory. Rather than prematurely optimize I find it is best to try and write things in the most clear straightforward fashion first (even if it's not the most efficient implementation) and then go back later and make things more efficient if it proves to be necessary (often it doesn't because of real bottlenecks elsewhere).
And the funny thing is, absent real in-depth instruction-by-instruction profiling output from real production inputs on real production hardware, any "clever optimizations" introduced are just as like to slow things down as they are to speed things up.
I've found that out the hard way. Many times.
We deal with this by using something that can be described as code editors.
These are people that edit raw code committed by other programmers and refactor it in order to comply with a set of standards. Editing may entail just changing a few variable names, but it can also be almost a complete rewrite of the code. Of course, if code rewrites become the rule rather than the exception, something is wrong and some serious talks with the original programmer will be necessary.
As long as the code editors are knowledgeable people and agree among themselves about the specific style, best practices and architecture to be used, this can greatly improve the quality and consistency of the code.