Over the past 6 months or so, I've spent a lot of time in code reviews and discussions with various teams writing "enterprise" code (i.e. the boring plumbing stuff).
So here is my attempt to record the stuff I find myself repeating in these discussions, along with some notes to explain myself.
The team members I'm working with have varying experience levels and varying knowledge of the frameworks we're using, but despite these differences, there are various common discussions and pieces of (what I hope is) good advice that crop up regularly. My hope is that by stating them as memorable phrases, they'll become embedded as shortcuts we can use across our code discussions.
These quotes have either come from the elder demi-gods of software, or they are my attempt to get across ideas which others have probably said much better.
If I know a good single source of a quote, I'll try to reference it, but a lot of them are mangled versions of things other people have said. I dunno where the line between badly remembered plagiarism and new thought should be drawn, but I'll do what I can.
The best line of code is one you didn't have to write.
Use libraries, write shorter code, look for chances to delete code.
Every line of code you write is one you have to understand, test, debug, deliver, and support. If you can make use of code that means someone else has to do all that stuff, your life gets easier.
This should also help you win friends when others have to alter, debug, support your code in future. Code they don't have to read, or that they know because it uses the same libs they used, saves them time and mental load.
If it doesn't compile, it isn't code & can't be code reviewed.
Keep the code compiling, don't break the build with dodgy commits, and make sure you have at least got it running before declaring it finished.
I've occasionally found myself using this when explaining why pseudo-code and half-done code is not good enough to mark a Jira task complete. On the whole developers largely understand that the code they're writing has to run, but occasionally the reminder is needed.
For interpreted languages, the wording should technically be different, but the intent is the same - if the computer doesn't know what to do with it, it isn't "code" - it's just weird text.
Ugly, working code beats broken, pretty code.
Ideally code should be easy to read and work well, if you can only chose one, choose to make it work, and add a comment about the lack of prettiness - we can fix that later.
I'll sometimes use this approach as a pragmatic way to get through a knotty discussion or thought process and how a certain section of code should look. If it passes its tests, does what the customer needs and we can understand it, then it is at least a candidate for "good enough".
This also kind of chimes with Sandi Metz's idea of "Omega Debt" - well contained technical debt at the end of a message chain. If there's a nasty tangled pile of existing code which is fairly well encapsulated and does what we need, rewriting it to something easier to read which doesn't work (or pass its test) isn't an improvement.
Draw diagrams first, write words later
When working out a design, start from rough sketches, then expand and refine those until you get to a point where words say it better. You'll probably need far fewer words in the end.
This doesn't mean formal UML or levelled DFDs are required, just that when we're trying to understand a system or problem it's likely that we'll have a clearer mental picture if we start with a physical picture.
They are also easier to draw large on a whiteboard and then scribble over.
Coding to a spec is like walking on water - easier when its frozen.
— paraphrasing Edward V. Berard
If you are doing ye olde school waterfally spec-driven-development, that spec has to be pretty solid.
Even when you're acting more agile, a stable core set of requirements is a pretty powerful helper. It means the team can be far more confident about what they're doing and less likely to be demoralised by expectations of each day meaning a new chunk of rewrite.
It also helps make it clearer what we're talking about in discussions about changes and additions.
If you can't do it in the command line, you can't automate it
Make everything scriptable, don't rely on IDEs and webapps, use scripts for anything you do frequently.
Also when you do automate it, you can put that script into source control - which you really want to do.
Learn your editor/IDE
— paraphrasing The Pragmatic Programmer
Your IDE (and associated tools) is your main toolbox, learn the tools in it. Keyboard shortcuts, quick refactoring, regexp search & replace, themes and plugins galore ...
This might be seen as a counter to the previous quote, but most IDEs also work with command line automation and plugin tools. Really these two go together - make sure you can do everything important from the command line, then use your IDE to make all those things happen neatly within your chose dev environment - the IDE can use the command line behind the scenes.
Never trust the client. NEVER trust the client
i.e. anything coming from the outside. You will be given bad data, the connection will go slow and die, validate everything you didn't create yourself.
It's a common security mantra, but it bears repeating especially when you're doing anything that involves a UI or network connections of any kind.
YAGNI is your friend
You Aint Gonna Need It. Don't spend time designing and implementing things that haven't been asked for, unless you know it is needed.
It'll save you time, mental effort and disappointment when that neat thing you coded is either not appreciated, or gets in the way of whatever they do ask for.
If you can't debug it, you can't fix it.
This has two meanings - the first of which is to reach for your debugger early and often. rather than println statements, write code you can understand when stepping through it, concentrate on what the debugger is telling you.
The other meaning is related to cognitive limitations - if you can't understand the code well enough to debug it, you can't fix any bugs in it. There's a related quote about debugging being twice as hard as coding, so if you've coded something you only just understand, you can't debug it.
Debuggers don't care about "should" or "shouldn't", only "did" and "didn't".
There's no arguing with the debugger when it tells you the code has acted a certain way (if the sourcecode and JVM/image are in sync).
A common cry when we're looking at the value of a variable, or the route through some logic, is "but that shouldn't happen!" or "but it should be set to X now!". Debugger don't care, debugger just shows what is, learn to deal with it.
The exception to this is when you find yourself stepping to empty lines, or comments, or outside any code at all. That's a sure sign the code that is running is not the code you're looking at. When you see that: stop, tear down, and "redo from start".
Rule 1 of performance optimisation: Don't do it
Rule 2 of performance optimisation: Don't do it yet
Rule 3 of performance optimisation: measure carefully, before and after
— Paraphrasing Michael A. Jackson (and adding a 3rd rule)
Premature optimisation causes painful problems and often doesn't actually work. Concentrate on get the system working, correct and maintainable first. Then measure the problem, then fix it.