Refactoring: Improving the Design of Existing Code / Рефакторинг: улучшение дизайна существующего кода

Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.

Refactoring (verb): to restructure software by applying a series of refactorings without changing its observable behavior.

О книге

Ах, Мартин Фолер, каждый программист хотя бы один раз слышал его имя. По какой-то ещё не осознанной причине, я всегда ассоциирую Мартина со своеобразным духовным лидером разработчиков и архитекторов. Его выступления всегда заставляют задуматься. На этой неделе я с грустью дочитал его книгу по теме рефакторинга. С грустью? Я очень, очень медленно шел по последним 30 страницам книги, переодически останавливаясь, откладывая «на потом». Что-то внутри меня не хотело заканчивать эту книгу – хотелось чтобы приключение продолжалось. Но все хорошее когда-либо заканчивается, а значит пора подвести итог.

Заметок и мыслей собралось у меня много и поэтому начну с конца: книга хорошая – стоит времени и денег! Я лично считаю, что мне стоило прочитать эту книгу на пару лет раньше – возможно, это помогло бы мне с некоторыми неправильными представлениями о разработке и рефакторинге. У книги есть 2-е редакции, первая базирована на языке Java, а вторая на Javascript. Я прочитал вторую редакцию и, хотя мой “боевой” язык программирования Java, мне очень понравились приведённые в книге примеры и идеи на Javascript-е. Стоит отметить – я НЕ фанат Javascript-а по многим причинам, однако после Java, это как доза беспечной свободы и креатива – делай что хочешь, как хочешь, даже если тебя это впоследствии убьет. Также, по словам автора, он изменил пару советов во второй редакции, так как за прошедшее время некоторые традиции в программировании изменились, однако большинство советов остались прежними. Книга делится на две части: первые 100 страниц – история о разработке софта, почему и как рефактор является неотъемлемой частью разработки и дизайна. Вторая часть (300 страниц) – “бесконечные” техники рефакторинга из одной структуры кода в другую и наоборот, с объяснениями и хорошо разобранными примерами. В итоге, я считаю, что книга подойдет разработчикам с разными уровнями опыта, но возможно не начинающим! Как ни странно (сарказм), но автор очень сильно опирается на тесты, поэтому желательно усвоить тематику заранее, а также быть хотя бы немного знакомым с TDD, не зря со-автором книги является Кент Бэк.

Итого:
+: Простое и доступное изложение
+: Детально описанные примеры
+: Набор методик с объяснениями
+: Для всех разработчиков, за исключением начинающих
+: Отличные наставления
=: Хорошая, доступная, полезная книга – стоит вкладывать деньги и время.

Название: Refactoring: Improving the Design of Existing Code
Авторы: Martin Fowler & Kent Beck
Обложки:

Разработка и жизненный опыт

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

Не рефактор

“If someone says their code was broken for a couple of days while they are refactoring, you can be pretty sure they were not refactoring.”

“Если кто-то сказал что код был сломан пару дней, потому что они делали рефакторинг, можете быть уверены, это был не рефакторинг”.

Довольно рано в моей карьере я лично повстречался с таким феноменом. Один программист уходил в “рефакторинг” не на пару дней, а на неделю или две. После этого фичи ломались, новый код невозможно было смерджить и наступал хаос. Как минимум ещё неделю программисты ходили с перьями, бубнами, барабанами на шее, зачитывая мантры, танцуя вокруг огня в попытке воскресить этого Франкенштейна. Со стороны все это выглядело жутко, так как сроки горели, софт работал плохо и менеджмент смотрел на нас как на врагов народа, мечтая о плетке и кандалах.

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

Много

“The whole purpose of refactoring to me is to program faster, producing more value with less effort”. “Refactoring is always done to make the code easier to understand and cheaper to modify.”

“Для меня, вся цель рефакторинга – программировать быстрее, создавая больше ценности с меньшим усилием”.
“Рефакторинг всегда делается для того, чтобы код было легче понимать и дешевле модифицировать”.

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

Теоретически, проблему можно решить на корню – писать минимальный и чистый код, однако реальность диктует свои правила. Когда первый раз решаешь проблему, то редко получается с первого раза. Вариаций на “первый раз” может быть много: новая платформа, новая библиотека, отсутствие опыта, незнание домена и так далее. Реалистичное решение проблемы – постоянный рефакторинг: начал работать над кодом; прочитал; понял; посмотри, что можно исправить (очень часто, исправить можно много чего). Добавил код, пройдись ещё раз, посмотри, если ты понимаешь что-то лучше теперь, чем изначально, исправь – сделай проще.

Энтузиасты

“To really operate in an agile way, a team has to be capable and enthusiastic refactorers – and for that, many aspects of their process have to align with making refactoring a regular part of their work.”

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

К большому сожалению опыта с этим у меня нет. Для меня рефакторинг это часть моего личного процесса разработки. Перед тем как я пишу код, я читаю много кода, пытаясь понять что происходит и как оно работает. Пока я это делаю, я также рефакторю код по мере возможности и ценности. Потом я добавляю новую фичу и опять читаю, смотрю, думаю и рефакторю код по мере возможности и ценности. Такой режим работы возможен потому что:
⁃Я практикую TDD
⁃Большинство команды или практикует TDD или пишет хорошие тесты (советую книгу)
⁃ Там, где тестов нет или они плохие, я делаю рефакторинг исключительно автоматизированными средствами IDE.

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

Методические рекомендации

“Here’s a guideline Don Roberts gave me: The first time you do something, you just do it. The second time you do something similar, you wince at the duplication, but you do the duplicate thing anyways. The third time you do something similar, you refactor.“

“Вот методические рекомендации от Дона Робертса: Когда ты первый раз что-то делаешь, то просто сделай. Когда ты делаешь что-то похожее второй раз, поморщись и сделай дубликат кода. Когда ты делаешь похожее третий раз, то делай рефакторинг”.

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

Оптимизация цикла

Я всегда придерживался аксиомы: дубликат кода – всемирное зло, которое должно быть найдено и уничтожено. Часто, когда обрабатываешь массив данных, используешь for-loop (цикл), в котором находятся “правила” изменения данных. Если правил много, то кода в цикле получается тоже много. Читать такой код занимает время и можно было бы все упростить, если сделать несколько циклов и выполнять разные правила в разных циклах по мере необходимости. Однако такой подход значит, что по массиву надо будет проходить несколько раз – в свою очередь большая “О” будет расти, а это как мы знаем из обучения в университете – зло!

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

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

Когда хочется написать комментарий

“When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.”

“Когда чувствуешь, что нужно написать комментарий, сперва попробуй отрефакторить код таким образом, чтобы комментарий стал излишним”

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

Не будьте великим программистом

Statement Kent Beck often makes about himself: “I’m not a great programmer; I’m just a good programmer with great habits.”

Кен Бек часто говорит о себе: “Я не великий программист, я просто хороший программист с отличными привычками”.

Из личного опыта мне довелось поработать с великим программистом и опыт довольно интересный. С одной стороны “писькомер” с другой “Дартаньян”. Для этого великого программиста ВСЁ было крайне просто: написать сложный код; пропустить тесты, потому-что “код тривиальный”; оптимизировать до того как надо. С одной стороны я выучил много чего, работая с ним, с другой я видел ошибки, которые он делал и он не хотел даже выслушивать доводы. Великий программист ушел, его код остался и до сих пор его дизайн поражает воображение, так как там черт ногу сломит, программисты обходят его код стороной!

Тут я хочу дать пару советов программистам. Учитесь, всегда учитесь, практикуйтесь, читайте книги, блоги и документацию! Не изобретайте колесо там где оно уже давно есть. Практикуйтесь писать чистый, понятный код – помните простота сестра таланта. Изучите разные техники, включая TDD, оно всегда поможет. Заприте свое эго под большой замок, оно никому не нужно и в итоге будет только мешать. Взращивайте отличные привычки и знания.

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

“What do I tell my manager about refactoring? Of course, many managers and customer don’t have the technical awareness to know how code base health impacts productivity. In these cases I give my more controversial advice: Don’t tell!”

“Что говорить менеджеру о рефакторинге? Конечно, многие менеджеры и клиенты не имеют технических знаний о том как хороший код влияет на продуктивность. В таких случаях я даю свой спорный совет: Не говорите!”

Этот совет я слышу не первый раз и не от одного человека. Много раз, когда я ходил на семинары, эта тема всплывала и ответ был одним и тем же. Если вы находитесь в таком положении, то я поддерживаю совет – делайте что надо и не нужно никому ничего говорить. Однако помните выше описанные советы и методики – это очень важно! Так же прочитайте эту книгу, она вам очень поможет.

Теперь хочу поделиться опытом альтернативного пути развития событий. Такой путь обычно происходит в не шибко умной команде с бесхребетным тимлодом, которого больше интересуют политические игры, чем технологии. В какой-то момент, рефакторинг попадет на горизонт и будет расценен как что-то мифически-полезное, но опасное и будет принят на вооружение как оружие массового поражения. Другими словами рефакторинг включат в официальный процесс работы и будут применять только там, где нужно изменить “все”. Из личного опыта такое заканчивается по двум сценариям. Первый сценарий: пишутся рефактор-карты и кладутся в бэклог, где они долго бродят, протухают и в итоге выкидываются. Второй сценарий: выделяется неделя или две на рефакторинг какого-нибудь Титаника. И тут в зависимости от программиста: или переставляются стулья на палубе или происходит такой кап-ремонт, что в последствии принимается решение такого больше не делать, подписывая договор с менеджментом об ограничении использования оружия массового поражения.

Тесты

“I’m sure you have heard many times that you cannot prove that a program has no bugs by testing. That’s true, but it does not affect the ability of testing to speed up programming.“

“Я уверен что вы слышали много раз, что нельзя доказать что в программе нет багов через тестирование. И это правда, однако это не значит что тесты не помогают вам программировать быстрее.”

“Don’t let the fear that testing can’t catch all bugs stop you writing tests that catch most bugs”

“Не позволяйте страху остановить себя от написания тестов которые поймают большинство багов, лишь потому что тесты не поймают все баги”

“A suite of test is a powerful big detector that decapitates the time it takes to find bugs”

“Набор тестов это очень мощный детектор, который позволяет сократить время поиска багов”

Я лично фанат TDD и почти всегда пишу тесты. Теперь стоит отметить, что я не фанатик и понимаю, что не всегда и не везде нужно писать тесты, однако по большинству я их всегда пишу. К такому состоянию я пришел из личного опыта написания кода и считаю что тесты действительно помогают писать код быстрее и допускать меньше ошибок. Если взять один момент из моего опыта, то тесты спасли меня когда я в аварийном режиме разрабатывал патч для прода, работал по 12 часов в день и если бы не тесты, я бы не успел закончить во время. Так же стоит отметить что на протяжении почти 2-х лет, код работал четко и без ошибок или багов. Позже код был удален, так как больше не был востребован.

Pull Request

“The common pull request model, where a reviewer looks at code without the original author, doesn’t work too well. It’s better to have the original author of the code present because the author can provide context on the code and fully appreciate the reviewers’ intentions for their changes. I’ve had my best experience with this by sitting one-on-one with the original author, going through the code and refactoring as we go. The logical conclusion of this style is ‘pair programming’: continuous code review embedded within the process of programming.”

“Обще принятая модель пул реквестов, где рецензент просматривает код без автора, не работает особо хорошо. Намного лучше сидеть с автором кода, который может предоставить контекст к изменениям и обьяснить, почему были приняты те или иные решения. Из моего опыта лучше всего сидеть вместе с автором, разбирая код и делая рефакторинг на лету. Логическое завершение такого стиля работы называется: “парное программирование”, где процесс рецензии происходит по ходу разработки.”

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

Однако у парного программирования есть и свои косяки. Одна большая проблема – это личность человека. Не все могут работать в паре, может кто-то жуткий интроверт и ему очень тяжело. Так же если в команде нет способа избавиться от непригодного программиста (допустим он не хочет учиться и/или не умеет программировать, а такое тоже бывает), тогда парная работа превращается в один работает, а другой спит! У нас на работе такое явление частое, а команда ничего по этому поводу сделать не может. Менеджмент по непонятным причинам не увольняет таких чудо-работников, а дает бесконечные вторые шансы. В таких ситуациях программисты начинают отказываться работать парно и по понятным причинам, в итоге результат на лицо.

Переименуй

“Renaming is not just an exercise in changing names. When you can’t think of a good name for something, it’s often a sign of a deeper design malaise. Puzzling over a tricky name has often led us to significant simplifications to our code.”

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

Как говориться в программировании есть две сложные задачи: придумывать названия и кэширование. Интересно, сколько существует вариаций этой шутки? Я даже не знаю сколько раз я повторял выше описанное своим программистам. Когда я перешел в новую команду и посмотрел на их тесты, то вздрогнул. Спустя пару месяцев я ввел обязательную методику по названию тестов (если интересно, пишите я раскажу) и ещё 8 месяцев объяснял почему и как, не раз объясняя, если тест не соответсвует названию, то тест слишком сложный – разбейте на несколько отдельных тестов. Уже на данный момент все идет по маслу, битв больше нет, тесты плюс/минус в хорошем состоянии. Невероятно как маленькие изменения в названии ведут к большим изменениям в коде и работе.

Запомните это

“I was just as surprised myself when Kent Beck showed me how to do this in a hotel room in Detroit two decades ago. The key to effective refactoring is recognizing that you go faster when you take tiny steps, the code is never broken, and you can compose those small steps into substantial changes. Remember that – and the rest is silence.”

“Я был очень удивлен, когда 20 лет назад Кен Бэк показал мне как это делается в комнате гостиницы в Детройте. Ключ к эффективному рефакторингу – это осознание что ты программируешь быстрее когда делаешь маленькие изменения, код никогда не ломается и ты можешь составлять маленькие изменения в большие. Запомни это, а остальное тишина.”

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

Я советую вам попробовать этот подход на себе, главный трюк – разбить работу на маленькие шаги. Стратегий много и описывать их не буду, однако оставить с пустыми руками тоже не могу – посмотрите на “Как это решить”.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.