General software system theory and design trade offs
https://bit.ly/2WG39HF http://avancier.website
Surprisingly
little is new in the word of software design.
Discussions in Linkedin, January 2019, promoted me to put on record that:
· software system theory is older and broader than “object-oriented thinking”
· design tradeoffs related to decomposition and decoupling are eternal and universal.
The general principles of software system design inform OO
thinking, but stand independent of it.
This paper introduces some general design tradeoffs that are
relevant to agile software development
The next paper
adds notes on basic “object-oriented” principles, and their limitations.
Contents
General
system theory – basic terms and concepts
The
simplicity v flexibility trade off
Where
to specify and code business rules?
In classical
cybernetics, systems exhibit regular or repeatable behaviors.
Generally, the behaviors are performed by some actor(s) and modify some structure(s) or state variables.
That is the kind of system most system theorists are interested in.
The
more particular system of interest here is a software system.
It
is a discrete event-driven system.
It
responds to input events (messages) by performing processes.
It
is deterministic; it determines what to do by comparing input data against
persistent state data (memory).
The memory takes the form of a data structure that relates data types of interest to users of the system.
A system can be described from various viewpoints, as shown in this table.
|
Behavioral perspective |
Structural
perspective |
External perspective |
Service contracts |
System interface |
Internal perspective |
Processes |
System / subsystems |
The whole quadrant defines one system; but all is recursive.
Each subsystem (bottom right) is itself a system and recursively
describable using the whole quadrant.
Synonyms used by software designers include
·
Service
contract = method or operation
·
Process
= method body or procedure
·
System
interface = API, WSDL-defined interface
·
Subsystem
= module, component or class
(Unfortunately,
people also use the term service for an interface or a component.)
Structural
perspective
A system is a structure that can be triggered by events to perform one or more processes.
External
perspective - interface
A system can be defined from the outside by its interface, which lists the services it can perform.
The interface encapsulates whatever internal processes and resources the system needs.
The encapsulation boundary is chosen by the system describer or designer, it is logical rather than physical.
(Which means that systems can overlap.)
Internal
perspective- subsystems
A system may be composed of interacting subsystems
A system may be described or designed as composed of a few large subsystems or many small subsystems.
A subsystem may be further decomposed, meaning that coarser-grained subsystems contain finer-grained subsystems.
At the bottom level are atomic subsystems - not further decomposed.
Behavioral perspective
A process that runs over time from start to end.
One system-level process may span several subsystems, which each performs a part of the higher/wider process.
A system can act as either or both:
· a client, which requests another (server) system to perform a process
·
a server, which
performs a process at the request of another (client) system.
Here, client and server or logical terms, nothing to with hardware.
External
perspective- service contracts
An
invocation is an event or message that triggers a process.
The
full contract for a process may be presented in the form of service contract:
· Signature (process name, input parameters and output/response message).
· Business rules (preconditions and post conditions that apply to system state variables).
To invoke a process, a client needs only its signature.
However (see the section on business rules below) a client may also test preconditions and/or test post conditions.
Internal
perspective- processes
A
process is a sequence of activities.
Both
structured and OO methods divide them into two kinds.
An
enquiry process returns/outputs a message to inform or direct the behavior of external entities (it has no effect on the
system’s state).
An
update process has an effect on the system’s state; it changes the value of one
or more internal state variables (or else returns/outputs a failure message).
For many decades, general system design
principles have included:
·
Decomposition:
modularise a large monolithic system into subsystems.
·
Decoupling: strive for
tight cohesion within a subsystem and loose coupling between subsystems
(Constantine, 1968).
Decomposition and decoupling are very general
system design principles.
The aim of these principles is to facilitate
the design, management and change of subsystems.
Taken too far however, both principles have negative effects, and designers must strike a balance between extremes.
Decomposing a system into many tiny subsystems, each of them simple, creates complexity in the structure of the system.
This table contrasts two options.
Subsystem |
Inter-subsystem |
|||
Size |
Processes |
Messaging |
Coupling |
|
Macro subsystems |
Larger |
Longer |
Less |
Looser |
Micro subsystems |
Smaller |
Shorter |
More |
Tighter |
As the table indicates, size matters; many smaller, subsystems typically merit tighter coupling than fewer, larger subsystems.
Note however, decoupling is not a single concept - our architect classes cover a dozen or more ways to decouple subsystems.
Agile development thinkers, OO thinkers and enterprise architects are all fond of promoting principles.
It is important to recognise where principles can be in conflict.
Agile
principle |
Contrary
agile principle |
Keep the system simple |
Decouple subsystems |
You ain’t gonna need it |
Design for future flexibility |
In “Applying UML and patterns”, OO thinker Craig Larman said to pick your battles.
“It is not high coupling per se that is the problem; it is high coupling to elements that are unstable in some dimension, such as their
· interface [the list of processes/services that are provided or required]
· implementation [internal procedures, physical features or technologies]
· mere presence [availability when needed]”
“If we put effort into “future proofing” or lowering the coupling when we have no realistic motivation, this is not
time well spent.”
A
theme here is that balancing tradeoffs is more important than following uni-directional principles.
Skillful decoupling of subsystems should help people manage and change each subsystem on its own.
But increasing the agility of small subsystems can make it harder to meet higher/wider goals.
The price can be dis-integrity,
duplications and delays in a wider system.
A
software system (being deterministic) applies business rules that compare input
events/messages to internal state/memory.
Business
rules can be expressed in the form of pre and post conditions.
Preconditions define the state a system should be in before an event can be processed successfully
Post conditions define the state a system should be in after the event (some call them “side effects”).
Specifying business rules in service contracts
Computer
scientist Charles Anthony Hoare was interested in the formal specification of a
system.
His
logic can be expressed in the form of what is called the Hoare triple.
· If the preconditions for a process are met.
· And the process completes successfully
· Then the system’s state will meet the post conditions of the process.
For
example:
· If a customer’s debt meets the precondition that Debt + Sale Value < Limit.
· And the sale process completes successfully
· Then the customer’s debt will meet the post condition that Debt (after) = Debt (before) + Sale Value.
OO
thinker Bertrand Meyer wanted to
define a system’s interface in a formal, precise and verifiable way.
He
proposed it should specify business
rules related to system state, in way that can be tested.
So
he extended interface definitions to capture system invariants and more.
A
process may be presented in the form of a service contract thus:
· Signature (process name, input parameters and output/response message).
· Business rules (preconditions and post conditions that apply to system state variables).
Notice that one way or another, a client
often gets to know something of server system’s internal state.
Internal state variables (or synonyms for
them) may appear in the signature and in business rules.
Coding business rules in process procedures
At
run time, who tests the preconditions of a process? Client or
server?
Bertrand Meyer first promoted Design
by Contract in Object Oriented Software Construction, Prentice Hall,
1988.
But
again there is a tradeoff to be made between design
patterns.
Design by contract
Premise: a client must guarantee the preconditions of a process before invoking that process.
The server is then expected to create the post condition that the Service
contract promises.
This might help to keep the system simple.
But it is impractical and/or risky in multi-user
client-server database systems.
Servers cannot rely on as-yet-unknown clients guaranteeing servers’
preconditions.
And in distributed systems, clients may not be able guarantee the
preconditions of a process before invoking that process.
So in the design of distributed systems, people apply defensive design
instead.
Defensive design
Premise: a client is not expected to ensure preconditions hold true.
This means designing such that:
· a server handles any failure of any client to send valid data or ensure preconditions
· a client can either ignore or cope with any failure of any server to produce the desired effects/results.
The server must test the preconditions of a process are met, and if not, it likely return a failure message to explain that.
This
might add some complexity to the system.
But it is the normal choice when client and server systems are designed by different teams (see the Bezos mandate in this SOA paper).
Test-driven design
There
is an agile development method called “test-driven design”.
This
requires developers to code test cases that test post conditions - using
assertions.
The general principles
of software system design inform OO thinking, but stand independent of it.
This paper introduces
some general design tradeoffs that are relevant to agile software development
The next paper adds notes on basic “object-oriented” principles,
and their limitations.
For more on general system theory come to our next System Theory for Architects tutorial in London