"An object-oriented program's run-time structure often bears little resemblance to its code structure. The code structure is frozen at compile-time; it consists of classes in fixed inheritance relationships. A program's run-time structure consists of rapidly changing networks of communicating objects. In fact, the two structures are largely independent. Trying to understand one from the other is like trying to understand the dynamism of living ecosystems from the static taxonomy of plants and animals, and vice versa." E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1994. (pp. 22-23).
For many code modification tasks, developers often need to understand both the code structure and the execution structure of object-oriented programs. But current tools provide little insight into the execution structure at compile-time. Class diagrams extracted from source code are often sufficient to understand the code structure. However, existing static or dynamic analyses that produce an execution structure consisting of raw graphs of objects and relations between them, do not convey design intent or readily scale to large programs.
The code structure is often referred to using the term static structure. The execution structure is often referred to using the terms dynamic structure, runtime structure or even execution architecture. In the following discussion, we use the terms dynamic and static to denote whether the analysis is dynamic (requires running the program) or static (happens at compile-time). We use code structure and execution structure to qualify the design structure we are talking about. We avoid using the term architecture.
Imposing an ownership hierarchy on the execution structure through source code ownership domain annotations provides an intuitive and appealing mechanism to: a) provide stronger encapsulation properties than visibility mechanisms; b) express and enforce design intent regarding object encapsulation and communication; and c) obtain a sound hierarchical execution structure of the system, the Ownership Object Graph -- at compile-time.
To evaluate our approach, we implemented a set of tools and conducted case studies on two real Java programs, each consisting of 15,000 lines of code. One of the subject systems was developed by experts in object-oriented design and the other by undergraduates. In both cases, the automatically generated Ownership Object Graph fit on one page, helped us refine the annotations, and gave us insights into the implementations. These insights would be otherwise hard to obtain by looking at the original code without annotations, at existing class diagrams, or at unreadable visualizations of the runtime object graph produced by existing compile-time approaches.
We give the intuition behind the Ownership Object Graph (OOG) execution structure by example. CourSys is a simple course registration system to keep track of courses, students, and register students for courses, implemented following a three-tiered architectural style.
A class diagram obtained from the implementation using Eclipse UML is available here (PDF).
The UML class diagram might mislead the reader into thinking that the same ArrayList object is shared between Data, Course, and Student objects, when at runtime, there are distinct ArrayList instances: (a) the list of all available Courses; (b) the list of Students registered in a Course; (c) the list of Courses for which a Student has registered; and (d) the list of Courses a Student has previously completed.
A partial flat object graph for obtained at compile time using Pangaea is available here (PDF).
A partial flat object graph for obtained at compile time using SuperWomble is available here (PDF).
A top-level Ownership Object Graph for CourseSys is available here (PDF).
The Ownership Object Graph shows explicitly object objClient in a user tier, object objLogic in a logic tier, object objData in a data tier, and objects of type Student, and lists thereof in a state tier. Furthermore, it shows that objects log and lock are owned by objLogic. The solid edges show field references and the dashed edges show domain links from domain user to domain logic, and from domain logic to domain data.
Ownership hierarchy is different from the hierarchy found in class diagrams that use packages to organize related classes. Placing the Logic and the Logging classes in a coursys.logic package indicates that they belong to the same layer in the code structure. The execution structure may want to indicate that an instance of Logging is owned by an instance of Logic, i.e., hidden in its representation and inaccessible to other objects in the system, although both are in the same architectural tier at runtime.
The original JHotDraw version 5.3 is available here.
A flat object graph for JHotDraw obtained using the Pangaea tool by Spiegel, ported to the Eclipse infrastructure, is available here (PDF): you need to zoom in by at least 3200% to read it.
A flat object graph for JHotDraw obtained using the SuperWomble tool by Jackson and Waingold is available here (PDF): you need to zoom in by at least 400% to read it.
JHotDraw version 5.3 with ownership domains annotations will be available here soon.
The Ownership Object Graph for JHotDraw version 5.3 with Ownership Domains annotations, is available here (PDF).
The source code for HillClimber is not in the public domain, so it cannot be posted here.
A flat object graph for HillClimber obtained using the Pangaea tool by Spiegel, ported to the Eclipse infrastructure, is available here (PDF): you need to zoom in by at least 800% to read it.
The Ownership Object Graph for HillClimber with ownership domains annotations is available here (PDF).