preface

We introduced the current state of CloudDisk’s business and code. Having shared the “ideal” (future architectural design) and the “reality” (current state of the code), before we start refactoring, we first need to know how many problems there are in the evolution to the ideal design architecture. On the one hand, as input to start refactoring, on the other hand, we have data metrics that allow us to better assess effort and measure progress.

Next, we will summarize the analysis tools and methods based on the architectural design adopted by the architecture team and the current code.

Architecture design

Let’s start by recalling the architectural design the team used in the architecture section.

  1. Code reuse
  • Public capability reuse: There is a layer dedicated to unified management of common basic capabilities, such as images, networks, storage capabilities, and security
  • For common service reuse, there is a layer dedicated to unified management of common service components, such as sharing, push, and login
  1. Low coupling
  • Service modules rely on each other through APIS, and do not depend on specific modules
  • The direction of dependency is clear. The upper module depends on the lower module
  1. Research and development of parallel
  • Business modules support independent compilation and debugging
  • Service modules are published independently

Combining this four-tier architecture, existing code, and the subsequent evolution of the business, the team designed the following new architecture

Analysis tools

ArchUnit

With the architectural design in place, we can identify the boundaries of the code, where we can use Archunit to describe boundary constraints. There are two general guardian rules.

  1. In vertical direction, the lower module cannot rely on the upper module
  2. In the horizontal direction, components cannot depend on each other

A test to convert to ArchUnit looks like this:

  @ArchTest
    public static final ArchRule architecture_layer_should_has_right_dependency =layeredArchitecture()
            .layer("Library").definedBy(".. cloud.disk.library..")
            .layer("PlatForm").definedBy(".. cloud.disk.platform..")
            .layer("FileBundle").definedBy(".. cloud.disk.bundle.file..")
            .layer("DynamicBundle").definedBy(".. cloud.disk.bundle.dynamic..")
            .layer("UserBundle").definedBy(".. cloud.disk.bundle.user..")
            .layer("AllBundle").definedBy(".. cloud.disk.bundle..")
            .layer("App").definedBy(".. cloud.disk.app..")
            .whereLayer("App").mayOnlyBeAccessedByLayers()
            .whereLayer("FileBundle").mayOnlyBeAccessedByLayers("App")
            .whereLayer("DynamicBundle").mayOnlyBeAccessedByLayers("App")
            .whereLayer("UserBundle").mayOnlyBeAccessedByLayers("App")
            .whereLayer("PlatForm").mayOnlyBeAccessedByLayers("App"."AllBundle")
            .whereLayer("Library").mayOnlyBeAccessedByLayers("App"."AllBundle"."PlatForm");
Copy the code

Of course the execution of this use case is a failure because our basic package structure has not been adjusted. But with the architectural guardian test case, we can gradually move the code into the corresponding Package until the guardian case runs through.

Next, we first use the IDE tool to adjust the basic package structure, which is as follows

The following is the result of the ArchUnit test run

The hints of these exceptions are the exception dependencies that we need to handle. But ArchUnit’s hint is a little less unfriendly, so let’s look at another way to analyze abnormal Dependencies, using Intellij Dependencies.

Intellij Dependencies

Select the corresponding Package, select Analyze menu, and click Dependencies to find out the related classes that the Package depends on.

After selecting dynamic Package for analysis, we found that according to the existing architecture constraints, there are horizontal Bundle dependencies that need to be removed.

I’m in the actual refactoring process, where we can frequently use this feature to verify decoupling and at the same time be guarded by ArchUnit tests.

See the detailed codeCloud Disk

conclusion

In this post we have shared how to use tools to analyze abnormal dependencies. After we have the architecture design in the future, we can use ArchUnit to run the architecture test encies, and we can use Intellij’s Dependendencies to facilitate dependency analysis by Package or Class.

Once we have analyzed the abnormal dependencies that need to be addressed, we can then step through the refactoring process. In the next part, we will share some refactoring routines for practice summary, mobile application legacy System refactoring (5) – Refactoring methods.

Series of links

Refactoring legacy Systems for mobile Applications (1) – Start

Refactoring legacy systems for mobile applications (2) – Architecture

Refactoring legacy systems for mobile applications (3) – Examples

The outline

about

Welcome to the CAC Agile Coach public account. Wechat search: CAC Agile Coach.

  • Author: Huang Junbin
  • Blog: junbin. Tech
  • GitHub: junbin1011
  • Zhihu: @ JunBin