mardi 1 mai 2018

Bug Generator: Use of indices

Let me just start by stating what I mean by a Bug Generator. It's a style of code that is likely to contain bugs or produce bugs in the future as the code is extended. This is of course an anti-pattern. There are corresponding Prevention Patterns, basically less error-prone alternatives. That being said, let's dive into the Bug Generator Use-of-indices.


Use of indexed access is low level, off-by-one errors are very common. Also index out of bounds can happen. Usually we can simply avoid this by using higher level constructs such as for-each-loops and higher-order functions such as map and filter.


Bug: Off-by-one errors

We access the data by some index. The problem can range from some simple error in a loop construct. For instance we use <= instead of < in loop. To harder-to-spot errors like passing the index to some function and using the index while modifying it by a -1 or +1. 
A basic example of this. Say we need to find the first cat in a list of animals. The bug will only occur when there is no cat in the collection

Bug: Index-out-of-bounds 

Variation of the above bug. This is off-by-one where we actually step outside the array.

Prevention pattern: use lambdas and higher-order-functions

higher order functions like map, filter, some/first, etc have already implemented the looping and we just have to provide a function that the higher order function will use on each element.

Prevention pattern: for-each-loop

If we really must use imperative style

Prevention pattern: link the structure length to the index calculation

E.g. modulo on length. An example would be picking cards from a deck. Lets assume that whenever we get to the end of the deck we're supposed to start from the beginning. A naïve implementation would be to

Prevention pattern: Wrap the array and index in a class (they are nearer).

This is particularly useful when the same calculation is done in several places. Whenever we have a class it is easy to find the code we need to manipulate the date inside. Another advantage is that the behaviour becomes easily testable when isolated in a class.
It'd be very easy and natural (i.e. likely) that we'd test getNextCard both by calling it many times in a row and with large values of someStep.

This solution is related to the Bug generator Primitive-Obsession that will probably be described in the future.

Credits to CodeCop (Peter Kofler) with whom I've worked a lot to explore the concept of Bug Generators. We sketched out this pattern together.