There are very few people who can write the error-free code just from scratch. I personally feel always uneasy if rather long chunk of my code compiles and runs immediately and my intuition fails only seldom.
As long as you accept the these that you can not write the error-free code directly it is easier to find a trade-off between the efforts you invest into your code and the (potential) frequency of bugs in it.
One very good approach to minimizing the bugs in your code is the already mentioned Test-driven development. I use it often when I speak in public by adapting it in the following way.
Every independent piece of code is written and re-written in several iterations consisting of the following:
- Design the main idea of what you code should do.
- Write down the schematic representation of your algorithm.
- Re-write the schematic representation so that it is syntactically correct.
- Write some most important unit tests for your code (smoke test, for example).
- Implement the algorithm to satisfy your existing test(s).
- Refactor your code to improve it.
- Repeat from 1-4 (depending upon the code maturity) for every iteration and every new feature.
Here are some examples.
(1) I start with something like
I want to calculate pi, so I will simulate a target being a circle
with diameter d and use random numbers to cast arrows to it. I will
then use the proportion of circle area to the total target size to
(2) Then I move to
Request size of the target.
Request number of arrows.
Cast arrows randomly to the target.
Calculate the arrows that met the target.
Calculate the pi value.
(3) I re-write it in C# (just an example):
var Radius = RequestFromUser<double>("Radius of Target");
var NumberOfShots = RequestFromUser<long>("Number of shots");
long GoodShots = 0; long TotalShots = NumberOfShots;
while (--NumberofShots > 0)
if (ShootTarget(Radius)) GoodShots++;
(4) I create all method stubs in IDE (automatically). This allows me to write my unit tests in semi-automated way (get some templates automatically created for them)
(5) I design the smoke test:
var computed = ComputerPi(Radius: 10.0, NumberOfShots: 10000);
Assert.IsTrue(computed > 3.0 && computed < 3.5);
(6) I quickly (meaning without polishing the code) implement all stubs to start testing.
(7) As long as my tests shows green I re-factor my implementation trying to make it "nicer".
(8) I repeat from (5) if my implementation is not complete, or from an earlier step if I want to extend it.
This helps me to keep my code rather clean, and the slowly emerging unit tests serve as regression tests if I do too dramatic changes to my code.