Roles and Activities > Developer Role Set > Software Architect > Incorporate Existing Design Elements
Look for existing subsystems or components which offer similar interfaces. Compare each interface identified to the interfaces provided by existing subsystems or components. There usually will not be an exact match, but approximate matches can be found. Look first for similar behavior and returned values, then consider parameters.
Modify the newly identified interfaces to improve the fit. There may be opportunities to make minor changes to a candidate interface which will improve its conformance to the existing interface. Simple changes include rearranging or adding parameters to the candidate interface, and then factoring the interface by splitting it into several interfaces, one or more of which match those of the existing component, with the "new" behaviors located in a separate interface.
Replace candidate interfaces with existing interfaces where exact matches occur. After simplification and factoring, if there is an exact match to an existing interface, eliminate the candidate interface and simply use the existing interface.
Map the candidate subsystem to existing components. Look at existing components and the set of candidate subsystems. Factor the subsystems so that existing components are used wherever possible to satisfy the required behavior of the system. Where a candidate subsystem can be realized by an existing component, create traceability between the design subsystem and the component in the implementation model.
In mapping subsystems onto components, consider the design mechanisms associated with the subsystem; performance or security requirements may disqualify a component from reuse despite an otherwise perfect match between operation signatures.
Based upon the results of Activity: Incorporate Existing Design Elements, existing code and database definitions can be 'scavenged' to make work done on previous projects or iterations available to the current project/iteration. By using potential reuse opportunities as a filter, the work that is reverse engineered can be focused on just the components which are reusable for the current iteration.
Reverse Engineer Components
In organizations which build similar systems, there is often a set of common components which provide many of the architectural mechanisms needed for a new system. There may also be components available in the marketplace which also provide the architectural mechanisms. Existing components should be examined to determine their suitability and compatibility within the software architecture.
Existing components, either developed during prior iterations but not yet included in the Design Model, or purchased components, must be reverse-engineered and incorporated into the Design Model. In the Design Model, each component is represented as a Subsystem with one or more Interfaces.
Reverse Engineer Databases
Databases, and the data residing in them, represent one of the most important sources for reusable assets. To reuse the implicit class definitions embodied in existing databases, determine which information used by the application already resides in existing databases. Reverse-engineer a set of classes to represent the database structures that hold this information (for information on how to do this, see Guidelines: Reverse-engineering Relational Databases). At the same time, construct a mapping between the application's class representation and the structures used in the database. For mapping between classes and tables in a relational database, see Guidelines: Data Model.
As new elements have been added to the Design Model, re-packaging the elements of the Design Model is often necessary. Repackaging achieves several objectives: it reduces coupling between packages and improves cohesion within packages in the design model. The ultimate goal is to allow different packages (and subsystems) to be designed and developed independently of one another by separate individuals or teams. While complete independence is probably impossible to achieve, loose coupling between packages tends to improve the ease of development of large or complex systems.
A 'flat' model structure (where all packages and subsystems reside at the same conceptual level in the system) is suitable for a small system; larger systems need an additional structuring tool called 'layering' (see Guidelines: Layering and Concepts: Layering). Layering rules define restrictions on allowed relationships between certain types of packages. These rules recognize that certain dependencies should not exist: application functionality should not be directly dependent on specific operating system or windowing system services - there should be an intermediate layer containing logical operating system and windowing services that insulate the application functionality from changes in low-level implementation services. Layering provides a way to reduce the impact of change: by enforcing rules which restrict the dependencies between packages and subsystems, reducing the degree of coupling between packages and subsystems, the system becomes more robust. It tolerates change.
As new model elements are added to the system, existing packages may grow too large to be managed by a single team: the package must be split into several packages which are highly cohesive within the package but loosely coupled between the packages. Doing this may be difficult - some elements may be difficult to place in one specific package because they are used by elements of both packages. There are two possible solutions: split the element into several objects, one in each package (this works where the element has several 'personalities', or sets of somewhat disjoint responsibilities), or move the element into a package in a lower layer, where all higher layer elements may depend upon it equally.
As the system grows in complexity, a larger number of layers will be needed in order to have a maintainable and understandable structure. More than 7-10 layers, however, are unusual in even the largest systems, since complexity increases and understandability decreases with the number of layers.
An example of layering, including middle-ware and System-software layers, is shown below:
Sample package layering for a Java/Web-based application. Note: the dependencies on the TCP/IP package would not normally be explicitly modeled as the use of TCP/IP services is encapsulated within the Java VM, java.rmi and the Web Browser. They are depicted here only for illustration.
Assign responsibilities for the subsystems and layers to individuals or teams. Each package or subsystem should be the responsibility of a single person (if its scope is small) or a team (if its scope is large).
When classes, packages and subsystems (model elements) are important from an architectural perspective, they should be included in the Logical View section of the Artifact: Software Architecture Document. This will ensure that new architecturally significant model elements are communicated to other project team members.
Rational Unified Process