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.
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).
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.
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):
- 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
Abstraction can significantly reinforce the bridging role of use cases between business and UML models.
On one side specialized use cases can be associated to operations and functions directly implemented, e.g by factoring out authentication and authorization:
One standard solution is to define a common use case controlling accesses for all users providing they can be identified before being subsequently (i.e during UC execution) qualified and authorized. Apparently, that could be done with <<include>> (a) or <<extend>> (b) connectors.
But the second option would not be possible with the semantic distinction suggested above for UC patterns, which specifies that use cases can only be extended from existing sessions.
A more generic approach (possibly with patterns) could try to “abstract” Open Session UC, e.g to cover a broader range of actors and identification mechanisms.
Understanding UC abstraction in terms of a partial specification to be <<included>> and run by the current thread will be inconsistent because there would be no concrete actor for the identification mechanisms (c).
By contrast, since inheritance connectors apply to types and not to instances (i.e execution threads), abstracted identification mechanisms are meant to be part of Manage Session and can be applied to triggering actors (d).
Such a clear distinction between the specification of threads (using connectors) and activities (using inheritance) should provide the basis of architecture-based UC patterns.
Al in all, that will greatly help to align business cases, business opportunities, and functional architectures.
- Thread: use cases
- Use Cases
- Use Cases Patterns
- Users Patterns
- Use Cases shouldn’t know about Classes
- Business Processes & Use Cases
- Use Cases & Action Semantics
- Focus: Business Cases for Use Cases