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

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

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

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

За пределами кодовой базы

Понимание бизнеса

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

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

Документация

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

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

Сквозные тесты

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

it('intercepts a request and returns mocked data', () => {
  cy.intercept('GET', 'https://api.openweathermap.org/data/2.5/weather*', {
    fixture: 'melbourne-weather.json'
  }).as('getWeather')

  cy.visit('http://localhost:3000/');

  cy.get('[data-testid="search-input"]').type('Melbourne');
  cy.contains('Search').click();

  cy.get('[data-testid="search-results"] .search-result').first().click();

  cy.get('[data-testid="my-weather-list"]').contains('Melbourne');
  cy.get('.weather-category').contains('clouds');
  cy.get('.temperature').contains('14°');
})

Такие инструменты, как Cypress или Playwright, позволяют разработчикам проверять, успешно ли приложение позволяет конечному пользователю выполнять свои задачи.

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

Внутри кодовой базы

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

Интеграционные тесты

Сквозные тесты должны охватывать только самые важные пути пользователя. Интеграционные тесты оказываются полезными для непредвиденных обстоятельств, таких как сбои сети или ошибки серверной службы. Для этих тестов требуются фиктивные серверы (например, json-server) и поддельные почтовые серверы для имитации возможных сценариев сбоя.

Цель состоит в том, чтобы обеспечить совместную работу различных компонентов в относительно изолированной среде. Такие инструменты, как mirage.jsили msw, могут имитировать сетевой уровень в браузере, облегчая проверку взаимодействия между компонентами.

В моей книге Maintainable React я рассмотрел множество паттернов для устранения запахов кода и способов их рефакотинга с помощью подхода Test-Driven Development.

Код Запахи

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

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

Рефакторинг

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

  • Упрощение условных выражений: это может сделать ваш код более читабельным и понятным.
  • Извлечение методов или классов. Это помогает уменьшить дублирование и сложность кода. Это также увеличивает возможность повторного использования и ремонтопригодность.
  • Переименование переменных, методов или классов: это может улучшить читабельность и ясность вашего кода.
  • Замена магических чисел именованными константами. Это делает код более читабельным и снижает вероятность ошибок.
  • Перемещение функций между объектами. Это поможет вам лучше организовать код и придерживаться принципа единой ответственности.

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

Разработка через тестирование (TDD)

Разработка через тестирование (TDD) — это процесс разработки программного обеспечения, основанный на повторении краткого цикла разработки: требования превращаются в конкретные тестовые примеры, а затем код улучшается, чтобы тесты проходили.

Вот как вы можете применять TDD при работе с устаревшей кодовой базой:

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

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

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

Краткое содержание

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

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

Надеюсь, вам понравилось это читать. Если вы хотите поддержать меня как писателя, рассмотрите возможность подписки стать участником Medium. Всего 5 долларов в месяц, и вы получаете неограниченный доступ ко всем моим статьям на Medium — а также ко всем статьям упомянутых авторов и всех остальных!