«Не трогай это, это работает» проблематично в инженерии
5 апреля 2023 г.Старая инженерная поговорка: "Не трогай, это работает" ужасна. Не слушайте это. Это может быть нормально в небольшом масштабе, но со временем битовая гниль распространяется по вашему коду и серверам, загрязняя все. Большие участки вашей системы становятся «нейтральной зоной».
Когда вы разрабатываете новую систему, вы всегда должны «прикасаться к ней» и следить за тем, чтобы мы нанимали инженеров, которые не боятся этого делать.
Да, я понимаю. Раньше я часто произносил эту фразу. Я понимаю мотивацию. Менеджменту нет дела до гнили в нашем будущем. Им важно здесь и сейчас. Почему вы тратите время на эту функцию?
Работает. Тебе уже мало на тарелке?
Вы Мари Кондо в программировании? Разве этот код не вызывает радости?
Это больше похоже на тухлое яблоко в бочке. Плохой код и запретные зоны имеют тенденцию разрастаться и метастазировать. Живой проект должен быть полностью доступен текущей команде. Он может продолжать работать и без этого, но это делает каждый следующий шаг болезненным.
Когда у нас есть гибкая команда с относительно небольшой и знакомой кодовой базой, трогать все подряд несложно. В этом случае все просто.
Наследие
Самая сложная часть – работа с кодом в устаревших проектах. Мне, как консультанту, приходилось делать это часто. Как войти в проект с миллионом строк кода и начать рефакторинг?
Хорошо, что мы все похожи. Инженеры, создававшие проект, обучались по аналогичным книгам и сходным мыслительным процессам. Как только вы поймете их логику, вы сможете понять, почему они что-то сделали. Но большая часть трудностей заключается в инструментах. В проектах, которые были созданы 20 лет назад, использовались инструменты, которые больше не доступны. Код может больше не компилироваться в современной среде IDE. Нашей немедленной реакцией было бы попытаться использовать старую IDE и старые инструменты.
Это может быть ошибкой.
Старые инструменты держат черствый немного гнили. Это возможность. Пересмотрите проект и обновите инструменты. Несколько лет назад я немного поработал над старой кодовой базой C++. Я не разбирался в кодовой базе, но первоначальные разработчики построили ее в более старой версии Visual Studio. Заставить его работать на моем Mac с LLVM и VS Code помогло мне более четко визуализировать движущиеся части.
Как только у меня был запущен отладчик, исправление ошибок и странных проблем стало тривиальной задачей. Не могу сказать, что полностью понял этот код. Но процесс переноса и обновления инструментов выявил множество нюансов и проблем.
Когда нельзя
Обратной стороной этого были случаи, когда существующая устаревшая система является требованием клиента. Мне пришлось реализовать интеграцию с устаревшими системами, которые были внешними черными ящиками. Нам не нужно было трогать их код, но нам нужно было взаимодействовать с этими системами и полагаться на их поведение. Это очень сложная ситуация.
Нашим решением в таких случаях было создание макета системы, чтобы мы могли моделировать и тестировать различные сценарии. В одной из таких ситуаций мы написали приложение, которое отправляло запросы и сохраняло ответы из такого «черного ящика», чтобы создать простой регистратор. Затем мы использовали записи в качестве основы для тестов в нашей реализации. Это может быть не вариант, поскольку иногда черный ящик напрямую связан с производством (в одном случае напрямую с фондовым рынком).
Мои правила обращения с таким черным ящиком:
- Единый изолированный модуль обрабатывает все подключения, поэтому мы можем создавать единые способы обхода сбоев. Мы можем использовать физически изолированный микросервис, который идеально подходит для этого конкретного случая.
- Представляйте результаты с помощью асинхронных вызовов. Это предотвращает взаимоблокировки и перегрузку устаревшей системы. Мы можем использовать очередь для сопоставления причин сбоя, а обработка ошибок упрощается, поскольку сбой просто не вызывает обратный вызов результата.
- Нам нужно защищаться от кода. Используйте автоматические выключатели, ведение журнала и общие средства наблюдения. Ожидайте провала на каждом шагу, так как это будет самая спорная часть проекта.
После того, как мы завершим это наследие, нам нужно активировать оповещения о сбоях. Некоторые сбои могут не отображаться в пользовательском интерфейсе и вызывать успешные повторные попытки. Это может быть серьезной проблемой. Например. в случае неудачной команды покупки на фондовом рынке трейдер может нажать повторную попытку, которая выдаст новую успешную команду. Но исходная команда может неявно повторить попытку в устаревшей системе, и мы можем получить две покупки.
Такие ошибки могут быть очень дорогостоящими и исходить из этого черного ящика. Без полного изучения устаревшего кода и его понимания мы не можем дать никаких гарантий. Что мы можем сделать, так это быстро и точно реагировать на сбои такого типа. В таких ситуациях важна возможность отладки, отсюда и важность наблюдаемости и изоляции в таком черном ящике.
Уверенность через наблюдаемость
Раньше мы просматривали журналы сервера всякий раз, когда выпускали новую версию. Ждем, когда посыплются жалобы пользователей. Благодаря наблюдаемости мы первыми узнаем о проблеме на нашем производстве. Наблюдаемость перевернула сценарий.
К сожалению, существует огромная пропасть между знанием проблемы и ее пониманием, исправлением и замечанием. Если мы посмотрим на консоль наблюдаемости, мы можем заметить аномалию, которая высвечивает проблему, но может не вызвать оповещение, даже если происходит регрессия. Хорошим примером этого может быть просчет. Изменение логики приложения может сообщить о неправильных результатах, и это очень маловероятно отразится в данных наблюдаемости.
Теоретически тесты должны были найти эту проблему, но тесты очень хорошо проверяют, что предсказанные нами вещи не произошли. Они не проверяют наличие неожиданных ошибок. Например. Мы могли выделить размер поля для финансовых расчетов, и это отлично сработало для наших разработчиков из США. Однако клиент в Японии, работающий в иенах, может иметь гораздо большее число и испытать регрессию из-за этого ограничения.
Мы можем отлаживать такие проблемы с помощью инструментов наблюдения разработчиков, но когда мы глубоко интегрируем устаревшие системы, мы должны глубоко применять принципы отказоустойчивости, чтобы слой наблюдения знал о проблеме. Нам нужно утверждать ожидания и проверять условия не в тесте, а в рабочем коде. Здесь реальная ошибка будет лучше скрытой ошибки.
Большое внимание было уделено ненулевым возможностям языков. Но концепции проектирования по контракту, впервые появившиеся в таких языках, как Eiffel, вышли из моды. Это понятно, сложно и неудобно писать такой код. Проверяемые исключения часто являются самой ненавистной особенностью языка Java. Представьте, что вам нужно написать все ограничения, которые вы ожидаете для каждого ввода.
Не говоря уже о зависимости от состояния окружающей среды. Это неприемлемо, и принудительное выполнение этой регистрации будет еще дороже. Однако это то, что мы можем сознательно делать в точках входа в наш модуль или микросервис. Принцип отказоустойчивости важен при интеграции с устаревшими системами из-за непредсказуемого характера результата.
Обзор
В 90-х я ездил на работу на автобусе. Каждый день, когда я шел в офис, я проходил мимо банкомата, и каждый раз, когда я приближался, он перезагружался. Это, вероятно, было частью их политики цикличности, у банков есть традиция перезагружать машины по расписанию, чтобы избежать потенциальных проблем.
Однажды утром я подошел к машине, и она не перезагрузилась. Я сделал то, что сделал бы каждый хороший программист/хакер; Я вытащил свою карту и попытался использовать ее. Он мгновенно перезагрузился и не брал мою карту, но то, что я инстинктивно хотел «попробовать», это хорошо. Даже если это не самая умная вещь в мире, нам нужно, чтобы код был доступным и свежим. Устаревший код — это не дом с привидениями, и нам нечего бояться.
:::информация Также опубликовано здесь.
:::
Оригинал