Programmers have near unlimited memory?Filed Under: Weekly Tuesday Dose of goodness
Have you heard the following sentences before?
“I know what I’ve written so I don’t need to document my own codes!”
“It’s my project! I’ve done it for many years therefore I don’t need to document my codes!”
“I know my code very well, I don’t need to document them for myself at all!”
Obviously, today I’m going to discuss about the memory programmers have. It seems that every programmer out there have the kind of memory that nobody can have! I mean, remembering childhood memories is one thing, remembering logical lines of codes is another!
Although it’s possible to remember how the code itself work logically in bits and piece, but can a developer really remember all the detailed logic and rationale? If yes, does it mean that we no longer or shouldn’t even need code documentations in the first place?
Let’s find out.
First, let us take a look at the types of code documentations we can do to help people or ourselves understand the code. After which, we’ll discuss the 2 perspectives towards code documentations and which perspective should a programmer choose.
Function/Method/Subroutine Documentations
These are the most common forms of code documentations that are usually mandatory for many software house (if they seek to survive longer in the industry that is).
There’re many forms of such documentations. In Java, javadocs are used to demarcate certain types of predicates in the method.
But in general, the following list would be in such documentations:
1) Function description, ie what it’s supposed to do
2) Parameters and description of how each parameter will be used.
3) Parameter usage, IN, OUT, IN/OUT
4) Return value
5) Cautionary notes and Exceptional behavior (ie, Exceptions thrown based on certain range of scenarios)
6) Other notes to warn or caution the user on the nature of the logic of the method
Direct Code Documentations
The other form of documentations would be direct code documentations. This goes without saying, refers to leaving comments that indicate what’s being done, why it is being done and how is it being done.
The crux of this article is, does programmers really remember all the What, Why and How?
To be honest, there’s probably a handful of people who can really do that. But so what, most of us are not in that group. It’s best not to even think of it!
Most of us on the other hand, can remember What and Why. That is, what we’ve roughly done and why it’s done roughly that way. Abstract understanding of the work done is usually enough as a summary to the lesser technically project manager.
How about the HOW portion? I mean, one can roughly remember how certain things are done. One can even remember exactly how certain things are done. But how many such modules can a developer remember?
Assuming 1 module has 5 functions. Each function has 20 lines of codes. If you can remember 5-10 modules, that’s pretty normal. But if you’re referring to the getters/setters, I suggest that you go knock your head on the wall, HARD.
So, 20×5x10 = 20×50 = 1000 lines of codes. That’s hardly the size of any applications out there! It’s probably just 1% to 10% of the entire source code base. Not to mention that developers move on from project to project after each cycle. So how? Hands off?
That’s fine actually if the code is working and no longer needs to be enhanced. But what if there’re issues? What if there’re feature requests and change requests? One may think - ahhh.. the Support Engineer will handle it, which is grossly irresponsible and childish by the way. What if the company assigns YOU the originator of the codes to work on the changes?
Let’s take a look at the following example: (with function documentations)
//--------------------------------------------------------------------------------
// Gets the distance travelled based on a velocity.
// Where iterations refer to the number of increment/decrement is required for
// a speed to reach a certain velocity.
// Iterations for a speed of 5 with acceleration of 0.05 would be 5/0.05 = 100
// Parm :
// int - The number of iterations of calculations to add to achieve full speed
// float - velocity to be calculated
// Return :
// float - The total distance travelled based on the current speed
//--------------------------------------------------------------------------------
float getDistanceTravelled(int iterations, float velocity)
{
if(iterations < 1)
return 0;
--iterations;
return (static_cast< float >((iterations * (iterations - 1 ) >> 1))) * velocity ;
}
So, logically, these codes can be understood from the way they work logically. But that alone doesn’t explain HOW this code actually works. Let me share with you why:
if(iterations < 1)
return 0;
Why? So what if iterations is 0? At a glance, I can only tell that if iterations is smaller than 1, the code returns a zero. But WHY?
--iterations;
Next, we have –iterations . To some, this is a simple optimized self decrementing operation, but could it have other purposes? Don’t know.
return (static_cast< float >((iterations * (iterations - 1 ) >> 1))) * velocity ;
Lastly, we have the return statement itself - let’s break it up into several parts
answer = (iterations * (iterations - 1 ) >> 1)
resolves into:
static_cast< float >(answer)
which finally resolves into:
answer(float) * velocity
Even by logically analyzing the codes, we can only understand the logical operations, but not necessarily the rationale of the logic and why it has to be done this way. For example:
(iterations * (iterations - 1 ) >> 1)
What’s with the bit-shift? What’s with iterations multiplied by iterations - 1?
Guess what? By the time you’ve figured it out, you’d have wasted at least 30 minutes or so. Probably 15 minutes if you’re smarter.
Solution
This is how it should be been:
//--------------------------------------------------------------------------------
// Gets the distance travelled based on a velocity.
// Where iterations refer to the number of increment/decrement is required for
// a speed to reach a certain velocity.
// Iterations for a speed of 5 with acceleration of 0.05 would be 5/0.05 = 100
// Parm :
// int - The number of iterations of calculations to add to achieve full speed
// float - velocity to be calculated
// Return :
// float - The total distance travelled based on the current speed
//--------------------------------------------------------------------------------
float getDistanceTravelled(int iterations, float velocity)
{
//STEP 1: Check against 0 to prevent unnecessary operations
if(iterations < 1)
return 0;
//STEP 2: Since the caller would have processed the previous iteration already
// we can reduce the iterations here for the next step
--iterations;
//STEP 3: Need (iterations * (iterations - 1) / 2) to calculate the distance travelled already
// Since iterations is an int, we need the product to be in float to get an accurate distance travelled value
// Bit-shifted to the right by 1 for quick division by 2.
// Lastly multiply by the velocity to get the distance travelled so far
return (static_cast< float >((iterations * (iterations - 1 ) >> 1))) * velocity ;
}
Guess what? How long did it take to understand all these? 5 minutes? How much will it help you? Well, at least you know what you HAD done and will be able to minimize regression problems when you apply your changes.
Step Documentations - When?
One of the most important questions asked is probably WHEN should I write these documentations?
The answer?
1) If it’s a new method, you’ll have the luxury of writing what you intend to do without considering regression possibilities. Write it before you code a single line of code into that method.
2) If it’s an existing method, and if there’s already step documentations in place, the same approach applies, but for changes to the existing codes, you’ll have to change the step documentations as well.
Is Step-Documentations enough?
Of course not!
Step documentations only indicate what you intend to do. It’s a demonstration to translate requirements into technical codes.
You’ll need to conduct a peer code review with an architect or project lead to ascertain whether if the understanding of requirements are correct or not. Once this part is done, you’d have save EVERYBODY a shit load of issues in the near future.
Towards the end of this module development, a technical code review has to be done in order to ascertain whether the technical translation are done properly or not.
Conclusion
There’re many tools out there that assist in code review and static analysis. These assets can be invaluable when they find critical slip ups in adherence to coding standards and language standards.
In regards to programmers having near unlimited memory, let’s face it. Unless you’re going to chew on the same project for the rest of your life, proper code documentations are required for every method you code in order to help remind yourself again of what you’ve done, how you’ve done it and why you’ve done it that way.
Other Perspectives
Some may disagree with me and suggests that code documentations are meant for others to understand. I agree to a certain extent since turnover rates in developers can be high at times. Developers can come and go, bringing away precious domain knowledge with them. Code documentations is one of the ways to retain domain knowledge, thus reducing the learning curve of newcomers. (And thus saving costs for hiring them to learn :P)
Let’s just take a look at what the 2 types of code documentations can help:
| Function/Method/Subroutine Documentations | In-function Step Documentations |
| Mostly Others since they’ll most probably make calls to your codes.
Could be self as well if you’re using your own codes from another part of the application. |
Self mostly, till others need to change your codes |
| Describes how to use a function/method/subroutine | Describes how the code works in detail |
Again, I hope that this has been an informative session for all. (Until Strides Octopus tutorials are up)
Signing off,
Jeremy
- Permalink
- Admin
- 19 Oct 2009 10:27 PM
- Comments (2)
October 20th, 2009 at 1:20 pm
what is a getter/setter? i can’t find a wall hard enough.
October 20th, 2009 at 11:08 pm
Hahaha, a getter/setters are basically methods that read/mutate internal attributes.
Most of the time nothing much is done other than to set a new value. For example:
void myClass::setMyValue(int parmValue)
{
this->myValue = parmValue;
}
As for the wall, I guess you’ll find it one day should you override ur own codes that was supposedly working.