>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;
И пусть вас не смущает, что в сумме кода стало немного больше. Мне ещё ни разу не приходилось жалеть о такого рода рефакторинге. То есть были, конечно, случаи, когда он был не оправдан и только путал… У каждого бывали ошибки. Но никогда проблемы не были связаны с увеличением суммарного объема кода. Иногда, даже если вы смогли разделить функцию на две функции того же размера (суммарное увеличение кода в два раза), но, при этом хорошо разделили их логически — это бывает оправдано.
Я не хочу сказать, что разбить большую функцию на две или несколько маленьких можно и нужно всегда. Принять решение об этом — задача, в ряде случаев, очень сложная. Поэтому, я хотел бы посвятить следующую главу признакам необъодимости такого рефакторинга.
Признаки необходимости выделения функции
Как я уже написал выше — тема довольно сложная и неоднозначная. Подобных признаков может быть сколько угодно, у каждого они свои, но какие–то общие рекомендации на основании своего опыта я постараюсь дать.
1. Размер функции. Первое, что должно насторожить — это слишком большой размер функции. Проще всего измерять их в экранах. Экран в данном случае — это количество кода, которое вы можете увидеть без использования прокрутки. Лучше всего читаются функции, влезающие на экран полностью.
И это не связано с «лишней работой» в виде листания текста. Дело в том, что даже в художественной литературе, для полного понимания, приходится возвращаться к началу абзаца. Что уж говорить о коде, который, зачастую, куда менее линеен.
Человек одновременно может держать в быстрой памяти довольно мало информации и лучше не забывать её ещё и тем, из какой строчки вы пришли и куда, соответственно надо вернуться. Я уже не говорю о том, что зачастую, один и тот же кусок длинной функции приходится искать снова и снова, а это ощутимые затраты по времени.
2. Непонятный код. Если вы, разбираясь в том, как работает функция, наткнулись на кусок кода, в котором пришлось разбираться дольше, чем обычно — подумайте о том, чтобы вынести его в отдельную функцию с понятным названием.
Действительно, если вы сейчас уже потратили время и разобрались в чём–то, почему бы не закрепить результат, чтобы оградить себя (и других в случае коллективной разработки) от совершения той же самой работы в бедующем? Как правило это не очень сложно и быстро окупается.
3. Локальные переменные. Если в вашей функции есть фрагмент кода, в котором инициализируются и используются локальные переменные, которые не используются за пределами этого фрагмента — это также является сигналом к тому, чтобы попытаться вынести данный код в отдельную функцию.
В качестве иллюстрации — можете посмотреть пример к прошлой главе. Там мы благополучно избавились от переменных Width и Height в функции RectsLength. Опятьь же из опыта скажу, что большое количество локальных переменных в функции усложняет восприятие.
4. Внутри функции выполняется какое–то законченное, осмысленное действие. Даже если три строки, вычисляющие периметр не кажутся вам сложным фрагментом кода, рекомендую его всё равно вынести в отдельную функцию. Причин для этого можно назвать несколько:
— Через какое–то время ваш фрагмент и функция в целом может стать значительно сложнее, в середину понятного ранее куска кода могут попасть посторонние, не относящаеся к нему строки. В результате этого на минутное изначально дело можно потратить в разы большее количество времени. При этом риск допустить ошибку будет также выше;