Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1: Added Layer rules L1-L12 #10

Merged
merged 5 commits into from
Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions src/test/java/com/devonfw/sample/archunit/ArchitectureTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,14 @@ public class ArchitectureTest {
@ArchTest
private static final ArchRule shouldOnlyAccessValidLayers = //
layeredArchitecture().consideringAllDependencies() //
.layer("common").definedBy("..common..") //
.layer("logic").definedBy("..logic..") //
.layer("dataaccess").definedBy("..dataaccess..") //
.layer("service").definedBy("..service..") //
.layer("batch").definedBy("..batch..") //
.layer("ui").definedBy("..ui..") //
// TODO
.because("Dependency of technical layers violates architecture rules.");
.layer("common").definedBy("com.devonfw.sample.archunit.common..") //
.layer("logic").definedBy("com.devonfw.sample.archunit.logic..") //
.layer("dataaccess").definedBy("com.devonfw.sample.archunit.dataaccess..") //
.layer("service").definedBy("com.devonfw.sample.archunit.service..") //
.layer("client").definedBy("com.devonfw.sample.archunit.client..")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vlad961 the package root and especially the component should not be encoded here:

  • We might have multiple components in the same application and each could have any up to all out of this layers
  • As we want to provide a "starting point" and "template" for projects using devonfw and arch-unit we should not tie this to com.devonfw.sample.archunit as otherwise every project would have to adopt this to their own root package what is however not neccessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed each layer definition by exchanging the prefix: "com.devonfw.sample.archunit" with a second "." (dot).


.withOptionalLayers(true)
hohwille marked this conversation as resolved.
Show resolved Hide resolved
.because("Dependency of technical layers violates architecture rules.");
// ...

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package com.devonfw.sample.archunit;

import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

@AnalyzeClasses(packages = "com.devonfw.sample.archunit", importOptions = ImportOption.DoNotIncludeTests.class)
public class LayerDependencyRulesTest {
hohwille marked this conversation as resolved.
Show resolved Hide resolved

// 'access' catches only violations by real accesses, i.e. accessing a field, calling a method; compare 'dependOn' further down

// L09: verifying that code from logic layer does not access service layer (of same app).
@ArchTest
static final ArchRule logic_should_not_access_services =
noClasses().that().resideInAPackage("..logic..")
.should().accessClassesThat().resideInAPackage("..service..");
hohwille marked this conversation as resolved.
Show resolved Hide resolved

// L10: verifying that dataaccess layer does not access service layer.
// L12: verifying that dataaccess layer does not access logic layer.
@ArchTest
static final ArchRule persistence_should_not_access_services_or_logic =
noClasses().that().resideInAPackage("..dataaccess..")
.should().accessClassesThat().resideInAnyPackage("..service..", "..logic..");

@ArchTest
static final ArchRule services_should_only_be_accessed_by_clients_or_other_services =
classes().that().resideInAPackage("..service..")
.should().onlyBeAccessed().byAnyPackage("..client..", "..service..");

@ArchTest
static final ArchRule services_should_only_access_logic_common_or_other_services =
classes().that().resideInAPackage("..service..")
.should().onlyAccessClassesThat().resideInAnyPackage("..service..", "..common..", "..logic..", "java..", "javax..");
hohwille marked this conversation as resolved.
Show resolved Hide resolved

// 'dependOn' catches a wider variety of violations, e.g. having fields of type, having method parameters of type, extending type ...

// L09: verifying that code from logic layer does not depend on service layer (of same app).
@ArchTest
static final ArchRule logic_should_not_depend_on_services =
noClasses().that().resideInAPackage("..logic..")
.should().dependOnClassesThat().resideInAPackage("..service..");

// L06: verifying that service layer does not depend on batch layer.
// L08: verifying that service layer does not depend on dataaccess layer.
@ArchTest
static final ArchRule services_should_not_depend_on_batch_or_persistence =
noClasses().that().resideInAPackage("..service..")
.should().dependOnClassesThat().resideInAnyPackage("..batch..", "..dataaccess..");

// L10: verifying that dataaccess layer does not depend on service layer.
// L12: verifying that dataaccess layer does not depend on logic layer.
@ArchTest
static final ArchRule persistence_should_not_depend_on_services_or_logic =
noClasses().that().resideInAPackage("..dataaccess..")
.should().dependOnClassesThat().resideInAnyPackage("..service..", "..logic..");

@ArchTest
static final ArchRule services_should_only_be_depended_on_by_controllers_or_other_services =
classes().that().resideInAPackage("..service..")
.should().onlyHaveDependentClassesThat().resideInAnyPackage("..controller..", "..service..");

@ArchTest
static final ArchRule services_should_only_depend_on_logic_common_or_other_services =
classes().that().resideInAPackage("..service..")
.should().onlyDependOnClassesThat().resideInAnyPackage("..service..", "..logic..", "..common..", "java..", "javax..");

// L01: Common Layer does not depend on any other layer
@ArchTest
static final ArchRule common_should_only_depend_on_common =
classes().that().resideInAPackage("..common..")
.should().onlyDependOnClassesThat().resideInAnyPackage("..common..", "java..", "javax..");

// L02: verifying that only client layer code may depend on client layer.
@ArchTest
static final ArchRule client_should_only_depend_on_client =
classes().that().resideInAPackage("..client..")
.should().onlyDependOnClassesThat().resideInAnyPackage("..client..", "java..", "javax..").allowEmptyShould(true);

// L03: verifying that client layer does not depend on logic layer.
// L04: verifying that client layer does not depend on dataaccess layer.
// L05: verifying that client layer does not depend on batch layer.
@ArchTest
static final ArchRule client_should_not_depend_on_logic_persistence_or_batch_layer =
noClasses().that().resideInAPackage("..client..")
.should().dependOnClassesThat().resideInAnyPackage("..logic..", "..dataaccess..", "..batch..").allowEmptyShould(true);

// L07: verifying that batch layer does not depend on service layer.
// L11: verifying that batch layer does not depend on dataaccess layer.
@ArchTest
static final ArchRule batch_should_not_depend_on_service_or_persistence =
noClasses().that().resideInAPackage("..batch..")
.should().dependOnClassesThat().resideInAnyPackage("..service..", "..dataaccess..").allowEmptyShould(true);
}