First, no matter what the methodology is, we all write software for our users (a.k.a. customers, project sponsors, end users, or clients). Second, no matter what the methodology is, we write incrementally, releasing features and bug fixes one by one. Maybe Iām saying something absolutely obvious here, but itās important to remember that each new version should first of all satisfy the needs of the user, not of us programmers. In other words, the way we decompose a big task into smaller pieces should be user-targeted, and thatās why you always work top down. Letās see what I mean through a practical example.
Say Iām contracted by a friend of mine to create a word-counting command line tool very similar to wc. He promised to pay me $200 for this work, and I promised him Iād deliver the product in two incrementsāan alpha and beta version. I promised him Iād release the alpha version on Saturday and the beta version on Sunday. He is going to pay me $100 after the first release and the rest after the second release.
Iāll write in C, and he will pay in cash.
The tool is very primitive, and it only took me a few minutes to write. Take a look at it:
#include <stdio.h>
#include <unistd.h>
int main() {
char ch;
int count = 0;
while (1) {
if (read(STDIN_FILENO, &ch, 1) <= 0) {
break;
}
if (ch == ' ') {
++count;
}
}
if (count > 0) {
++count;
}
printf("%d\n", count);
return 0;
}
But letās be professional and not forget about build automation and unit testing. Here is a simple Makefile that does them both:
all: wc test
wc: wc.c
gcc -o wc wc.c
test: wc
echo '' | ./wc | grep '0'
echo 'Hello, world! How are you?' | ./wc | grep '5'
Now I run make from a command line and get this output:
$ make
echo '' | ./wc | grep '0'
0
echo 'Hello, world! How are you?' | ./wc | grep '5'
5
All clean!
Iām ready to get my $200. Wait, the deal was to deliver two versions and get cash in two installments. Letās back up a little and thinkāhow can we break this small tool into two parts?
On first thought, letās release the tool itself first and build automation and testing next. Is that a good idea? Can we deliver any software without running it first with a test? How can I be sure that it works if I donāt ship tests together with it? What will my friend think about me releasing anything without tests? This would be a total embarrassment.
Okay, letās release Makefile first and wc.c next. But what will my friend do with a couple of tests and no product in hand? This first release will be absolutely pointless, and I wonāt get my $100.
Now weāre getting to the point of this article. What Iām trying to say is that every new increment must add some value to the product as it is perceived by the customer, not by us programmers. The Makefile is definitely a valuable artifact, but it provides no value to my friend. He doesnāt need it, but I need it.
Here is what Iām going to do. Iāll release a skeleton of the tool, backed by the tests but with an absolutely dummy implementation. Look at it:
#include <stdio.h>
int main() {
printf("5\n");
return 0;
}
And I will modify the Makefile accordingly. I will disable the first test to make sure the build passes.
Does my tool work? Yes, it does. Does it count words? Yes, it does for some inputs. Does it have value to my friend. Obviously! He can run it from the command line, and he can pass a file as an input. He will always get number ā5ā as a result of counting, though. Thatās a bummer, but itās an alpha version. He doesnāt expect it to work perfectly.
However, it works, it is backed by tests, and it is properly packaged.
What I just did is a top-down approach to design. First of all, I created something that provides value to my customer. I made sure it also satisfies my technical objectives, like proper unit test coverage and build automation. But the most important goal for me was to make sure my friend received something ⦠and paid me.
What from would you start making a new webservice?
— Yegor Bugayenko (@yegor256) May 24, 2020
