The Contract Mindset: Transforming the software engineering process
TLDR: Merely borrowing a term from the field of legal writing can boost process effectiveness and quality.
In my teenage years, I tried to stay away from legal professions like lawyers. They were absolute “masters of word” to me and as a technical nerd at that time I was kind of at the opposite side — I understood nothing of what they do and how they do it.
Three decades later I find myself fascinated by the field of law and amazed how similar it is to the software engineering. Especially such area as legal writing / contract law: taken to an extreme, one can say a programmer writes instructions for machines and a lawyer — instructions for people.
There are many more similarities: Legal writing process also involves rewriting statements until it “works”, both rely on libraries of existing knowledge — there are even “variables” in the legal documents (you’ve definitely seen something like “This service agreement, further referred to as ‘Agreement’”). The legal text is expected to be precise, compact and at the same time complete — not allowing room for misinterpretation — exactly like source code.
Yet software engineering has more levels that just writing code: patterns, architecture, interaction, functional specification. In essence, any piece of software exists only to do what we expect it to do. In other words, the software shall fulfil its contract. And our responsibility is to compose this contract.
We used to work with “Requirements” to express our needs. In the projects I am involved in, I try to persuade the team to use the concept of a “Contract” instead. The change is more profound as it may seem at first glance.
Through our lives, our brain accumulates a huge network of semantic meaning so when we see a specific word we not just plain read it, but activate the semantic chains. If we try to perceive the word “Requirement” it rolls out to something like “Someone requires something from someone”. Now, how it affects me? Why should I care? Who requires from whom?
Compare with reading the word “Contract”: we all are familiar with semantics of contract documents in real life. We might perceive it as something like “carefully formulated conditions between known parties, where the parties are supposed to agree upon”. This puts our thinking in quite different gear.
When we are exposed to a contract, we automatically take it more seriously as it includes a notion of an agreement. We do not normally want to agree with something we do not like or we cannot fulfil. So faced with a contract, we would want to engage ourselves into modifications for more precise terms, less unclear meanings and completeness. At the end we are supposed to end up with a concise, compact and complete document about our expectations, where everyone agrees on. That’s a much more stable basement for all further processes, without any explicit pressure involved.
Such a contract is a natural input for all other processes. It drives implementation (and results in less rework efforts as the input contains little or no ambiguity), it can be straightly used for defining test cases and for functional verification at the end.
Contracts are naturally applicable on different levels of development process. A little illustration — imagine we are developing an app for the Smart Speaker, controllable over Bluetooth Low Energy protocol.
A Feature Contract defines the expected high level end-user experience, ensuring all stakeholders are aligned on the final goal.
An Interaction Contract outlines functional requirements for specific screens, streamlining communication between designers and developers.
A Component Contract defines what needs to be changed / added to the involved software component, framework, library in order to fulfil the higher level contracts.
After all, in current times of AI rise it became clear that being able to articulate what you want to achieve is essential for producing the right result.