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. 1

Decomposition and decoupling. 3

The simplicity v flexibility trade off. 3

Where to specify and code business rules?. 4

Conclusions. 5

 

General system theory – basic terms and concepts

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).

Decomposition and decoupling

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.

The simplicity v flexibility trade off

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.

Where to specify and code business rules?

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.

Conclusions

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