I've been playing with SA4J a Structural Analysis Package for Java by IBM. This package helps with the analysis and maintenance of legacy systems, as well as helping to improve existing designs.
One real benefit of the package it helps unroll complex inter-dependancies between objects. Sometimes these "tangles" are not always easily noticable looking at the code. Just over time the system does not scale.
It identifies structural patterns in the system that hinder maintenance over time:
- A tangle is a large group of objects whose relationships are so interconnected that a change in any one of them could affect all of the others. Long tangles are a major cause of instability in large systems.
- Local Butterfly
A local butterfly is an object with many immediate dependents. It has many immediate relationships where another object depends upon it. This is normally a basic interface, abstract base class, or utility. Be careful when changing a local butterfly because the changes affect many immediate objects. Local butterflies are not necessarily problematic,but in an unstable system changes can affect areas beyond immediate notice.
- Global Butterfly
A global butterfly is an object with many global dependents. Many objects are affected when a global butterfly changes. A global butterfly is normally a basic interface, abstract base class, or utility. You can think of the difference between a global and local butterfly in terms of degrees of separation. A local butterfly is determined by only considering which of the butterfly's immediate relationships affect other objects. For a global butterfly, Structural Analysis follows those relationships and determines how many objects are affected in the entire system.
- Local Breakable
A local breakable is an object that has many immediate dependencies. It has many immediate relationships where it depends on another object. In a sense, a local breakable is the opposite of a local butterfly.Local breakables are objects likely to break when changes are made in their immediate areas. Local breakables are typically undesirable because they "know too much." To improve stability and usability, refactor a local breakable into several classes to distribute its dependencies.
- Global Breakable
A global breakable is an object that has many global dependencies. A global breakable is often affected when anything changes in the system. Typically, global breakables are implementations of the highest-level concepts in your system. In a sense, a global breakable is the opposite of a global butterfly.
Except for high-level concrete implementations, global breakables are generally undesirable because they indicate lack of modularity in the system. Pay particular attention to global breakables when making changes anywhere in your system.
- Local Hub
A local hub is an object with both many immediate dependencies and many immediate dependents. It has both many immediate relationships that affect other objects and many immediate relationships where other objects affect it. You can think of a local hub as a combination of a Local Butterfly and Local Breakable. However, an object can be a local hub even if it falls short of being a local butterfly or a local breakable.Local hubs are typically undesirable because they amplify the effects of change throughout the system. To improve stability, refactor a local hub into several classes to distribute dependencies.
- Global Hub
A global hub is an object with both many global dependencies and many global dependents. It is often affected when anything is changed, and it affects a significant percentage of the system when it changes. You can think of a global hub as a combination of a Global Butterfly and Global Breakable. However, an object can be a global hub even if it falls short of being a global butterfly or a global breakable. Global hubs are very harmful and indicate a poorly conceptualized, unstable system. Global hubs imply that the entire system is entangled and interdependent. Small changes can have ramifications that spread throughout the system. To refactor global hubs, break circular dependencies and restructure your system into independent modules.
- Implementation Dependencies
An implementation dependency occurs when a concrete class is used instead of an underlying interface or abstract class. This causes future dependency on that concrete implementation. Implementation dependencies are rarely justifiable, except when small utility classes are used. Most dependencies in a system should be interface or abstract dependencies.