Хабрахабр

[Перевод] Дорогой клиент, вот почему это изменение заняло столько времени

Изменения в сложных программных системах, кажется, занимают вечность, не так ли? Даже инженерам часто кажется, что изменения идут больше положенного, хотя мы сознаём всю сложность системы!

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

Они очень нам доверяют, но иногда кажущееся незначительным изменение отнимает действительно много времени. Поэтому рано или поздно заказчик пришлёт письмо: «Почему, чёрт возьми, это занимает так много времени?» Не будем забывать, что у нас как инженеров-программистов есть окно в мир, которого они зачастую лишены. В то же время, вы можете предложить пути улучшения ситуации. Из-за этого и возникают вопросы.
Не обижайтесь на этот вопрос; воспринимайте его как возможность проявить сочувствие и дать человеку более чёткое представление о сложности системы. Когда кто-то расстроен, это наилучший момент, чтобы предложить решение!

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

Дорогой Клиент,

Здесь для справки я обобщу свои мысли, необязательно отвечать. Я видел ваш комментарий на карточке «Уведомить перед истечением срока выполнения задания» и буду рад обсудить его на нашей следующей встрече.

Перефразируя вашу заметку:

Как оно может занять 4−8 часов? Изменение срока выполнения задач на один день для уведомления по почте должно занимать одну строчку. Что я упускаю?

Достаточно просто изменить часть запроса с tasks due <= today на tasks due <= tomorrow. С одной стороны, я с вами согласен.

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

Это простое, небольшое изменение, одна строка кода. Тратить на него целый день, даже полдня, кажется чрезмерным.

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

Это уведомление для внутренних сотрудников. Здесь сравнение выходных данных может быть минимальным, лишь небольшая выборочная проверка: убедиться, что результаты имеют смысл и т. д. Если бы это было, скажем, электронное письмо для ваших клиентов, потребовалось бы более глубокое изучение. Если математика по дате неверна (лёгкая ошибка), мы быстро услышим об этом от команд. Копание в данных может съесть время. Но для этого лёгкого тестирования и ревью достаточно 20−40 минут, в зависимости от того, появляется ли что-то странное или неожиданное. Выпуск изменений без проведения ревью — просто непрофессиональная небрежность.

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

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

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

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

Она различает общие и индивидуальные задачи, открытые и приватные, повторяющиеся, функцию дополнительного уведомления менеджера в случае просроченной задачи и т. д. И тогда логика уведомлений сложнее, чем вы думали. И только одно нужно изменить, чтобы достичь цели. Но мы можем довольно быстро выяснить, что фактически для уведомлений используются только 2 из 6+ определений просроченной задачи.

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

Таким образом, мы достигли 1,5 часов, чтобы чувствовать себя уверенно, что изменение будет выполнено как положено.

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

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

Таким образом, мы вышли в диапазон 2–2,5 часа для выполнения задачи с уверенностью, что всё пройдёт нормально, без непреднамеренных побочных эффектов или путаницы в работе пользователя.

К сожалению, единственным результатом этих усилий является только выполнение поставленной задачи. Это неоптимально, что весьма разочаровывает. Знания, полученные разработчиком в ходе работы, являются личными и эфемерными. Если другому разработчику (или нам самим через 6 месяцев) снова потребуется внести изменения в эту часть кода, процесс придётся повторить.

Есть две основные тактики для исправления ситуации:

  1. Активно чистить кодовую базу для уменьшения дублирования и сложности.
  2. Писать автоматизированные тесты.

Примечание: мы уже обсуждали документацию, но в данном случае это не лучшее решение. Документация полезна для высокоуровневых идей, например, для объяснения бизнес-логики или часто повторяемых процессов, таких как список новых партнёров. Но когда дело доходит до кода, документация быстро становится слишком объёмной и устаревает по мере изменения кода.

Вы заметили, что ни одна из этих тактик не включена в наши 2–2,5 часа.

Например, поддержание чистой кодовой базы означает, что вместо простого выполнения поставленной задачи мы задаём вопросы:

  • Почему существует так много разных способов определить задачи, чей срок подошёл/истёк?
  • Все ли они нужны и над ними работают?
  • Можно ли свести эти способы к одной или двум концепциям/методам?
  • Если концепция разделена между старой и новой системами, можно ли её консолидировать?

И так далее.

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

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

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

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

  1. изменение работает правильно;
  2. изменение ничего не сломало (это ещё более ценная информация, чем в первом пункте).

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

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

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

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

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

Если бы эта часть кодовой базы была чище и имела хорошее покрытие автоматическими тестами, то компетентный опытный разработчик выполнил бы её за час или меньше. Другими словами, 4−8 часов на данную задачу — это запас примерно в 2−4 раза, но он значительно уменьшит усилия для подобных изменений в будущем. И ключевой момент в том, что у нового разработчика работа займёт ненамного больше времени.

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

Спасибо,
Эл

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть