Что такое рефакторинг кода и когда он нуже

Здравствуйте, в этой статье мы постараемся ответить на вопрос: «Что такое рефакторинг кода и когда он нуже». Если у Вас нет времени на чтение или статья не полностью решает Вашу проблему, можете получить онлайн консультацию квалифицированного юриста в форме ниже.


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

Есть еще несколько методов, использование которых поможет провести грамотный refactoring программы и сделать ее структуру более понятной:

  • Непонятные имена. Все названия классов, методов, переменных и других конструкций кода должны иметь интуитивно-понятные наименования, по которым можно понять, что именно они делают. Следование правилу сделает структуру понятной для других разработчиков.
  • Большие методы и классы. Громоздкие конструкции сокращаются путем вынесения фрагментов в компактные методы и классы, которые правильно ссылаются друг на друга.
  • Длинные списки параметров. Здесь работает аналогичное правило, что и выше. Число аргументов сокращается максимум до четырех-пяти, иначе структура программы будет сложной.
  • Цепочки сообщений. Метод любого объекта должен ссылаться только на собственные либо переданные извне параметры, а также на те участки кода, к которому есть прямой доступ. Это правило называется законом Деметры. Если в программе это не так, нужно перепроверить все связи и правильно их настроить.
  • Статика. Обилие статических переменных увеличивает непредсказуемость программы и делает код более процедурным, нежели объектно-ориентированным. Чтобы избежать этого, разработчик должен инстанцировать объекты, позволяя им управлять данными так, как им нужно.
  • Универсальные объекты. Такие конструкции, имеющие доступ к другим универсальным участкам программы, нарушают закон Деметры и увеличивают связность системы. Это не идет на пользу приложению, поэтому в процессе рефакторинга важно инжектировать только необходимые зависимости.

Увеличить эффективность и скорость рефакторинга помогут хорошие тесты – функциональные, интеграционные и unit-тесты. Необходимо перепроектировать программу небольшими итерациями, после каждого такого шага проводить тестирование, и, если все в порядке, продолжать процедуру.

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

Рефакторинг и проектирование

Рефакторинг — дорогой для бизнеса процесс. Программисты получают зарплату, но не добавляют новых функций и не ускоряют код. Вместо этого они переписывают уже существующий. Данный процесс зачастую необходим и может сохранить много времени и денег в будущем, но возможно ли убрать полностью или сократить время, которое тратится на рефакторинг? Ответ: да, можно.

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

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

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

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

При проведении рефакторинга важным предварительным условием является наличие надежных тестов.

Правила разработки тестов

  • Делайте все тесты полностью автоматическими, так чтобы они проверяли собственные результаты.
  • Комплект тестов служит мощным детектором ошибок, резко сокращающим время их поиска.
  • Чаще запускайте тесты. Запускайте тесты при каждой компиляции — каждый тест хотя бы раз в день.
  • Получив сообщение об ошибке, начните с создания теста модуля, показывающего эту ошибку.
  • Лучше написать и выполнить неполные тесты, чем не выполнить полные тесты.
  • Подумайте о граничных условиях, которые могут быть неправильно обработаны, и сосредоточьте на них свои тесты.
  • Не забывайте проверять, чтобы в случае возникновения проблем генерировались исключительные ситуации.
  • Опасение по поводу того, что тестирование не выявит все ошибки, не должно помешать написанию тестов, которые выявят большинство ошибок.

Проблемы рефакторинга

Изначально понятие рефакторинга (refactoring) сформировалось применительно к Smalltalk, а потом уже концепция постепенно распространилась среди сторонников других языков программирования. Собственно, рефакторинг — это уже неотъемлемый элемент процесса разработки структуры приложений (framework development). Речь идет именно о рефакторинге, когда структурщики работают над иерархией классов и сокращением кодов.

Грамотные специалисты понимают, что слёту хорошую структуру не создать, она совершенствуется в ходе работы, как говорится «на опыте». И еще они знают, что чаще речь идет об улучшении читаемости и модификации старого кода (а не о создании нового). Вот тут и вступает в силу рефакторинг, применимый и для всего ПО, и отдельно для структур (frameworks).

Связаны ли с рефакторингом какие-либо риски? Да, они есть. Дело в том, что анализу и рефакторингу подвергается чистый, уже работающий код, и по ходу дела в нем могут появиться ошибки, на поиск которых потом придется потратить целые дни, а то и недели. Еще хуже, когда рефакторинг проводится бессистемно и без соблюдения формальностей.

Оценка эффективности рефакторинга

Анализ и рефакторинг сделан успешно, если в результате вы имеете чистый, простой и понятный код.

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

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

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

Еще один способ упростить код – все функции собрать в самостоятельный файл, а потом уже ввести его в программу.

Как встроить рефакторинг в свой рабочий процесс?

Обычно самый первый вопрос — как правильно выделить время под рефакторинг. Заводить ли для этого отдельные таски и когда рефакторить, если фичи в приоритете?

Ответ такой: рефакторинг должен проводиться непрерывно на всем этапе разработки.

Обычно это выглядит так:

— Вы взяли задачу и начали читать код. На этом моменте обычно вам уже придется что-то подрефакторить.

— Потом вы приступили к разработке. Буквально через 5-10 минут, максимум полчаса-час, у вас должен быть рабочий кусок кода, покрытый тестом. Тут же надо его рефакторить.

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

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

Читайте также:  Материнский капитал в 2023 году: подробности

Если вы делаете это в парадигме TDD, то этот подход будет называться Red-Green-Refactor. То есть сначала пишете красный тест на какой-то фрагмент функционала, потом пишете код, который делает ваш тест зеленым, потом рефакторите.

Когда нужен рефакторинг в программировании

Существует два вида рефакторинга: плановый и при необходимости.

Рефакторинг, который изначально закладывается программистами в цикл разработки, называется плановым. Например, его могут планировать на каждые 6 месяцев или каждые 4 сплита.

В крупных компаниях, где обычно много legacy-кода, вообще формируются отдельные команды, занимающиеся исключительно рефакторингом старья. Благодаря этому остальные команды легче и быстрее понимают, что происходит в этом коде и как его использовать.

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

Ресурсы для дополнительного погружения в рефакторинг

Самая известная книга о рефакторинге — это “Рефакторинг. Улучшение проекта существующего кода” Мартина Фаулера. Также есть интересное издание о рефакторинге, написанное на основе предыдущей книги — “Рефакторинг с использованием шаблонов” Джошуа Кириевски. Кстати о шаблонах. При рефакторинге всегда очень полезно знать основные паттерны проектирования приложений. В этом помогут эти отличные книги:

  1. “Паттерны проектирования” — авторства Эрика Фримена, Элизабет Фримен, Кэтти Сьерра, Берта Бейтса из серии Head First;
  2. “Читаемый код, или программирование как искусство” — Дастин Босуэлл, Тревор Фаучер.
  3. “Совершенный код” Стива Макконнелла, в которой изложены принципы красивого и элегантного кода.

Вам нужны специальные инструменты для рефакторинга? Мартин Фаулер говорит, что автоматизированные инструменты полезны, но не важны. Он отмечает:

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

Многие среды разработки автоматизируют механические аспекты рефакторинга. Инструменты рефакторинга ключевого кода:

  • Visual studio intellicode
  • Eclipse IDE
  • Spring Tool Suite 4
  • Rider
  • IntelliJ IDEA
  • SonarQube

Каковы преимущества рефакторинга?

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

Например, в 2014 году инженеры Kickstarter столкнулись с проблемой экспоненциального роста числа пользователей, что привело к снижению производительности запросов. В ответ они перенесли запросы MySQL на Redis и сократили типичное время загрузки более чем на 100 мс, что привело к уменьшению дисперсии времени загрузки и в целом более быстрой работе сайта.

Представим такую ситуацию: мы открыли кафе, построили там классную кухню и наняли шеф-повара. Когда кафе только запускалось, в меню были самые простые блюда, которые можно было разогреть в микроволновке. Вы купили микроволновку и поставили на кухне. Рядом разместили стеллаж для всего нужного.

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

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

Читайте также:  Калькулятор компенсации за задержку зарплаты по ст. 236 ТК РФ

В этот момент приходит кухонный проектировщик и рисует всё заново: где что должно стоять.

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

Еще несколько правил написания кода, которыми я бы хотел закончить статью

  • Используйте [] в массивах, а не старую версию array();
  • Используйте === оператор вместо == в случае, когда важно проверять dataType;
  • Всегда будет хорошей идеей давать открытым методам содержательные, понятные и в то же время короткие названия. У приватных методов могут быть длинные названия, так как у них ограниченный объем;
  • Используйте общие названия только в методах, которые реализуют интерфейс, например, add(). Содержательные названия понадобятся единственным методам класса addUser() и addDocument();
  • Убирайте неиспользованные методы из классов;
  • Используйте префиксы is и has для функций, которые используют логическое выражение: isAdmin($user), hasPermission($user);
  • Всегда пользуйтесь модификаторами доступа в классовых методах и параметрах;
  • Остерегайтесь загрязнения интерфейса: выбирайте только те методы, которыми пользователи могут пользоваться открыто;
  • Организуйте классы методов так, чтобы открытые методы были на поверхности;
  • Всегда применяйте принцип единственной обязанности к своим классам.

Как избежать рефакторинга?

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

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

Пример тестового исследования рефакторинга кода

Далее мы смоделируем потенциальный пример из реальной жизни любой продуктовой компании, когда тестировщик может и/или должен поработать с программным кодом после завершения процесса его рефакторинга.

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

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

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

Как видим, ничего сложного, если вовремя и правильно структурировать процесс тестирования.


Похожие записи:

Добавить комментарий