Примеры можно приводить бесконечно, понимание таких вещей обычно приходит с опытом. Важно то, что если у функции или переменной есть какая–то особенность, которую можно подчеркнуть слегка поменяв название — почему не сделать это. Когда читаешь код — важна каждая мелочь. Это как в детективе — любой штрих может привести к разгадке. Только в отличии от преступников, программисты обычно делают что–то полезное или на худой конец безвредное, и большое количество деталей тут только в плюс.
Преобразование одной большой функции в две маленькие
Сейчас мы добрались до куда более сложной и куда менее однозначной темы. Дело в том, что человеческое восприятие так устроено, что анализировать сразу большой объём информации ему крайне сложно. Именно по этому, книги принято разбивать на главы, а сами главы на абзацы.
В программировании всё обстоит немного иначе и это может быть причиной путаницы. Тут текст разбит на функции (процедуры, методы, классы, сейчас это не так важно), а основное назначение функций — это возможность их повторного использования. То есть по сути, с их помощью суммарный объём кода уменьшается, они позволяют избежать многократного повторения одних и тех же фрагментов кода и тому подобное.
Использование функций как инструмента для улучшения читабельности кода, на мой взгляд, сильно недооценёно. Как показывает практика, небольшое усложнение кода ухудшает его восприятие значительно.
>type
>TRect = record
>Left: Integer;
>Right: Integer;
>Top: Integer;
>Bottom: Integer;
>end;
>function RectsLength(Rects: array of TRect): Integer;
>var
>I: Integer;
>Width, Height: Integer;
>begin
>Result:= 0;
>for I:= 0 to Length(Rects) — 1 do
>begin
> Width:= Rects[I].Right — Rects[I].Left;
>Height:= Rects[I].Bottom — Rects[I].Top;
> Result:= Result + 2 * Width + 2 * Height;
>end;
>end;
Выше приведён простой пример, который рассчитывает сумму периметров прямоугольников в массиве. Пока он не выглядит сильно сложным, но, предположим, что задача немного изменилась и нам сказали не учитывать прямоугольники площадью меньше некоего числа MinLength.
>function RectsLength(Rects: array of TRect; MinLength: Integer): Integer;
>var
>I: Integer;
>Width, Height, Len: Integer;
>begin
>Result:= 0;
>for I:= 0 to Length(Rects) — 1 do
>begin
> Width:= Rects[I].Right — Rects[I].Left;
>Height:= Rects[I].Bottom — Rects[I].Top;
>Len:= 2 * Width + 2 * Height;
>if Len >= MinLength then
> Result:= Result + Len;
>end;
>end;
Не скажу, что намного сложнее, но взгляд спотыкается. А если бы мы сразу выделили функцию RectLenght, считающую площадь отдельного прямоугольника вышло бы несколько проще:
>function RectLength(Rect: TRect): Integer;
>var
>Width, Height: Integer;
>begin
> Width:= Rect. Right — Rect. Left;
>Height:= Rect. Bottom — Rect. Top;
>Result:= 2 * Width + 2 * Height;
>end;
>function RectsLength(Rects: array of TRect; MinLength: Integer): Integer;
>var
>I: Integer;
>Len: Integer;
>begin
>Result:= 0;
>for I:= 0 to Length(Rects) — 1 do
>begin
>Len:= RectLength(Rects[I]);
>if Len >= MinLength then
>Result:= Result + Len;
>end;
>end;
И пусть вас не смущает, что в сумме кода стало немного больше. Мне ещё ни разу не приходилось жалеть о такого рода рефакторинге. То есть были, конечно, случаи, когда он был не оправдан и только путал… У каждого бывали ошибки. Но никогда проблемы не были связаны с увеличением суммарного объема кода. Иногда, даже если вы смогли разделить функцию на две функции того же размера (суммарное увеличение кода в два раза), но, при этом хорошо разделили их логически — это бывает оправдано.