The first day of the first semester programming class, I introduced the students to the concept that the most important part of building a system, whether it is something physical like a bridge to cross a river or a computer system, is to understand the problem.
Many novice programmers believe that if they are writing code, they are making progress, and if they are not writing code, they are wasting time.
The problem with that mindset is that, to be making progress, they must be writing the correct code correctly. They cannot possibly know if they are writing the correct code, or if they are writing it correctly if they do not fully understand the problem.
Every problem has two sides: the requirement and the solution set.
We speak of a solution set because there are potentially multiple solutions to any given problem. However, we cannot begin to discuss a solution when we do not fully understand the requirement (the problem). We solidify our understanding by asking questions.
A problem typically has constraints. You hope that the customer told you the constraints up front, but perhaps he does not even know them all. You have to discuss the problem and ask questions.
If you instead jump into proposing solutions, you waste time and might end up like this contrived example:
Get me across the river
1. Take off your shoes and wade
a. The water is too cold
a. The river is 15 feet wide
3. Use a canoe
a. The river is running too fast
4. Use a ferry
a. The river is at the bottom of a 100-meter deep canyon
5. Cut a tree and use it as a bridge
a. I have a car
6. Construct a bridge from steel and concrete
Now, if the contractor had instead asked questions, it might go more like this:
Get me across the river
1. What are the river’s dimensions?
a. 15 feet wide at the bottom of a 100-meter deep canyon
2. Are you walking?
a. No, I have a car
3. Construct a bridge from steel and concrete
By thinking about the problem and asking appropriate questions, the engineer was able to expose constraints and provide a workable solution in half the time as otherwise. In both examples, however, the customer thought he gave a reasonably simple explanation of a simple problem.
Sometimes a simple requirement is complex in more subtle ways. For example, the simple problem of importing data from text files into a database. That sounds like a simple problem until you start asking questions and learn that there are multiple kinds of text files.
We can have comma delimited files, string delimited files, column delimited files, some use ASCII encoding, others use EBCDIC encoding, some use UTF-8, others, UTF-16. Microsoft versions use a different line ending than UNIX and the same is true for file endings.
As you ask questions about this, you might decide that it is not a single requirement with multiple constraints. Perhaps it is actually multiple requirements, with on high-level requirement that generalizes them. However, you can only learn that by asking effective questions. Additionally, analyzing the problem above shows that once we have determined the specific differences in the input files, mapping the fields to the database is probably common between he different file types. That means that the beginning and the end of the process probably uses common code, but the details in the middle will have some differences.
So, by asking questions and thinking about the problem, you have identified several requirements that had been masked as one, but also commonalities in the sub-requirements that are probably areas for hidden code duplication. You probably noticed that there are potential areas that you can remove duplication by applying polymorphism, so when you have written code to import two file versions, you start looking at ways to refactor and take advantage of that.
These are things that, if you are not actively asking questions and discussing the problem with the customer and the other programmers, you are not as likely to realize and the system suffers as a result.
Remember, the customer wants the system badly enough to pay for it. He will appreciate these questions because that helps to assure that he gets the system that he wants. Well-reasoned questions are likely to remind the customer of details that he had forgotten to include, or perhaps has not even thought of himself.
When you are preparing for, and sitting in the planning meeting, ask questions relentlessly until you fully understand the problem. Then, ask more questions.
One of the things that I consider fundamental concerns a
method or function. Historically, a method does exactly one thing, which its
name describes. It starts at the top and ends at the bottom; i.e., it has
exactly one entrance and one exit.
With such a simple guideline, how can anybody submit a method
that deviates from it? For example, the following method names tell when it
happens, not what it does:
Interestingly, these names do not seem to tell us anything:
One reason that I have observed that causes difficulty for programmers
to choose an appropriate name is that their method violates the “one thing”
part of the guideline. Their methods do several different things.
So, how can a programmer know if the method they wrote meets
these guidelines? They should be able to explain:
- first, what the method does (this should take a
very few words, and the method name should already prep us for that)
- next, (from a high level) the algorithm they
used (this will take more words than the introduction, but not many more)
If they cannot do that, it is possibly a sign that the code
is not ready for review. Send it back for refactoring. A method with more than
10 lines is probably not ready for review. The programmer will not be able to
do those two things above.
A junior programmer might not yet have developed the skills
to get all of his method to fewer than ten lines. A code review should help
with that. Ideally, methods should be less than about five lines.
When you write a short method, it is hard to make it do more
than one thing, and easy to give it a descriptive name.
I regularly rant about programmers not knowing the fundamentals
without giving any concrete examples. An acronym that I coined with an
esteemed colleague during one such rant is FBC (Fully Buzzword Compliant). Many
programmers can spew buzzwords like pickup lines in a bar, and many of them can
even give a correct definition. However, when it comes time to apply the
associated technique or technology, they are clueless regarding where to start.
One thing that perplexes me about this is that there is so
much information on the Web that would help foster this capability, but these
programmers do not seem inclined to educate themselves. A second thing is that
these fundamentals have been around longer than most of these programmers have
been alive. They are nothing new or groundbreaking. Modern programming
languages and techniques build on them; hence, they are fundamental.
Furthermore, I consider internalizing these fundamentals an
ethical responsibility and necessary to becoming a true craftsman, rather than
being a code hack who is FBC. Given the plethora of writings on the Web and published in
books, I do not feel alone in this regard.