Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Wildwuchs eindämmen mit ArchUnit

Wildwuchs eindämmen mit ArchUnit

Das Entwicklungsteam hat sich auf Namenskonventionen für Klassen und Pakete geeinigt. Und letztens fiel beim Code-Review wieder die eine Klasse auf, die öfter falsch benutzt wird und damit zu Fehlern führt.

Solange dies nur auf einer Wiki-Seite steht, sind automatische Prüfungen nicht möglich. Werkzeuge, die aus diesen Regeln Dashboards erzeugen, sind auf den ersten Blick schön anzuschauen, geraten jedoch bald in Vergessenheit.

Die Bibliothek ArchUnit erlaubt es dem Entwicklungsteam Regeln als Java-Code zu schreiben und sie wie andere Unit Tests auszuführen. Entwickler können sie jederzeit lokal vor dem Commit ausführen. Der Continuous Integration Server führt sie zusammen mit den anderen Unit-Tests aus. Schlagen die Tests fehl, so weist eine verständliche Meldung auf das Problem hin.

Dieser Vortrag zeigt wie Architektur- und Best-Practice-Regeln als ArchUnit Tests geschrieben werden. Er vergleicht ArchUnit mit anderen Werkzeugen und zeigt Vor- und Nachteile auf.

Alexander Schwartz

December 10, 2020
Tweet

More Decks by Alexander Schwartz

Other Decks in Programming

Transcript

  1. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz 2 Principal IT Consultant @ msg 15+ Jahre Java & Web 7 Jahre PL/SQL 7 Jahre IT-Consulting 3,5 Jahre Online-Banking 700+ Geocaches @ahus1de 7 Jahre Absatzfinanzierung
  2. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz 3 Wildwuchs eindämmen mit ArchUnit Konventionen und Erfahrungen 1. ArchUnit Intro 2. Regel für Namen, Struktur und Konventionen 3. Vertrauen durch Kontrolle 4. Grenzen 5. Zusammenfassung 6.
  3. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz 4 Wildwuchs eindämmen mit ArchUnit Konventionen und Erfahrungen 1. ArchUnit Intro 2. Regel für Namen, Struktur und Konventionen 3. Vertrauen durch Kontrolle 4. Grenzen 5. Zusammenfassung 6.
  4. Nach vielen Stunden von Vermutungen und Nachforschungen: Trotz der Annotation,

    warum liefert findById() immer noch die Entität? © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit | Alexander Schwartz 5 Es war einmal… Konventionen und Erfahrungen @Modifying @Query("delete from Ship s where s.type = ?1") void deleteInBulkByType(String type); Lösung: die Annotation macht gar nichts, solange die Properties gesetzt werden: @Modifying(clearAutomatically = true, flushAutomatically = true)
  5. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz Konventionen und Erfahrungen Frage: Wie bereiten wir uns vor, damit zukünftig niemand mehr in diese Falle tappt? Möglichkeiten: 1. Im Wiki aufschreiben (bei den Namens-Konventionen und Package-Vorgaben) 2. Prüfung automatisieren (und die anderen Sachen im Wiki gleich mit) 6 Post Mortem Analyse Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  6. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz 7 Wildwuchs eindämmen mit ArchUnit Konventionen und Erfahrungen 1. ArchUnit Intro 2. Regel für Namen, Struktur und Konventionen 3. Vertrauen durch Kontrolle 4. Grenzen 5. Zusammenfassung 6.
  7. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz ArchUnit Intro 1. Bibliothek zum Java-Projekt hinzufügen 2. Definieren von Regeln: • Package-Struktur • Klassennamen • Abhängigkeiten • … 3. Ausführen von Regeln: • Standalone • JUnit 4 • JUnit 5 Homepage: https://www.archunit.org/ Lizenz: Apache 2.0 8 ArchUnit Überblick
  8. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz 9 Wie es funktioniert ArchUnit Intro Java Bytecode ArchUnit Liste mit Verstößen Rules JUnit
  9. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz 10 Wildwuchs eindämmen mit ArchUnit Konventionen und Erfahrungen 1. ArchUnit Intro 2. Regel für Namen, Struktur und Konventionen 3. Vertrauen durch Kontrolle 4. Grenzen 5. Zusammenfassung 6.
  10. „Alle mit @Configuration annotierten Klassen sollen auf Configuration enden“ (Umgebung:

    JUnit 5) © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit | Alexander Schwartz 11 Herausforderung 1: Klassennamen Regel für Namen, Struktur und Konventionen @AnalyzeClasses(packages = "de.ahus1.archunit.naming", importOptions = ImportOption.DoNotIncludeTests.class) public class NamingArchUnitTest { @ArchTest public final ArchRule configurationsShouldBeNamedConfiguration = ArchRuleDefinition.classes().that().areAnnotatedWith(Configuration.class) .should().haveNameMatching(".*Configuration"); } Fluent API mit Code-Vervollständigung
  11. „Alle mit @Configuration annotierten Klassen sollen auf Configuration enden“ (Umgebung:

    JUnit 5) © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit | Alexander Schwartz 12 Herausforderung 1: Klassennamen Regel für Namen, Struktur und Konventionen Architecture Violation [Priority: MEDIUM] – Rule 'classes that are annotated with @Configuration should have name matching '.*Configuration'' was violated (1 time): Class <de.ahus1.archunit.naming.SomeConfig> does not match '.*Configuration' in (SomeConfig.java:0)
  12. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz Regel für Namen, Struktur und Konventionen „In einer Zwiebel-Architektur können äußere Schichten innere Schichten sehen, eine innere Schicht weiß nichts über die äußeren Schichten. Adapter sind unabhängig voneinander.“ Ziele (Auszug): Unabhängige Testbarkeit von Domäne und Adaptern Adapter können unabhängig hinzugefügt und versioniert werden Mittel: Dependency Injection mit Interfaces in der Domäne Jeder Teil in einem eigenen Java-Package 13 Herausforderung 2: Abhängigkeiten zwischen Packages https://www.infoq.com/news/2014/10/ddd-onion-architecture Core Domain Application Adapter A Adapter B Adapter C Adapter Z
  13. „In einer Zwiebel-Architektur können äußere Schichten innere Schichten sehen, eine

    innere Schicht weiß nichts über die äußeren Schichten. Adapter sind unabhängig voneinander.“ © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit | Alexander Schwartz 14 Herausforderung 2: Abhängigkeiten zwischen Packages Regel für Namen, Struktur und Konventionen @ArchTest ArchRule adaptersShouldNotDependOnEachOther = SlicesRuleDefinition.slices().matching("..adapter.(*)..") .should().notDependOnEachOther(); @ArchTest ArchRule onionArchitecture = Architectures.layeredArchitecture() .layer("adapter").definedBy("..adapter..") .layer("domain").definedBy("..domain..") .layer("application").definedBy("..application..") .whereLayer("adapter").mayNotBeAccessedByAnyLayer() .whereLayer("application").mayOnlyBeAccessedByLayers("adapter");
  14. „Du sollst nicht java.util.logging benutzen!“ © msg | März 2021

    | Wildwuchs eindämmen mit ArchUnit | Alexander Schwartz 15 Herausforderung 3: Verbotene Klassen und Methoden Regel für Namen, Struktur und Konventionen @ArchTest ArchRule shouldNotUseJavaUtilLogging = GeneralCodingRules.NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING .because("we use log4j2"); Projektspezifische Begründung hinterlegt Wiederverwenden einer vordefinierten Regel in ArchUnit
  15. „Bei @Modifying sollen immer beide Properties gesetzt sein“ © msg

    | März 2021 | Wildwuchs eindämmen mit ArchUnit | Alexander Schwartz 18 Herausforderung 4: Verwendung von Annotationen Regel für Namen, Struktur und Konventionen @ArchTest ArchRule modifyingAnnotationsShouldHavePropertiesSet = ArchRuleDefinition.members().that().areAnnotatedWith(Modifying.class) .should(HAVE_MODIFYING_PARAMETERS_SET) .because("so they will flush the persistence context ..."); Custom Condition
  16. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz 19 Herausforderung 4: Verwendung von Annotationen Regel für Namen, Struktur und Konventionen ArchCondition<? super JavaMember> HAVE_MODIFYING_PARAMETERS_SET = new ArchCondition<JavaMember>("have clearAutomatically/flushAutomatically set") { @Override public void check(JavaMember javaMember, ConditionEvents events) { Modifying annotationOfType = javaMember.getAnnotationOfType(Modifying.class); if (annotationOfType != null) { if (!annotationOfType.clearAutomatically()) { String message = String.format( "clearAutomatically is not set to true on %s", javaMember.getFullName()); events.add(SimpleConditionEvent.violated(javaMember, message)); } if (!annotationOfType.flushAutomatically()) { String message = String.format( "flushAutomatically is not set to true on %s", javaMember.getFullName()); events.add(SimpleConditionEvent.violated(javaMember, message)); } } } };
  17. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz 20 Wildwuchs eindämmen mit ArchUnit Konventionen und Erfahrungen 1. ArchUnit Intro 2. Regel für Namen, Struktur und Konventionen 3. Vertrauen durch Kontrolle 4. Grenzen 5. Zusammenfassung 6.
  18. Mit einem JUnit Test prüfen, ob die Regel wirklich das

    findet, was sie finden soll: © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit | Alexander Schwartz 21 Regeln testen Vertrauen durch Kontrolle public class TestingTheNamingTest { @Test public void shouldFindViolationsForModifying() { JavaClasses importedClasses = new ClassFileImporter().importPackages("de.ahus1.archunit.naming.violation"); ArchRule rule = new NamingArchUnitTest().configurationsShouldBeNamedConfiguration; Assertions.assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> { rule.check(importedClasses); }) .withMessageContaining("classes that are annotated with @Configuration should have") .withMessageContaining("(1 times)"); } }
  19. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz 22 Wildwuchs eindämmen mit ArchUnit Konventionen und Erfahrungen 1. ArchUnit Intro 2. Regel für Namen, Struktur und Konventionen 3. Vertrauen durch Kontrolle 4. Grenzen 5. Zusammenfassung 6.
  20. Verstöße unterdrücken für Legacy Code: • Datei mit regulären Ausdrücken

    • Selbstdefinierte Annotation um Ausnahmen zu markieren • „Einfrieren“ von Verstößen in Legacy-Projekten (new in v0.11.0) ArchUnit entnimmt alle Informationen dem Java Byte Code • Keine Informationen zu Java Generics (wegen Type Erasure) • Keine Annotationen mit RetentionPolicy von SOURCE • Kein Zugriff auf nicht-Java Dateien, Maven Dependency Information, Git Commit Verlauf, etc. (dafür wäre ggf. jQAssistant besser geeignet) ArchUnit hat keine UI, um die bestehende Architektur zu visualisieren (dafür wäre ggf. jQAssistant besser geeignet) © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit | Alexander Schwartz 23 Wo es passt und wo es etwas anderes braucht Grenzen https://jqassistant.org/
  21. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz 24 Wildwuchs eindämmen mit ArchUnit Konventionen und Erfahrungen 1. ArchUnit Intro 2. Regel für Namen, Struktur und Konventionen 3. Vertrauen durch Kontrolle 4. Grenzen 5. Zusammenfassung 6.
  22. © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit

    | Alexander Schwartz • Erlaubt einem Team seine eigenen bewährten Praktiken und Architektur-Regeln zu formulieren und automatisch zu überprüfen • Entscheidungen sind in der Versionshistorie mit einer Begründung dokumentiert • Verstöße werden mit verständlichen Meldungen beschrieben • Regeln laufen als Teil des normalen Testlaufs. Bei Verstößen schlägt der Build fehl. • Entwickler können die Regeln lokal vor dem Check-In laufen lassen • Keine zusätzlichen Werkzeuge auf dem Server notwendig für Continuous Integration & besser als eine Wiki-Seite :-) 25 Zusammenfassung ArchUnit https://www.archunit.org/
  23. ArchUnit https://www.archunit.org/ Source Code & Slides https://www.ahus1.de/post/archunit-entropy © msg |

    März 2021 | Wildwuchs eindämmen mit ArchUnit | Alexander Schwartz 26 Links @ahus1de
  24. msg systems ag Amelia-Mary-Earhart-Straße 14 60549 Frankfurt am Main Germany

    value – inspired by people Contact Alexander Schwartz Principal IT Consultant +49 171 5625767 [email protected] @ahus1de © msg | März 2021 | Wildwuchs eindämmen mit ArchUnit | Alexander Schwartz 27