Improved Radial Encapsulation
Improved Radial Encapsulation
Putting more focus on your dependencies and how they relate can drastically improve scalability and flexibility. Start with a ground package and work from there.
Join the DZone community and get the full member experience.Join For Free
Akka from A to Z, An Architects Guide starting off with Actors and Akka Streams, then on to clustering, sharding, event sourcing & CQRS, and more.
That idea is almost trivial.
Oracle supplies the official term, "Subpackage," when it writes, "The naming structure for packages is hierarchical. The members of a package are class and interface types ... and subpackages."
Oracle does not define a "parent" package but genealogical terminology proves useful: thus given package structure a.b.c, we can say that b is the parent of c, a is the grand-parent of c, and that, in general, a and b are both antecedents of c, and b and c are descendants of a.
Radial encapsulation allows package dependencies only on antecedents.
Thus in the example above, a.b.c could not depend on a.d, because d is not a parent, grand-parent, or any antecedent of c.
This constraint snubs Oracle's anemic package mandates, by which, "... hierarchical naming structure for packages is intended to be convenient for organizing related packages in a conventional manner, but has no significance in itself." The constraint, however, heaves with it the tremendous benefit of allowing programmers to design package structures of arbitrarily low structural disorder. See figure 1 where the program on the right is radially encapsulated.
Figure 1: Left structural disorder 76%; right structural disorder: 3%.
To continue the example above, what if a.b.c does indeed require the services of a.d? Must we contort our package structure to squeeze d in as an antecedent of c? Of course not. We use the facade design pattern and have d export its interfaces into a, where those interfaces are then available to all.
That was classical radial encapsulation.
Steve is, unfortunately, correct. Radial encapsulation of large systems does encourage a certain ... bottom-heaviness.
So this post proposes a small improvement on radical encapsulation with the introduction of: the ground.
Take any package and declare it the "ground parent." The ground is then the set of immediate subpackages of this ground parent, on which the guiding principle of radial encapsulation is loosened: this set of subpackages that may be depended upon by any descendant of the ground parent.
Figure 2 presents a radially encapsulated structuring of the following 5 qualified packages:
Figure 2: A radially encapsulated package structure.
In classical radial encapsulation, package e, for example, could not depend on b because b is not an antecedent of e.
With improved radial encapsulation, however, e can now depend on any of the ground packages (shown in green) and on packages a and com (both are antecedent). It cannot, however, depend on packages d or h, those packages being neither ground nor antecedent — encapsulation remains strengthened over and above Oracle's defaults.
Let's take a look at refactoring a classic radially encapsulated program into the updated variety.
Figure 3 shows the package structure of Spoiklin Soice. A typical model/view/controller split, note that the neither the model nor view nor controller packages are antecedent to one another and thus for, say, the controller to use the services of the model, then model must export its interfaces into link or spoiklin (com, edmundkirwan, and base were deliberately kept sparse).
Figure 3: A radially encapsulated package structure.
This left spoiklin a little bloated: Figure 4 shows these dependency lines (unlike figure 3, which shows hierarchy) with the thickness proportional to the number of dependencies.
Figure 4: Dependencies in the program of figure 3.
Figure 4 shows another drawback of the old approach: the diagram fails to show which interfaces in spoiklin — whether exported from model, view or controller — are most depended upon. Which part of the system suffers most from change-sensitivity because so many others depend on it?
Figure 5 presents the same system refactored to the improved radial encapsulation.
Figure 5: The new radial encapsulation.
Here, spoiklin is declared the ground parent and hence model, view, or controller (and others besides) form the ground. The controller sub-tree of packages can now export its facades not into a common package but into the controller package itself, with other sub-trees similarly possessing their own dedicated ground packages. This both removes bloat and clarifies system dependencies, as shown in figure 6.
Figure 6: Dependencies in the newly radially encapsulated system.
Figure 6 reveals that model is the most depended-upon package (and hence functionality) of the system. Yet of course, as with classical radial encapsulation, all the model sub-tree of implementation packages are hidden from all the view and controller implementations, affording the system substantial flexibility.
Establishing a ground, that is, a set of packages that may be depended upon by any descendant of the ground parent, improves radial encapsulation's scalability.
Which is good.
Opinions expressed by DZone contributors are their own.