Menu
Home
Log in / Register
 
Home arrow Economics arrow Building Evolutionary Architectures: Support Constant Change
Source

Controlling Quantum Size

The quantum size of an architecture largely determines how easy it will be for developers to make evolutionary changes. Large quanta like monoliths and ESB SOA are difficult to evolve because of the coordination required for each change. More decoupled architectures like broker event-driven and microservices offer many more avenues for easy evolution.

The structural constraints on evolving architecture depend on how well developers have handled coupling and functional cohesion. Evolution is easier if developers have created a modular component system with well- defined integration points. For example, if developers build a monolith, but are diligent about good modularity and component isolation, that architecture will offer more opportunities to evolve because the size of the architectural quantum is smaller due to decoupling.

TIP

The smaller your architectural quanta, the more evolvable your architecture will be.

Case Study: Guarding Against Component Cycles

PenultimateWidgets has several monolithic applications under active development. When designing components, one of the architect’s goals is to create self-contained components — the more isolated the code, the easier it is to make changes. A common problem in many languages with powerful IDEs is the package dependency cycle, which describes the common scenario illustrated in Figure 4-14.

Package dependency cycle

Figure 4-14. Package dependency cycle

In Figure 4-14, the package com. company. data imports from com. company. utils, and com. company. utils imports from com. company. data — neither component can be used without dragging the other along, creating a component cycle. Obviously, cycles hurt changeability because an elaborate network of cycles makes incremental change difficult. Languages like Java or C# have development environments that assist developers (via code insight helpers built into the IDE) by suggesting missing imports. Because developers implicitly import so many things in the course of daily coding with the help of the IDE, preventing package dependency cycles is difficult because the tooling fights against this effort.

The PenultimateWidgets architects on these systems worry about developers accidentally introducing cycles between components. Fortunately, they have a mechanism to help guard against factors that harm the evolvability of applications — fitness functions. Rather than abandon the benefits of IDEs because they encourage bad habits, an engineering safety net via fitness functions can be built instead. Both commercial and open source tools exist for many popular platforms to help untangle cycles. Many take the form of a static code analysis tool that looks for cycles, while others provide “to-do” lists of refactorings to assist developers in fixing them.

After the cycles have been removed, how can you prevent a developers’s idle habits from introducing new ones? Coding standards don’t help for this type of problem because developers have a hard time remembering bureaucratic policies in the heat of coding. Instead, they prefer to establish tests and other verification mechanisms to guard against too-helpful tools.

The PenultimateWidgets developers use a popular open source tool for the Java platform called JDepend, which includes both textual and graphical interfaces to help analyze dependencies. Because JDepend is written in Java, developers can utilize its API to write structural tests of their own. Consider the test case in Example 4-1.

Example 4-1. Using JDepend to identify cycles programmatically_

import java.io.*; import java.util.*; import junit.framework.*;

public class CycleTest extends TestCase { private JDepend jdepend;

protected void setUp() throws IOException { jdepend = new JDepend();

jdepend.addDirectory("/path/to/project/util/classes"); jdepend.addDirectory("/path/to/project/web/classes"); jdepend.addDirectory("/path/to/project/thirdpartyjars");

}

/**

  • * Tests that a single package does not contain
  • * any package dependency cycles.
  • */

public void testOnePackage() { jdepend.analyze();

JavaPackage p = jdepend.getPackage("com.xyz.thirdpartyjars"); assertEquals("Cycle exists: " + p.getName(), false, p.containsCycle());

}

/**

  • * Tests that a package dependency cycle does not
  • * exist for any of the analyzed packages.
  • */

public void testAllPackages() {

Collection packages = jdepend.analyze(); assertEquals("Cycles exist",

false, jdepend.containsCycles());

}

}

In Example 4-1, the developer adds the directories containing packages to jdepend. Then, the developer can test either a single package for cycles or the entire codebase, as shown in the unit test testAllPackages(). Once the project has gone through the laborious task of identifying and removing cycles, put the testAllPackages() unit test in place as an application architecture fitness function to guard against future cycle occurrence.

 
Source
Found a mistake? Please highlight the word and press Shift + Enter  
< Prev   CONTENTS   Next >
 
Subjects
Accounting
Business & Finance
Communication
Computer Science
Economics
Education
Engineering
Environment
Geography
Health
History
Language & Literature
Law
Management
Marketing
Mathematics
Political science
Philosophy
Psychology
Religion
Sociology
Travel