Saturday, December 1, 2012

Connections...


We have approximately 100 billion neurons and we use it intensively, but the real power of our brain is not in cell itself (soma), it is in axons and dendrites, in other words - connections.


We have several trillions connections and we use it to process our daily life, our fantasies, our fears, our happiness, in other words everything, with these connections life have meaning. 


It is similar in programming.


Good programs always have constraints - a lot of them. 

And what are constrains - connections. We define how one thing is related to another. With this approach we can constraint ourselves in our own universe of definitions.


So, what does it mean?


Well, this post is dedicated to constants. I hate 'em. 


OK, it is not so bad you say, after all, constants are useful and they are providing you a way to repeat yourself less, to be more explicit in your code and eventually your code will be also less obscured.


But... I’ve seen it many times that constants are really misused. 


Constants can be used just to replace plain data, not for code itself - for code branching or any other way involved in code execution.


So in case that you have function like this:


              public int Foo(int p)

              {

                     return p + 20;

              }



It is good idea to replace naked constant with the real constant like:

              private const int PAGE_PADDING = 20;


              public int Foo(int p)

              {

                     return p + PAGE_PADDING;

              }


But what about this:

              public int Foo(string key)

              {

                     if (key == "CommandOpen")

                     {

                           return 1;

                     }

                     else if (key == "CommandSave")

                     {

                           return 2;

                     }                   

                     else

                     {

                           return 0;

                     }

              }


You say, it easy one, you just need to rewrite it:

              public const string KEY_COMMAND_OPEN = "CommandOpen";

              public const string KEY_COMMAND_SAVE = "CommandSave";


              public int Foo(string key)

              {

                     if (key == "CommandOpen")

                     {

                           return 1;

                     }

                     else if (key == "CommandSave")

                     {

                           return 2;

                     }

                     else

                     {

                           return 0;

                     }

              }



But this is BAD!


Your constants are part of code execution, you use it to evaluate something and it is really, really BAD!


But OK, what can be done?


You could define enumeration, you could define class itself, it is fine with me, but just don’t use constants in this way.


Bu you could say that enumerations are the same thing, only a bit fancier constants, but then you just don’t seem to understand what are the enumerations.

First, let’s see how can be this rewritten with enumeration:

              public enum Commands

              {

                     Open,

                     Save,

              }


              public int Foo(Commands key)

              {

                     if (key == Commands.Open)

                     {

                           return 1;

                     }

                     else if (key == Commands.Save)

                     {

                           return 2;

                     }

                     else

                     {

                           return 0;

                     }

              }


No, let’s see how this function is called when we use constants:

Foo(KEY_COMMAND_OPEN);


And with enumeration:

Foo(Commands.Open);


OK, it’s almost the same, no big differences – WRONG!

In first example, your function really doesn’t tell you nothing, it receives string and it is totally acceptable to pass something like this:

        Foo("CommandCopyToExcel");


Or

        Foo("Something is passed here - probably it’ll work");


But you can say it is bad to pass string anyway; you should infer which constants are used where. OK, but how can I know where your constants are defined? I mean, you could write function in one class and use constant from another class just because you don’t want to have redundancy, which is OK, but how can I know that as consumer of your class, your function doesn't tell that, even if you wrote somewhere comment it will be probably skipped by my eyes. But what if you decided to remove some constants from your definitions, just because you don’t won’t to support some part anymore, like:

              public const string KEY_COMMAND_OPEN = "CommandOpen";

              public const string KEY_COMMAND_SAVE = "CommandSave";

              public int Foo(string key)

              {

                     if (key == "CommandOpen")

                     {

                           return 1;

                     }

                     else if (key == "CommandSave")

                     {
                           return 2;
                     }
                     else

                     {

                           return 0;

                     }

              }


But in my code I am still calling your function like:

              Foo(KEY_COMMAND_SAVE);


How can I know that this is not supported anymore?


Well, I will find it in run-time which is probably the worst case you can have.


And, now let’s go back to enumerations (or you can use classes also).


You can’t pass anything, you can try to pass another enumeration because function is expecting enumeration but you will be enforced by compiler to change your opinion and that's because function exactly tells you which enumeration it expects. If you delete some enumeration value it will be automatically detected by compiler and you will know it and you will fix it before you even run project or make any test.


So, to summarize, if you are using constants as values it is OK, but if you are using for code branching then it is BAD, really BAD.



    

No comments:

Post a Comment