4.1. Defining design object types for SADP
Before developing a SADP project, it is necessary to identify which types of design objects should be captured. Possible design objects must be classified according to the different types managed in the domain (e.g., component, port, system, quality requirement, etc.).
In order to identify them for defining a SADP domain, it is important to consider the numerous architecture description languages (ADLs) that have been proposed in the literature, specially those adopted by industry practitioners and those familiar to the project's architects. ADLs embody a set of concepts to be modelled (from which design object types can be derived) and a particular approach to the specification and evolution of an architecture (Medvidovic et al., 2002; Medvidovic et al., 2007). Besides, we consider relevant to include also some concepts relative to the architectural design method preferred by the designer.
To this end, the proposed model is extended defining a possible SADP domain that includes different design object types derived from concepts taken from ADD method (Bass et al., 2003) and the architectural description language ACME (Garlan et al., 2000).
The first set of design object types for the SADP domain is identified from concepts present in the ADD method proposed by SEI (Bass et al., 2003). ADD method is based on a decomposition process, where architectural patterns are chosen at each iteration to fulfil a set of requirements (functional and quality requirements). From the instantiation of an architectural pattern, several elements (like components and connectors) are included in the architectural model. The inputs to ADD are quality requirements, which are expressed as a set of system specific quality scenarios, and functional requirements, which are translated into a set of responsibilities that are assigned to components. Quality scenarios and responsibilities can be delegated to other components when the original component is refined. When a method iteration is finished, the designer verifies how approached is the architecture to each proposed scenario and set an assessment.
At the end of an ADD iteration, a partial architecture model is obtained. The IEEE recommended practice for architectural description of software-intensive systems (IEEE, 2000) recommends describing an architectural model by using different viewpoints. In the scope of this contribution, Component&Connector views are considered (Clements et al., 2010). However, this proposal supports the definition of several design object types relative to any view. Then, to represent Component&Connector views, the ACME architectural description language is chosen (Garlan et al., 2000). ACME defines a component as a computational element and data store of a system. A component may have multiple interfaces, each of which is termed port. The connectors represent interactions among components and have interfaces that are defined by a pair of roles. A system in ACME comprises components and connectors, by setting attachments between roles and ports. Moreover, ACME proposes elements to document extra-structural properties of a system's architecture, which are named characteristics.
The concepts (design object types) introduced above can be formally defined in a SADP domain by introducing appropriate first-order logic constructs and writing axioms to capture their properties and possible relationships with other concepts. We introduce the unary predicate designObjectType. This predicate has one term, which is the name of the concept that constitutes the design object type. Using such a predicate, the concepts defined above are included in the SADP domain by means of the facts in (18).
The SADP domain also states which are the types of the relationships that rule the valid ways in which design objects can be associated. This is expressed by means of domainRelationship predicate. domainRelationship predicate has three terms, where the first one represents the name of a relationship type and the two others are the types of design objects that are involved in the relationship type. In (19), some relevant domain relationships are included in the SADP domain.
Design object types have a set of versionable characteristics denominated properties. This means that object versions will have particular values for the properties defined by its design object type. Each property (p) of a design object type (dot) is explicitly stated in the SADP domain by means of a binary predicate property(dot, p). In (20), the facts that describe the properties of Component and Connector design object types are listed. Particularly, in this domain, besides the property Name for Component, two additional properties were defined: MaxCantOfTables and IndexingType, which are characteristics of databases components. On the other hand, a Connector type defines properties for communicating two components in an architectural model, like a name (given by Name property in (20)), the type of connection indicating whether it is physical or logical (given by Type property in (20)), and the adopted communication protocol (given by Protocol property).
When design object types share common properties, it is worthwhile to generalize these concepts by defining an abstract design object type, or, with a different perspective, to specialize a concept in a set of new concepts that inherit its properties. A binary predicate isSubtypeOf(dot1, dot2) allows expressing that design object type dot1 is a subtype of design object type dot2. Examples are given in (21) by specializing the possible requirements of a system in FunctionalRequirement and QualityRequirement.
Sometimes, an expert concerned in the definition of a SADP domain, might decide to include a new design object type to represent the associations rules that exist between two types. This means the transformation of a domain relationship in a design object type, which is called reification. By doing that, a domain relationship becomes a design object type. An example is given by RCompResp domain relationship, which can be transformed in a design object type called RHasResp that links Component and Responsibility design object types by means of RHRComponent and RHRResponsibility domain relationships. These facts are represented by designObjectType(RHasResp), domainRelationship(RHRComponent, RHasResp, Component), and domain Relationship(RHRResponsibility, RHasResp, Responsibility)). In addition, properties like AssignedBy and Visibility could be assigned to RHasResp design object type to represent who is the responsible actor that assigns that responsibility to a component and the visibility of the responsibility (public or private).
Binary predicates isDesignObjectType and isAssociationType complete the set of predicates for representing the types of products and associations that arise during a design process. Continuing with the example presented in Section 'Design process products representation', a Domain level is added (Figure 2). A set of facts represents the knowledge about the type of the versionable objects Cov and Sov, and the kind of domain relationship of the association Asc that links them (Figure 2).
Figure 2. Facts expressing partial knowledge about SADP domain and the types of the design objects generated in during a project and their associations.
Download figure to PowerPoint
4.2. Defining operations suitable for SADP
The primitive operations add, delete, and modify are not enough for capturing and tracing a SADP execution. Although an architectural design decision can be materialized by a complex sequence of these primitives, its very low abstraction level precludes capturing the meaning of the decision made, thus the decision is lost. Consequently, the model previously introduced must be extended in terms of the suitable high-level operations for SADP design domain, which really capture the performed architectural decisions. The proposed operations should be applicable to the design objects included in the domain. Table 1 lists some examples of architectural operations for SADP domain. An extensive catalogue of architectural design operations with their functional specifications can be found in Roldán (2009).
Table 1. Possible operations for the software architecture design domain
|Architectural patterns and tactics|
Such operations are grouped in categories that range from the most basic to more complex ones, in order to understand the operation abstraction level. Basic operations allow creating and deleting basic design objects (like components and connectors) (some functional specifications are given in Figure 3). Special operations are more complex and comprise design activities like object refinement or delegation (some specifications are given in Figure 4). With a higher level of abstraction, Architectural patterns and tactics operations are defined. They generate several design objects, which follow a configuration based on the applied architectural style (some specifications are given in Figure 5).
Figure 3 presents functional specifications for two of the basic operations defined in Table 1. Operations are defined in terms of primitive operations such as add and non-primitive ones, such as addPort. For example, the addComponent(s, nc, lResps, lPorts, lprops) operation adds a component called nc as part of a system s. As it can be seen in Figure 3, this operation is defined by a series of commands. First, a version of component c is added (add(c, Component, lprops)). After that, a set of responsibilities (whose names are given by the lResp collection) and ports (whose names are provided by the lPorts collection) are added.
Finally, an association between the new component c and an existing system s is set. This last operation is performed by an auxiliary function addAssociation whose effect is described by the association predicate introduced in Section 'Representing how the SADP is performed' (12). It should be noted that when performing an add operation both an object version and a versionable object are included, at versions and repository levels, respectively. The versionable object maintains the references to all versions it assumes during a SADP, which belong to different model versions (fact represented by means of version predicate introduced in Section 'Representing how the SADP is performed'). In addition, associations are set among versionable objects (repository level).
Although functional specifications of operations (Figure 3) are expressed by using non-primitive operations or other operations already defined in the domain, they can be translated in a sequence of primitive operations add, delete, and/or modify. From this, it is possible to express these more complex operations in terms of added and deleted predicates introduced in (7) and (8). For illustration purposes, let us consider again the addComponent(s, c, lResps, lPorts, lprops) operation. If it is applied to a model version m, then a version of a component c (and its ports and responsibilities), will belong to the successor model version (apply(φ, m)), as it is defined in (22).
Therefore, the definition of new operations allows enlarging the set of operations, without modifying the successor state axiom defined in (9), maintaining the coherency of the proposed model.
The precondition for applying the addComponent operation is specified in (23), where the poss(op, m) predicate expresses that an operation op is applicable to a given model version m.
Similarly to definition of basic operations, it is possible to define the special ones. Figure 4 presents an example of special operations. The delegateResponsibility(r, c1, c2) operation enables delegating a responsibility r from a component c1 to a component c2. Responsibility delegation generally occurs when a component is removed from a model version as a consequence of a refinement activity, and a new (set of) component (s) assumes (assume) the responsibilities of the original component. If r is a responsibility of a component c1 that belongs to model version m, and delegateResponsibility(r, c1, c2) operation is included in the sequence of operations applied to m, then, the responsibility r is assigned to c2 in the resulting model version.
The functional specification of delegateResponsibility in Figure 4 presents the commands that compose this operation. The arguments of delegateResponsibility are the responsibility to be delegated (r), the component to what r is currently assigned (c1), and the new component (c2) to what r is going to be delegated. The delegation works by adding a new RHasResp version (hr2), which represents a reified association between c2 and r. Finally the version (hr1), which represents that r was assigned to c1, is deleted.
In the same way as in (22) for addComponent operation, delegateResponsibility operation can be described in terms of added (7) and deleted (8) predicates. Expression (24) presents delegateResponsibility specification using first-order logic.
In addition, expression (25) indicates the preconditions of delegateResponsibility, which have to be satisfied to allow the designer performs the operation. The precondition axiom indicates that components c1 and c2, and the responsibility to delegate (r) have to belong to the model version m, and in such a model version, responsibility r is assigned to c1, by means of hr1 version. Also, in model version m there is not association among r and c2 representing that r is a responsibility of c2.
Operations that apply an architecture pattern refine an existent component in a new set of components and connectors that are instantiated from the elements types provided by the pattern. They interact with the designer asking for the responsibilities to be delegated, the way in which connections of the external components should be attached to the new ones. An example of pattern applying operation is defined in Figure 5. In this case, applyControlLoop operation is specified.
The applyControlLoop pattern comes from the process control paradigm and defines an architecture, where monitoring policies are activated in response to different events produced by several sensors (Shaw, 1994). When applying these policies, they may also generate new events or actions. The applyControlLoop(c) operation consists on refining a component c. Such a component has several responsibilities and is located on top of a layer (a type of component) named SensorsActuatorsLayer. This layer acts as an interface to the various devices that operate on the environment to be controlled. To apply the control loop pattern, applyControlLoop operation performs a series of addComponent adding the main elements of the solution: the Diagnosis component is the responsible of monitoring the state of the devices and their action rules; the Reactor component encapsulates actions predefined for certain situations requiring immediate attention; and the PolicyManager component provides the features for defining the possible actions to respond to the possible situations informed from the sensors. Then, addConnector operation is employed to add two connectors to create the pattern configuration. The roles of the connectors are attached to the respective ports of the previously added components, which are provided in an argument collection of addConnector command. The next step is to delegate the responsibilities of the original component c to each new component. This is made by means of the get auxiliary commands, to obtain a list of responsibilities, and the select auxiliary command, to select just the ones to delegate. Then the loop auxiliary command (translated in this syntax as for each – in) is using for iterating over the list of selected responsibilities (lresps) and delegating each one to a child component. Afterwards, it is necessary to reconfigure the attachments among the components that existed before executing the applyControlLoop operation. This is made, firstly, by getting the ports of the c component (get command). Also, the rest of the ports belonging to the model version are obtained and assigned to lap. Finally, by iterating over the collection of ports of the original component, the attached role of a port of the original component is recovered and the designer selects a port from lap (all ports in model version) to attach to p.
Figure 6 shows the evolution from one model version to other one, after applying a sequence of operations that contains applyControlLoop(c) operation. It represents two successive versions of the architectural model by using a Component&Connector view. It is described by means of a notation similar to ACME, in which the relationships between versions are inferred. More operations for architectural patterns applications are detailed in Roldán et al. (2006) and Roldán (2009).
Other design operations that apply architectural patterns, called tactics by Bass et al. (2003), do not modify the structure of the architectural model, but modify some properties of the affected design objects. Examples of these operations are applyIncreaseComputationaIEfficiency and applyIntroduceConcurrency (Figure 7). The first one, which was introduced in the example of Section 'Design process products representation' works by generating a new version of component c (by means of modify operation). This new version of c has a better processor since its Processor property (introduced in Figure 1) has the value provided by the CPUspeedValue argument, whereas the rest of the properties keeps the same values as the previous version). The second tactic applyIntroduceConcurrency works by adding a characteristic denominated Concurrency to the component c (by means of addCharacteristic operation) and adding a new responsibility to c for achieving load balancing features (by means of addResponsibility operation).