Case Study: Checking for Side-effects with DepAn Filters

Case Study: Checking for Side-effects with DepAn Filters

One of the recurring challenges in software maintenance is unexpected interactions between components. Although architectural boundaries should isolate components, large systems often have unexpected couplings between components. In a richly featured application, a full investigation can be prohibitive. This inability to ensure isolation can impede necessary changes.

A bug fix in DepAn demonstrates an effective strategy to visualize dependents and to ensure isolation between different components. The most natural fix for a rendering bug included a risk of unforeseen interactions between the node rendering and the node tree components. With DepAn’s filter and collapse mechanisms, it was straightforward to show that no troublesome interdependencies were present.

With call-chains collapsed, isolation among the components is transparent.

With call-chains collapsed, isolation among the components is transparent.

The dependency analysis strategy was simple and effective:

  1. Select the nodes for your methods of interest,
  2. Using filters, compute the entire call tree for these nodes,
  3. Collapse the result based on call relations,
  4. Expand the collapse roots, incrementally exposing dependencies and side effects.

In just a few minutes, I was able to confirm safety for a change that involved dozens of interdependent components.

Problem details

The initial rendering of a reopened View document (.dvi file) was not using the saved collapse-state information. As a result, these reopened documents were cluttered and confusing. One method, collapseChanged(), did render collapse-state changes properly, but only for already opened document. Although the collapseChanged() method updated several GUI features, the reuse of a handleCollapseRendering() method within the prepareView() method appeared to be a natural fix for this problem.

As tempting as this is, the separation between the diagram renderer and the node tree view was suspect. The essential question is whether the node tree handling or dirty-state handling interacts with collapse-state rendering process. These components evolved from a more monolithic architecture where the underlying data structures had multiple access paths. Do the other calls from within the collapseChanged() method alter collapse-state or rendering-state in an undesirable manner?

In order to address this question, I used DepAn to display the entire call tree for the collapseChanged() method. In just a few seconds, I was able to see all methods that are reached from collapseChanged(). More importantly, is was clear that the three call trees were independent of each other. DepAn made it obvious that behaviors from the updateExposedGraph() call were independent from actions of the handleCollapseRendering() call.

Analysis Details

The use of DepAn to determine that the side-effects from collapseChanged() were independent from handleCollapseRendering() was quite straightforward.

  1. Using the GraphEditor, open the analysis file (.dgi) and select the collapseChanged() method.
  2. Create a ViewEditor for this one Java element.
  3. Using the NodeFilter view, select the Call Closure filter.
  4. Computing the results reveals 42 nodes (methods) in these call chains.
  5. Open another ViewEditor for the computed results, using a Radial layout over Java Uses relation set.
Call closure diagram for collapseChanged() method.

Call closure diagram for collapseChanged() method.

A little rearranging shows that the call tree from updateExposedGraph() is completely independent from the methods in the handleCollapseRendering() call tree. This provides great confidence that these methods do not interact with each other’s side-effects.

Although the rearranged call graph for collapseChange() is compelling, the 42 nodes are a bit too cluttered to be totally convinced. Using the collapse feature, the independence of these methods becomes stark.

The original call tree diagram is dramatically simplified by using Collapse Hierarchy on the Uses relation set in the NodeFilter view. Initially, everything collapses into the collapseChanged() node. By expanding that node, and the Java generated accessor methods, the call trees for updateExposedGraph(), handleCollapseRendering() and markDirty() are summarized as individual nodes. As seen in the earlier diagram, the independence of the call trees is quite striking and transparent. There are no Use edges between any of these collapsed node.

Conclusion

Validating that components are isolated is critically important when identifying solutions. When components have significant interdependencies, simple strategies may not work. However, complex strategies have other costs and should be avoided unless they are required. The selection of a change strategy is an important engineering decision. DepAn’s filtering and collapse tools provide an effective way to visualize dependencies and to validate cost effective engineering solutions.

Leave a comment