ArchUnit에서 Java/Kotlin 애플리케이션의 아키텍처 CI

(추기)

JJUG CCC 2019 Spring에서 발표했습니다.

How to check and improve the Java-based application architecture with “ArchUnit”
htps : // speake r에서 ck. 코 m / 가와 나미 유 / 쏘 g-c 2019-sp 링 g

현재 내 팀에서는 HRTech 기반 신규 서비스 개발에 작업하고 있으며 최근 ArchUnit이라는 도구를 도입했으므로 소개합니다.
  • GitHub: htps : // 기주 b. 코 m / Tng G / 아 r 츄니 t
  • 사용자 안내서: htps //w w. 아 r 츄 t. rg / 우세 r 구이데 / html / 000_ 인데 x. HTML

  • 진화적 아키텍처 책을 읽고 아키텍처 특성 요구 사항 준수 정도를 측정/담보하는 적응도 함수 중 하나로 클래스 종속성을 테스트 할 수있는 JDepend이 소개되어 유사한 도구를 찾습니다. 우리가 ArchUnit을 발견했습니다. 올해의 Technology Radar VOL.19에서도 TRIAL로 소개되었습니다.

    ArchUnit이란?


  • 한마디로 Java/Kotlin 응용 프로그램의 패키지 및 클래스 종속성을 JUnit 테스트 코드로 표현하고 테스트 할 수있는 테스트 프레임 워크입니다
  • 종속성 외에도 제품 특정 명명 규칙과 같은 구현 규칙도 테스트 할 수 있습니다

  • 처음 ArchUnit (Qiita)는 입문 기사로 이해하기 쉽습니다

  • 뭐가 기뻐?


  • ArchUnit에서 테스트 할 수있는 일은 예를 들어 문서로 주지하거나 코드 리뷰에서 지적함으로써 인력에서도 커버하는 것은 일단 가능합니다. 다만, 인간이 체크하는 경우, 그들을 매번 잊지 않고 할 수 있을까 하면 어렵기 때문에, 역시 자동화할 수 있는 것에 가치가 있습니다
  • 아키텍처 및 제품 별 구현 규칙이 코딩되어 설계에 대한 암시 적 지식을 형식화합니다
  • 기술력에 편차가 있는 개발팀에서 일정한 강제력으로 아키텍처 설계를 담보할 수 있습니다
  • 레거시 코드를 사용하여 명문화되지 않은 관습 및 규칙을 위반하는 구현을 찾는 데 도움이됩니다

  • 구체적인 예



    현재 개발 중인 제품의 CI에 내장된 테스트 코드의 일부를 소개합니다.

    (1) 도메인 공통의 범용 클래스는 다른 특정 도메인의 클래스에 의존해서는 안된다


    common 패키지가 더 이상 공통이 아닌 것을 방지합니다.

    ※전제로서, 도메인층(domain 패키지) 자체의, 다른 층에 대한 의존관계는 별도 구현하고 있다 레이어 체크 테스트에 의해 담보되고 있는 것으로 합니다.
    
    @Test
    void domainCommonPackageShouldNotDependOnOtherPackages() {
        noClasses()
            .that().resideInAPackage(ROOT_PACKAGE + ".domain.common..")
            .should()
            .dependOnClassesThat(new DescribedPredicate<>("domain パッケージ下の common パッケージ以外のクラス") {
                @Override
                public boolean apply(JavaClass clazz) {
                    return clazz.getPackageName().startsWith(ROOT_PACKAGE + ".domain")
                        && ! clazz.getPackageName().equals(ROOT_PACKAGE + ".domain") // domain パッケージ直下の基底インターフェイス/クラスへの依存は許容
                        && ! clazz.getPackageName().startsWith(ROOT_PACKAGE + ".domain.common");
                }
            })
            .check(CLASSES);
    }
    

    (2) JsonSerializable 를 구현한 enum 는 deserialize 방법도 구현해야 한다



    JSON 속성을 숫자 열거로 deserialize 할 때 명시 적으로 deserialize 방법을 구현하지 않으면 숫자에 해당하는 열거가 아닌 열거 형의 ordinal 값에 해당하는 열거가 인스턴스화된다는 JSON 라이브러리 사양에 한 번 빠진 적이있었습니다.

    같은 일에 두 번 빠지지 않도록 디시리얼라이즈 방법 (@JsonCreator 으로 어노테이트한 팩토리 메소드)의 구현 잊어버림을 체크하는 테스트를 추가했습니다.
    
    @Test
    void jsonSerializableShouldImplementJsonCreator() {
            classes()
                .that(new DescribedPredicate<>("JSON シリアライズされる enum") {
                    @Override
                    public boolean apply(JavaClass clazz) {
                        return clazz.isEnum() && clazz.isAssignableTo(JsonSerializable.class);
                    }
                })
                .should(new ArchCondition<>("@JsonCreator でアノテートしたファクトリーメソッドを実装する") {
                    @Override
                    public void check(JavaClass clazz, ConditionEvents events) {
                        boolean hasJsonCreator = clazz.getMethods().stream()
                            .anyMatch(method -> method.isAnnotatedWith(JsonCreator.class));
    
                        if (! hasJsonCreator) {
                            events.add(SimpleConditionEvent.violated(
                                clazz,
                                clazz.getName() + " should implement a factory method annotated with @JsonCreator."
                            ));
                        }
                    }
                })
                .check(CLASSES);
    }
    

    요약



    어땠습니까? 아키텍처를 테스트하는 도구는 지금까지 별로 없었던 것 같습니다. 이번에 소개한 예 이외에도 아이디어에 따라 다양한 관점의 테스트를 구현할 수 있을 것 같습니다. 자동 테스트로 아키텍처의 품질을 담보하면서 제품 개발을 통해 지속적으로 아키텍처를 연마해 나갈 수 있다면, 흥분되네요

    좋은 웹페이지 즐겨찾기