Design for Reusability
Reuse at the Policy Level: Apache Open Source License promotes software reuseMaking the software an open source project enables projects to adapt the code for their purposes. However, the choice of open source license is perhaps the most important aspect for supporting these adaptions.
Reuse of Ideas: Functional requirements, design issues and the architecture have all been documentedHopefully the design documents included in the release will remain synchronised with the code base over the long term. However, even if the documents become dated, they become reusable products that can help inform design discussions on other projects. The functional requirements, design issues and architecture description can also be used to help other projects measure how appropriate it would be to reuse CST in their own use cases.
Reuse of Code for Other Applications
Test plan and automated test cases provide quality assurance which motivates software reuseSoftware reuse assumes that the software already works. Quality assurance measures need to be taken to convince other projects that the software does in fact do what it claims it can do. CST comes with a test plan document which describes what test cases could be applied to the software, which ones were applied to the software and the expected outcomes for a test run. Many of the test cases are supported through automated test suites. Developers can run all of the test cases using a software tool called JUnit, whose libraries are included in the release.
Minimising technological dependencies makes application portableCST depends on only two technologies: JDK 6.0 and MySQL 5.1. Adapting or reusing the software in other client applications only requires that they support a few dependencies. Many of the libraries required by JDK and MySQL may already be included in the target application.
Following coding standards and naming conventions invites reuseFollowing standard coding practices reduces the time needed for developers on other projects to assess whether the code suits their needs.
Generating tool suite from a model makes CST domain-independentA common barrier to software reuse is a product’s dependencies on concepts in a specific domain. CST was initially designed to track human case studies through health procedures and evaluations related to bone density and cardiac activity. The quickest way to make tracking software for the Centre would have been to hard-code forms and database code that catered to those concepts. However, creating the software in this way would have eliminated any possibility that the product could be reused on other projects.
Although administrators and data curators are presented with concepts relevant to their use case, the architecture with notions of “trial subjects” and “trial activities”, which are more general concepts than those used in any one specific use case. The fields in TrialSubjectModel and TrialActivityModel classes can be parameterised with domain-specific concepts that are specified in a configuration file. This feature of design effectively makes CST a software suite that can generate software to suit a specific kind of curation task but not be tied to specific domain.
Ability to launch tools as standalone applications or components makes the tool suite versatileCST anticipates that the software tools it generates may either be used on their own or become components of other larger systems. It is feasible that a client application could launch two instances of the Logging Tool which manage completely different sets of activities and case studies. A number of steps were taken to ensure that these instances would be independent of one another.
Notion of session variables supportedA subclass of
HashMapcalled SessionProperties was created to manage references to software objects that could be accessible in different parts of the code. The variables are relevant to a single session of use by a single user. The
SessionPropertiesobject is used to help limit the scope of effect of variables so that multiple instances of tools can be launched. The use of a session variable mechanism is borrowed from the way most web applications are designed to support concurrent use by multiple users.
Minimal use of static variablesStatic variables can be useful in standalone applications. Although the use of global variables is often discouraged in programming, sometimes the practice can be useful. For example the use of a static variable can eliminate the need to pass an instance variable as a parameter down a chain of method calls to small piece of code that actually needs it. Using a globally accessible variable in this case can help simplify the signatures of methods in classes that would not need access to it. Static variables can also be useful in setting properties which apply to all instances of a class. For example, note that in the Java class
TrialActivityModel, there is an instance variable called “enforceChronology”. This flag is set using settings in the configuration file which apply to all instances. It would seem appropriate that this flag should be a property of the
TrialActivityModelclass rather than of each instance.
Now consider a trial study which supports one activity where a chronology in the steps is enforced and one activity where it is not. Using a static flag would mean that both activities would either be enforced or not enforced.
Finally consider a software application which launches two independent instances of the Logging Tool, each addressing entirely different activities. Suppose that in one instance the chronology of steps in each activity are enforced. It may seem useful to make a static flag that applies to all instances of TrialActivityModel. However, suppose chronology was not enforced in activities managed by the other instance. The use of a static variable for the configuration setting would produce undesirable side effects in either instance.
A session status flag is used to indicate whether the tools are running in standalone or component modeThe
SessionPropertiesobject hashes a boolean flag to the key “SessionProperties.IS_COMPONENT_MODE”. The flag is used in different parts of the code which are concerned about whether a tool is operating as a standalone application or as a component. For example, the flag is used to determine the behaviour of shut down operations. When a tool operates in standalone mode, pressing “Close” in the file menu should cause a System.exit() call to end the program. When the tool operates in component mode, this call would be inappropriate because it would terminate the JVM being used by the client application. Instead, the close operation causes the dialog to be hidden.
Startup options for the tools can be parameterised through property filesThe task of launching tools as components is helped by a feature which allows them to be configured through a properties file. A property file specify attributes such as the location of the configuration file which generates the Administration Tool and the Logging Tool. The properties can be changed without having to recompile the client application.
LoggingServiceAPI and AdminServiceAPI APIs allow business logic to be reused by client applicationsClient applications may want to limit their ‘buy-in’ for using the tool to using APIs that exercise business operations. CST encapsulates business code into reusable units by exposing it through APIs that support administration and logging tasks. Client applications have the choice of invoking the Logging Tool or an API which they can use to manipulate data automatically. In other cases, they can use the API published as the AdminServiceAPI to load trial subject data from another database.
Ability to support plugins promotes integration of other software componentsCST was designed to support a minimal feature set that could be enhanced through different kinds of plugins. These address the following functional areas:
- importing activity data
- exporting activity data
- retrieving additional information about trial subjects using their unique identifier
- generating progress graphs
Generic code that does not refer to specific application concepts is maintained in the “util” package
The code base contains a number of general purpose classes which are not dependent on either the concepts of any one study domain or on the kinds of tasks supported by the tool suite. For example,
HTMLGenerationUtility contains methods for render common fragments of HTML code. The class is not dependent on either an activity related to bone density or instances of
TrialSubjectModel. The general purpose classes have been gathered together into a “util” package to help developers easily identify code they could use in other applications.
Reuse of Code within the ApplicationOne of the main aims of object-oriented programming is to promote re-use of code. When duplicated code appears throughout a code base, the software can become difficult to test and maintain. Developers tend to minimise the costs of these activities by consolidating repetitive code fragments into classes that have a purpose, a role and dialogue with other collaborating classes. The two most common ways of promoting code reuse within an application are to apply design through inheritance and design through composition.
Inheritance has been used to consolidate code used by related classesDuring the initial design of CST, it became clear that the fields for trial subjects shared common traits with activity step fields in trial activities.
TextFieldModelrepresents the primary key field used in
TrialActivityModelclasses. It also represents filter fields used by the Logging Tool to identify subsets of trial subjects.
DateFieldModelrepresents an activity step and manages a date field value. Both
DateFieldModelhave attributes to describe a display name showed to end-users and a data storage name which corresponds to a field in a data base. Both kinds of fields require identical methods for setting and getting a display name and a data storage name. Instead of repeating this code in both classes, the code is placed in a parent super class called AbstractFieldModel. TextFieldModel and DateFieldModel both inherit the shared code from this class.
Another example of consolidation of code through inheritance appears in the design of filter commands used in the menu of the Logging Tool.
CompletionFilterCommand share common code through the superclass
Inheritance works well when classes are related.
DateFieldModel are both fields with a name and a value.
The filter commands all share the following needs:
- a menu name
- access to filter methods in
- ability to update the display to show a subset of trial subjects
When classes are not related, another way of consolidating code is needed.
Composition has been used to consolidate code used by unrelated classesInheritance defines a relationship that says “Class A is a type of Class B”. Design through composition defines a relationship that says “Class A uses Class B”. It is a technique to consolidate common code in classes which are not related to each other. For example, consider the classes ShowActivityChangeHistoryDialog and ImportSpreadsheetErrorReport. The former class is responsible for showing the audit trail of changes made in activities for a given trial subject identifier. The latter class generates an error report for importing activity data. The classes serve different purposes but they share the common need to present information in HTML. Both of these classes use HTMLGenerationUtility, which consolidates code used to write HTML tags.
A second example of design by composition is the use of the StartupOptions class, which reads command line arguments and interprets the configuration file. The class is used to initialise both the administration and logging tools, which serve different purposes.
A third example is the use of UserInterfaceFactory, which encapsulates code used to create buttons, text fields and labels. The Login Dialog, various data import dialogs and dialogs for the two tools all make use of the same code that is managed by this class.
Reuse of Data: Support for Data MigrationOther projects may wish to reuse the data without reusing either the business logic used to store them or the GUIs used to present them in a display. Data for
TrialSubjectModelrecords and each type of TrialActivityModel can be separately exported to a tab-delimited text file. The text files can be used to import data into spreadsheets or other databases.
Author: Kevin Garwood