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

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

Какие можно привести примеры:

— практически все называют переменные цикла буквами i, j, k, для циклов первой, второй и третьей вложенности соответственно;

— какие–то временные, короткоживущие переменные часто снабжают префиксом «temp» или «tmp», например, tempFileName для файла, который вскоре удалится;

— логические переменные становятся куда нагляднее с префиксами типа is, has, can, например, isButtonVisible, canAddPoint, hasPoint;

— в случае коптрования данных из одной переменной в другую, лучше использовать префиксы source и dest, а не суффиксы 1 и 2, «copy(array1, array2)» выглядит менее понятно, чем «copy(sourceArray, destArray)».

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


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

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

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

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


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

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

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


Признаки необходимости выделения функции

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

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

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


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

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


Хорошо

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


Тень иллюзии

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


Рекомендуем почитать
Язык PL/SQL

В учебно-методическом пособии рассматриваются основы языка программирования PL/SQL, реализованного в системе управления базами данных Oracle Database Server. Приводятся сведения о поддерживаемых типах данных, структуре программ PL/SQL и выполнении SQL-предложений в них. Отдельно рассмотрено создание хранимых в базах данных Oracle программ PL/SQL – процедур, функций, пакетов и триггеров.


Пишем драйвер Windows на ассемблере

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


Язык программирования С# 2005 и платформа .NET 2.0.

В этой книге содержится описание базовых принципов функционирования платформы .NET, системы типов .NET и различных инструментальных средств разработки, используемых при создании приложений .NET. Представлены базовые возможности языка программирования C# 2005, включая новые синтаксические конструкции, появившиеся с выходом .NET 2.0, а также синтаксис и семантика языка CIL. В книге рассматривается формат сборок .NET, библиотеки базовых классов .NET. файловый ввод-вывод, возможности удаленного доступа, конструкция приложений Windows Forms, доступ к базам данных с помощью ADO.NET, создание Web-приложений ASP.NET и Web-служб XML.


Вариации на тему STL. Адаптер обобщенного указателя на функцию-член класса

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


Информационная технология. Руководство по управлению документированием программного обеспечения

ГОСУДАРСТВЕННЫЙ СТАНДАРТ РОССИЙСКОЙ ФЕДЕРАЦИИИнформационная технологияРУКОВОДСТВО ПО УПРАВЛЕНИЮ ДОКУМЕНТИРОВАНИЕМ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯInformation technology. Guidelines for the management of software documentationИздание официальноеДата введения 1994-07-01ГОССТАНДАРТ РОССИИ Москва© Издательство стандартов, 1994.


Самоучитель UML

Самоучитель UMLПервое издание.В книге рассматриваются основы UML – унифицированного языка моделирования для описания, визуализации и документирования объектно-ориентированных систем и бизнес-процессов в ходе разработки программных приложений. Подробно описываются базовые понятия UML, необходимые для построения объектно-ориентированной модели системы с использованием графической нотации. Изложение сопровождается примерами разработки отдельных диаграмм, которые необходимы для представления информационной модели системы.