- PVSM.RU - https://www.pvsm.ru -

Почему проекты переписываются и почему это не удается

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

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

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

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

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

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

Кризис

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

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

Плотину срывает — инженерами на стол выкладываются неопровержимые доказательства того, что дальше так нельзя и вот почему:

  • Помните вот ту функциональность, которую просил клиент? Мы отказали из-за нашей текущей базы данных, которая так не умеет.
  • А вот из-за этой, когда-то принятой архитектуры, мы не в состоянии быстро написать реализацию этой задачи.
  • Код старый, там никогда не было тестов, потому их и теперь нет.
  • Фреймворк старый, таких теперь не делают.
  • Язык программирования старый, такие еще делают, но вообще это уже опасно для жизни на таком писать, и новички к нам не идут поэтому, ага.
  • Тут вообще какие-то скрипты для развертывания окружения, которые никто не понимает, а автор давно уволился.
  • Нам просто больно каждый день трогать такой код руками, а вы нам еще никогда не давали времени что-то с ним сделать хорошее, и вот сейчас уже совсем поздно.

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

С другой стороны стола от инженеров в данный момент сидят несчастные люди. Они загнаны в угол, их планы, их обещания бизнесу рушатся на глазах. Оставить все как есть нельзя — статистика упряма и явно показывает, что положение ухудшается. Всех уволить и нанять новых разработчиков — слишком рискованно для обеспечения работоспособности системы и уж точно гарантирует отставание и задержку выполнения планов развития. А с другой стороны — может действительно всё так плохо и переписывание системы это последнее прибежище? И менеджменту остается только торговаться.

Звук победных фанфар раздается в сознании инженера ровно в момент произнесения фразы “сколько времени вам потребуется на переписывание?”. Победа! Конечно, 100% времени никто не сможет выделить — нужно поддерживать старое, может сделать какие-то небольшие изменения, и все же доделать вот то, что начато. Но это уже не имеет значения, как и общая оценка необходимых ресурсов, как и то, в каких пропорциях будет разделена работа между старым и новым — 50/50, 60/40, треть и две трети. В этот момент случается один из важных и опасных фазовых переходов в сознании — существующая система начинает считаться временной, соответственно, временными выглядят и неудобства по работе над ней.

Благая весть

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

Если вы это слышите, либо же это вы произносите, то знайте — ваш проект, ваша работа в большой опасности.

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

Но вернемся к основной теме и ещё раз посмотрим на описываемую ситуацию. С одной стороны — разработчики, настоявшие на своем видении ситуации, а с другой — менеджмент, загнанный в угол своими же сотрудниками и своим же вышестоящим начальством или заказчиком. Последние хотят вернуть стабильность и предсказуемость ситуации, первые же хотят начать все сначала, с чистого листа. Избавиться от некоего груза обстоятельств, чтобы… но, об этом чуть позже.

Пока же я предлагаю обратится к собственному жизненному опыту, особенно детскому. Наверняка, у каждого были моменты, когда хотелось разбить, разломать наполовину собранную игрушку из конструктора, скомкать и выбросить наполовину исписанный лист сочинения, бросить играть в игру с друзьями после пятого проигрыша подряд. Моменты гнева, бессилия и отчаяния, когда что-то не получается. Когда мы старались следовать инструкции, правилам, советам, но ничего не выходит — детали игрушечного автомобиля не встают на свои места, слова не складываются в предложения, а предложения в повествование, вы не подсчитываете свои очки после партии, потому что “и так все ясно”, но ожидаете следующей в надежде отыграться. Знакомо? Внезапно, это все продолжает случаться с нами и во взрослой жизни, тем более в профессиональной ее части. Желание переписать систему, в которой настолько все плохо, как это пытаются показать разработчики, возникает ровно по одной причине — не получилось.

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

Сложности

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

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

Одну из частей этой сложности, зачастую неосознанную и незримую, представляет собой контекст взаимодействия людей с системой. Скажу проще — в подавляющем большинстве случаев, в компании нет ни одного сотрудника, который знает, как работает их программный продукт. Эти знания либо слишком общие и высокоуровневые, либо слишком локальные и частные. Кое-где вообще Terra incognita, потому что написавший ее человек уже уволился. Кто-то просто что-то забыл, например, что именно это место в коде было сделано потому, что какой-то конкретный клиент (с которым уже не работают) просил о подобных изменениях. Кто-то из отдела поддержки использует старую, не документированную возможность какой-то части системы, чтобы добыть отсутствующие данные для отчета. Но это еще цветочки, по сравнению с тем, что творится у пользователей.

Вы не знаете, не можете знать того, как пользователи взаимодействуют с продуктом. Как они обходят ограничения. Какая функциональность используется, а какая нет. Куда они нажимают, с помощью чего они работают с вашим публичным API. Изобретательность людей по ту сторону http-соединения поистине безгранична. Мой любимый пример — клиент нашей платформы, по каким-то причинам не дождавшись того, чтобы определенные данные появились в offline-отчетах, с помощью кого-то написал Selenium-скрипты, которые вытаскивали нужные данные с UI, чтобы потом присовокупить их к отчетным. С этого момента разметка страницы стала не документированным, но публичным API.

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

Падение

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

  1. не справились со сложностью ведения точно такого же проекта, и не осознали этого
  2. не обладают всеобъемлющим знанием контекста

Может ли у них что-то получиться? В каких-то случаях да — на короткой дистанции в пару месяцев это может и будет возможно. Другой вопрос — как быстро технический долг накопится вновь, ведь люди вокруг все те же. Как об этом писал Джоель Спольски в своей статье “Вещи, которые вы никогда не должны делать” [1]: “Важно помнить, что если вы начинаете все с начала, то нет ни единого основания предполагать, что у вас получится сделать свою работу лучше, чем вы сделали ее в первый раз”. А уж если мы говорим о длинных марафонских дистанциях, то тут вступают в игру осложняющие факторы, начиная от “Эффекта второй системы” Брукса [2], заканчивая простым фактом того, что переписывающим нужно бежать очень быстро, чтобы догонять постоянно удаляющуюся цель — зачастую, в “старую” систему продолжают вносить изменения в то время, как пишется новая. Хватит ли ресурсов команды, чтобы вести разработку двух продуктов сразу?

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

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

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

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

После всего описанного выше, может сложиться впечатление, что переписывать что-либо категорически противопоказано и невозможно. Но это не так. Важным ключом к решению проблемы будет смена мышления [3] — не “переписать”, но “развивать”. Причём, мыслить об этом не как о единоразовой акции, а как о части каждодневных рабочих задач.

Поток

Крупные, большие системы, обладающие активной пользовательской базой не переписываются целиком, даже если есть возможность разделить изменения по версиям. Если оглянуться на успешные компании, выпускающие программные продукты, особенно это касается web-сервисов, то их подход в большинстве случаев сводится к тому, что называют инкрементальными изменениями — непрерывный поток трансформаций, которые не нарушают общего равновесия. Вспомните, когда вы в последний раз получали сообщение от владельца социальной сети о том, что у них выходит новая версия их продукта и там уже есть ваш аккаунт, но все сообщения и записи остались в старой версии и миграции этих данных не будет — заново напишите и “подружитесь”? Никогда? А что бы вы подумали, все же получив такое письмо? Наверняка, реакция была бы очень негативной. Так почему же у нас возникает желание проделать ровно то же самое, но уже с клиентами нашего приложения, нашей компании?

Позитивный опыт, накопленный индустрией, говорит нам о том, что код — довольно податливый материал. Тут показательна история Twitter, который был плавно, в несколько этапов, перенесен между технологиями, без простоев и вместе со всеми своими пользователями и их данными, причем незаметно для последних. Были заменены подсистемы поиска, рендеринг страниц, хранилище данных и другие компоненты. И вот платформа, начавшаяся как приложение Ruby on Rails, теперь работает в основном на JVM, по пути полностью сменив архитектуру. Пример более чем впечатляющий.

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

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

P.S.

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

Автор: Дмитрий Стропалов

Источник [4]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/razrabotka/361856

Ссылки в тексте:

[1] “Вещи, которые вы никогда не должны делать”: https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/

[2] “Эффекта второй системы” Брукса: https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%B2%D1%82%D0%BE%D1%80%D0%BE%D0%B9_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B

[3] мышления: http://www.braintools.ru

[4] Источник: https://habr.com/ru/post/543706/?utm_source=habrahabr&utm_medium=rss&utm_campaign=543706