CPS-380 - Getting issue details... STATUS


Introduction

We are implementing a testing library which will help improve architecture design within CPS-Core

Leading to

  • Less Complex Project Architecture
  • Easier Understanding of Architecture Layout for New Developers
  • Speed Up Overall Development


Problem Description

Existing architecture already exists for CPS-Core.

This can lead to issues when implementing dependency architecture rule tests such as:

DependencyArchitectureTest
    @ArchTest
    static final ArchRule noUpperPackageDependencyRule = NO_CLASSES_SHOULD_DEPEND_UPPER_PACKAGES;


The Purpose of this test is to prevent classes depending on other classes in upper packages. The purpose of this being that it "might prevent packages on that level from being split into artifacts in a clean way".

This has lead to the following error 

java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'no classes should depend on upper packages, because that might prevent packages on that level from being split into separate artifacts in a clean way' was violated (23 times)
Class <org.onap.cps.api.impl.CpsAdminServiceImpl> implements interface <org.onap.cps.api.CpsAdminService> in (CpsAdminServiceImpl.java:0)
Class <org.onap.cps.api.impl.CpsDataServiceImpl> implements interface <org.onap.cps.api.CpsDataService> in (CpsDataServiceImpl.java:0)
Class <org.onap.cps.api.impl.CpsModuleServiceImpl> implements interface <org.onap.cps.api.CpsModuleService> in (CpsModuleServiceImpl.java:0)
...


Proposal

This seems to be mostly happening in regard to the classes which lie in the impl packages one layer above the defined service interfaces. My proposed solution here would be to create a new package for the service interfaces. So both packages are on the same level, which would prevent this issue.

Similar to this:


Problem Description.

Due to multiple packages existing in the cps-service module. It can lead to overly complicated architecture tests like this where the Spi services is accessed by 7 individual packages from 6 different layers

LayeredArchitectureTest
    @ArchTest
    static final ArchRule layeredArchitecturesRulesRespected = layeredArchitecture()
        .layer("Controller").definedBy(REST_CONTROLLER_PACKAGE)
        .layer("apiService").definedBy(API_SERVICE_PACKAGE)
        .layer("ncmpService").definedBy(NCMP_SERVICE_PACKAGE)
        .layer("Repository").definedBy(REPOSITORY_PACKAGE)
        .layer("spiService").definedBy(SPI_SERVICE_PACKAGE)
        .layer("ncmpController").definedBy(NCMP_REST_PACKAGE)
        .layer("yangSchema").definedBy(YANG_SCHEMA_PACKAGE)
        .layer("utils").definedBy(UTILS_PACKAGE)
        .whereLayer("Controller").mayNotBeAccessedByAnyLayer()
        .whereLayer("apiService").mayOnlyBeAccessedByLayers("Controller", "ncmpService")
        .whereLayer("spiService").mayOnlyBeAccessedByLayers("Controller", "apiService", "ncmpService", "ncmpController", "yangSchema", "utils")
        .whereLayer("Repository").mayOnlyBeAccessedByLayers("apiService", "spiService");


LayeredArchitectureTest
    @ArchTest
    static final ArchRule spiServiceDependencyRule =
        classes().that().resideInAPackage(SPI_SERVICE_PACKAGE).should().onlyHaveDependentClassesThat()
        .resideInAnyPackage(REST_CONTROLLER_PACKAGE, API_SERVICE_PACKAGE, SPI_SERVICE_PACKAGE,
            NCMP_SERVICE_PACKAGE, NCMP_REST_PACKAGE, UTILS_PACKAGE, YANG_SCHEMA_PACKAGE);

Whereas the Api Services are only accessed by the one rest controller package, being the cps rest controller, along the ncmp services rest, and it's own impl services.

LayeredArchitectureTest
    @ArchTest
    static final ArchRule apiServiceDependencyRule =
        classes().that().resideInAPackage(API_SERVICE_PACKAGE).should().onlyHaveDependentClassesThat()
        .resideInAnyPackage(REST_CONTROLLER_PACKAGE, API_SERVICE_PACKAGE, NCMP_SERVICE_PACKAGE);


Proposal

Adding another within the module package below the current services layer, containing these sub packages, similar to how rest module has a package below the controller and exceptions layer. This could lead to us covering both API and SPI services, along with the classes dependent on these services. In turn, cleaning up the project architecture in the process and simplifying these tests.

Example:

LayeredArchitectureTest
    @ArchTest
    static final ArchRule layeredArchitecturesRulesRespected = layeredArchitecture()
        .layer("Controller").definedBy(REST_CONTROLLER_PACKAGE)
        .layer("SERVICES").definedBy(SERVICES_PACKAGE)
        .layer("ncmpService").definedBy(NCMP_SERVICE_PACKAGE)
        .layer("Repository").definedBy(REPOSITORY_PACKAGE)
        .whereLayer("Controller").mayNotBeAccessedByAnyLayer()
        .whereLayer("Services").mayOnlyBeAccessedByLayers("Controller", "ncmpService")
        .whereLayer("Repository").mayOnlyBeAccessedByLayers("apiService", "spiService");
    @ArchTest
    static final ArchRule apiServiceDependencyRule =
        classes().that().resideInAPackage(SERVICE_PACKAGES).should().onlyHaveDependentClassesThat()
        .resideInAnyPackage(REST_CONTROLLER_PACKAGE, NCMP_SERVICE_PACKAGE, NCMP_REST_PACKAGE,SERVICES_PACKAGE);
  • No labels