Статьи

Арочный блок

Если архитектура программного обеспечения выполнена в соответствии с разумным стандартом, мы должны ожидать:

  • Хорошо разработанные шаблоны, которые могут соответствовать как функциональным, так и нефункциональным требованиям.
  • Никакой сумасшедшей сумасшедшей связи, проблемы правильно разделены, и все поддается проверке.

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

Arch Unit — это супер механизм для реализации некоторых архитектурных правил и шаблонов в вашей кодовой базе. Прошло около нескольких лет, но кое-что только я обнаружил в этом году. Я сталкивался с этим, когда пытался придумать, как пакет « утилит », пресловутый, не превратился в пресловутый « дампинг ». В идеале, у нас никогда не было бы пакетов утилит, но в реальном мире они почти всегда существуют. У пакета utils не должно быть много эфферентных зависимостей . Например, предположим, у вас есть пакет с названием ShoppingCart . Тогда вам понадобится какая-то полезная функция, чтобы добавить всего две корзины, удалить специальные предложения, добавить скидки лояльности, бла-бла-бла. Последнее, что вы хотите увидеть, это кто-то проверяет это в пакете utils с зависимостями от пакета shoppingcart. Потому что, если он так сфокусирован на покупательской корзине, он действительно должен быть в пакете покупательской тележки. Если это произойдет, очень скоро ваш пакет утилит будет зависеть от всего, и все будут зависеть от него. Катастрофа. Какой смысл в пакетах, если что-то может зависеть только от чего-либо. Они перестанут предоставлять какие-либо преимущества в отношении интервалов имен или инкапсуляции.

Итак, как Arch Arch может помочь? Очень просто, вы определяете архитектурные правила как тест JUnit. Подождите секунду … Это тест JUnit. Пакет efferent (внешний) и afferent (внутренний) для вас utils очень просто выражается как:

1
2
3
4
5
@ArchTest
public static final ArchRule utilPackageDependenciesRules = classes().that().resideInAPackage("com.company.application.util")
           .should().onlyDependOnClassesThat().resideInAnyPackage(getAllowedDependencies("com.company.application.exception"))
           .andShould().onlyHaveDependentClassesThat().resideInAnyPackage("com.company.application.shoppingcart"
 "com.company.application.payment);

Ну это все. Теперь повторите для каждого пакета, и у нас есть контроль кода. Работает как любой другой тест JUnit. Таким образом, поэтому он будет легко работать как часть вашего CI и т. Д. Теперь, если вы хорошо спроектировали свои пакеты, вам не нужно постоянно проверять код. Вместо этого правила являются частью вашего тестирования. По мере развития вашего программного обеспечения, появления новых пакетов и изменения правил зависимостей, просто измените правила, выраженные в хороших API-интерфейсах. Кто-то новый присоединяется к командам и хочет быстро освоить архитектурные правила — просто, просто посмотрите на архитектурные тесты.

ArchUnit не только дает вам возможность выражать правила пакета, вы также можете определять свои собственные правила или условия, а затем применять их к любому коду, который вы хотите. Например, предположим, что вы хотите условие, что объект является неизменным. Поэтому вы, естественно, не хотите сеттеров. Это может быть выражено этим условием.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
static ArchCondition noPublicSettersCondition =
         new ArchCondition("class has no public setters") {
             @Override
             public void check(JavaClass item, ConditionEvents events) {
                 for (JavaMethod javaMethod: item.getMethods()) {
                     if (javaMethod.getName().startsWith("set") &&
                       javaMethod.getModifiers().contains(JavaModifier.PUBLIC)) {
                         String message = String.format(
                             "Public method %s is not allowed begin with setter", javaMethod.getName());
                         events.add(SimpleConditionEvent.violated(item, message));
                     }
                 }
             }
         };

Затем вы можете применить условие noSetter к любому пользовательскому исключению, которое может написать разработчик. Не было бы хорошо, если бы у Исключения был сеттер, не так ли?

1
2
3
@ArchTest
    public static final ArchRule noExceptionsHaveSetters = classes().that()
      .areAssignableTo(RuntimeException.class).should(noSettersCondition);

Предположим, вы продолжаете замечать, что логгеры, определенные в классах либо
не являются частными, не являются статичными или не являются окончательными . Не тратьте время на разговоры об этом. ArchUnit это!

1
2
3
4
5
6
7
@ArchTest
    public final ArchRule loggers_should_be_private_static_final =
            fields().that().haveRawType(TaLogger.class)
                    .should().bePrivate()
                    .andShould().beStatic()
                    .andShould().beFinal()
                    .because("we agreed on this convention");

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

Опубликовано на Java Code Geeks с разрешения Алекса Стейвли, партнера нашей программы JCG . Смотреть оригинальную статью здесь: Arch Unit

Мнения, высказанные участниками Java Code Geeks, являются их собственными.