×
Traktatov.net » Рефакторинг. Зачем? » Читать онлайн
Страница 2 из 11 Настройки

Примеры можно приводить бесконечно, понимание таких вещей обычно приходит с опытом. Важно то, что если у функции или переменной есть какая–то особенность, которую можно подчеркнуть слегка поменяв название — почему не сделать это. Когда читаешь код — важна каждая мелочь. Это как в детективе — любой штрих может привести к разгадке. Только в отличии от преступников, программисты обычно делают что–то полезное или на худой конец безвредное, и большое количество деталей тут только в плюс.


Преобразование одной большой функции в две маленькие

Сейчас мы добрались до куда более сложной и куда менее однозначной темы. Дело в том, что человеческое восприятие так устроено, что анализировать сразу большой объём информации ему крайне сложно. Именно по этому, книги принято разбивать на главы, а сами главы на абзацы.

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

Использование функций как инструмента для улучшения читабельности кода, на мой взгляд, сильно недооценёно. Как показывает практика, небольшое усложнение кода ухудшает его восприятие значительно.


>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;

И пусть вас не смущает, что в сумме кода стало немного больше. Мне ещё ни разу не приходилось жалеть о такого рода рефакторинге. То есть были, конечно, случаи, когда он был не оправдан и только путал… У каждого бывали ошибки. Но никогда проблемы не были связаны с увеличением суммарного объема кода. Иногда, даже если вы смогли разделить функцию на две функции того же размера (суммарное увеличение кода в два раза), но, при этом хорошо разделили их логически — это бывает оправдано.