So what did the Elizabethans know about software development? Well, in truth, nothing whatsoever. But what they had begun to do is codify and systematise the knowledge and experience of masters in manuals, treatises and books. Some of the earliest documents of this form refer to the martial arts or, as it was known at the time the ‘Arts of Defence’
In martial arts one learns practical skills (in this case how to defend oneself against any enemy) through practice and training. The practical skills are usually an extension of some ‘core’ principles, which form the basis of the art. These core principles state some fundamental truth about the nature of the art. Without understanding these fundamental principles one is merely performing a ‘dance’ and one will never be truly effective.
In the late 16th century George Silver, an English gentleman, wrote a martial arts treatise called ‘Paradoxes of Defence’ (A transcription of the original can be found here). The treatise is well known in the Western Martial Arts community for being one of the earliest treatises in English; and also for Silver’s prolonged and somewhat vitriolic attacks against the Italian fencing masters of his day, who he saw as frauds.
Silver followed up his ‘Paradoxes of Defence’ with a more practical publication ‘Brief Instructions Upon My Paradoxes of Defence’ where he attempted to set out his fighting principles and practices (a transcription can be found here)
Silver used the phrases ‘True Fight’ and ‘False Fight’ to describe effective fighting techniques. True fight was correct application of the principals of fighting; False Fight was to ignore, misunderstand or misuse the principals of fighting. He also talked of ‘Perfect’ and ‘Imperfect’ fighting. Perfect fighting had nothing to do with being a great fighter: as long as you used the correct technique all the time (the True Fight) then your fight was perfect; however skilled you were. So a beginner, using the principals of the True Fight, even if slow and ungainly, was fighting a Perfect fight. On the other hand, even if you were fast, skilled and deadly, if you used ‘False’ techniques Silver considered your fight to be ‘Imperfect’. In Silver’s mind using correct principles was always superior to using ineffective techniques. That didn’t mean the Perfect Fight always won; but that the Imperfect fighter was doomed, by definition, eventually to fail.
Silver based his techniques on what he called his Four Groundings and Four Governors. The Four Groundings were the fundamental principles upon which all fighting – irrespective of the weapon used – were based. The Four Groundings are tightly inter-related to each other. Ignoring one principle will affect all the others (and lead to False fight). Each Grounding must be understood, and how it affects all the others, also understood.
The Four Governors were the elements of a fight that controlled its outcome. The Governors control your actions and your approach to the fight. As the Governors change, so must your approach to the fight, and the techniques you can, or must, use.
The question is: can we apply Silver’s ideas of True Fight and False Fight to software development? What is ‘True’ development; and what is ‘False’? What are the Groundings of software development; and what are the Governors? Can we define ‘Perfect’ and ‘Imperfect’ software?
‘Imperfect’ software development
Firstly we need to make a distinction between Correctness and Intrinsic Quality. Correctness is the ability of software to fulfil its requirements. Intrinsic Quality refers to how the software is designed and built – that is, how ‘good’ or ‘bad’ the software is.
Incorrect software, irrespective of how good it is, must be considered ‘Imperfect’ by our definition. No matter how ‘good’ the software is, if it doesn’t fulfil its requirements, it’s useless (and if the requirements are wrong it’s also useless, or at least of questionable value).
Correct software must be our starting point. Is all correct software Perfect? Or should the ‘perfection’ of software be judged by its Intrinsic Quality?
If we apply Silver’s logic ‘Perfect’ software will always result from ‘True’ software development. True development is that which applies the Four Groundings and Four Governors of software development. So we need to understand what the Groundings and Governors are for software development.
The Groundings and Governors for software development must be those principles that give our software high intrinsic quality, both in its development (its static design, coding) and at runtime (its dynamic testing and execution).
What makes poor software?
It is challenging to define what makes ‘good’ software since we so rarely see it. On the other hand most engineers are used to seeing (and maintaining!) what they consider ‘bad’ software. Often engineers cannot qualify what makes the software bad; it just is. Typically, though, bad software suffers from one or more of the following maladies:
It is difficult to understand.
The code is difficult to read; variable names are unhelpful; comments are missing (or worse, incorrect); code is badly structured and laid-out; etc.
It is fragile.
Fragile code will break at the slightest provocation. Fixing a bug in one part of the code can cause a cascade of other bugs in other parts of the code; often quite un-related to the problem.
It is rigid.
Rigid code has been designed to fulfil one requirement – and that is all it will ever do. If the requirements change the software must be almost completely re-written to support the new behaviour.
It is immobile.
Engineers often build really useful software modules. However, if the useful module is so tightly intertwined with the structure of the program it’s in, the effort involved in unpicking the useful code is so great is often impractical to even try to re-use it somewhere else. Sometimes it’s just easier to write it again from scratch.
The Four Governors
In Silver’s system understanding and controlling your Governors determined how successful you were in a fight. If you fail to control your Governors you will ultimately lose the fight. In engineering terms success can be measured in terms of money. That is, failing to understand and control the software Governors will ultimately lead to spending more money (or making less money, however you want to look at it) than you need to.
Our Governors must therefore relate to the effectiveness of our software development. Effectiveness is about doing things that add value; in contrast to efficiency, which is focussed on doing more work with less resource.
If the above qualities define bad software then the opposite must define good software. Thus we can use our definition of bad software and invert them to give us our Four Governors of software development. They are:
Good software must be easy to read and understand. There should be no surprises in the code; its purpose and implementation should be obvious and equivalent.
It should require little effort to adapt existing software to new requirements.
Software should be tolerant to invalid inputs. Performance should be unhindered by incorrect inputs, or should be degraded in a known, controlled, way. The impact of change should be controlled and limited.
Software should be easily adapted to new environments, platforms or problem domains, without requiring major modification.
The Four Groundings
The Groundings are the set of (inter-related) principles upon which all actions are based. The principles are normally inter-dependent – adjusting one principle often affects the others. Thus the Groundings must be ‘balanced’ to meet the needs of the Governors. As the Governors change, so must the application of the Groundings.
In software our Groundings are the principles of good, modular, design. A module, in this case, refers to a unit of software construction (or decomposition, if you prefer). A program is constructed of one or more modules. A module should ideally be self contained, with a well-defined interface and a well-defined, localised purpose and functionality.
By correct application of the Groundings we achieve high intrinsic quality software. Once again, our Groundings are inter-dependent – focussing on any one Grounding at the expense of the others is no guarantee of producing good software.
The Four Groundings of software development are:
Coupling is the inter-dependence between modules. The inter-dependence depends on the number of, and complexity of, connection between any two modules.
Ideally, we aim for low coupling – that is, a small number of simple connections. Reducing the inter-dependency between modules allows greater flexibility in design and greater potential for re-use.
There is a compromise to be made between coupling and performance. Typically, low-coupling comes at the expense of system performance; highly-coupled systems can often be much higher performance than lower coupled systems.
The engineer’s skill is in understanding when to design for low coupling and when to design for performance.
As a rule-of-thumb always design for intrinsic quality of code, monitor the actual performance, and only then optimise the coding or coupling of the key areas that need it. Most times the problem isn’t where you think it is (dynamically).
Encapsulation literally means ‘to put in a capsule’. Encapsulation is separating ‘what’ the module does (its interface) from ‘how’ it does it (the implementation). Ideally, clients should never be able to directly access the module’s implementation – or even need to if the interface is designed well.
Strong encapsulation can reduce coupling by eliminating the ability of one module to access the internal behaviour or data of another module.
It enables the module to be easily tested in isolation before combining it with other modules that make up the program.
Encapsulation also provides ‘insulation’. By separating the interface from its implementation the implementation may be changed without affecting the client code – in other words, the client is ‘insulated’ from change.
Cohesion defines how well elements fit together. There are several models for cohesion in software (The most well known being Constantine’s 7-level scale of cohesion) but most cover the following aspects:
Functional cohesion focuses on the coherence of the interface of a module. For high cohesion the operations that form a module’s interface must be mutually self-supporting. The operations should all contribute to a unified overall behaviour for the module By contrast, the operations in a low cohesion module are independent and unrelated. Removing or replacing any operation has no effect on any other operation in the module. A highly cohesive module typically performs a single, high-level responsibility.
Temporal cohesion focuses on the concurrent or parallel execution behaviour of modules. Modules that execute in sequence with one another executing in the same thread of control are temporally cohesive. Modules that must run in parallel but are executing within the same thread of control are not temporally cohesive.
Contextual cohesion refers to design abstraction. During design engineers should organise the design into different levels of detail; each level used to focus on a different aspect of problem definition. For example, high level design should focus on architecture and design validation; lower level designs should focus on implementation and verification. A cohesive design does not mix high and low level constructs on the same design. For example, focussing on implementation artefacts during architectural design is inappropriate and therefore contextually non-cohesive.
Cohesive modules tend to limit the impact of change, since the change typically affects only the (related) operations/data in a single module; and has no impact on other modules.
Abstraction may be defined as filtering out detail that is unnecessary in the context being considered.
When we build software we are constructing models of the problem domain and manipulating them to provide some benefit to the customer. Context is important because it defines how you view the situation: what is relevant, that is, the abstractions that are useful in that context.
For any particular problem domain there are concepts that are important, and concepts that have no relevance. A good abstraction captures the relevant information about the problem domain, and ignores the superfluous. You could think of this as looking at a problem from a particular viewpoint.
Basing a design on problem domain abstractions provides resilience to change since the concepts of any particular domain are likely to remain stable over time; unlike implementation technologies which are likely to change rapidly.
The Four Groundings are all inter-dependent, but not necessarily mutually inclusive: Although a good problem domain abstraction domain is likely to be cohesive, it can be made incoherent through bad design; a coherent module should provide strong encapsulation, but that can be broken through poor design; strong encapsulation should provide lower coupling, but poor cohesion in the design and poor abstractions may lead to increased coupling.
A good engineer must understand the Four Groundings in detail and how they inter-relate.
‘Perfect’ software development
True development is one that applies the Groundings and Governors:
A design with well-chosen abstractions of problem domain elements, strongly and cohesively encapsulated with low coupling. Such a design is likely to be comprehensible, robust, flexible and mobile.
False development is one that ignores the Groundings and Governors:
An incoherent design, focussing on implementation elements, with poor encapsulation, weak cohesion and high coupling. Such a design is likely to be incomprehensible, rigid, fragile and immobile.
A Perfect development is therefore one that is always True; Imperfect development is one where we use False techniques.
Of course, we can always ignore the Groundings and Governors and still produce working software; but this will always be (in Silver’s view) Imperfect.
Even if we aren’t particularly skilled with the Groundings and Governors as long as we apply them our development will always be True. And we can always improve.
If we always choose the False development (cutting corners) our software can never be Perfect.
As it suggests Perfect development is an ideal; it is something to strive for. We will almost certainly have to compromise our development because of time, resource or money constraints. Wherever possible, though, we should aim for True development.
Perhaps those Elizabethans knew more about software development than we realise, after all.
Summary of the True development
The Four Governors
The Four Groundings