The 'Lost In My Own Code' Feeling

How do you prevent getting confused in your own code?
The 'I haven't worked on this project in three days and forgot everything
sort-of-deal'
I know using comments is most likely the number one way to do it, but is there others?
Keep a general "road map" of your program, and keep track of where you are on that map. Then when you come back to it after a week, you know where you are, what you just finished, what needs to get finished, and where you're going.
On KDevelop on Linux, I can put in to-do comments. The system can show a to-do list window (which shows all of them for the whole project) - when I click on one of them it takes me to that point in the code.

I also tend to put plain comments about the completeness status of functions.

HTH
I try to use comments only as a last resort.

Some of my personal tricks for not getting confused by my own code (in order of importance):
0. If you cannot tell immediately what a piece of code does, you need to rewrite it.

1. If you cannot tell what a variable stands for by its name you have to rename it.

2. Two pieces of code doing the same thing are not tolerated: one of them must go.

3. No change serving clarity may be denied on the basis that it will require a lot of work. Postponing such changes is allowed but only with a great feeling of guilt.

4. Similar actions for different objects must have similar (possibly identical) names.

5. Similar actions for different objects that can be templated-in should be templated in, and the repeating code eliminated. Here having the same names for similar actions on different objects may actually play an essential role.

6. I try to split longer functions into smaller steps. Even if there is no clear logical separation in phases, I often split just to increase readability. I have functions with names such as ComputeSystemStep1, ComputeSystemStep2, etc.

7. I try to write code with minimal indentation. My only reason is I find such code more readable. For example, I would prefer:
1
2
3
4
5
6
7
if (extra_special_condition_holds)
{ 
  handle_extra_special_condition();
  return false;
} 
handle_regular_case();
return true;

rather than
1
2
3
4
5
6
7
8
9
if (extra_special_condition_holds)
{ 
  handle_extra_special_condition();
  return false;
} else
{ 
  handle_regular_case();
  return true;
}
Last edited on
tition wrote:
2. Two pieces of code doing the same thing are not tolerated: one of them must go.

What if they do the same thing (i.e., achieve the same goal) but in different ways?

I agree with everything else. Especially 6. Ideally, every function should be 1-3 lines long, and as many functions as possible should do almost nothing but call other functions. I also try to write functions with no side-effects. Most functions should take some input data and return some output data, and do nothing else if possible. Just like how functions in maths map elements from their domain to their range.

Good to see you back btw.

What if they do the same thing (i.e., achieve the same goal) but in different ways?


I presume you mean different algorithms for achieving the same end goal (say, different algorithms for sorting)? To me those are different.

By two functions doing the same thing I mean literally that: the same algorithm, the same basic implementation. You would ask, why would anyone ever write the same algorithm and more or less the same implementation twice?

Well, you shouldn't, but it happens way more often than you think.
Here's an example. You have class MatrixRational; and class MatrixInteger;. Then you realize that the two classes can be merged in template <class Element>class Matrix;.
You merge the two classes. You have so many methods you don't remember what they do. So, you just do one big copy+paste+formal transformation job. And so, you end up with a bunch of repeating methods, whenever you happened to give different names to the same operations.

If you have more than one person working on a project that will happen even more often. Btw, my Matrix class has at the moment 107 methods.
Last edited on
Okay, I understand. Hence #4.
Thanks for that Tition, I think it's a great list for beginners to get an idea of this.

Perhaps you could add some good/bad examples to it and make an article of it if you have the time :)

All the best,
NwN
Pickle Gunner wrote:
I know using comments is most likely the number one way to do it, but is there others?


I'd say that using comments effectively1 is the #2 way to avoid getting lost while 5 - 10 years of experience is # 1.

One other thing that I can inject here is to never leave an externally visible method that isn't somehow protected from bad input. Saying things like "well, I'll remember to never pass '4' to this method!" -- will always eventually blow up later on. All methods should always behave just as their documentation promises with absolutely no fringe cases.

1 http://www.stack.nl/~dimitri/doxygen/
What kind of code are you writing if you get lost in it after not working on it for 3 days? I can go months and still remember how to navigate old projects o_o
One other thing that I can inject here is to never leave an externally visible method that isn't somehow protected from bad input.


I have also suffered a lot from exposing methods which do not tolerate bad input. However, only very rarely do I change a method from public to private - that is the fourth and last method I use to deal with the situation. Here are my tricks in the order I (usually) use them.

1. Add a list of assert()'s in the beginning of the function body which cover all bad corner cases. This fixes no problem but makes sure the issue is discovered on the spot.
2. Rename the function to include the bad input cases in its name. For example:
 
void GaussianEliminationBuffersMUSTbeDIFFERENT(Matrix* buffer1, Matrix* buffer2);

[Edit:] Again, this fixes no errors, but as the C++ FAQ points out, a plain English language warning is often far more successful than the most intricate programming techniques.
3. Eliminate the corner cases by adding extra code. Remove the obsolete asserts.
4. If absolutely necessary make the method private. This should be used only for extremely time-critical methods, in which checking the corner cases can blow performance.

Last edited on
Generally when I'm designing a project, I lay out a set of internal methods that only use assertions -- no corner case checking left in release code. All input checking happens at the public API layer and is handled promptly by throwing an exception at the user (always a strong exception guarantee). That divides my work into a 'perfect world' internal side and an 'evil user' external side with absolutely no blending of the two (which would manifest as internal input checking!).


*I've found that the smaller a public API is, the less I have to maintain it regardless of the size of the internal code. To vaguely quantify: 5% public 95% internal seems to cost me drastically less maintenance time than 50% public 50% internal.
Last edited on
Topic archived. No new replies allowed.