Когда стоит переписывать код проекта и как это донести до заказчика

Всем привет! Меня зовут Елена Шаровар, я Lead Node.js developer в Waverley Software. В этой статье мы рассмотрим ситуацию, когда программисты говорят: «Нужно все переписать», но это тяжело донести до заказчика.

Разберемся, что с этим делать и как помирить программистов и бизнес, если вы — Lead проекта, Project Manager или тот самый программист, который хочет улучшений, а вас как будто не слышат. Скорее всего, об этой проблеме вы знаете не понаслышке: такое случается то с вами, то с вашими друзьями или коллегами, и в очередной раз начинается обсуждение: а что же делать?

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

Стейкхолдеры проекта

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

  1. Инвесторы — потому что они вкладывают свои финансовые средства в этот проект и ожидают хороший Return on Investment (ROI).
  2. Product Owner — человек, который занимается управлением этого проекта и приоритизирует функционал, который вы разрабатываете. Он общается с программистами и инвесторами.
  3. Пользователи — те, кто использует ваш продукт и, скорее всего, платит за него.
  4. Программисты — да-да, они также являются стейкхолдерами, проект должен их устраивать, иначе у вас не будет программистов.

Как проект выглядит для всех, кроме программистов

Извините, но это все! Магия, которая происходит внутри, интересна только программистам. Пока программа делает то, что нужно — она устраивает владельца продукта, инвесторов и даже пользователей.

Почему программисты хотят переписать код проекта

Во-первых, потому что у нас есть потребность делать хорошо. К сожалению, понятие «хорошо» у всех разное. Например, код хочется переписать тогда, когда достался legacy-проект, а у тех, кто писал его — понятие, что такое «хорошо», было другим, отличающимся от вашего. Или если вам достался прототип, который делался в спешке, и программисты и сами понимали, что работают не очень качественно.

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

В-третьих, для работы нам нужно понимать то, с чем работаем. Когда ты изменяешь то, что не понимаешь — это вызывает стресс. Кому хочется работать в постоянном стрессе во время разработки, тестирования, деплоя?

Где интересы программистов и других стейкхолдеров пересекаются

Кроме функциональных характеристик, у программ есть нефункциональные характеристики. К ним относятся:

  • скорость ответа (response time, performance);
  • отсутствие багов (reliability, usability);
  • доступность (availability);
  • устойчивость к отказам (resilience);
  • расширяемость (extendability);
  • поддерживаемость (maintainability);
  • среднее время починки (mean time to repair);
  • стоимость разработки и поддержки (cost);
  • тестируемость (testability);
  • возможность аудита и отладки (auditability).

Первые четыре характеристики очень интересуют пользователей, они заметны невооруженным глазом. Точнее, эти характеристики не интересуют пользователей, пока не станут плохими.

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

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

Если в проекте очень сложный и запутанный код, то, скорее всего, хромает maintainability, скорость разработки и тестируемость. Если там старые библиотеки и фреймворки, то, скорее всего, у вас проблемы с расширяемостью. Если архитектура не предполагала большого количества запросов, а они ожидаются — это грядущие проблемы с scalability и performance. Если вы тратите половину рабочего времени на поиск причин багов — явно стоит улучшать auditability & traceability.

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

Почему стороны не могут договориться

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

СтороныЖеланияОпасения
ИнвесторыПолучить хороший IRR и много платящих пользователейВпустую слить бюджет
ПользователиИметь надежный продукт, решающий их бизнес-задачи.Нестабильная работа продукта в тот самый момент, когда он очень нужен.
Product OwnerИдти в соответствии с разработанным roadmap, превосходить конкурентов, выпускать те фичи, которые имеют наибольшую конечную ценность.Думает об Opportunity Cost — убытках, которые понесет компания, если будет делать переписывание вместо новых фич
ПрограммистыПолучать удовольствие от работы на проекте, понимать систему, программировать, работать с новыми технологиямиНестабильная программа, в которой приходится чинить баги по ночам или выходным

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

Note: если во всем этом еще участвует аутсорсинг-компания, то к опасениям инвесторов добавляется страх, что им просто хотят продать дополнительные человеко-часы разработки. Я не вижу другого способа развеять этот страх, кроме как заказать аудит проекта у третьей незаинтересованной стороны, которой доверяет Product Owner.

Что по поводу переписывания говорят эксперты

Joel Spolsky написал 20 лет назад:

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

Проблема в том, что когда придет следующий программист — он снова сочтет код сложным, и снова захочет его переписать. В доказательство этой аксиомы [о том, что код проще писать, чем читать] — спросите почти любого программиста о том коде, с которым он сейчас работает. Он ответит, что это та еще каша.

«Никто не хочет делать те части работы, которые не веселые. Чинить баги — это не весело. А писать с нуля — весело», — пишет Jamie Zawinski.

Так что же, совсем не переписывать?

Неверный вывод. Принцип «работает — не трожь» также не подходит. В книге «Object-Oriented Reengineering Patterns» упоминается, что если система функционирует, но вы не можете ее ни поддерживать ни расширять, она сломана.

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

Примерно то же самое произошло с AngularJS — когда возникло желание его переписать, был выпущен новый фреймворк Angular, и таким образом риски сломать то, что уже работает, были нивелированы.

Microsoft переписала Visual Studio и выпустила VSCode, которым многие, я думаю, пользуются. Google переписала свой Inbox, однако оставила работать обе версии — старую Inbox и новую GMail.

Достойные причины переписать проект

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

Недостойные причины переписать проект

  • Здесь написано на промисах, а я хочу async/await.
  • Здесь фреймворк N, а мои друзья говорят, сейчас модный Y.
  • Я хочу добавить парочку технологий себе в резюме.
  • Я не люблю код, который писал не я.
  • Код работает, но я не понимаю как.

Подводные камни

  • Переписывание всегда занимает больше времени, чем ожидается (по мировой статистике, упоминаемой в книге МакКоннелла «Сколько стоит программный продукт», программные проекты обычно недооцениваются на 30% и больше).
  • Простое переписывание дает мало ценности для конечного пользователя.
  • Вы «забудете» или «потеряете» часть функционала, если нет полной документации по старой системе.
  • Вы сделаете те же баги, которые уже делали и чинили до вас предыдущие программисты.
  • При переписывании с нуля вам придется какое-то время поддерживать обе версии — и старую, и новую.

Переписать или отрефакторить?

Переписывание (rewrite from scratch) — это когда вы заново, с нуля, пишете код, используя старый только для чтения. Рефакторинг — это когда путем последовательных преобразований старого кода вы приходите к новому его виду.

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

Но рефакторинг считается более безопасным по таким причинам:

  • он делается небольшими этапами, а небольшие изменения проще планировать, тестировать и выпускать;
  • если по какой-то причине переписывание будет остановлено на полпути, заказчик не окажется в ситуации, когда новая версия продукта еще не дописана, а старая осталась такой же, как и была (ни туда ни сюда, а время и деньги потрачены).

А где ваш план!

Вы делали ремонт? Помните, что вас интересовало? Цена, качество и сроки, верно? Здесь то же самое. Чтобы заказчик сказал вам «да» — предоставьте ему информацию о цене, качестве и сроках.

Цена и сроки

Цена и сроки тесно связаны. Для того чтобы максимально точно сделать эстимейт, вам нужен план работ. Для того чтобы сделать план работ — вам нужно четкое понимание, что же вы хотите получить в итоге:

  • Сделайте схемы и диаграммы того, что вы хотите получить в итоге.
  • Объясните в комментариях или в design document, чем новая структура лучше старой.
  • Разбейте работу на этапы и составьте эстимейт (оптимистичный, пессимистичный, реалистичный).
  • Продумайте риски (например, уход ключевого разработчика).
  • Кто и как будет тестировать результат, есть ли у вас чек-лист для полного тестирования?
  • Не забудьте включить в эстимейты работу по настройке деплоймента, переносу данных и миграции пользователей.

С этим планом вы можете обращаться к стейкхолдерам с предложением переписать.

Качество

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

Пару слов об инженерной этике

При вступлении в профессию врачи дают клятву Гиппократа. В ней несколько пунктов, и один из них — «доминанта интересов больного» — в процессе лечения врач обязуется следовать интересам больного, а не своим. Будет ли он это делать на самом деле — вопрос воспитанности врача.

При вступлении в профессию программиста мы не даем [еще пока] никаких клятв, но кодекс этики программиста существует здесь и здесь, и похожий пункт там тоже есть: «Principle 2: Software engineers shall act in a manner that is in the best interests of their client and employer consistent with the public interest»

Преследовать свои личные цели, а не цели бизнеса — неэтично.

Дайте цифры

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

Стоимость переписывания посчитать проще всего, она прямо пропорциональна времени на переписывание и выкатывание новой версии.

Стоимость поддержки продукта состоит из таких составляющих: это время, которое тратится на разработку новых фич, багфиксы и тестирование, ввод человека в проект, деплоймент, а также минимально необходимый для поддержки и понимания уровень программистов (Senior vs Junior).

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

Выберите подходящее время

Если вы привели хорошие аргументы и разработали детальный план — у Product Owner все еще может быть достойная причина для отказа: «Не сейчас».

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

Mожно обсудить с Product Owner, когда, по его мнению, все это можно будет реализовать, и запастись терпением. Подумайте: можно ли переписать не все, а часть? Определите самые проблемные части проекта, просмотрев историю баг-репортов или жалоб пользователей.

Спросим коллег

Oleksandr Brychuk, Head of IT Department at UniSender

На початку роботи в UniSender ми стикнулися з тим, що продукт за своєю природою був страшним легасі з практик початку 2000-х.

Час на адаптацію нової людини в проєкті був немалим, деякі частини проєкту взагалі було важко підтримувати, один баг нам обійшовся в кругленьку суму. Їх було багато, і зменшити кількість нам не вдавалося.

Я і колеги взяли ініціативу в свої руки. Зробили документ, в якому описали бачення того, куди потрібно рухатися з технічної точки зору. Приблизно оцінили терміни. Варіантів було два: переписувати все з нуля або рефакторити. Запрошували зовнішніх експертів для аудиту і перевірки власних гіпотез. І презентували це власникам. У кінці-кінців вирішили рефакторити, і почали з найбільш важливого для нашого бізнесу.

Ми рефакторили, а не переписувати з нуля, тому що часто зупинялися в процесі і робили те, що було потрібно на ту мить, а не в перспективі — це додало гнучкості. Перші півроку нічого не робили, крім рефакторингу, потім займалися ним по-різному: від 30-40% до 60-70% часу. Все залежало від цілей на той момент.

На початку роботи в UniSender ми стикнулися з тим, що продукт за своєю природою був страшним легасі з практик початку 2000-х. Час на адаптацію нової людини в проєкті був немалим, деякі частини проєкту взагалі було важко підтримувати, один баг нам обійшовся в кругленьку суму. Їх було багато, і зменшити кількість нам не вдавалося.Я і колеги взяли ініціативу в свої руки. Зробили документ, в якому описали бачення того, куди потрібно рухатися з технічної точки зору. Приблизно оцінили терміни. Варіантів було два: переписувати все з нуля або рефакторити. Запрошували зовнішніх експертів для аудиту і перевірки власних гіпотез. І презентували це власникам. У кінці-кінців вирішили рефакторити, і почали з найбільш важливого для нашого бізнесу.

Ми рефакторили, а не переписувати з нуля, тому що часто зупинялися в процесі і робили те, що було потрібно на ту мить, а не в перспективі — це додало гнучкості. Перші півроку нічого не робили, крім рефакторингу, потім займалися ним по-різному: від 30-40% до 60-70% часу. Все залежало від цілей на той момент.

Eugene Naumenko, Founder at Adferret.tech

Коли говорять «все переписати» — саме в такому абсолютному формулюванні — це у більшості випадків просто непрофесійно. Коли справді є потреба переписати, найчастіше це робиться інкрементально — нові версії з новими можливостями, еволюція, а не революція. У випадках, коли переписати все справді потрібно, програмісти мають навести раціональні і логічні обґрунтування для бізнес-людей і разом сформувати бізнес-потребу, бізнес-цінність такого рішення і його загальну стратегію.
Коли говорять «все переписати» — саме в такому абсолютному формулюванні — це у більшості випадків просто непрофесійно. Коли справді є потреба переписати, найчастіше це робиться інкрементально — нові версії з новими можливостями, еволюція, а не революція. У випадках, коли переписати все справді потрібно, програмісти мають навести раціональні і логічні обґрунтування для бізнес-людей і разом сформувати бізнес-потребу, бізнес-цінність такого рішення і його загальну стратегію.

Eugene Bogatyriov, VP of Engineering, Waverley Software

Расчеты — это ключевой момент: нужно предоставить расчеты ROI проекта по переписыванию/рефакторингу. ROI — время, за которое окупится инвестиция в переписывание. Если переписывание окупается за год-полтора — эту идею примут и «спасибо» скажут. Расчеты желательно презентовать стейкхолдерам по одному, индивидуально, начиная снизу по иерархии. Есть неписаное правило о том, что продукт надо переписывать с нуля минимум каждые 10 лет в связи с устареванием технологий. У меня был пример как раз такого типа, где десктопный продукт переписывали с нуля под веб. Команда 80 человек, три года.
Расчеты — это ключевой момент: нужно предоставить расчеты ROI проекта по переписыванию/рефакторингу. ROI — время, за которое окупится инвестиция в переписывание. Если переписывание окупается за год-полтора — эту идею примут и «спасибо» скажут. Расчеты желательно презентовать стейкхолдерам по одному, индивидуально, начиная снизу по иерархии. Есть неписаное правило о том, что продукт надо переписывать с нуля минимум каждые 10 лет в связи с устареванием технологий. У меня был пример как раз такого типа, где десктопный продукт переписывали с нуля под веб. Команда 80 человек, три года.

Summary

Итого, если вам кажется, что ваш проект нужно переписать:

  • Убедитесь, что причины весомые, а не просто «мне не нравится этот код».
  • Найдите точку пересечения ваших интересов и интересов других стейкхолдеров.
  • Определите опасения стейкхолдеров и способы снижения их опасений.
  • Составьте детальное описание того, что хотите получить в результате: схемы, диаграммы, design document.
  • Подумайте, почему нельзя прийти к тому же результату путем рефакторинга.
  • Сделайте оптимистичный, реалистичный и пессимистичный эстимейт.
  • Сравните затраты и выгоды, получаемые в результате.
  • Выберите подходящее время.
  • Заручитесь доверием со стороны ЛПР (лиц, принимающих решения).
  • Попробуйте менять поэтапно и начать с самых критичных частей.

Полезные ссылки

Похожие статьи:
В выпуске: как жить с лицензиями React, инвестиции Webpack — чего ждать? Поднимаем производительность наших приложений и разбираемся...
[DOU Hobby — рубрика о нетехнических проектах IT-специалистов: творчество, интересное хобби и другие lifestyle-достижения. Если вам есть...
Необходимо сделать лирическое отступление и констатировать факт, что со времени написания оригинальной серии статей по Kotlin...
Лише за перші 12 днів грудня в Україні майже вдвічі зросла кількість пожеж, пов’язаних з порушеннями при експлуатації печей...
В Интернет попало пресс-изображение смартфона Samsung Galaxy S7 edge, его опубликовал Эван Бласс (Evan Blass, владелец Twitter-аккаунта @evleaks)....
Яндекс.Метрика