Рефакторинг программного обеспечения способы проведения рефакторинга программного обеспечения

Рефакторинг — мощь сокрытая в качественном коде

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

Проектирование

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

Начать проектировать можно очень легко. Всегда держите на рабочем месте блокнот и несколько цветов ручек. Прежде чем писать код, нарисуйте схему — как приложение будет работать в целом, UML-диаграмму классов (продумайте как можно с минимальным количеством классов, достигнуть максимального результата), структуру баз данных (оптимизируйте БД еще до ее создания, подумайте какие запросы у вас должны будут «бегать» к вашей БД, продумайте индексы, конечно же нормализируйте вашу модель данных).

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

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

Несколько принципов, которые точно нужно знать при проектировании классов вашей «Feature»:

1. SOLID (single responsibility, open-closed, Liskov substitution, interface segregation и dependency inversion)

Это основа основ в проектировании классов. Если вы еще не знакомы с SOLID, здесь можно ознакомиться.

2. DRY (do not repeat yourself)

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

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

— Вместо использования функции progress50(), лучше применить более абстрактную progress($percent).

— Отдавать предпочтение внешним зависимостям между модулями, внутренним (DI), что делает модуль более гибким и позволяет его использовать в нескольких местах.

3. KISS (keep it simple, stup. )

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

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

Стиль кода

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

Стандарт стиля кода (и не только) PSR (PHP Standards Recommendations), здесь можно ознакомиться. Содержимое на английском языке, так как английский более ясно дает понять степень применения одного или другого правила («MUST», «MUST NOT», «REQUIRED», «SHALL», «SHALL NOT», «SHOULD», «SHOULD NOT», «RECOMMENDED», «MAY», and «OPTIONAL»).

Несколько замечаний, которые автор счел важными:

1. Ознакомьтесь с PHPDOC для написания комментариев к вашему коду.

2. Лучший комментарий — это правильно названный класс, метод, параметр или переменная.

3. Используйте утилиты PHPMD, PHPCS, их применение шире, чем только для определения несоответствий в стиле кода. Вот документация: PHPMD, PHPCS.

4. Используйте продвинутое IDE.

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

Очень простая аксиома — на продакшн должен попадать только код, прошедший рефакторинг. Иногда после разработки вы сами делаете рефакторинг, что очень даже не плохо (к примеру, разработка через тестирование вообще включает рефакторинг, как обязательный шаг, так как изначально пишется «работающий код», а потом уже «чистый»), но для того, чтобы код был по-настоящему качественным, он должен пройти проверку кода (code-review) другим программистом. Если проект позволяет выделить время на проверку кода, то на таком проекте ты будешь учиться писать код чище и чище, что в последствии приведет к автоматическому написанию качественного кода.

Читайте также:  Дорожные знаки как способ регулирования движения

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

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

1. Длинные методы (лучше разделить функционал на несколько методов).

2. Громоздкие классы (ваш класс должен исполнять одну функциональную задачу в вашей системе).

3. Неясная структура класса (методы в хаотическом порядке, конструктор в середине класса, вместо констант — магические значения в коде — класс должен легко отображать, что он делает в правильной последовательности).

4. Слишком много параметров в методе (некоторые расчеты можно сделать внутри метода, используя внутренние константы, значения полученные с атрибутов и геттеров).

5. Классы, содержащие одинаковые переменные и методы. Проблему можно решить через создание дополнительного класса).

6. Сложно читаемый IF (выражение можно вынести в отдельную переменную и разделить на логические части, которые также вынести в переменные, если много проверок на null, то лучше всего использовать NullObject — количество проверок значительно уменьшится).

7. Громоздкий SWITH (выносим в отдельный метод).

8. Использование наследования из-за одинаковых методов и свойств, в разных по своей сути сущностях (кошка и стул имеют ноги, но их нельзя группировать в категорию «животные»).

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

10. Слишком сложный функционал в одном классе, который можно разделить на несколько классов.

11. Класс делает слишком мало, чтобы его оставлять в системе.

12. «Мертвый код» — его следует удалить.

13. Не использованные структуры классов, которые вы проектировали на будущее, но они так и не пригодились — такие лучше удалить.

14. Методы класса больше используются в другом классе, а в своем вообще не используются или же реже (стоит перенести метод в тот класс, где он больше используется).

15. Слишком длинная цепочка вызовов ($a->b()->c()->d()->e()), в этом случае стоит создать дополнительные методы.

16. Класс, содержащий только один метод, который создает другой класс. (Такой класс нужно использовать с умом, к примеру, для паттерна «Прокси», в противном случае этот класс только увеличивает время и ресурс на поддержку проекта).

17. Слишком много действий в конструкторе. (Конструктор должен только устанавливать свойства класса, если же в конструкторе создаются другие классы, происходят какие-то расчеты, то это делает его сложным для понимания, приходится вникать в суть реализации. Чтобы создать объект и выполнить какие-то действия, добавьте статический метод create($param1, . ), который создаст экземпляр класса с дополнительными действия над ним, этот метод можно назвать более подходящим к тому, что он будет все же делать).

Источник

Рефакторить или не рефакторить?

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

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


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

Читайте также:  Определение морфологические способы его выражения

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

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

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

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

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

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

Читайте также:  Способ толкования норм права понятие

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

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

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

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

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

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

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

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

Источник

Оцените статью
Разные способы