
Ask HN:  How to reduce sloppy mistakes? - Everest
Hi,<p>I make a ton of sloppy mistakes when I code.  Stuff that leaves me kicking myself when I spend 20 minutes trying to debug it.  Even though I've gotten better at programming, the number of sloppy mistakes I make is still way too high and its my biggest time drain.<p>I think part of the problem comes from writing code, glancing through it quickly, and then testing it with a large number of "F5s".  I'm trying to get away from this and am reading my code more thoroughly before testing to see if it works. Anyone struggle with the same issues?  HOw did you improve?<p>Thanks!
======
gaika
Don't use a debugger - think when something doesn't work. The feedback you get
by thinking about your own code teaches you much faster than anything you get
with compile/run/debug cycle.

"I think that without a debugger, you don't get into that mindset where you
know how it behaves, and then you fix it from there. "
[http://linuxmafia.com/faq/Kernel/linus-im-a-bastard-
speech.h...](http://linuxmafia.com/faq/Kernel/linus-im-a-bastard-speech.html)

~~~
j2d2
I have downvoted you by accident while using an iPhone. This is terrific
advice though!

------
pg
Making fewer mistakes isn't the only solution. You can also make them cost
less.

For example, I make a lot more typing mistakes typing into text editors than I
used to do when typing on a typewriter. But I type net faster, by a lot,
because fixing mistakes is so easy.

There are several ways to make mistakes cost less in programs: writing
functional code; using a very abstract language; writing programs in layers;
testing every change as you make it, in a repl.

You can switch modes, too. I sometimes start by writing something rapidly and
comparatively carelessly, and then later when I reach a natural stopping
point, I'll reread it carefully.

------
idlewords
Try setting yourself a mental challenge of having a subroutine/code snippet
work the first time you run it. Start very small. You'll be surprised at how
hard this is, and trying this repeatedly can build good habits of reasoning
about code.

~~~
MaysonL
Strangely I had the experience (almost 46 years ago) of writing a program a
week for a semester, without encountering either a bug or compilation error.
It wasn't until my first assembly language program that I encountered one (a
period in one statement where a comma should have been). They were to be sure,
very simple programs (similar to the very easiest problems on Project Euler).

------
pj
I like to write my code in my head before I write it with code. Try to imagine
all your code and then the code you are going to write and then run through it
in your mind. Think of some special cases in your mind. Suppose you are
writing a function that accepts a parameter. Okay, so go write it in your head
and then imagine, what if someone passes in a string or an int? are these
different cases? do I throw an exception, do I return a particular value? How
will that affect the rest of the code? What if the code is converted to a
library and used by someone else? Could a string be a valid parameter?

Then run through the code in your mind. Does it work? Pass in some variables.

Your mind can process information much faster than you can type it out. If you
build the image of your code in your mind, you can map it out in a matter of
minutes, but if you start coding without the image, you make more mistakes.

Some other commenters have said write it out or draw it out. This is a good
idea if you can't keep it in your head. Do flow charts and state diagrams and
things like that _before_ you start coding.

------
edw519
_...the number of sloppy mistakes I make is still way too high..._

Compared to what?

You may not have a problem.

Sometimes "code, mistake, fix, code, mistake, fix, code, mistake, fix,..." is
faster than "code it perfectly once".

For me it usually is. I'd rather crank stuff out quickly and fix it than drive
myself nuts thinking it through.

Stupid syntax and typing errors will go away with repetition. Otherwise I
wouldn't worry too much as long as you keep cranking forward.

[For what it's worth: I do not use an IDE, I do not use color or syntax
highlighting, and I use debug as a last resort. Many here disagree with me,
but I believe my brain internalizes those things that help me avoid stupid
mistakes by coding without training wheels.]

~~~
ramchip
Why would syntax highlighting, etc. be "training wheels"? I understand that
training wheels restrain what you can do with your bike, but what's the
downside to coding in an IDE?

~~~
edw519
My experience is that when I code in a simple monochrome text editor, I have
instinctually learned and internalized syntax, reserved words, etc. much more
quickly. Kinda like shooting a basketball into a smaller hoop or driving a
stick shift. Everything just flows better and I rarely have OP's problems.

------
warwick
Using a statically typed language might also help, as the compiler can catch a
lot of really stupid errors.

~~~
mjl-
exactly. when i read the question i thought: i bet you are using some dynamic
scripting language.

use a language a programming style that lets you catch errors early. it's
amazing how much time i've wasted testing for errors after small changes in
ruby programs. errors that a decent language & compiler wouldn't have allowed
or detected much earlier. some languages just weren't designed with this in
mind. i no longer program in ruby.

related: once upon a time, i had the idea that i should be able to write a
program and have it compiler & work at the first & final attempt. code was in
c. of course that failed miserably. especially with the lack of c coding
experience. the lesson: don't try to be silly/"smart", use the tools to your
advantage. (if your tools don't have advantages, don't use them).

------
diiq
I'd say even more F5s (assuming that's how you compile/run). There's nothing
wrong with using the computer to catch a missing semicolon or parenthesis. If
it takes you 20 minutes to find the error, maybe it's because you haven't been
running your code _often_ enough, rather than the reverse.

Coding is debugging just like writing is revising.

------
rabidgnat
“The road to wisdom? Well, it's plain and simple to express: Err and err and
err again but less and less and less.” ~ Piet Hein

In other news, I try to check my answers by deriving them two ways. If they
agree, then I at least have a good defense :). If I'm working on something
that can only be reached one way (like pulling data from a database), I assert
boneheaded things that should be true about code + data structures. Sometimes
it's superfluous, sometimes it catches mistakes.

If you don't work in a language that provides stack traces on crashes, add
logging. You'll get a rudimentary stack trace of what was happening when
everything went to hell, as well as have a small radius for where the crash
occurs.

~~~
MaysonL
+1 for Piet Hein - I love his hypererllipse and super eggs, as well as Melior
(based on hyperellipes).

------
amichail
I would say get better at using a debugger and/or use a higher level language.

My guess is that worrying too much about low-level correctness while writing
your code could lead to very poor productivity and even OCD.

------
gdp
Try to consider all possibilities for failure and all inputs or contingencies.
If you are still coding and don't want to interrupt your "flow" to go write an
error handler, just put an assertion or a comment or something that will force
you to go back and write it before you compile. That way you'll know when the
problem is actually solved.

With that in mind, perhaps also think about the way you are structuring your
development. Do you have a mental (or physical) sketch of the code before you
write it? There's something to be said for having a bit of paper to scribble
on before and during the coding process. Map out little examples (e.g. "test
cases") and think about how you will deal with all of them.

Finally, writing stubs (i.e. functions or modules that are basically empty)
when you first start can be great. If you know you're going to need some
pieces of functionality in order to solve your problem, then write stubs for
those and then solve the problem (i.e. write the main program flow). Hopefully
then when you come to write the supporting functions that do most of the heavy
lifting, you will have clarified your intuitions around how they are supposed
to work.

So my advice would be to be a little more rigorous in your approach _before_
you get to the point of having screenfuls of code in front of you.

------
agmiklas
I carefully read my patches before I commit them. Probably sounds pretty
obvious, but I find that I can catch most problems by simply running "git
diff" and then carefully and slowly reading through the output.

This is especially true when I'm editing existing code rather than checking in
new functionality. I read the diff while mentally asking myself "is this going
to change anything other than what I intended it to change".

------
MaysonL
Code review. Even if you don't have someone to review it, you can pretend to
explain it to someone else, a line at a time.

Error logging. When you make a mistake, and find it, document it, with as much
of the reason why you made the mistake as you understand. Keep a diary of
these for a few months, and you'll be surprised by how much you learn, as well
as learning which mistakes you're most prone to.

------
jodrellblank
Speculation: Based on the principal that you can't improve what you don't
measure (or, what you measure you improve), you could keep a log of the sloppy
mistakes you make. After a while, maybe patterns will emerge and you can
attack 'mistyping numbers' separately from 'missing cases in a switch block'
and 'correct behaviour of nested-if took 5 attempts'.

~~~
bodhi
I was going to write exactly the same thing, but you've put it more eloquently
than I could. Also, it would seem to me that just "writing more test-cases"
wouldn't get one very far as the tests are going to be as sloppy as the
original work.

------
icey
This sounds like a symptom of typing too much and thinking too little.

This may be a little old fashioned of me, but any time I try to solve a
problem that isn't immediately obvious, I write it down on paper first (or
whiteboard it).

If you can't hold the solution in your head and visualize it, then you should
try to break the problem down into smaller chunks so that you can at least
fully visualize all of the moving parts.

Around my office, I have a set of maxims that I always emphasize in order to
keep our quality high - #2 on the list is to always measure twice before
cutting (or writing, in this case); rule #1 is to pick the low hanging fruit
first. There's no point in starting to code a solution until you know with a
level of certainty what it is you're trying to achieve. Lots of people with
debugger syndrome don't know where they're going until they happen upon a
solution by coincidence instead of by intention.

------
thisisnotmyname
I've found that copious use of assert statements has done wonders for reducing
the amount of time I spend debugging. Its a good idea to use enough assert
statements that when there's a problem it is reported immediately instead of
propagating and causing weird symptoms that you have to track down. At the
beginning of every function I think to myself "what am I expecting here" and
then put in 2-3 assert statements to make sure my expectations are met. For
example, if I'm passing a data structure that I expect to be filled, I assert
that it is non empty.

When I encounter a bug I write an assert that reveals the problem before I fix
it in order to prevent having to deal with the same issue more than once. This
is especially big for me since I work with a lot of (other people's) data.

------
bsaunder
Use shorter code/compile/run cycles. Use print statements instead of a
debugger (much faster to scan input than step through a debugger). If
something doesn't work, it's likely related to the change you just made. If
you coded for a long time since last testing, it's much harder to mentally
identify where the problem might be.

It's ok if you don't get it perfect all of the time. It's the 20 minutes
debugging that's killing you. Shorten your cycle and eventually you will get
less sloppy (or immediately know where/what the sloppiness is before you even
run). It will be like that typo you "know" you made even before you finished
typing (something won't feel right and you'll go back and fix it before you
read the debugging output).

------
fireandfury
Before you hit compile, look at the key lines of code that you just wrote and
think about exactly what you expect them to do. Then compile and run the code.
Don't rush to compile. It'll take longer in the long run. Also, it's less
enjoyable to program that way. I prefer a careful, focused style where every
line is carefully written.

I know what you mean about hitting F5 all the time. I usually program that way
when I don't feel like thinking. I want to cross my fingers and hope that it
works. When I notice I'm doing this, I need to stop and think about what it is
that I'm doing. I'll often write down in text what I'm trying to do. Or I'll
turn off the computer and think about it.

------
wooby
Write tests before you code, and spend more time planning software with pen
and paper before you actually write it. If you're having doubts about your
abilities or solutions and work as part of a team, ping team members or
friends.

------
bayareaguy
While it can be fun to make big sweeping changes, I find that silly errors are
easy to catch when I keep all my changes small so here's what I do:

\- When I'm working with a fast compiler, I setup a small CI system to
immediately compile my code and run my tests every time I save my changes. If
I can't do this for some reason then I setup a trivial background script to do
this constantly and watch the output in another window.

\- I try not to cut corners. It's easy to stay in the flow once I have things
setup so that I can build and extend my tests and scaffolds along with my
code.

Small moves, Everest, small moves...

------
daleharvey
tests tests tests

I use a little tool that runs unit tests on compilation, when Im doing
something new that unit tests works well with, I write a bunch of tests and
just code until I have 100% tests passing.

~~~
mrtron
Exactly. We aren't writing code on punch cards, getting it right the first
time isn't a huge deal.

If you make a lot of mistakes, have sanity tests cover your ass.

------
leif
Everyone's going to say "test driven development" or "think before you write"
but honestly, the only thing that has ever truly worked for me is pair coding.
Just have a buddy sit over your shoulder and watch you work.

It's a bit like the integrity mechanism of developing two copies of the same
software, done by totally separate teams. You and your friend are both
thinking about how to solve the problem, but separately, which means the
likelihood that both of you make the same dumb mistake is fairly low.

------
gaia-forming
1\. Get a good editor, and watch the syntax highlighting.

2\. Start unit testing your code, there are plenty of libraries available for
this.

3\. It comes with experience.

------
10ren
Code a little bit at a time. If there's a bug, you know it was due to what you
just added.

------
nkohari
Automated testing is the only way to improve the baseline quality of your
code. It's painful to do in the beginning, but think about it like exercise --
once you make it part of your routine, you'll be healthier overall.

------
notaddicted
Some good advice already.

Don't try to always be coding. You need to have total focus when you work. If
you work when you don't have it you are just creating more work for yourself
later. It's a net loss.

------
whughes
In addition to the methods suggested here, make sure you're taking care of
yourself. Eat well, get enough sleep and exercise, and so on.

------
lallysingh
Two parts:

1) ASSERT. Catch the mistakes while they're still dumb.

2) Take advantage of your type checker to catch mistakes.

------
californiaguy
You just need the following: proper editor, proper debugger, years of painful
experience.

