Как эффективно применять TDD в разработке корпоративных приложений

Как эффективно применять TDD в разработке корпоративных приложений

3 ноября 2022 г.

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

Ну, почти.

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

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

Без лишних слов, приступим!

Свет и тени TDD

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

Более того, TDD — это мощная практика, которая позволяет разработчикам не бояться исправлять, очищать и адаптировать свой код к обновлениям функциональных требований. И это все здорово. Однако применить TDD на практике не так-то просто.

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

Однако восходящий процесс разработки программного обеспечения лучше подходит для TDD. По сравнению с альтернативой «сверху вниз» подход «снизу вверх» является более прагматичным подходом, поскольку он позволяет нам, разработчикам, постепенно охватывать все уровни косвенности, начиная с самого основного (т. абстракция. Это позволяет создавать более надежные основы кода приложения, что, в свою очередь, дает нам большую уверенность в нашей работе. Однако для применения TDD в нисходящем подходе необходимо сначала написать тесты для программных компонентов, расположенных на более высоких уровнях. Таким образом, разработчикам не нужно имитировать какие-либо зависимости от каких-либо компонентов более низкого уровня, поскольку их просто еще не существует.

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

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

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

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

Итак, как мы можем эффективно применять TDD при создании корпоративных приложений с учетом набора функциональных требований?

Гексагональная архитектура спешит на помощь

В Интернете есть много литературы по гексагональной архитектуре. Я особенно рекомендую прочитать белую книгу на эту тему, написанную Алистером Кокберном.

Для целей настоящей статьи позвольте мне рассказать вам короткую историю из реальной жизни, призванную кратко объяснить мотивацию и основные преимущества гексагональной архитектуры: За многие годы, что я разрабатывал корпоративные приложения, я видел много людей ( включая меня) начинаем новые проекты, фокусируясь на других темах, а не на нашей реальной миссии. Такая миссия состоит в том, чтобы приносить реальную пользу компаниям, в которых мы работаем. Это значение находится в доменной логике наших приложений.

Перефразируя дядю Боба в его книге «Чистая архитектура», все остальное — отвлечение, деталь реализации, которую можно (и нужно) отложить, в идеале — на конец разработки. Примерами деталей реализации являются технологии баз данных, логика контроллера или интерфейсная технология. Даже внутренняя структура — это деталь реализации, которую мы могли бы выбрать позже в процессе разработки, если бы действительно захотели. Шестиугольная архитектура, также называемая Порты и адаптеры, представляет собой архитектурный шаблон, призванный отделить основную логику программного приложения от деталей внешней реализации.

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

Следующая картинка является одной из многих существующих иллюстраций шестиугольной архитектуры:

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

Как эффективно использовать TDD в корпоративных приложениях на основе гексагональной архитектуры

Как я уже говорил ранее, применять TDD проще, если следовать восходящему процессу разработки программного обеспечения. Однако многим из нас легче рассуждать о проектировании системы, следуя нисходящему подходу. И хотя кажется, что мы сталкиваемся с конфликтом интересов, это нормально, потому что мы можем начать проектирование (т. е. набрасывать псевдокод или некоторую диаграмму UML) наших прикладных сервисов сверху вниз, не написав для них ни единой строки кода; пока мы не завершим реализацию модели предметной области.

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

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

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

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

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

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

Последнее замечание о деталях реализации: мы могли бы обновить нашу модель предметной области, чтобы указать некоторые из этих деталей, написав аннотации/декораторы технологии базы данных и ресурсы проверки входных данных из базовой структуры, которая лучше всего адаптируется к характеру нашего приложения. Однако я бы не советовал этого делать, так как это приведет к утечке деталей реализации в нашу модель предметной области, что не является лучшей практикой, поскольку детали реализации и модель предметной области имеют тенденцию меняться по разным причинам и с разной частотой. С другой стороны, как объяснил Вон Вернон в своей книге «Реализация проектирования, управляемого предметной областью» (DDD), гексагональная архитектура тесно связана с DDD. Однако вам не нужно следовать набору методов и шаблонов DDD для создания сложных корпоративных приложений, основанных на гексагональной архитектуре, хотя я настоятельно рекомендую вам это делать. Но эти решения, в конце концов, полностью зависят от вас.

Заключение

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

н


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE