A beginner guide to bad programming (v0.1)
2026-05-30
This guide, written by the ONDA Lab, is a humorous collection of bad programming habits. While many guides explain how to write good code, we realized that another way to learn is by looking at what not to do.
After all, most of us (certainly we, at least) are naturally prone to becoming bad programmers. So instead of only focusing on the “right” way, this guide highlights the habits you really shouldn’t have (but probably already do).
Enjoy!
P.S. If you think we’re writing this because we’re excellent programmers, you couldn’t be more wrong. But we’re trying to unlearn these bad habits!
P.P.S. Click here to download the PDF version 📄
The truth: unless you have a very short task, a very long script is often difficult to work on, to reuse, to mantain, and to share.
When you write long script you tend to think in a less modular way and you don’t break down you problem.
The truth: manually versioning files leads to chaos. You end up with analysis_v1.R, analysis_v2_final.R, analysis_v2_final_REAL.R, and no idea which one is actually current — or what changed between them.
Use version control (e.g. Git) instead. Every change is tracked, timestamped, and reversible, without a graveyard of files cluttering your folder.
The truth: coding without a plan often means solving the wrong problem, or building something that needs to be completely rewritten once the real structure becomes clear.
A few minutes spent thinking about inputs, outputs, and the steps in between saves hours of untangling cryptic code later.
The truth: over-planning is just procrastination in disguise. You can’t anticipate every problem until you start writing real code, and a perfect design on paper rarely survives contact with reality.
Design just enough to start, then iterate. The code itself will show you what you didn’t think of.
The truth: copy-pasted code means that when you find a bug (and you will) you have to hunt it down in every single copy. You will always miss at least one.
Write a function instead. Fix the logic once, and every caller benefits automatically. Your future self will thank you.
The truth: code you wrote six months ago might as well have been written by a stranger. Without any comments, you’ll spend more time re-understanding your own work than writing new code.
But don’t explain what the code does: explain why. A good comment captures intent and hidden constraints, not mechanics that the code already shows.
The truth: x, tmp, df2, f — these names say absolutely nothing. The next time you open the file (or someone else does), you’ll have no idea what any of it means.
Names are free documentation. patient_age_at_baseline is always better than pab. If the name needs a comment to explain it, the name is wrong.
The truth: building a perfectly general-purpose function for a one-off task is over-engineering. It takes longer to write, harder to test, and more often than not, it never gets reused.
Write for the problem in front of you. You can generalize later, if and when you actually need to. “You Aren’t Gonna Need It” is a principle, not an excuse to be lazy.
The truth: over-commenting clutters the code and makes it harder to read. A comment that just restates what the code obviously does adds noise, not signal.
# add 1 to i above i <- i + 1 is not a comment: it’s just noise. Save your comments for the non-obvious parts: the edge case, the workaround, those parte that aren’t obvious from the code alone.
The truth: refusing to use AI tools when they’re available is (in some way) like refusing to use a calculator. It slows you down on routine tasks and leaves less mental energy for the parts that actually require thinking.
But don’t outsource your thinking entirely either. If you can’t read, understand, and explain the code AI wrote for you, you don’t own it. Also you won’t be able to fix it when it breaks.