Avoding adhocity

I am thinking about how to avoid adhocity in the code. By “adhoc” I mean something that should not be there in the first place but was added later due to some reason: to fix a bug, to quickly add a feature or alike.

One way to deal with adhocity is simply bear with it. And it works sometimes surprisingly well. Especially in the case if you are never looking at that place in code again. What is wrong here is that you actually never know when and where you will look, so it is a kind of lottery – you may find yourself lucky later or you may get stuck in your own adhocs when you finally need to make some serious adjustments to the code.

I can think only about two other ways. One is to avoid adhocity altogether, another is to fix it later. First way definitely sounds better, but it will not help if it is already there. So if your code is already adhocish, well, you are stuck. You may try to fix it by refactoring the code, but it may take a lot of time which will be a waste if you never have to deal with it again. Or you may choose risky path and live with it, but then you are risking ending up with a mess.

To avoid this choice, it is better to go the first way and avoid adhocity altogether. What left is to only understand how. And here I have got some kind of philosophical idea. The idea is to believe that every problem has a proper solution (well, at least one) and that this solution is always better in long-term meaning than any kind of adhoc. I am sure that I am not the first one who came up with this idea, but I did not try to live by it yet so I can say nothing about whether it really works or not. What I mean here is that if you are making a change to your software that looks like it does not fit in well even slightly, you better stop correcting anything and carefully think about it. The goal is to find a way to implement the same but in the most elegant manner possible, even if that means significantly more coding.

For example, let us suppose we have some kind of function that processes one byte. It was implemented using some kind of table with 256 entries. Since one byte never can (and never will) hold more than 256 values, constant “256” was used literally in many places. Now suppose that we have to make this function process a special case when the input is empty. Now it accepts “int c” instead of “char c” with value c == -1 meaning “empty input”. It is 257th case in our function which we did not think of. Adhoc solution would be adding a lot of “if”s for empty output. Or globally replacing 256 with 257 and adding one more entry to the beginning of the table, and replacing “c” with “c + 1” in function. A more proper solution would be:
* to define a constant like CASES_COUNT = 257 and replace these 256s with this constant;
* define a mapping from the input to the index in the table. Impossible input should be mapped to something like “-1” so we will know right away that something is wrong (for example, if we get -5 or 257 on input).

Of course, this example is too simple. In this case I would probably go the right way anyway. But the whole point of all this blabbing is that it is always better to do it right, even if it seems like an overkill. I shall try it in QuaWeb development and see how it works. I am too tired of all these adhocs in my software, they look like nothing at the early stages, but then one day I find that my nice application turned into adhoc monster where it is harder and harder to change anything.

Leave a Reply