Martin Doms' Design Study

From CSSEMediaWiki
Revision as of 00:53, 25 September 2010 by Martin Doms (Talk | contribs)
Jump to: navigation, search

Contents

Martin Doms Design Study

The problem

This design study is based on a project that my team in the COSC325 Group Project full-year class built. The full system is a round-trip engineering tool that allows users to generate and modify UML diagrams from existing code, and push modifications through to the code. The program exists as a plugin for Eclipse written in Java.

The aspect of the project I am working on redesigning is the model and command infrastructure. The existing system is a transactional system, which means that the user makes arbitrary modifications to the UML representation and at any time can commit those modifications to the code as a single unit of work. Transactions are summarized for the user before committing.

There are two main problems with the existing system that I wish to solve. The first is in the model. The model is essentially a simplified representation of the code which is derived from a much more complex abstract syntax tree, provided by the Eclipse platform. The main problem with the current model is that due to poor design decisions early in the project (to be discussed later), modifications and extensions to the model are difficult. Many changes to the model result in bugs that would not exist in a more robust system.

The second issue is the command system. In the current system, UI actions result in the generation of Command objects which act on the model and the underlying code. For example, if the user renames a class on the UML diagram, the rename action afforded by the UI generates a rename Command object which is executed. There are no dependencies between the UI actions and the model, as the command infrastructure acts as an insulating layer between them. Commands can also be generated by events that occur on the file system, such as a file system listener creating a remove type Command object when the user deletes a source file.

Because of the transactional nature of the program, actions that occur on the UI currently generate two commands: a command that changes the UI (called a CommittableCommand) and the command to push that change into the code (called a CommitCommand). The CommittableCommand object is in charge of creating its own CommitCommand. This system worked well early in the project but as the program grew it has resulting in an explosion of CommittableCommand and CommitCommand subtypes which have become difficult to manage and often duplicate code.

The old command system became messy and unwieldy to word with. The details of this system are not relevant, this is just a demonstration of the difficulty of working with the previous design.

The Redesign

The following are two UML diagrams showing the redesign of the system, followed by an explanation of them.

Model

Newly designed model for Trip.

The model UML diagram is necessarily complex, but is not difficult to understand. JavaComponent is the base class for all elements that are represented in a Java program or source file. JavaComponents can be composed of other JavaComponents (for example, Classes are composed of methods, fields and inner classes). Other elements are no composed of JavaComponents, such as methods, parameters and fields.

It could make semantic sense to say that JavaMethods are composed of JavaParameters, but I elected to keep methods as leaf nodes and contain parameters as lists because the order of a parameter is important in a method declaration and at the abstract level I defined child nodes in the composite as Sets, not lists.

The decorator pattern was used under JavaType to model arrays and generic types. The main reason for this is that for the purposes of this model we often want to treat certain types as identical to their array or generic versions, while still being able to leverage the additional behaviour and data of the decorated versions. For example, if we are modelling a class diagram in which ClassA contains a field ClassB[10], then we still want to maintain an association between ClassA and ClassB on the diagram, and it would make no sense to have a class ClassB[10] on the class diagram. The decorator pattern allows this to be done fairly easily.

JavaRelationships are simple types that relate two JavaComponents. Each relationship has a source and target JavaComponent. In a UML class diagram these would be used for things like inheritance and dependency relationships, as shown in my UML diagram. They could also be used to model relationships between packages, messaging relationships and any kind of relationship where two Java elements are involved. Relationships in this manner are implicitly directed (ie, they have a source and a target) but clients are free to ignore this directionality.

In this model relationships are generated and instantiated lazily as needed. Client code would be advised not to store collections of relationships, but allow JavaComponents to supply the relationships on demand. For example, asking a JavaClass for all of its source relationships would result in a collection containing a relationships representing its superclass connection, implementation connections and association connections sources from itself.

Because of this behaviour, clients can easily extend the system to allow for additional relationship types. For example if the client was modelling a UML Sequence Diagram, they would be free to extend JavaRelationship with a MessageRelationship subclass and extend the behaviour of JavaType to allow for this.


Commands

Newly designed model for Trip.