Abstractions, and corollary inheritance, are primarily understood with objects. Yet, since business processes are meant to focus on activities, semantics may have to be refined when abstraction and inheritance are directly used for behaviors.
Abstract objects cannot be directly mapped to abstract behaviors (Antony Gormley).
Considering that the primary purpose of abstractions is to tackle business variants with regard to supporting systems, their representation with use cases provides a good starting point.
Business Variants: Use case’s <extend> & <include>
Taking use cases as a modeling nexus between business and systems realms, <extend> and <include> appear as the default candidates for the initial description of behaviors’ specialization and generalization.
- <include>: to be compared to composition semantics, with the included behaviors performed by instances identified (#) by the owner UC (a).
- <extend>: to be compared to aggregation semantics, with the extending behaviors performed by separate instances with reference to the owner ones (b).
Included UCs are meant to be triggered by owners (a); that cannot be clearly established for abstract use cases and generalization (c).
Abstract use cases and generalization have also been mentioned by UML before being curiously overlooked in following versions. Since none has been explicitly discarded, some confusion remains about hypothetical semantics. Notionally, abstract UCs would represent behaviors never to be performed on their own (c). Compared to inclusion, used for variants of operations along execution paths, abstract use cases would describe the generic mechanisms to be applied to triggering events at UC inception independently of actual business operations carried out along execution paths.
Nonetheless, and more importantly, the mix-up surrounding the generalization of use cases points to a critical fault-line running under UML concepts: since both use cases and classes are defined as qualifiers, they are supposed to be similarly subject to generalization and specialization. That is misguided because use cases describe the business behaviors to be supported by systems, not to be confused with the software components that will do the job. The mapping between the former and the latter is to be set by design, and there is no reason to assume a full and direct correspondence between functional requirements and functional architecture.
Use Cases Distilled
As far as use cases are considered, mapping business behaviors to supporting systems functionalities can be carried out at two levels:
- Objects: UCs being identified by triggering agents, events, and goals, they are to be matched with corresponding users interfaces and controllers, the former for the description of I/O flows, the latter for the continuity and integrity of interactions.
- Methods: As it’s safe to assume that use cases are underpinned by shared business functions and system features, a significant part of their operations are to be realized by methods of shared business entities or services.
Setting apart UIs and controllers, no direct mapping should be assumed between use cases and functional qualifiers.
The business variants distilled into objects’ or services’ methods can be generalized and specialized according to OOD principles; and the same principles can be applied to specific users’ interfaces. But since purely behavioral aspects of UCs can neither be distilled into objects’ methods, nor directly translated into controller objects, their abstraction semantics have to be reconsidered.
Inheritance Semantics: Structural vs Functional
As far as software artifacts are concerned, abstraction semantics are set by programming languages, and while they may differ, the object-oriented (OO) paradigm provides some good enough consolidation. Along that perspective, inheritance emerges as a critical issue due to its direct impact on the validity of programs.
Generally speaking, inheritance describes how structural or behavioral traits are passed from ancestors to descendants, either at individual or type level. OO design is more specific and puts the focus on the intrinsic features (attributes and operations) supported by types or classes, which ensues that behaviors are not considered as such but through the objects’ methods that realize them:
- Structural inheritance deals with attributes and operations set for the whole life-cycle of instances. As a consequence corresponding inheritance is bound to identities (#) and multiple ascendants (i.e identities) are ruled out.
- Functional inheritance deal with objects behaviors which may or may not be frozen to whole life-cycles. Features can therefore be inherited from multiple ascendants.
That structural vs functional distinction matches the one between composition and aggregation used to characterize the links between objects and parts which, as noted above, can also be applied to uses cases.
Use Cases & Abstraction
Assuming that the structural/functional distinction defined for objects can also be applied to behaviors, use cases provide a modeling path from variants in business processes to OOD of controllers:
- Behaviors included by UCs (a) are to be set along the execution paths triggered by UC primary events (#). Inheritance is structural, from UCs base controllers to corresponding (local) ones, and covers features (e.g views on business objects) and associated states (e.g authorizations) defined by use case triggering circumstances.
- Behaviors extending UCs (b) are triggered by secondary events generated along execution paths. Inheritance is functional, from extending UCs (e.g text messaging) to UCs primary controllers.
Yet this dual scheme may not be fully satisfactory as it suffers from two limitations:
- It only considers the relationships between UCs, not with the characteristics of the use cases themselves.
- It ignores the critical difference between the variants of business logic and the variants of triggering conditions.
Both flaws can be patched up if abstract use cases are specifically introduced to factor out triggering circumstances (c):
Use cases provide a principled modeling path from variants in business processes to the OOD of corresponding controllers.
- Undefined triggering circumstances is the only way to characterize abstraction independently of what happens along execution paths.
- Abstract use cases can then be used to specify inception mechanisms to be inherited by concrete use cases.
That understanding of abstract use cases comes with clear benefits with regard to security and confidentiality.
What is at Stake
Factoring out authentication and authorization epitomizes the benefits of abstract UCs:
- Concrete schemes with included UC will give access to all registered users with the particulars of managers or customers checked later (a).
- Alternatively, abstract schemes will use inheritance of inception mechanisms in order to explicitly prevent separate access (c).
- Applying <include> with abstract UC should be ruled out because it would make room for the execution of operations with undefined triggering circumstances.
Interactions can only be triggered by concrete actors.
As a conclusion, by enabling a clear distinction between business logic and operational circumstances, abstraction can reinforce the security of functional architectures.