Рефакторинг. Зачем? - [3]

Шрифт
Интервал

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

2. Непонятный код. Если вы, разбираясь в том, как работает функция, наткнулись на кусок кода, в котором пришлось разбираться дольше, чем обычно — подумайте о том, чтобы вынести его в отдельную функцию с понятным названием.

Действительно, если вы сейчас уже потратили время и разобрались в чём–то, почему бы не закрепить результат, чтобы оградить себя (и других в случае коллективной разработки) от совершения той же самой работы в бедующем? Как правило это не очень сложно и быстро окупается.

3. Локальные переменные. Если в вашей функции есть фрагмент кода, в котором инициализируются и используются локальные переменные, которые не используются за пределами этого фрагмента — это также является сигналом к тому, чтобы попытаться вынести данный код в отдельную функцию.

В качестве иллюстрации — можете посмотреть пример к прошлой главе. Там мы благополучно избавились от переменных Width и Height в функции RectsLength. Опятьь же из опыта скажу, что большое количество локальных переменных в функции усложняет восприятие.

4. Внутри функции выполняется какое–то законченное, осмысленное действие. Даже если три строки, вычисляющие периметр не кажутся вам сложным фрагментом кода, рекомендую его всё равно вынести в отдельную функцию. Причин для этого можно назвать несколько:

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

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

— Код станет проще читать.

Следует отметить, что код выполняющий отдельное осмысленное действие в общем случае не обязан идти подряд.


>function RectsLength(Rects: array of TRect; MinLength: Integer): Integer;

>var

>I: Integer;

>Len: Integer;

>Widths, Heights: array of Integer;

>begin

>Result:= 0;

>SetLength(Widths, Length(Rects));

>SetLength(Heights, Length(Rects));

>for I:= 0 to Length(Rects) — 1 do

>begin

>Widths[I]:= Rects[I].Right — Rects[I].Left;

>Heights[I]:= Rects[I].Bottom — Rects[I].Top;

>end;

>for I:= 0 to Length(Rects) — 1 do

>begin

> Len:= 2 * Widths[I] + 2 * Heights[I];

>if Len >= MinLength then

> Result:= Result + Len;

>end;

end;

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

5. Сложные условия. Логические выражения по праву занимают одно из лидирующих мест по сложности восприятия. Именно по этому, по возможности, их следует выделять в отдельные функции. Единственный совет, при этом — старайтесь избегать отрицаний в названиях функций.


>procedure AddPointToRect(x, y: Integer; Rect: TRect);

>begin

>if (x >= Rect. Left) and (x <= Rect. Right) and (y >= Rect. Top) and (y <= Rect. Bottom) then

>AddPoint(x, y);

>end;


>Лучше заменить на:


>function PointOnRect(x, y: Integer; Rect: TRect): Boolean;

>begin

>Result:= (x >= Rect. Left) and (x <= Rect. Right) and (y >= Rect. Top) and (y <= Rect. Bottom);

>end;


>procedure AddPointToRect(x, y: Integer; Rect: TRect);

>begin

>if PointOnRect(x, y, Rect) then

>AddPoint(x, y);

>end;


Однако для функции PointOutsideRect, добавляющей точку за пределами прямоугольника, лучше не писать «if PointOutsideRect(x, y, Rect) then», а написать «if not PointOnRect(x, y, Rect) then».

6. Высокий уровень вложенности. Бывает функция как матрёшка. Блок кода, в нём ещё блок кода, в нём ещё и так далее. Читать это также довольно трудно. Пример приводить не буду, чтобы не захламлять текст, отмечу лишь, что блок целиком (текст между скобками «begin end» или «{}» для C-подобных языков) очень часто легко переносится в отдельную функцию.


Еще от автора DarkGoodWIN
Хорошо

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


JavaScript. Учебник начального уровня

Несколько слов об особенностях JavaScript, другими словами - что я знал об этом языке до начала его изучения. Первое и главное: JS код легко интегрируется в HTML разметку и является де факто стандартом для интернет браузеров. Из этого следует, что если вы совершенно не знаете HTML - JS, вероятнее всего, будет для вас бесполезна. В данном опусе я постараюсь разжевать всё максимально детально, но надо иметь в виду, что HTML и JS идут бок о бок, дополняя, а не заменяя друг друга. Для тех, кто сталкивался раньше с Delphi программированием или чем-то подобным можно, в первом приближении, привести такую аналогию: HTML - это форма, а JS - сам код программы.Другая важная особенность языка - высокая интерактивность.


Тень иллюзии

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.