3.8. Refactoring Classes

Refactoring is restructuring code to simplify and enhance its internal abilities while retaining the same outward functionality. In practice it can mean creating new, usually private, methods to remove potentially duplicated code or adding new classes when the current structure of the code has become difficult to maintain.

3.8.1. UMLAssociation

Where appropriate Umbrello stores items as a combination of internal UML objects which can be seen in the tree view and displayed widgets which can be seen on the diagrams. This allows the same objects to be represented in more than one diagram. Associations were not treated this way and were only represented as diagram widgets. This caused code generation to be much more complex than it had to be as all the diagrams had to be searched for relevant associations.

Adding a new class UMLAssociation to move the associations into the internal UML model required a change in the file format and associated code to successfully import old version files. It also provided the opportunity to add more functionality to associations which now allow for roles, constraints and documentation at each association end. There were significant changes required to each of the other UML objects to hold a list of their associations and several bugs were introduced, not all of which have yet been fixed (such as saving break points). However it greatly simplified the code export routines which no longer have to search through the diagrams looking for associations.

3.8.2. UMLObject

UMLObject is the super-class used for items held in the internal UML model. This includes items which will be displayed as widgets such as classes and activities, classifier items such as attributes and operations, and following the refactoring of UMLAssociation, associations. This is a diverse group of functions for one class and I found that the derived classes often shared a lot of code. To review what was the existing situation I used Umbrello to create a class diagram of the existing layout.

The classes representing UML objects which have associated widgets share a lot of duplicated code, although the above class diagram indicates that UMLActor and UMLUseCase had not been updated to handle the new association code. These classes could share a common super-class. There is also some shared code between UMLConcept and UMLInterface, which both handle operations. In the UML metamodel classes and interfaces share a common classifier superclass along with other UML objects such as datatypes and subsystems which Umbrello does not yet support. By giving these two classes a common super-class UMLClassifier, I could reduce duplicated code, better follow the UML metamodel and make it easier to add these currently unsupported UML objects in the future. UMLAttribute, UMLOperation and UMLTemplate all share a common purpose and I decided to give these a common super-class too. I drew up these ideas in a simplified class diagram and sent it to the developers mailing list for peer review.

The refactoring of the widget related UML objects went smoothly. In one move I was able to remove large sections of duplicated code, update classes which did not have the new association code and reduce dependence throughout the programme on checking enum values, methods which check for canvas objects can now simply check if the object is a UMLCanvasObject. Another developer volunteered to create the UMLClassifier class to sit between UMLCanvasObject and the UMLInterface and UMLConcept classes (UMLConcept was also renamed to UMLClass to reduce confusion). It will now be a trivial matter to add Datatypes and other UML classifiers.

I had less luck with refactoring the code for attributed, operations and templates. My hope was to create a generic framework which could easily be extended to other classifier properties such as exceptions or slots which are also allowed by UML. The framework would also allow for stereotypes to be mixed in with the lists, an occasionally requested feature. Unfortunately the classes involved share little code which is not already shared in UMLObject, they are simply not the same classes on any lower level. Add the possibility of stereotypes to the requirements and there is no shared functionality at all. The code is also heavily reliant on these classes being direct children classes of UMLObject, with many hard coded calls to parent(). In the end I had to abandon my work on this. It seems likely that any general framework to handle more arbitrary classifier lists will have to work with UMLObject rather than a more specific class.

3.8.3. Data Classes

One of the stranger and more problematic elements of the design of Umbrello is the separation of the widget classes into two, one half derived from UMLWidget which contain the code to draw the widget on the canvas, and the other half derived from UMLWidgetData which stores the properties of the widget. The theory of this is a separation between display and model but in practice all properties are accessed through the UMLWidget anyway and Umbrello already has a separation between display and model, the UML objects exist quite separately from the widgets.

The UMLWidgetData class and its derivatives complicated the design of Umbrello significantly, but I decided not to get rid of them. The changes would have been too much effort for little programmer gain, and no end user advantage. It would almost certainly have introduced bugs to the programme and it would have been difficult to keep file compatibility. There is a trade off between creating a clean internal design and actually creating the features that users will see and in this case I considered that with the time constraints it would be hard to justify.