Тестирование архитектуры
Тестирование архитектуры

Предпосылки

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

Когда-то
Когда-то

Теперь простое сохранение файла сопутствует приведению его к нужному формату, об этом даже не надо задумываться, редактор заботливо расставит отступы и аккуратно отформатирует твой код. Если у вас ещё не так то советую вам этим озаботиться. Но к слову говоря, всем не угодить - всегда найдется то, что кому-то не нравится (мне например не нравится что нельзя оставить точку запятую на новой строке после вызовов методов объекта с "текучим" интерфейсом) однако смирение с таким "меньшим" злом открывает путь к менее нервному погружению в новые проекты.

Зачем

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

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

Часть команды - часть корабля
Часть команды - часть корабля

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

Что проверять

1. Думаю каждый сталкивался с обсуждением "толстых" контроллеров с различными вариантами решения этой проблемы. В данном пункте прошу сконцентрироваться на симптомах данной проблемы, а не на вариантах её решения. Конечно же это размер метода контроллера и так в процессе теста мы можем выбрать контроллеры из проекта (их выборка может быть обусловлена различной фильтрацией: например по расположению в конкретной папке проекта или же по наследованию от базового класса контроллера) и сравнить количество строк в их методах с эталоном.

2. Планомерно отсюда вытекает зависимости объектов:

2.1. Мы можем протестировать класс контроллера на количество зависимостей тем самым стараясь отсечь объекты обладающие слишком большим набором ответственностей.

2.2. А так же проверить на нежелательные зависимости. Решая "толстые" контроллеры мы можем внедрить в проект классы сервисов, в данном случае мы можем принудить разработчика к использованию их в контроллерах запретив напрямую обращаться к репозиториям.

3. Обязательность тестов в каждом из модулей.

4. Обязательность наследования от базового класса. Например вы внесли изменения в базовый класс контроллера и хотите чтоб в проекте все контроллеры были у наследованы от вашего.

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

  1. Выделение списка объектов проекта по каком либо критерию.

  2. Проверка характеристик данных объектов на соответствие требованиям.

План которому надо следовать
План которому надо следовать

Чем

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

Deptrac

Один из наиболее известных, на мой взгляд, пакетов. Конфигурируется при помощи yaml файла. Имеет набор инструментов для объявления слоя из коробки (регулярные выражения, маски) и возможность добавления своих. Позволяет указывать правила связей между слоями приложения, но не направлен на создание каких либо других проверок.

PHP Architecture Tester

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

PHPArch

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

PHPUnit Application Architecture Test

Пакет встраивается в базовый класс PHPUnit - теста при помощи подключения трейта и предоставляет набор методов по выборке группы объектов: по маске, регулярным выражениям или замыканию. И дальнейшего её тестирования на зависимость между слоями, размеры методов, публичности свойств и тд.

Перспективы

Каким должно быть будущее для данного направления тестирования? Если рассматривать локально это повышение удобства - увеличение количества доступных "из коробки" проверок и упрощение механизма выборки объектов тестирования. В глобальном же смысле это создание готовых наборов тестов для фреймворков: те или иные механизмы работы с кодом что нельзя закрепить по средствам самого языка можно подкрепить написанием архитектурных тестов. Такие наборы тестов с поддержкой сообщества могут перерасти в появление архитектурных стандартов.

В том числе такого рода тесты могут нести описательный и вспомогательный характер для реализации архитектурных решений таких как CQRS, package by future и т.д.

Итог

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

Комментарии (4)


  1. XaBoK
    30.11.2021 13:03

    Static code analysis не новость и есть куча готовых пакетов и метрик. И для архитектуры, и для качества, и для безопасности. Solution unit-test использую с десяток лет. А что вы хотели сказать то?


    1. toratoda Автор
      30.11.2021 15:48
      +1

      В превью статьи есть краткое описание о чем она.

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


      1. samizdam
        30.11.2021 23:53

        Тема интересная, но статья ну очень краткая, оставляет ощущение незаконченности, анонс 4 либ скорее. Круто было бы добавить ссылки, примеры.


        1. toratoda Автор
          01.12.2021 12:06

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

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