- Published on
The ambiguity of software: information, interactions and interpretations
- Authors
- Name
- Damian Płaza
- @raimeyuu
Software?
What is software, dear Reader?
I bet you have an answer ready. The thing that runs. The binary, the container, the pod that got restarted at 3 AM.
Ask around in your team and you will probably hear "the code" (we already played with that one in The ambiguity of code).
Something technical.
Something that lives in repositories and pipelines.
Something light.
Invisible.
Something that doesn't fall down if you drop it.
After all, it's "just code", isn't it? One can always change it. Delete it. Generate a new one in a few seconds.
But not by talking about code.
Can we talk about "software" if no computing is involved?
Let's meet the family.
Grandma's birthday
Grandma Helen next Saturday turns 80.
Martha, her daughter, learned about the plans during a phone call with Grandma - a small party, at Grandma's place, at 4 PM.
Tom, Martha's husband, is in the picture too (yes, dear Reader, the same Tom you might recall - he does not only run businesses, he also has a family).
So is Zoe, their 9-year-old daughter.
And Theo, Martha's brother, lives in another city and promised to bring the cake (yes, "that uncle" - still far away, still with a shaky internet connection).
It's Monday morning. Breakfast.
Tom grabs a marker and writes on the family calendar hanging on the fridge: "Mom bday, Sat 4pm".
In the evening, Martha sends Theo a message: "Saturday, 4pm at Mom's. Cake for 12, remember about her diet!"
Theo replies with a thumbs up.
Zoe goes to her room and starts drawing a card.
Everything is fine, isn't it?
On Wednesday, Grandma calls again. Her sister, Great-Aunt Rose, can't travel on Saturday. The party moves to Sunday.
Martha tells Tom during dinner. Tom nods.
Nobody touches the calendar.
Nobody calls Theo - "I'll text him later", Martha thinks.
Zoe tells her best friend she can't come to the sleepover on Saturday, because of Grandma's party.
On Saturday morning, Theo picks up a cake for 12 people.
With sugar.
Four people, four birthdays
What just happened?
One could say: poor communication. Somebody forgot to text somebody. Case closed.
But let's look closer, dear Reader.
How many birthdays were there in this tale?
One, you would say. Grandma Helen turns 80, there's only one of her.
I counted four.
- For Martha, the birthday was a date and a promise - she talked to her mother, she knows what was agreed, she knows why it changed.
- For Tom, the birthday was an entry in a calendar - "Mom bday, Sat 4pm". Which mom, by the way? Zoe once read it as her mother's birthday and was very confused why nobody bought presents.
- For Zoe, the birthday was an obligation - make a card, be at Grandma's, skip the sleepover.
- For Theo, the birthday was a delivery - a cake, for 12 people, at a given time and place, "remember about her diet" (which diet?).
The same word. Four different meanings.
Four different consequences.
A date, an event, an obligation, a delivery.
Are all of them wrong? Are all of them right?
Here's the thing - none of them is the birthday.
The "real" birthday, whatever that means, never left Grandma's living room. What travelled were sentences, a calendar entry, a text message, a drawing on a piece of paper.
Representations.
Interpretations.
Each of them re-created from the previous one, by a different person, for a different reason.
Where is the software?
But shouldn't it be a tale about software?
Where is "it"?
There's no app. No database. No API. Tom did not even install a calendar app - the family calendar is a sheet of paper on the fridge.
And yet, look what we have:
- concepts - a birthday, a party, a cake, a guest, a diet,
- representations of those concepts - a spoken sentence, a calendar entry, a text message, a card,
- interactions - who tells whom, when, through which channel, and what are the consequences (e.g. who is expected to react),
- boundaries - Zoe does not need to know about the diet, Theo does not need to know about the sleepover,
If you squint a little, dear Reader, this is a distributed system.
The information and meaning leaves one head and travels to another, transformed by each person's interpretation.
With eventual consistency (very eventual, if you ask Theo, with his flaky internet connection).
"A system? It's a family, Damian!", you might say, dear Reader.
Let me bring back a pie. Or rather - a PIE.
In Composing a PIE we followed a foodtruck crew, a bunch of distributed services and a web of objects, and found the same pattern in all of them: Purpose, Interactions, Elements. A system's capability to fulfill its purpose emerges from interactions between elements.
The family has all three:
- a purpose - make Grandma's 80th a good day (with a cake she can actually eat),
- elements - Martha, Tom, Zoe, Theo, but also the phone, the paper calendar, the text message,
- interactions - calls, conversations at the table, notes, messages, promises.
PIE does not care what the elements are made of.
Roles people play, services, actors, objects, teams, whole enterprises - for PIE they are all elements.
It's agnostic to the domain. A family organizing a birthday is as much a system as a cluster of microservices processing payments.
The only difference? One runs in a living room, the other in a data center.
Information get exchanged and interpreted through interactions.
Now imagine that Martha asks us to build "an app for family events".
What would we do?
We would take this exact structure - these concepts, these representations, these interactions - and we would encode it. Make it executable. Make it faster, maybe more reliable.
But the structure was already there, before the first line of code.
We tend to think of software as the running artifact. But isn't it a consequence, one of many?
Software is first a structure of representations (which concepts we make explicit, and how) and a structure of interactions (who exchanges which representation, when, and what they do with it). The code is that structure made executable.
Or, to put it in a more provocative way:
Software is a system of representations in motion. The running program is just where it happens to execute.
Peter Naur brilliantly articulated the concept of Programming as Theory Building - the program text is not the real product, the theory in the heads of its builders is.
That theory is expressed through representations and their interactions.
Designing them is our job.
And when does "designing process" start?
It starts with naming.
The lawless domain?
Let's take a little detour, dear Reader.
Imagine a structural engineer designing a footbridge. She can be creative, bold, even a bit crazy. But at some point gravity enters the room. Loads, materials, tension. If the beam is too thin, it bends. If it's much too thin, it breaks - and everyone sees it.
An electrical engineer has Ohm's law and Kirchhoff's laws. Put too much current through a wire that's too thin and the wire will inform about its state.
Previous state, sometimes with smoke.
Nature pushes back. The material resists.
Physics is non-negotiable.
Now look at software world.
What "laws" do we have?
- Conway's law - an observation from a 1968 paper about how organizations design systems.
- Brooks's law - "adding people to a late project makes it later", from a book of essays.
- Hyrum's law, Postel's law, Lehman's laws - observations, guidelines, patterns noticed over the years.
- And the borrowed ones - technical debt (from finance), entropy (from thermodynamics), gravity (from Newton).
I don't want to diminish any of them. They are useful. I use them all the time.
But let's be honest. Let's summon the definition:
a statement of an order or relation of phenomena that so far as is known is invariable under the given conditions.
Invariable. Under the given conditions.
Which of our laws was tested like that? Which one was measured, falsified, replicated?
Most of them are anecdotal. Very wise anecdotes, collected by very observant people - but anecdotes nonetheless.
And I am guilty too. In Modularity Uncertainty Heuristic I borrowed from Heisenberg.
In The knowledge gravity problem I borrowed from Newton (and I explicitly said the formula was made up).
I even dared to coin The law of eventual composition.
We are, I think, in "a lawless domain". Our "laws" are quasi-laws, borrowed from here and there, held together by experience and metaphors.
Is that bad?
Not necessarily. Metaphors are lenses, they help us see.
How?
By building meaning.
But it has consequence that we don't often talk about.
When nothing physical stops us (and I am not saying about "the speed of light"), it might seem that we are not constrained by this "invisible", "lawless world" we operate in.
If "material" (the information) is invisible then it must be not constrained?
Limitless?
Any structure compiles.
Any representation of a concept can be serialized to JSON.
Any two services can be wired together.
Nothing falls down.
No gravity, so no collapse.
It just quietly stops fitting.
Slowly becoming a problem itself, even if it was supposed to be a solution to a problem.
The (quasi) law of mean meaning
Since we could pretend we are in "a lawless domain" anyway, let me add one more quasi-law to the collection.
Why not making up another anecdotal law?
Go back to the family for a second.
Did the information about the birthday travel from Grandma to Theo?
It seems so. Theo knew about the party. He brought a cake.
But what reached Theo was not Grandma's knowledge. It was Martha's text message - a representation Martha built from her own understanding, which she built from a phone call, which Grandma built from her own plans and her sister's travel limits.
Each interaction was a representation transformation. Each transformation lost something (the diet details, the reason for the date) and added something ("cake for 12" - Grandma never said twelve).
Gregory Bateson defined information as "a difference that makes a difference". To whom, dear Reader? To someone, for some purpose.
So here it goes:
Information is mean - stingy, withholding - until a receiver makes it mean something. By itself it does not carry meaning: it needs a carrier.
Three consequences follow (if you believe the quasi-law, of course):
- There is no canonical representation. A date, an event, an obligation, a delivery - none of them is the birthday. Looking for the model is chasing reality (we saw where it leads in The ambiguity, the curse and the fallacy of domain model).
- Ambiguity is conserved, not eliminated. You can't remove it. You can only move it to a boundary where someone resolves it - a person, a mapping, a translation layer. Martha resolved "which mom" for Tom, but nobody resolved "which diet" for Theo.
- A representation is judged by the decisions it supports. Not by how faithfully it mirrors "reality". Zoe's card did its job. Theo's message didn't.
Now, if you squint again, you'll see that this is what we do every day as system designers.
We choose which concepts become explicit.
We choose their representations.
We choose who exchanges them, and where interpretations happen.
We structure information and interactions in the certain way, to achieve something.
We design a system of meaning that tries to solve somebody's problem.
What does 1 mean? I don't know, you tell me.
Sometimes it is an order status, sometimes it's quantity (kilograms), and sometimes literally no one knows.
What about null?
Sometimes it is an absence of value, sometimes it's a placeholder, and sometimes literally no one knows.
A bit (= binary digit) is a contextless unit of information.
People need to name the concept to frame the context, express the perspective and attach meaning.
Which does not travel with the information.
Same table, other room, other city
You might have noticed, dear Reader, that the change of date reached people differently.
Let's rewind and look at it through distance (if you read Modularity Uncertainty Heuristic or "Microoffices" vs "Officeolith", you know I like this game).
Same table. Martha says "Sunday now, Aunt Rose can't make it on Saturday". Tom nods. If Tom misheard, Martha would see his face and correct him in a second. The representation is poor - four words - but it doesn't matter. Shared context does the heavy lifting.
Other room, same house. The calendar entry still says "Sat". Zoe reads it on her way to school. To correct it, somebody needs to notice it's wrong, walk over, and fix it. Nobody did. A representation that was "good enough" at the table became a lie on the fridge.
Other city. Theo has only what Martha sent him on Monday. He can't lean over and ask. He can't read Martha's face. Everything he knows must be inside the message itself - and the message did not say "which diet", nor "it might change". So the cake arrived. With sugar. On Saturday.
See the pattern?
The farther apart the participants (the elements), the more meaning must travel inside the representation itself, because less of it can be rebuilt from shared context.
Distance turns context into contract.
And it mirrors the Modularity Uncertainty Heuristic, this time for information. When participants are close, misunderstandings are hidden but cheap to fix. When they are far, misunderstandings surface quickly - but fixing them means renegotiating a published contract.
And it is always related to feedback loops.
Receiving a signal, interpreting it, learning from it and acting upon it.
It's the true nature of "the desired agility" (see (Fr)Agile)
Now translate it to our daily job:
- inside a function or a module - shared types, implicit assumptions, a rename takes seconds,
- between modules in one process - explicit interfaces, a change ripples through call sites,
- between services - schemas, serialization, versioning, an event that must carry its own context because the consumer cannot ask "what did you mean?".
Splitting the office doesn't only move people apart. It forces us to redesign the way they interact.
That's the hidden cost of distribution.
Knowledge attracts knowledge
Let's fast forward. The family survived Saturday (the cake was eaten anyway - Tom and Zoe made sure of it).
Sunday's party is getting closer, and something interesting is happening.
"Grandma's birthday" is not only a date anymore.
It now has a guest list. A new cake (sugar-free this time). A ride for Great-Aunt Rose. A gift that everyone chips in for. A seating plan (Uncle Theo and cousin Mark don't talk since the wedding). A photographer, because "she turns 80 only once".
Where did all that land?
Into "the birthday". And into Martha's head.
Every question goes through her: "Ask Martha". Every message she sends is a pale projection of what she knows.
If you read The knowledge gravity problem, you might already smell it, dear Reader.
The moment someone named "Grandma's birthday", a knowledge boundary was established. A named space. And this space started attracting concepts that felt conceptually close to it - the cake, the ride, the seating, the gift.
The more it attracted, the stronger it pulled.
Until "the birthday" knew everything about everything. A God concept, wearing a party hat.
All inside Martha's cognitive, conceptual boundary.
A single perspective integrating all perspectives.
As I said in that tale - I can't prove it. The formula I played with was made up, a thought experiment. It's an observation I keep making, not a law.
But look what would happen if the family named things differently:
- cake order - Theo's concern: size, diet, delivery time,
- guest arrival - who comes, when, who needs a ride,
- gift collection - who paid, what we buy,
- the card - Zoe's concern, and only Zoe's.
Smaller named spaces. Each with its own representation of "the birthday", carrying only what it needs.
Of course, The law of eventual composition never sleeps. On Sunday at 4 PM, all of it must compose back into one party, in one living room. In "the runtime".
There's no free lunch. Not even at a birthday party.
Namespace?
Did you notice the phrase I used a moment ago, dear Reader?
A named space.
Let's bring a tiny line from .NET C#, innocent one:
And what do we usually do with namespaces?
We treat them as a technical necessity. Something that must mirror the folder structure. Something that avoids name collisions. A place to dump Models, Services, Helpers and the eternal Common.
Plumbing.
But read the word slowly. Name. Space.
A space in which names mean something specific.
Let's go back to our four birthdays:
Three spaces.
Three meanings of "a birthday".
Three perspectives of "a birthday" (are they only applicable to "a birthday"?).
Not because we were clever with names - because each name lives in its own space, where it means exactly one thing.
That's not plumbing. That's contextual decomposition.
In Time, angle and depth: dimensions in software design we saw that "absolute" concepts like User, FloorPanel or GroupChat stop existing once we slice them by angle (whose perspective?) and by time (when does it appear?). Our family did exactly that, without any diagram: Martha's birthday lives before the party (planning), Theo's lives at the moment of delivery, Zoe's at the moment Grandma opens the card.
A namespace is one of the cheapest tools we have to make such perspectives visible. (and if you want to go further, there's Context Segregation Principle)
It helps us with three things at once:
- conceptual integrity - inside a namespace, names are strongly coupled with each other, and this is a desired thing; integrity is local, not global (Fred Brooks would forgive me, I hope),
- structuring representations - what lives inside a namespace is a representation built for one purpose,
- structuring interactions - what crosses a namespace boundary is a hand-off, a transformation.
So next time you see using Family.CakeOrder; at the top of a file in Family.Card, ask yourself: why certain representations need to interact?
And when the namespaces are Models, Services and Helpers?
It's like organizing the family by "things written on paper" and "things said aloud".
Technically correct.
Conceptually useless.
Even dangerous.
A namespace is a boundary of meaning, not a folder.
Composing, decomposing, sensing
Let me ask you something, dear Reader.
Where did Martha do her "design work"?
She never opened an IDE. She never drew a box-and-arrow diagram (I hope - otherwise we'd need to discuss the ambiguity of arrows).
And yet she was constantly doing what we, system designers, are paid for:
- she sensed that the cake and Grandma's diet belong together - cohesion,
- she sensed that every change of date touches everyone - coupling,
- she decided Zoe only needs "card, Sunday, Grandma's place" - a boundary,
- she split the work into Theo's part and Tom's part - decomposition,
- and she knew that on Sunday all of it must meet in one room - composition.
Composing, decomposing, establishing boundaries.
All by sensing coupling and cohesion. On various levels - between concepts, between people, between households, between cities.
Here's my (slightly heretical) claim:
Coupling and cohesion are not properties of code. They are properties of a system of information. The code only shows the side effects - like symptoms showing that something is going on underneath.
When we notice a "god class", a chatty pair of services, or a module that changes with every feature - we're looking at symptoms. The disease lives elsewhere: in how people exchange information, in which concepts they named, in who needs to know what from whom.
I wrote about it some time ago in Systems: by, with, for people - the systems we build, grow and operate are consequences of communication between people.
Mr. Conway would probably nod here.
So if we want to see coupling and cohesion where they originate, we need to look away from the code for a while. Listen to the conversations. Watch who asks whom. Notice which words keep attracting other words.
When did you last look for coupling outside of your repository?
Made in our image
Earlier I said that software has no gravity. Nothing falls down.
I lied a bit.
There are no physical constraints, true. But it doesn't mean there are no constraints at all.
Look at what the family's "system" was made of.
A birthday - a convention humans invented to count years. A date - a convention on top of a calendar, another convention. A promise to bring a cake. Trust that Martha's message is accurate. Trust that the calendar entry is up to date (oops).
None of these things exist in nature. They exist because people keep them alive - by exchanging information, by interacting, by trusting each other.
"The beauty is in the eye of the beholder."
And guess what, dear Reader - this is the world of almost every domain we work in.
Invoices, contracts, orders, accounts, appointments, permissions, money itself. A world created and maintained by human beings, held together by information exchange, interactions and trust.
The world that exists, because people can name things, agree on their meaning, and communicate that meaning through symbolic representations.
Whatever we build reflects that world.
But it goes further.
Our methods and techniques reflect us. Layers, modules, contexts, "one reason to change", naming conventions - why do we need them?
Because our heads can hold only a handful of things at once.
Because we need names to think, to be constrainted by those name-frames.
We designed the tools around our own limits.
As if we were gods creating worlds in our own image - and projecting our own constraints onto everything we create.
So the constraints are there. They are just not made of steel and copper.
They are made of people and their understanding.
Cheap structures, expensive misfits
Now, let's bring the elephant into the living room. Or rather - the tokens.
Producing structure has never been cheaper. Ask for FamilyEventManagementService with fourteen entities, a repository per entity and a nice "REST API" (can you spot an irony here, dear Reader?), and you get it before your coffee cools down.
It compiles. The tests are green. It looks like work.
But which birthday did it model? Martha's? Tom's? All four squeezed into one Birthday class with an IsActuallySunday flag? (dear Reader, you know what I think about booleans)
Here's the uncomfortable part.
AI made representations cheap to produce. It did not make them cheap to be wrong about.
"Fit" - Christopher Alexander's word for the absence of misfit between form and context - is not generated from a prompt.
Isn't that just disambiguation, done right, for this one context, this one purpose?
In software engineering, a suspected "lawless domain", the ambiguity won't break a bridge.
It will accumulate.
Quietly. As mappers, translation layers, "special cases", flags, and bugs nobody can explain. Faster than ever, because producing it is faster than ever.
So who notices?
An aware operator.
Donald Schön, in The Reflective Practitioner, described design as a reflective conversation with the materials of a situation - the material that feeds signals back (emits "diagnostic signals").
Alexander also noticed we usually detect "fit" only through the misfits.
Don Norman, in The Design of Everyday Things, noticed something similar - good design is invisible, because it produces no friction while interacting with it.
Our material is representations (which are information structures and interaction structures). And it whispers back too, if we listen:
- a name that needs a comment to be understood,
- a concept that needs three flags to be represented,
- a translation layer that keeps getting more fluffy and hairy,
- a test that is painful to write,
- a change that ripples through places that "shouldn't care".
Those are diagnostic signals. Someone has to receive them, interpret them, and use them as feedback to correct the direction.
Tokens can produce what hands produce. The head that reads the material and the heart that cares whether it fits - that's still on us (I explored it more in Hands, heads and hearts: from coding to caring).
So what does it take to be a good system designer?
Not a framework. Not a pattern catalogue. Not a faster generator.
Understanding how to represent concepts from the human world - by structuring information and by structuring interactions. Knowing that every representation is a decision.
That's the craft. The code is how we write it down.
And eventually the bridge might fall down, as representations fail to produce faithful reflections of perspectives on physical reality.
What now?
I won't command you to learn the (quasi) law of mean meaning by heart. No exam tomorrow.
But next time someone says "it's just code", maybe think of Theo standing in front of Grandma's door.
On Saturday.
Nothing crashed.
No exception was thrown.
And still, the system failed.
That's the ambiguity of software, dear Reader.
We think we're building running artifacts.
We're designing how people's knowledge gets represented, exchanged and translated - and the running artifact is where it happens to execute.
What representation are you designing right now - and for whose purpose?