Development

Пишите маленькие функции, используя примеры

(В оригинале – Write Small Functions Using Examples)

Мы все хотели бы писать правильный код, а также убеждаться в том, что он правильный. В обоих случаях нам может помочь размер функции. Только не тот размер, который измеряется количеством строк кода (хотя этот параметр тоже интересен), а размер математической функции, которую мы реализуем.

Например, в игре Го есть положение, называемое «атари», в котором камни игрока могут быть пойманы его противником. Камень с двумя или более смежными свободными местами – не в положении «атари». Подсчитать количество свободных мест у камня может быть сложно, но после того, как оно подсчитано, определить «атари» очень легко. Первая версия функции может выглядеть так:

boolean atari(int libertyCount) libertyCount < 2

Функция эта больше, чем кажется. Математически функция – это множество, одно из подмножеств декартового произведения множества ее входных параметров и множества возможных значений. В данном случае множество входных значений – это int , а выходных – boolean . И для Java мы получим:

2L*(Integer.MAX_VALUE+(-1L*Integer.MIN_VALUE)+1L)

или 8 589 934 592 элемента в множестве int x boolean. Половина его будет нашим подмножеством, определяющим функцию, поэтому чтобы на 100% убедиться, что функция работает, нам нужно будет протестировать около 4.3×109 примеров.

Это показывает суть того, что тесты не могут гарантировать отсутствие ошибок. Тесты могут лишь подтвердить наличие функциональности. Но вернемся к размеру функции. Здесь нам может помочь предметная область. Суть игры Го такова, что количество свободных мест у камня – это не произвольный int, а всегда одно из следующих значений: {1,2,3,4}.

Поэтому мы можем переписать функцию:

LibertyCount = {1,2,3,4}
boolean atari(LibertyCount libertyCount)
     libertyCount == 1

Это сильно меняет дело. Теперь наша функция – множество из всего лишь восьми элементов. Четыре проверки смогут гарантировать, что функция работает верно. Вот почему стоит использовать типы из предметной области вместо встроенных обычных. Использование типов предметной области практически всегда позволяет сделать функции меньше (в вышеописанном смысле). Один из способов найти эти типы – это подобрать пример проверки в терминах предметной области до написания функции.

Автор оригинала - Keith Braithwaite