Wednesday, April 9, 2008

Write your source as if it was open

Sometimes you get to read some piece of code and you say "mmm, that's a good piece of code". Well, it doesn't necessarily occur too much, but I hope for you that it does happen, at least occasionally when reading your own code. But in many cases you come to code that makes you shout "who the hell wrote this stuff", and you may recall that it was you as well.

So, what makes a good code?

Is it comments?
Well, comments are important and we will surely dedicate a post to it sometime. But one can think of good code without too many comments. In fact in some cases comments are what makes bad code looks even worse.

Coding guidelines are surely important
Do you really think so? Making your code readable is a must, but as long as you are not doing crazy stuff you can keep your code readable without too much guidelines. Not saying that guidelines are
bad, but this is not what makes good code.

Should it be simple? Should it be sophisticated?
This is in fact a target you cannot really set. The level of simplicity or complexity is an outcome of the problem you are solving. You should not try to get a simple solution for a complex problem, and you should not be too happy with a beautiful monstrosity built for a simple problem having in mind all the other problems that this pretty hide
ous thing may also solve in the future. So simplicity or sophistication per-se is not the target.

Lacking a straightforward answer, let's ask the opposite question...
What makes a bad code?

  • Bad code is a code that you cannot explain
  • Bad code is a code that you find hard to use
  • Bad code is a code that repeats itself
  • Bad code is a code that is tightly coupled - everything needs everything, everyone needs to know anyone else, you cannot go easily from top to bottom, there is no top and no bottom
  • Bad code is a code that you will not feel proud to publish under your name

To avoid writing bad code I suggest that you will think you are writing an open source. Assume someone else, that you do not have direct communication with, is going to use your code, thus your code should have clear API and be modular enough so it can be used in pieces (i.e. one doesn't need to understand the whole thing in order to create the first "Hello World"). And you should write it so you will be proud to publish it. This is writing your code as if it was an open source.


To summarize
  • Pay attention to your API
  • Modularity counts
  • Be proud of your code, if you are not, think why and fix it

Do you have a theory?

In many cases when I sit with a novice developer who is working on fixing a bug I see him or her throwing lines of code from here to there. When I ask "why did you do that", usually when the code looks already like after a burglar paid a visit, the answer I get is "it wasn't working, so I'm trying to fix it."

Would you like someone to fix your car that way?

Debugging is considered sometimes a non-sceintific trial and error process - you try this and that, eventually the bug will be exhausted and you will break it. Well, it is not. This would only make you to mess your code and put new bugs in, break the original structure and leave the code in a strange, shaky position, usually explained later as "we needed to do that because there was a misterious bug in the original, proper code."

Just as when fixing your car, the mechanic would probably not try to shove your carburetor into the fuel tank as a possible solution (well, we haven't tried this yet, who knows maybe it works), this is not the way for debugging.

Debugging should be methodical.

  • Have a theory before you act
  • Try to prove your theory on a simple code
  • Divide and conquer - try to eliminate the bug by putting code in comments till the bug is gone, then analyze what is wrong in the lines commented out. But don't just throw these lines away, even if they look redundant at first sight, and don't move them around without understanding the problem
  • Analyze the problem and what causes the bug before you start changing your code, use logs to analyze the problem in complex scenarios
  • If you are changing the code as part of a theory ("I think we might have to call the super class at the beginning of the function and not at the end...") - remember what you have changed, if your theory fails (the bug persists and the change does not have a value of its own, it was just a whim of the moment) - return to the original code before you go on
  • If your theory prove itself right, still make sure that you fully understand it (moving the call to the super class to the beginning of the function fixed the problem - now let's understand why it should be this way... does it always have to be this way? do we need to check other similar places?)
And never try to shove your carburetor into the fuel tank, even if it makes the car go (maybe the problem was that the carburetor was too dry) - not understanding what you have done is NOT a fix!