Activity: Architectural Design
Identify
design mechanisms
Categorize
clients of analysis mechanisms
Identify the clients of each analysis mechanism. Scan all clients of a given analysis mechanism, looking at the characteristics they require for that mechanism. Identify characteristic profiles for each analysis mechanism. There may be widely varying characteristics profiles, providing varying degrees of performance, footprint, security, economic cost, etc. Group clients according to their use of characteristic profiles. Form groups of clients that seem to share a need for an analysis mechanism with a similar characteristics profile; identify a design mechanism based on each such need. These groupings provide an initial cut at the design mechanisms. An example analysis mechanism, "inter-process communication", may map onto a design mechanism "object request broker". Inventory implementation mechanisms
Proceed bottom-up and make an inventory of the implementation mechanisms that you have at your disposal:
Determine where existing implementation mechanisms can be used and where new implementation mechanisms need to be built. Map design mechanisms to
implementation mechanisms
Design mechanisms provide an abstraction of the implementation mechanisms, bridging the gap between Analysis Mechanisms and Implementation Mechanisms. The use of abstract architectural mechanisms during design allows us to consider how we are going to provide architectural mechanisms without obscuring the problem-at-hand with the details of a particular mechanism. It also allows us to potentially substitute one specific implementation mechanism for another without adversely affecting the design. Determine the ranges of characteristics. Taking the characteristics identified for the design mechanisms determine the ranges of design mechanism characteristic values for which it is reasonable, economical, or feasible to use the candidate-implementation mechanism. Consider the cost of acquisition for purchased components. For candidate implementation mechanisms, consider the cost of acquisition or licensing, the maturity of the product, relationship with the vendor, support, etc. in addition to purely technical criteria. Conduct a search for the right components, or build the components. You
will often find that there is no apparently suitable implementation mechanism for some
design mechanisms; this will trigger a search for the right product, or identify the need
for in-house development. You may also find that some implementation mechanisms are not
used at all. Document
architectural mechanisms
The role of the Architect in this activity is to decide upon and validate these mechanisms by building, or integrating them, and verifying that they do the job, then consistently impose them upon the rest of the system design. The mechanisms, the mapping between them, and details regarding their use, should be documented in the Artifact: Design Guidelines specific to the project. Identify design classes and
subsystems
The Activity: Use Case Analysis results in analysis classes, which represent conceptual things which can perform behavior. In design, analysis classes evolve into design classes and subsystems, reflecting the greater depth of design as well as the imposition of constraints imposed by the implementation environment. A subsystem is, effectively, a special kind of package which has only interfaces as public elements. The interfaces provide a layer of encapsulation, allowing the internal design of the subsystem to remain hidden from other model elements. The concept subsystem is used to distinguish it from "ordinary" packages, which are semantic-free containers of model elements; the subsystem is represents a particular usage of packages with class-like (behavioral) properties. Identify Classes. When the analysis class is simple and already represent a single logical abstraction, it can be directly mapped, 1:1, to a design class. Typically, entity classes survive relatively intact into Design. Since entity classes are typically also persistent, determine whether the design class should be persistent and note it accordingly in the class description. When identifying classes, they should be grouped into Artifact: Design Packages, for organizational and configuration management purposes. See Guidelines: Design Package for more information on how to make packaging decisions. Identify Subsystems. When the analysis class is complex, such that it appears to embody behaviors that cannot be the responsibility of a single class acting alone, the analysis class should be mapped to a design subsystem. The design subsystem is a used to encapsulate these collaborations in such a way that clients of the subsystem can be completely unaware of the internal design of the subsystem, even as they use the services provided by the subsystem. A design subsystem is logically equivalent to the Artifact: Component in the Artifact: Implementation Model. The decision to create a subsystem from a set of collaborating analysis classes is based largely on conjecture guided by experience; the actual representation may take a few iterations to stabilize. Examples of analysis classes which evolve into subsystems include credit or risk evaluation engines in financial applications, rule-based evaluation engines in commercial applications, security authorization services in most applications. Identify
interfaces
Identify a set of candidate interfaces for all subsystems. For each subsystem, consider its responsibilities: Organize the responsibilities into groups of cohesive, related responsibilities. These groupings define the initial, first-cut set of interfaces for the subsystem. To start with, identify an operation for each responsibility. Look for similarities between interfaces. From the candidate set of interfaces, look for similar names, similar responsibilities, and similar operations. Where the same operations exist in several interfaces, re-factor the interfaces, extracting the common operations into a new interface. Be sure to look at existing interfaces as well, re-using them where possible. Define the operations. For the new interfaces, define the operation names and parameters based on the responsibilities of the subsystem (or rather, from the analysis classes from which the subsystems derive). This is likely to be difficult and subject to much revision early on, but as the design progresses the operation signatures will stabilize. Define interface dependencies. The parameters of each interface operation each have a particular type: they must realize a particular interface, or they must be instances of a simple data type. In cases where the parameters are objects which realizes a particular interface, define dependency associations between the interface and the interfaces on which it depends. Map the interfaces to subsystems. Once interfaces have been identified, create realization associations between the subsystem and the interfaces it realizes. Package the Interfaces. Interfaces are owned by the Architect; changes to interfaces are always architecturally significant. To manage this, the interfaces should be grouped into one more packages owned by the architect. If each interface is realized by a single subsystem, the interfaces can be placed within the subsystem. If the interfaces are realized by more than one subsystem, they should be placed within a separate package. This allows the interfaces to be managed and controlled independently of the subsystems themselves. Identify reuse opportunities
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 the existing interface. Simple changes include rearranging or adding parameters to the the candidate interface. Next, factoring the interface by splitting it into several interfaces, one or more of which match the 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. Reverse-engineer components and databases
Based upon the results of the step Identify Reuse Opportunities,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 componentsIn 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 fill the need for 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 databasesDatabases, 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 applications 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: Mapping an Object Model into a Relational Database. Define the low-level organization
of subsystems
The lower layers of the architecture provide the interface to the infrastructure of the system. The lower level packages and subsystems provide a way to structure the Design Model to improve its stability, understandability and flexibility. Layering also 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. An example of layering, including middleware 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). Include
architecturally-significant model elements in the Logical View
When classes, packages and subsystems (model elements) are important from an architectural perspective, they should be included in the Logical View section of the Software Architecture Document. This will keep the design model homogeneous, and at the same time keeps the architecture sound and consistent. |
|
|