There are a bunch of little things -- habits -- that I’ve learned over the years that tend to make coding smoother and the results much better.
The primary one is to do as much as possible in advance of the actual coding. Make sure the environment is set up and working, including disks, peripherals, and furniture. Lay a good, solid foundation for things like logging, errors, config, secrets, and security. Get all of that out of the way first, not later as it is needed. When you sit down to write the core code, the last thing you want is distractions, so preparing your working environment to be able to get into that state of higher focus and stay there for longer is a key to being able to do a lot more things a whole lot faster.
The second one is to leave no stone unturned. That is, if you have questions about what or why you are coding, go answer those questions now. The answers don’t get better if you wait, and the lack of them always threatens to turn your labours into pure make-work. If you don’t know, then find out. Don’t assume, ignore, or procrastinate. Find out now.
Another one is to use way too many functions. Way too many. I use functions as a way to name clumps of code. It helps a lot. Even though there are a lot of functions, they shouldn’t end up with crazy or obfuscated names. Generally, they are just some verb as it operates on some input nouns. One word is preferable; two is acceptable. More than that is suspicious. Anything cryptic is offensive.
Functions, instead of comments, as a way to document what you are doing makes it way easier to review the code later and convince yourself that it really is doing what you thought it was doing. Also, they act as the primitives of decomposition. You break down the problem as far as you can put it into a bunch of small functions, but no further. An added bonus is that they make it easier to refactor. They are a powerful construct; use them wisely.
On that note, splitting out the pre-conditions and the core logic is big too. The first part of any function is there just to make sure the second part cannot get messed up. So, get all the asserts, error handling, little calcs, etc. out of the way at the top. Put every piece of data you will need later into its own unique variable; do not be shy. Similarly, use the language to clump stuff that must stay together all together. Clumping stuff saves on a lot of stupid typos.
Don’t waste time on makework, but also don’t be afraid to radically refactor some large chunk of code or a bad feature if it turns out that you were mistaken. If the logic is upside down, for example, and you persist rather than byte the bullet and correct it right now, it is just a time vacuum.
Make everything readable; spend effort on those tiny details. Partly because it shows you care, but also because those pesky things will hide lurking problems. Expect to have to revisit your own code in a few months, when you are too busy with other things; try to make that moment a lot easier.
Be terrified of names. They shouldn’t be robotic; there is no mindless convention for creating them. You really have to go out and find out what the parts are actually called, both technically and in the domain. Misnaming something is a magnet for bugs. If the poor name propagates all over the place, it can cause grief for decades. Give it the right name; put a lot of thought and effort into searching out that right name. Don’t be creative; that is usually just a failed shortcut.
Labour over your loops. Conditional logic is messy, but looping can be bloat. Don’t loop if you don’t have to; don’t bury the loops even if you think it's pretty. Split them out; you should be able to justify each and every one of them. Get rid of them whenever you can. Looping is where every performance problem begins and ends. Loops are not your friends; they are just the cost of doing business. Respect their power to make your evening awful.
Pull back. If it feels like you shouldn’t be spending 50 hours grinding out boilerplate, it is because you don’t need to be spending 50 hours grinding out boilerplate. There is a better way; you just have to calm down and find it. It’s exactly these types of moments where you learn to properly generalize or abstract stuff. The code would have been so similar that it is painful to type it out, but there is a way to get the same results, just smarter. Some techniques are easy, some take years to master, but all of them will keep you out of trouble. So, if it feels like you shouldn’t continue down this ugly brute force path, then don’t. Let that instinct push you into doing a search for a better way. It is out there.
Don’t be clever, be smart. I know’s tempting to find some clever little bit of syntactic sugar that can save a few characters here or there, but instead of being smart, it’s just a landmine. You or someone else will accidentally stumble over it and blow off their leg, usually in the middle of a production disaster or when there are -200 hours left on the clock. It almost always pays to be explicit, just not when it is tedious boilerplate. But otherwise, type it out in full. Eat that little expense, because later you will appreciate that you did.
The most important thing to understand is that although the code is not the system, the code itself is super important because it is your strongest way of controlling exactly what the system does, and you always need to control that to match everyone else’s expectations. It’s universally true that as the size of the code grows, the style, formatting, organization, consistency, and details get more and more important. A tiny demo can be messy, but a massive mission-critical system cannot. To be effective, you must be certain, and to be certain, you have to learn to be precise. That way, when everyone’s back is against the wall and you have to dive in and save the ship, you can go in and do exactly that, with no negative side effects. Perfect code is the dream, but the ability to perfect code quickly and reliably is good too. Don’t set yourself up to fail.
No comments:
Post a Comment
Thanks for the Feedback!