Рубрики
Без рубрики

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

В Applaud я каждый день работаю с крупными и малыми компаниями, которые хотят больше создавать и отправлять код… Помеченный как ruby, java, архитектура, рефакторинг.

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

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

Поэтому нам было интересно работать с разработчиками, которые поддерживают монолитные приложения Ruby и Java, объем которых достигает 1 миллиона строк кода. В этом масштабе решающее значение имеют чистая архитектура и модульность, а не академические проблемы. Самая веская причина этого, которую я видел до сих пор, – это проверяемость.

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

Но поскольку кодовая база становится действительно большой, просто невозможно запустить весь набор тестов за один час. Единственный способ, которым тестирование остается практичным, – это запустить подмножество всего набора, и именно здесь модульность становится критической. Для каждого предлагаемого изменения необходимо определить область затронутого кода или “радиус взрыва” этого изменения. Когда код является внутренне модульным и использует определенные границы службы, эти границы можно использовать для определения подмножеств набора тестов, которые необходимо выполнить.

Масштабирование, как у больших мальчиков

Именно такой подход использует Google. Система сборки и тестирования Google, Blaze[1], способна применять сложный подход к разрешению зависимостей. Blaze требует, чтобы границы служб определялись с использованием строго типизированного языка определения интерфейса (например, буферов протокола), что позволяет вычислять радиус действия большинства изменений кода. Чтобы сделать этот статический анализ максимально эффективным, Google также предпочитает использовать типизированные языки.

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

Система электронной коммерции с открытым исходным кодом Solidus [2] – хороший проект для понимания некоторых проблем масштабирования и модульности. Одно непосредственное наблюдение: Solidus не использует стандартную организацию проекта Rails. Скорее, он разделен на 5 различных библиотек Ruby (“драгоценные камни”): ядро , api , серверная часть , интерфейс , образец . Одной этой сегментации достаточно, чтобы обеспечить значительную степень модульности.

Чтобы представить хороший пример организации внутреннего кода, я нашел большой проект с открытым исходным кодом, похожий на Solidus. Затем я создал эту диаграмму[3], проанализировав более 5000 тестовых примеров в ее наборе тестов.

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

Рекомендации

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

1) Начните добавлять внутреннюю модульность . 2) Выявлять и ускорять особенно медленные тесты. 3) Соберите данные о путях выполнения кода и используйте их для вычисления наилучшего предполагаемого радиуса взрыва для данного изменения.

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

1) Измерьте модульность кода и найдите некоторые очевидные области недостатков. 2) Установите некоторые цели модульности и стремитесь к достижению этих целей с течением времени. Достижение этих целей также поможет владельцам бизнеса понять, как время, потраченное на эти усилия, приносит дивиденды. Хорошими начальными целями могут быть централизация доступа к базе данных в одном пакете или реорганизация логики домена из контроллеров и моделей в выделенные пакеты. 3) Информировать заинтересованные стороны об основном факте – чем быстрее можно проводить тесты, тем быстрее и чаще можно выпускать продукт.

Все понимают и любят ценность скорости!

Ресурсы с открытым исходным кодом

  • [1] Базел , инструмент для сборки и тестирования, основанный на Google Blaze.
  • [2] Солидус , система электронной коммерции, написанная на Ruby on Rails.
  • [3] Платформа Applaud , инструмент для записи, отображения и анализа сквозного кода и потоков данных.
  • Shopify/packwerk , библиотека Ruby для определения и обеспечения модульности.

Оригинал: “https://dev.to/kgilpin/why-modularity-matters-lessons-from-maintaining-monoliths-at-scale-5hg1”