Причины применения рефакторинга. Причины применения рефакторинга Ход выполнения работы

  • Дата: 07.12.2023

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

Если вы хоть немного разделяете мои ощущения, то нам есть о чём поговорить. Дело в том, что со временем что-то внутри меня начало подсказывать, что рефакторить всё подряд, везде и всё время - не самая лучшая идея. Поймите меня правильно, код должен быть хорошим (а лучше бы ему быть идеальным), но в условиях суровой реальности не всегда разумно постоянно заниматься улучшением кода. Я вывел для себя несколько правил о своевременности рефакторинга. Если у меня начинают чесаться руки что-нибудь улучшить, то я оглядываюсь на эти правила и начинаю думать: «А действительно ли сейчас тот момент, когда нужно нарефакторить?». Давайте порассуждаем о том, в каких же случаях рефакторинг уместен, а в каких - не очень.


Дисклеймер. Скорее всего, многим захочется после прочтения поста сразу сказать: «Да это уже 600 раз обсуждалось!» или «Это же настолько очевидно, зачем же об этом писать?». Возможно, вы и правы, но только вот какой момент: в окружающем мире по-прежнему творится хаос. Вроде бы всем всё понятно, но на деле получается, что не так уж и понятно. Поэтому я думаю, что не будет слишком вредно ещё разок взглянуть на эту тему. Но если конкретно у вас проблем с рефакторингом нет, то можете просто пропустить этот пост, у вас уже всё хорошо.

Слишком ранний рефакторинг

Можете ли вы припомнить, когда у вас последний раз было постоянное ТЗ, которое месяцами не менялось? У меня вот такое вспомнить не очень получается. Мы живём в реальном мире, требования всё время меняются. Причём это не обязательно внешние требования - это могут быть ваши собственные требования к проекту. Поясню мысль на примере: допустим, вы взяли задачку среднего размера на один-два дня. Первые несколько классов уже написаны, но запустить пока нечего - идёт процесс написания суровой архитектурной части. И тут вы замечаете, что одна из частей проекта написана не особо универсально: «А вот если через полгода понадобится сделать X, то все будут страдать». Вполне разумно, что вам не хочется отправлять в репозиторий хреновый код, чтобы другие разработчики потом вспоминали вас плохим словом. И вы начинаете рефакторить ещё не готовую фичу . Иногда это оправдано, но на подобном пути следовало бы повесить табличку «ОПАСНОСТЬ». Вот поправите вы одну штуку, потом другую, потом третью. Неделя прошла, фича всё ещё не запускается, а вы говорите: «Как-то всё неправильно сделано. Но теперь я точно понял , как надо делать. Сейчас быстренько всё перепишу с нуля». Основная проблема заключается в том, что фидбека по фиче ещё не получено, а вы уже начали работать над улучшением кодовой базы. Подобный подход редко приводит к успеху. Не знаю, как у вас, а у меня часто бывает, что после реализации фичи я начинаю понимать, что работать всё должно несколько иначе. И это не из-за того, что я такой глупый, заранее не смог нормально продумать. Просто некоторую функциональность нужно «пощупать», чтобы понять как всё должно быть в релизе. Иногда нужен небольшой прототипчик (пусть даже с говнокодом и багами), чтобы обсудить фичу с коллегами. Иногда нужно что-то показать заказчику, чтобы он мог сказать: «Не, ну я не так хотел, всё должно быть наоборот». Порой пользователями не нравятся нововведения, они хотят всё как было. Проблема новых фич в том, что сложно предсказать их судьбу. Нередко случается так, что все наработки отправляются в помойку, т. к. после обсуждения первой версии коллектив принял решение делать всё иначе. Общий вывод: не стоит рефакторить код слишком рано, особенно если вы не уверены, что этот код 100 % останется в проекте.

Нецелевой рефакторинг

Скорее всего, у вас есть план разработки на ближайшее время. Вполне вероятно, что у вас есть сроки (даже если вы их поставили сами). Релизы нужно делать вовремя, затягивать разработку не стоит. Нужно контролировать себя, нужно заниматься теми вещами, которые входят в ваши непосредственные цели. Допустим, у вас есть кусок кода, который выглядит как полное… Ну, в общем, плохо выглядит. Но, продолжим наше допущение, вы с ним сейчас не работаете. Этот плохой кусок кода стабильно работает, успешно справляется со своими задачами и никак не связан с вашей текущей задачей. Ну так и не трогайте его! Да, вас может крайне печалить то обстоятельство, что на другом конце проекта всё очень плохо . Но заметьте, что прямо сейчас вам это никак не мешает. У вас есть текущие задачи, занимайтесь ими. Конечно, бывают задачи по улучшению кодовой базы, но нечасто - зачастую важнее добавлять новый функционал или фиксить баги. Концентрируйтесь на текущих задачах и не бросайте их из-за того, что где-то там что-то как-то не так.

Рефакторинг ради рефакторинга

Ок, вы пришли к выводу, что нужно обязательно отрефакторить часть проекта. Хорошо, давайте отрефакторим. Вроде бы запланированные улучшения выполнены, но тут возникает мысль: «А что я могу ещё улучшить? Ага, вон ту штуку». А после вон той штуки появится вот эта штука, а потом ещё одна, а потом ещё и т. д. Нужно понимать, что есть плохой код, есть хороший код, есть идеальный код. Последнего в большом проекте у вас никогда не будет. Это не значит, что не нужно к нему стремиться, но нужно понимать его недостижимость. Обычно задача стоит в написании хорошего кода, а не идеального. Допустим, после рефакторинга у вас получился вполне читаемый код, который работает более или менее очевидным образом, в котором нет костылей и которым не так сложно пользоваться. Задайте себе вопрос: «А может, пора остановиться?». Да, код можно улучшать. Причём в достаточно большом проекте его можно улучшать до бесконечности. Но вот прямо сейчас он справляется со своими функциями, им удобно пользоваться, он практически не вызывает у вас дискомфорта. Очень важно определить для себя приемлемое качество кода, после которого вы перестанете его улучшать (до тех пор, пока свойство приемлемости не будет утрачено). Вспомните, что есть ещё так много разных клёвых штук, которые можно дописать. Не нужно рефакторить ради самого рефакторинга, ради идеального кода. Нужно рефакторить, когда у вас есть веские причины на это: код сложно прочитать, код сложно поддерживать, код сложно развивать, код сложно использовать и т. п. Если ни одного «сложно» не возникает, то веских причин тратить время на рефакторинг у вас нет.

Рефакторинг за день до релиза

Бывает так, что релиз послезавтра/завтра/сегодня/должен был быть вчера (нужное подчеркнуть). Это важный момент в жизни проекта. Нужно уделить особое внимание тестированию, фиксам критических багов, финальным доделкам. Поверьте, это действительно плохая идея - перерабатывать кодовую базу (а ещё хуже - качественно перерабатывать) в тот момент, когда нужно отдавать проект в продакшн. Опытная практика подсказывает, что нужно зарелизиться, а потом с чистой совестью спокойно улучшать код. Некоторые спросят: «А почему?». Если такой вопрос возник, то, наверное, вам ещё не приходилось делать сложный рефакторинг. Подскажу: при переписывании код не всегда обязательно улучшается - иногда он может сломаться. Да что там сложный рефакторинг - бывает, поправишь один метод на пять строк, не уследишь за какой-нибудь зависимостью, а на другом конце проекта выползет бага, с которой сразу же встретятся ваши любимые пользователи. Вот вроде бы ничего плохого и не делаешь, а тут внезапно на тебя нападает зверь «Это было неочевидно» и топит тебя в пруду ложной первоначальной оценки. Хотя, может, это просто я такой плохой программист - люблю что-нибудь сломать. Вполне возможно, что вы всегда рефакторите всё абсолютно правильно и с полным контролем всего проекта. В таком случае я могу вас поздравить, но от совета с запретом предрелизного рефакторинга всё-таки не откажусь. Поверьте, за несколько дней рефакторинг никуда не убежит, а сон у всей команды будет чуточку, но спокойней.

Рефакторинг очень старого кода

Вопрос тяжёлый, очень тяжёлый. Ситуация: есть огромное количество ужасных строк кода, которые достались вам от старых разработчиков (возможно, этими старыми разработчиками были вы несколько лет назад, ещё до того, как научились писать всё правильно и сразу). Код приходится поддерживать. То там, то тут возникают костыли и дублирования, энтропия растёт. С каждым днём всё больше хочется выкинуть всё и переписать с нуля. В такой момент нужно очень хорошо подумать о рисках. Да, вполне вероятно, что в перспективе такая деятельность будет полезна. Но в какой именно перспективе и насколько полезна? Скорее всего, в процессе большого рефакторинга или переписывания отдельных частей вы замените старый работающий говнокод новым, идеально написанным кодом, но с багами. И вовсе не из-за того, что вы плохой программист и пишете плохо. Просто вы можете не знать этот код в достаточной мере . Вы можете не знать, почему автор написал всё именно так, а ведь причины могли быть. Иногда приходится писать очень странный и кривой код. Я могу придумать очень много примеров: подавление хитрых оптимизаций процессора, подстройка под баги сторонней библиотеки, подавление каких-нибудь многопоточных косяков и т. д. Я не говорю, что нельзя все эти проблемы решить нормально. Просто иной раз при переписывании казалось бы абсурдного кода на нормальный появляются баги. Да, можно было всё сделать нормально, но вы можете просто не осознать всё величие шалаша из костылей вместо палок, если не узнаете у автора кода, почему он написал именно так (а подобная возможность предоставляется далеко не всегда). Будьте осторожны, когда переписываете старый код, который понимаете не до конца (а особенно, если думаете, что понимать там нечего).

А когда рефакторить-то?

Я прошу прощения, если из этой статьи у вас сложилось впечатление, что от рефакторинга одни проблемы. Я всё ещё настаиваю на том, что код должен быть читаемым и красивым, им должно быть удобно пользоваться, его должно быть легко развивать. Позитивный подход лучше негативного, так что относитесь к рефакторингу не как к источнику проблем, а как к своему очень хорошему другу, который выручит вас в трудную минуту. Более того, этот друг может сделать так, чтобы в вашем светлом будущем трудных минут было бы поменьше. Хотелось бы в завершении обозначить несколько моментов, когда рефакторинг действительно уместен.
  • Нечего делать. Бывают спокойные времена простоя, когда все важные задачи закрыты, а новых пока не поставлено. Ну, не то чтобы совсем нечего делать, но определённое количество свободного времени есть. Потратьте его на улучшение кода. Дайте сущностям понятные имена, избавьтесь от дублирования, перепишите неудачный кусок архитектуры. Хоть нового функционала и не добавляется, но вы вкладываете свою лепту в душевное спокойствие разработчиков, которые будут продолжать проект. Поверьте, это важно.
  • Каждодневные страдания. А бывает так, что есть кусок проекта, который заставляет вас тяжело вздыхать каждый день. А из-за соседних столов слышатся тяжёлые вздохи ваших коллег. Конечно, хоть и релиз и не завтра, но важных задач хватает. Тем не менее, за неделей проходит неделя, а смотреть на этот кусок проекта всё грустнее. Скажите себе: «Хватит это терпеть!». Если бизнес-план составляет начальник, то объясните ему, что этот код просто необходимо переписать. Если работаете на заказчика, то убедите его, что потраченная на рефакторинг неделя позволит сэкономить много времени на разработку в будущем. Если работаете на пользователей, то примите решение о том, что лучше бы этим пользователям в этот раз подождать релиза на недельку больше, но зато потом наслаждаться стабильным ПО и регулярными обновлениями. Да, договориться со всеми и с самим собой не всегда просто, но вы уж постарайтесь.
  • Проблема запоздалого рефакторинга. Не стоит абсолютизировать правило про слишком ранний рефакторинг. Некоторые считают так: «Я вот сейчас наулучшаю чего-нибудь, а оно не пригодится - обидно же будет». Нужно понимать, что в ядре программы вполне могут быть важные части, которым лучше бы быть написанными хорошо. Помните, что чем позже вы проводите рефакторинг - тем выше его цена, ведь вы потратите больше времени и сил на переписывание. Критические базисные вещи (которые используются по всему проекту) должны быть в максимально хорошей форме постоянно. Будет просто прекрасно, если в вашей команде будет работать тезис «Рефакторинг не опаздывает. Он приходит строго тогда, когда считает нужным» .
  • Встреча с монстром. Вы начинаете пилить новый функционал, который должен использовать старый кусок проекта, который выглядит как настоящий монстр: вам становится страшно только при взгляде на внешний интерфейс. Если время позволяет, то поправьте сперва базовую часть кода, чтобы потом сосредоточиться на новом функционале и не отвлекаться на то, чтобы вбить пяток костылей ради повторного использования кода.
  • Разумный перфекционизм. Заметили плохой кусок кода? Хочется его поправить? Очень хочется его поправить? Ну, если прям очень хочется, то можно. Но обратите внимание на слово «разумный». Соотносите время, потраченное на рефакторинг, с выгодой от улучшения кода. Не стоит срывать сроки и зарываться в бесконечные улучшения. Однако если своевременно и в меру заниматься рефакторингом, то проекту от этого станет только лучше.

Вместо заключения

Всё вышеперечисленное является чисто субъективным обобщением опыта работы над рядом проектов. Разумеется, я покрыл далеко не все жизненные ситуации. В каждой команде свои требования к коду, свой бизнес-план и свои правила. Уверен, что у многих найдётся пяток историй из серии «А вот у меня был случай, когда все эти советы не работают». Это абсолютно нормально, так и должно быть. Нет универсальной серебряной пули для определения количества усилий на улучшение кода («Мы будем каждый день 47 минут 23 секунды заниматься рефакторингом - и всё у нас будет хорошо»). Вам нужно исходя из собственного опыта в вашем конкретном проекте, в вашей конкретной команде попытаться найти золотую середину между написанием нового кода и улучшением старого. Я агитирую только за то, чтобы ко всему было рациональное отношение без фанатизма («Зачем улучшать код, нового функционала от этого не появится» / «Нужно срочно весь код сделать идеальным, чтобы потом с ним можно было нормально работать»). Подходите разумно к распределению времени на работу над существующим кодом - и всё у вас будет хорошо.

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

Цели рефакторинга

Цель рефакторинга - сделать код программы легче для понимания; без этого рефакторинг нельзя считать успешным.

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

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

Причины применения рефакторинга

Рефакторинг нужно применять постоянно при разработке кода. Основными стимулами его проведения являются следующие задачи:

  1. необходимо добавить новую функцию, которая недостаточно укладывается в принятое архитектурное решение;
  2. необходимо исправить ошибку, причины возникновения которой сразу не ясны;
  3. преодоление трудностей в командной разработке, которые обусловлены сложной логикой программы.

Признаки плохого кода

Во многом при рефакторинге лучше полагаться на интуицию, основанную на опыте. Тем не менее имеются некоторые видимые проблемы в коде (англ. code smells ), требующие рефакторинга:

  1. длинный метод;
  2. большой класс;
  3. длинный список параметров;
  4. «завистливые» функции - это метод, который чрезмерно обращается к данным другого объекта;
  5. избыточные временные переменные;
  6. классы данных;
  7. несгруппированные данные.

Рефакторинг кода

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

Иногда под рефакторингом неправильно подразумевают коррекцию кода с заранее оговоренными правилами отступа, перевода строк, внесения комментариев и прочими визуально значимыми изменениями, которые никак не отражаются на процессе компиляции, с целью обеспечения лучшей читаемости кода (см. code formatting).

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

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

Методы рефакторинга

Выделение метода (Extract Method)

Выделение метода заключается в выделении из длинного и/или требующего комментариев кода отдельных фрагментов и преобразовании их в отдельные методы, с подстановкой подходящих вызовов в местах использования. В этом случае действует правило: если фрагмент кода требует комментария о том, что он делает, то он должен быть выделен в отдельный метод. Также правило: один метод не должен занимать более чем один экран (25-50 строк, в зависимости от условий редактирования), в противном случае некоторые его фрагменты имеют самостоятельную ценность и подлежат выделению. Из анализа связей выделяемого фрагмента с окружающим контекстом делается вывод о перечне параметров нового метода и его локальных переменных.

Перемещение метода (Move Method)

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

Замена условного оператора полиморфизмом (Replace Conditional with Polymorphism)

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

Основные принципы:

Проблемы, возникающие при проведении рефакторинга

  • проблемы, связанные с базами данных;
  • проблемы изменения интерфейсов;
  • трудности при изменении дизайна.

Средства автоматизации рефакторинга

Технические критерии для инструментов рефакторинга:

  • базы данных программы;
  • деревья синтаксического разбора;
  • точность.

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

  • скорость;
  • отмена модификаций;
  • интеграция с другими инструментами.

Примечания

См. также

Литература

  • Фаулер М. , Бек К., Брант Д., Робертс Д., Апдайк У. Рефакторинг: улучшение существующего кода = Refactoring: Improving the Design of Existing Code (2000). - Спб: Символ-Плюс, 2009. - 432 с. - 3000 экз. - ISBN 5-93286-045-6
  • Скотт В. Эмблер, Прамодкумар Дж. Садаладж Рефакторинг баз данных: эволюционное проектирование = Refactoring Databases: Evolutionary Database Design (Addison-Wesley Signature Series). - М .: «Вильямс», 2007. - 368 с. - ISBN 0-321-29353-3
  • Джошуа Кериевски Рефакторинг с использованием шаблонов = Refactoring to Patterns. - Вильямс, 2008. - 400 с. - ISBN 5-93286-045-6

Ссылки

  • Что такое рефакторинг? (англ.)
  • Домашняя страница Мартина Фаулера о рефакторинге (англ.)
  • Ксензов Михаил Рефакторинг архитектуры программного обеспечения: выделение слоев . - Рассматривается один из основных методов рефакторинга архитектуры ПО – выделение слоев, а также его место в контексте рефакторинга архитектуры как многошагового итеративного процесса. Архивировано из первоисточника 25 августа 2011. Проверено 30 ноября 2007.

Wikimedia Foundation . 2010 .

Смотреть что такое "Рефакторинг" в других словарях:

    - (англ. database refactoring) это простое изменение в схеме базы данных, которое способствует улучшению ее проекта при сохранении функциональной и информационной семантики. Иными словами, следствием рефакторинга базы данных не может быть… … Википедия

    Разработка программного обеспечения Процесс разработки ПО Шаги процесса Анализ Проектирование Программирование Докумен … Википедия

    - (паттерн, англ. design pattern) это многократно применяемая архитектурная конструкция, предоставляющая решение общей проблемы проектирования в рамках конкретного контекста и описывающая значимость этого решения. Паттерн не является законченным… … Википедия

    Шаблоны проектирования (паттерн, англ. design pattern) это многократно применяемая архитектурная конструкция, предоставляющая решение общей проблемы проектирования в рамках конкретного контекста и описывающая значимость этого решения. Паттерн не … Википедия

Рефакторинг кода

При создании приложений многие разработчики сначала заботятся об их функциональности, а когда она обеспечена, переделывают приложения таким образом, чтобы они были более управляемыми и удобочитаемыми. Это называется рефакторингом (refactoring) . Под рефакторингом понимается процесс переделки кода для повышения удобочитаемости и производительности приложений, а также обеспечения безопасности типов и приведения кода к такому виду, в котором он лучше соответствует рекомендуемым приемам объектно-ориентированного программирования. К счастью, теперь в Visual Studio 2010 можно достаточно хорошо автоматизировать этот процесс.

За счет использования меню Refactor (Рефакторинг) , которое становится доступным при открытом файле кода, а также соответствующих клавиатурных комбинаций быстрого вызова, смарт-тегов (smart tags) и/или вызывающих контекстные меню щелчков, можно существенно видоизменять код с минимальным объемом усилий. В следующей таблице перечислены некоторые наиболее распространенные приемы рефакторинга, которые распознаются в Visual Studio 2010:

Возможности рефакторинга кода
Прием рефакторинга Описание
Extract Method
(Извлечение метода)
Позволяет определять новый метод на основе выбираемых операторов программного кода
Encapsulate Field
(Инкапсуляция поля)
Позволяет превращать общедоступное поле в приватное, инкапсулированное в форму свойство C#
Extract Interface
(Извлечение интерфейса)
Позволяет определять новый тип интерфейса на основе набора существующих членов типа
Reorder Parameters
(Переупорядочивание параметров)
Позволяет изменять порядок следования аргументов в члене
Remove Parameters
(Удаление параметров)
Позволяет удалять определенный аргумент из текущего списка параметров
Rename
(Переименование)
Позволяет переименовывать используемый в коде метод, поле, локальную переменную и т.д. по всему проекту

Чтобы увидеть процесс рефакторинга в действии, давайте модифицируем метод Main(), добавив в него следующий код:

Using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string args) { // Настраиваем консольный интерфейс (CUI) Console.Title = "Мое приложение"; Console.ForegroundColor = ConsoleColor.Yellow; Console.BackgroundColor = ConsoleColor.Blue; Console.WriteLine("Привет, это мой проект!"); Console.BackgroundColor = ConsoleColor.Black; Console.ReadLine(); } } }

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

Для этого выделите в окне редактора все содержащиеся внутри Main() операторы, кроме последнего вызова Console.ReadLine() , и щелкните на выделенном коде правой кнопкой мыши. Выберите в контекстном меню пункт Refactor --- Extract Method (Рефакторинг --- Извлечь метод).

После этого метод Main() станет вызывать новый только что сгенерированный метод MyConfigCUI(), внутри которого будет содержаться выделенный ранее код:

Using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string args) { //Настраиваем консольный интерфейс (CUI) MyConfigCUI(); Console.ReadLine(); } private static void MyConfigCUI() { Console.Title = "Мое приложение"; Console.ForegroundColor = ConsoleColor.Yellow; Console.BackgroundColor = ConsoleColor.Blue; Console.WriteLine("Привет, это мой проект!"); Console.BackgroundColor = ConsoleColor.Black; } } }

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

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

Цели рефакторинга

Цель рефакторинга - сделать код программы более легким для понимания; без этого рефакторинг нельзя считать успешным.

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

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

Причины применения рефакторинга

Рефакторинг нужно применять постоянно при разработке кода. Основными стимулами его проведения являются следующие задачи:

  1. необходимо добавить новую функцию, которая недостаточно укладывается в принятое архитектурное решение ;
  2. необходимо исправить ошибку, причины возникновения которой сразу не ясны;
  3. преодоление трудностей в командной разработке, которые обусловлены сложной логикой программы.

Признаки плохого кода

Рефакторинг кода

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

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

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

Методы рефакторинга

Выделение метода (extract method)

Выделение метода заключается в выделении из длинного и/или требующего комментариев кода отдельных фрагментов и преобразовании их в отдельные методы, с подстановкой подходящих вызовов в местах использования. В этом случае действует правило: если фрагмент кода требует комментария о том, что он делает, то он должен быть выделен в отдельный метод. Также правило: один метод не должен занимать более чем один экран (25-50 строк, в зависимости от условий редактирования), в противном случае некоторые его фрагменты имеют самостоятельную ценность и подлежат выделению. Из анализа связей выделяемого фрагмента с окружающим контекстом делается вывод о перечне параметров нового метода и его локальных переменных.

Перемещение метода (move method)

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

Замена условного оператора полиморфизмом (replace conditional with polymorphism)

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

Основные принципы:

Проблемы, возникающие при проведении рефакторинга

  • проблемы, связанные с базами данных;
  • проблемы изменения интерфейсов;
  • трудности при изменении дизайна.

Средства автоматизации рефакторинга

Технические критерии для инструментов рефакторинга.

George Carrette

Определение и применение рефакторинга кода

Что такое рефакторинг кода понять несложно – определений в сети достаточно много. Наиболее удачное и полное, на мой взгляд, в википедии, и не только потому, что оно исчерпывающее, но и потому, что в нем рефакторинг противопоставляется таким этапам , как оптимизация и реинжиниринг. Познакомиться с этим вариантом определения легко, набрав в строке слово "Рефакторинг" и открыв (скорее всего первую) ссылку на сайт свободной энциклопедии.

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

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

В жизни каждой программы, по крайней мере, в жизни тех, что разрабатываются на заказ, наступает этап, когда основные заказчика, по мнению разработчика, выполнены, и программный продукт поступает на . А может быть даже в опытную эксплуатацию. В ходе тестирования, если у того, кто его проводит, руки растут из нужного места и мозги работают в правильном направлении, на разработчика начинает валиться большое число bug-ов, связанных с исключительными ситуациями, “защитой от дурака”, экстремальными объемами данных, неприемлемым быстродействием и так далее (идеально работающие программы сразу не пишутся). Разработчик старается быстро реагировать на вызовы судьбы и вносит большое количество локальных исправлений, а иногда и “заплат”, вследствие чего код теряет первоначальную стройность и сбалансированность. Вот в моменты между основными волнами наплывов претензий со стороны отдела технического контроля или просто ОТК и следует проводить рефакторинг кода: анализировать код и, используя ряд эффективных приемов, преобразовывать его к более согласованному и “прозрачному виду.” Естественно, что этап рефакторинга нельзя считать однократным.

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

Как мне кажется, отдельного внимания, помимо прочих, должны быть удостоены и те части кода, которые давно не редактировались (не были затронуты в процессе исправления ошибок или расширения функциональности), поскольку вряд ли они настолько невосприимчивы к вносимым вами изменениям, хотя и сохраняют корректное поведение. Но это уже ответ скорее не на вопрос “Когда уместно…”, а на вопрос “Где искать…”

Кому может быть полезен рефакторинг кода?


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

Во-вторых, сложные программные компоненты часто разрабатываются совместно несколькими людьми. Инструментов для организации совместной существует много: например это Rational Suite, в состав которого входит bag-tracker Clear-Quest и инструмент контроля версий программных компонентов Clear-Case. В последних версий, например, есть замечательный инструмент Team Foundation Server. Понятно, что любой “зрелый” программный компонент должен сопровождаться подробным описанием его внешних программных интерфейсов (спецификаций), но нужно также понимать, что любой опытный разработчик, зная, как пишутся такие спецификации, захочет изучить логику работы вашего компонента, анализируя непосредственно его . Вот для этих целей хорошо было бы, чтобы ваш код был “читабельным”. Таким образом, можно сделать вывод, что рефакторинг кода может помочь ускорить процесс совместной разработки программного продукта.

Рефакторинг vs Реинжиниринг?

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

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

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

Рефакторинг vs Оптимизация

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

Именование переменных, свойств, методов и функций

Данная тема не имеет прямого отношения к рефакторингу кода, но, тем не менее, оказывает немалое влияние на его читабельность. Каждый разработчик со временем вырабатывает свой стиль кодирования и, как следствие, использует свои правила именования лексем, частично или полностью заимствованные из различных нотаций. Довольно часто используют соглашения так называемой венгерской нотации . Я не буду в этой статье перечислять все соглашения этой замечательной нотации, обсуждать ее плюсы и минусы, но сделаю акцент на основном, по моему мнению, преимуществе ее использования: обозначение переменной или константы, помимо ее семантики, также отражает ее тип и . Например: m_iIndex – переменная, член класса целочисленного типа; gc_bUseCache - глобальная константа булева типа и т.д. Согласитесь, это довольно серьезно может облегчить жизнь тому, кто пытается разобраться в чужом коде. Помимо использования соглашений венгерской нотации я также рекомендую следовать следующим правилам:

  • Наименования свойств и полей класса булева типа формировать с использованием модальных и вспомогательных глаголов в соответствии с их назначением, например: Is ReadOnly , Has Value , Can Restore и т.д.;

  • Наименования методов, выполняющих какие-либо служебные, не связанные со спецификой вашей программы операции стараться формировать с использованием таких же служебных, часто используемых для обозначения смысла этих операций глаголов: Update View , Evaluate Value , Refresh Context и т.д.

  • При именовании методов стоит учитывать наименование класса и не дублировать его в наименовании этих методов, например: для обозначения методов открытия и закрытия соединения с базой данных класса DbConnection стоит выбрать имена Open и Close , а не Open Connection и Close Connection , соответственно. Исключением могут являться случаи, когда действие, выполняемое методом специфично или вторично по отношению к основному функционалу класса, например: методы работы с журналом событий Open Log и Close Log для того же класса DbConnection .

  • Если метод или свойство открытое (public), а его назначение нетривиально (в том смысле, что не может быть сформулировано одним или двумя словами типа GetResource или SaveChanges), то скорее всего не стоит его именовать “склеиванием” сокращений нескольких слов типа GetNewClntProf – такой подход уместен для внутреннего использование, но не для метода, который “торчит наружу”, являясь частью открытого интерфейса - не все поймут правильно эту аббревиатуру, не говоря уже о том, что в разных языках (естественных) различные правила сокращения слов. Лучше не жалеть места и составить наименование, как конкатенацию всех слов целиком: GetNewClientProfile .

  • Для того, чтобы в контексте метода или функции отличать ее параметры от локальных переменных (глобальные переменные и члены класса и так выделяются префиксом типа m_ , c_ , g_ и т.д.) предлагаю имена этих локальных переменных начинать с подчеркивания “_” (естественно, если это позволяет синтаксис выбранного вами языка программирования) и дальше в соответствии с венгерской нотацией.