Many
novice programmers start a program with a "big bang" approach, meaning
they want to write the whole program in one step and then only they
would try to compile and run. However as humans we make many mistakes
when programming, especially given that we have to use a programming
language to do the job and most programming languages differ
drastically from natural languages. Because it is very likely that we
would make mistakes, we have to ensure that we leave room so that we
could easily identify the mistakes we have made.
The
solution to this situation is to adopt an incremental approach in
programming. The idea is to keep building your code using several small
working pieces. The pieces of code would not do a complete job. Rather
they will lay out the skeleton for the final complete program. Once you
are convinced the correct skeleton is in place, you could go on and add
muscle to the program.
In
incremental programming, the program is incrementally built using
several iterations. In each iteration of the program, it is compiled
and run to ensure that whatever we have in a given increment is
correct. It is very important to always have a working version of the
program, no matter how much logic we have implemented so far. Here is a
simple algorithm depicting the incremental programming process
Identify the main parts of the program
Write the initial stub to include all the parts
Compile and run to verify the correctness
Fix bugs if any
While whole program is not complete
Change the code to implement more logic
Compile and run to verify the correctness
Fix bugs if any
End while
Program complete
As
you could notice in the above process, we always compile and run the
program whenever we add some logic. The idea is to ensure that we write
a clean program all the time. One would think that this is going to
waste time as we compile and run the incomplete program many times.
However this process going to save time rather than waste time in the
long run. The rationale is that, when you write the whole program at
once and try to compile, you would introduce many bugs at once to the
program and it takes more time to debug. The incremental approach on
the other hand cut down time to debug by eliminating bugs along the
way.
Let's look at a very simple example
on how to apply incremental programming. The sample problem is to write
a simple billing program for a coffee dispenser utility. The input to
the program from the user would be the number of coffee cups. Given the
number of coffee cups to dispense, the program is required to calculate
the amount and display to the user.
The first step is to come up with the solution skeleton. The solution consists of main three steps.
The simplest skeleton one could write is:
#include
using namespace std;
int main()
{
cout << "Get input" << endl;
cout << "Calculate amount" << endl;
cout << "Output result" << endl;
return 0;
}
The next would be to break up the program into functions:
#include
using namespace std;
void getInput();
void calculateAmount();
void printResult();
int main()
{
getInput();
calculateAmount();
printResult();
return 0;
}
void getInput()
{
cout << "Get input" << endl;
}
void calculateAmount()
{
cout << "Calculate amount" << endl;
}
void printResult()
{
cout << "Output result" << endl;
}
As
you can notice, we just broke the program into a collection of
functions. It still does more or less the same thing. Ok the next step
is to complete the getInput function. We need to decide on the
parameters and return types. We need to read the number of coffee cups.
Hence we have to send a reference parameter to the method. Change the
signature if the method to:
void getInput(int &noOfCups)
and implement the method like the following:
void getInput(int &noOfCups)
{
cout << "Enter the number of cups: ";
cin >> noOfCups;
}
We got to change the main program to map this change. So replace the line
getInput();with
int noOfCofeeCups = 0;
getInput(noOfCofeeCups);
Now we got to compile and run the program before moving forward.
Next implement calculateAmount method: We need to define the constant containing the price of a single coffee cup:
const float PRICE = 5.50;
now
change the signature of the calculateAmount method and implement it. We
need 2 parameters here, the number of cups and the price at which each
cup is sold.
float calculateAmount(int noOfCups, float price)
float calculateAmount(int noOfCups, float price)
{
return (noOfCups * price);
}
Remember to compile and run again. Finally we implement the printResult method.
void printResult(int noOfCups, float price, float amount);
void printResult(int noOfCups, float price, float amount)
{
cout << noOfCups << " cups of cofee @ " << price << " each totals to " << amount << endl;
}
Ok the final version of the program is:
#include
using namespace std;
const float PRICE = 5.50;
void getInput(int &noOfCups);
float calculateAmount(int noOfCups, float price);
void printResult(int noOfCups, float price, float amount);
int main()
{
int noOfCofeeCups = 0;
getInput(noOfCofeeCups);
float result = calculateAmount(noOfCofeeCups, PRICE);
printResult(noOfCofeeCups, PRICE, result);
return 0;
}
void getInput(int &noOfCups)
{
cout << "Enter the number of cups: ";
cin >> noOfCups;
}
float calculateAmount(int noOfCups, float price)
{
return (noOfCups * price);
}
void printResult(int noOfCups, float price, float amount)
{
cout << noOfCups << " cups of cofee @ " << price << " each totals to " << amount << endl;
}
We now have a working program that we are convinced is logically correct and that solves the problem.The use of a coding standard when writing the code also made our lives easy.
We
would not have this much confidence in our program if we had used the
"big bang" approach. Incremental approach is more reliable, safe and
easy to follow. For students and beginners this would be an ideal way
to approach their programming problems with confidence.