To give you an example, suppose you’re developing a central business partner management application that is supposed to be used by a number of business applications.
- Human Resources requests the fields “Name”, “Salary” and “Entry Date”.
- CRM requests “Name”, “Sales Representative”, and “Sales Area”.
- Financials requests “Name” and “Debtor Status”.
If your architectural style is to take all these requirements and solve them in a cross-component software, you’re in Superset Hell™.
The cross-application component becomes a shared API by and for all of its consumers, resulting in a tight coupling of every user of the component with every other user of the component. In this blog I have worked out some examples and details of the possible consequences of this type of coupling.
Figure 1: Using the intersection vs. the subset
Superset Hell as a danger to maintainability and agility
Software architecture degenerates, but cross-application components that do not have an absolutely water-proof insulation against the specifics of their consuming applications decay at the rate of raw hamburger meat left out in the sun at noon.
Very soon, their code will be cluttered with IFs and ELSEs covering particular exceptions from the general rules as required by a number of consumers. Looking into the code, you will be baffled by data structures containing elements that are populated only under conditions and with semantics that are Too Complicated To Explain™. Senior team members sigh and point out that things are “historically grown”. (Note to junior project members: This means that you would be better off throwing them away, were it not for the risk of introducing new bugs.)
Any software with these characteristics is extremely difficult to use and maintain.
- As a new consumer of the software, you never know if there isn’t a hidden pre-condition or post-condition that will break your neck.
- Maintaining the software is difficult because diversity drives complexity stronger than genericity. For example, it is harder to understand and change code with many nested IFs and ELSEs than code with field symbols. (Generic code, though abstract, is often structurally simpler than application code expressing real-life business logic. This is why system programming is for sissies. Just kidding.)
All cross-application, cross-business domain components are naturally vulnerable to Superset Hell. This goes especially for areas which are close to the business logic, but represent an orthogonal aspect that crosses most applications. Examples are:
- File Import/Export Services
- Output Management and Printing
- Records Management
- Master Data Management
- Dispute Management
- Organizational Management
The way out of Superset Hell
A good way out of Superset Hell is provided by the following architectural pattern:
- For cross-application business components: Address only the overlap of requirements in the cross-component software (with some good measure).
- For technical components: Keep them purely technical.
- Provide a release-stable plug-in mechanism for each particular application to integrate their specific extensions.
- Avoid applications using each other’s add-ons whenever possible.
The following features of the ABAP Objects language and the Web Application Server ABAP will support you:
- Object-orientation – especially polymorphy through interfaces – is excellent for creating plug-in architectures.
- BAdIs are one very well-documented and fast example for this. Read all about them.
- Avoid inheritance (subclassing) unless the superclass defines a concise and stable API for subclasses. Prefer interfaces for polymorphy and composition for extending functionality.
- The Switch and Enhancements Framework introduces many valuable tools to define, implement, seamlessly integrate and manage enhancements to underlying software layers.
- Reduce complexity and achieve encapsulation by hiding implementation details in private and protected members of ABAP classes.
- The ABAP package concept helps you with encapsulation on a higher level by allowing you to declare which elements of a package are visible outside the package, and enforce the usage of your software through released APIs.