I’ve been coding for a lot of years — next year, it’ll have been 35 years since I wrote my first line of code — and I’ve worked on a lot of projects over those years. Some of those projects have wildly succeeded, and some have absolutely bombed. (I’d like to think my lifetime average is positive, though.) Through all that work, I learned a lot of lessons the hard way, and today, after a discussion at work, I decided I’d share with the younger crowd some of the most important programming lessons I’ve ever learned. The lessons below are hard-won, and they cycle through my head on every line of code I write, even to this day:
- The most stable piece of complex code ever written (Knuth’s TeX typesetting system) was written in the 1970s, so I should never assume that “newer” is necessarily “better;”
- Whole frameworks, languages, and even OSes that were once touted as “the new standard” are now dead and gone, taking code I wrote with them, so I should never jump on any technology or idea hastily, because the odds of its survival past a few years are maybe one-in-ten at best;
- I shouldn’t make something complex just because I can: There are plenty of actual hard problems out there, so I should always keep things as simple as possible, and reserve the complex solutions for the complex problems;
- My code may spend N days in development, but it’ll spend N*10 days in maintenance over its years in production, so I should write code that can be easily read, easily understood, and easily fixed by future maintainers (my future self included);
- Possession is nine-tenths of ownership: A passably-working solution defeats a wish list, even a wish list from the businesspeople, so if I care about how something should work, I should code it the way I think it should work, and my implementation will probably become the de-facto standard or close to it;
- Thanks to the Halting Problem, there’s always at least one more bug, so I should make the code as easy to debug as possible, partially for others’ use, but mainly so I myself can track down and squish bugs as quickly as possible;
- Isolated code is always both more reliable and more debuggable than interconnected code, so I should strive for tight interfaces, and avoid integrations, exposure, or violating encapsulation at all costs, even when that restricts functionality or performance;
- Somebody is always going to try to “fix” my code, thinking they’re doing the right thing but really only making it worse, so I should design it not only so that it’s easy to understand and easy to modify, but also so that it’s hard to alter in undesirable ways.
- Performance matters: The inefficient code I write today will be the complaining customer’s ticket I fix tomorrow, so I should upfront ensure the code isn’t wasteful of time or space;
- An ounce of study is worth a pound of effort: If I take the time to learn or decide how to do it the right way, I’ll save myself ten times as many hours of redesign and debugging later;
- And there are exceptions to every rule — except those from mathematics; so I must take everything I think I know with a grain of salt (or three).
Those are my rules of good software engineering. Feel free to steal them — or to learn them the hard way.