Heaps of Slime

The sorites paradox is a fancy name for a stupid-sounding problem. It’s a problem of meaning, of the kind software developers have to deal with all the time, and also of the kind software generates all the time. It’s a pervasive, emergent property of formal and informal languages.

You have a heap of sand. One grain of sand is not a heap. You take away one grain of sand. One grain of sand makes little difference – so you still have a heap of sand.

You have a grain of sand. You add another grain. Two grains of sand are surely not a heap. You add another. Three grains of sand are not a heap.

If you add only a grain or take away only a grain of sand, since one grain of sand can hardly make a difference, how do you tell when you have a heap?

That’s the paradox. The Stanford Encyclopedia of Philosophy has a more comprehensive historical overview.

 

Slime Baking

To make software, you build a machine out of executable formal logic. Let’s call that code a model, including its libraries and compiler, but excluding the software machinic layers below that.

The model has different elements which we represent in programming language structures, usually with names corresponding to our understanding of the domain of the problem. These correspond to phenomena in two ways: parsing, and delegation to an analogue instrument. Parsing is the process of structuring information using formal rules. An analogue instrument from this perspective is a thermostat, a camera, a human user, a rabbit user, or possibly some statistical or computational processes with emergent effects, like Monte Carlo simulations or machine learning autoencoders.

You can imagine any particular software system as a free-floating machine, just taking in inputs and providing outputs over time. Think of a program where all names of classes, functions, variables, button labels, etc, are replaced with arbitrary identifiers like a1, a2, etc, (which does have some correspondence to the processing happening inside a compiler, or during zip compression). We tether this symbolic system to the world by replacing these arbitrary names with ones that have representational meaning in human language, so that users and programmers can navigate the use and internals of the system, and make new versions of it.

To make it easier to understand, navigate and change this system, we label its interface and internals with names that have meaning in whatever domain we are using it for. Dairy farm systems will have things named after cows and online bookstores will have data structures representing books.

We have then delegated the problem of representation to the user of the system – a human choosing from a dropdown box, on a web form, for example, does the work of identification for the user+software system. But we run slap bang into the problem of vagueness.

Most of the users of our dairy software will not be on quaint farms in the English countryside owning one cow named Britney, so it will be necessary to represent a herd. How many cows do you need to qualify as a herd? Well, in practice, a programmer will pick a useful bucket data structure, like a set or a list, and name that variable “herd”. Nowadays it would probably be a collection in a standard library, like java.util.HashSet. The concept of an empty collection is a familiar one to programmers, furthermore there is a specific object to point to called “herd” (the new variable), so a herd is defined to be a data structure with zero or more (whole) cows. Sorites paradox solved <dusts hands>. And unwittingly too.

herd = []
# I refute it thus!

The loose, informal, family resemblance definition of a concept (herd) gets forced into a symbolic structure, like an everyday Python variable, to treat it as an object in a software system. This identification of a concept with a specific software structure is called reification. In the case of a herd (or a heap of sand) the formalism is a fairly uncontroversial net win; after getting over the slightly weird idea of the empty herd, the language will may converge around this new more formal definition, at least in the context of the system. (Or it may not. It is interesting to note the continuing popularity of the shopping cart usability metaphor, a concrete physical container that can be empty, rather than say, a pile of books that is allowed to have zero books in it.) 

The sorites might be thought of as a limiting case of vagueness, due to the deliberate simplicity of the concept involved (one type of thing, one collection of it). There are much messier cases. Keith Braithwaite points out that software is built on a foundation of universal distinguished types, and it is a constant emphasis of training in science and engineering. People without that training tend to instead organize their thinking around representative examples, and categorize by what Wittgenstein called family resemblance, ie, sharing a number of roughly similar properties. Accordingly Braithwaite suggests foregrounding examples as a shared artifact for discussion between programmers and users, and using legible, executable examples, as in Behaviour Driven Development (BDD).

Example-driven reasoning is also a survival technique in an environment lacking clearly distinguishable universal rules. Training in physical sciences emphasizes the wonderful discovery of universal physical laws such as those for gravity or electrical charge. Biologists are more familiar with domains where simple universal laws do not have sufficient explanatory power, and additional, much more local rules, are the only navigational aids possible. Which is to say, non-scientific exemplary reasoning was likely rational in the context it evolved in, and additionally, there are many times in science and engineering when we can not solve problems using universal rules. William Wimsatt names these conditions of highly localized rules “ontological slime”, and the complex feedback mechanisms that accompany them “causal thickets”. He points out that even if you think an elegant theory of everything is somehow possible, we have to deal with the world today, where there definitely isn’t one to hand, but ontological slime everywhere.

Readers who have built software for organizations may see where this is going. It’s not that (fairly) universal rules are unknown to organizations, but that rules run the gamut from wide generality right down to ontological slime, with people in organizations usually navigating vagueness by rule-of-thumb and exemplar-based categories which don’t form distinguished types. Additionally, well-organized domains of knowledge often intersect in organizations in idiosyncratic ways. For example, a hospital has chemical, electrical and water systems, many different medical domains, radioactive and laser equipment, legal and regulatory codes, and financial constraints to work within. And so the work of software development proceeds, one day accidentally solving custom sorites paradoxes, the next breaking everything by squeezing a twenty-nine sided Escher tumbleweed peg into a square hole.

 

Lunch

For software applications written for a domain, especially, software acts as a model to the world. This relation even holds for a great deal of “utility” software – software that other software is built on. An operating system needs to both use and provide functions dealing with time, for example, which has a lot more domain quirks than you might at first think.

Model is a specific jargon term in philosophy of science, and the use here is deliberate. For most software, the software : world relation is a close relative of the model : world relation in science. The image of code running without labels, untethered to the world, above, is an adaptation of an image from philosopher Chuang Liu: a map, showing only a selected structure, without labels or legend. We use natural language in all its power and ambiguity to attach labels to structures. This relation is organized according to a theory. Michael Weisberg calls the description, in the light of the theory, of how the world maps and doesn’t map to the model, a construal. Unlike scientific theories, the organizing theory for a software application is rarely carefully stated or specifically taught. So individual users and programmers build their own specific theory of the system as they work, and their own construals to go with them.

Software is not just a model: it’s also an instrument through which users act. The world it models is changed by its use, much more directly than for scientific models. Most observably, the world changes to be more like the model in software. Software also changes frequently. New versions chase changes in the world, including those conditioned by earlier versions of the software, in a feedback spiral. (Donald Mackenzie calls this “Barnesian performativity” when discussing economic models, the CCRU called it “hyperstition” when discussing fiction, and Brian Goetz and friends call it “an adventure in iterative specification discovery” when discussing programming.)

It is this feedback spiral which can eliminate ambiguity in terms by identifying them with exactly their use in software, therefore solving the sorites paradox in a stronger sense. It becomes meaningless to talk about an artifact outside its software context. We don’t argue about whether we have a pile of email, as it is obvious it is a container with one limit at Inbox Zero. This is one sense in which software can be said to be “eating the world”: by realigning the way a community sees and describes it.

There are other forms of software / language / world feedback, including ones that destroy meaning, dissolve formal definitions and create ambiguity. It’s often desirable, but perhaps not always, to collapse definitions into precise model-instrumented formality. Reifying an ambiguous concept by collapsing a sorites paradox into a concrete machine component is simply one process to be aware of when building software; an island of sediment in a river of slime.

References

Braithwaite – Things: how we think of them, what that means for building systems https://www.darkpeakconsulting.co.uk/blog/things-how-we-think-of-them-what-that-means-for-building-systems
Goetz et al – Java Concurrency In Practice
Hyde and Raffman – Sorites Paradox https://plato.stanford.edu/entries/sorites-paradox/
Liu – Fictionalism, Realism, and Empiricism on Scientific Models http://philsci-archive.pitt.edu/11162/
Mackenzie – An Engine, Not A Camera: How Financial Models Shape Markets
Visee – Falsehoods Programmers Believe About Time https://gist.github.com/timvisee/fcda9bbdff88d45cc9061606b4b923ca
Weisberg – Simulation and Similarity
Wimsatt – Re-Engineering Philosophy For Limited Beings

Duckrabbit Bugfeature

Programmer folk art, origin unknown

Programmer folk art, origin unknown

516. If somebody showed me the figure and asked me ‘What is that?’, I could answer him only that way. –I couldn’t answer: ‘I take that to be a . . .’ or ‘Probably that is a . . .’ Any more than I take letters to be this or that when I’m reading a book.
— Wittgenstein, Philosophical Investigations

Duckrabbit. Source: Wikimedia

Clean Sweep

Software engineering isn’t philosophy, as fun as both of them are. There are certainly intersections, as HXA7241 (Harrison Ainsworth) recently described:

The single core idea (to be rather bold and sweeping) in philosophy is the distinction of necessary and contingent: ‘necessary’ being what is always true, what is known logically; ‘contingent’ being everything else, that may or may not be known or true according to circumstance.

The single core idea in software engineering is abstraction: which is the fusion of a fixed part with a varying part. And this maps exactly to necessary and contingent. An abstraction says that within its context a particular thing is necessary – the fixed part – but also that the rest is contingent – the varying part. (A single bit number is always a number – by definition, but it might be 0 or 1 – completely by circumstance.)

It is indeed a sweeping generalization, beautiful in its bold wrongness. Thinking mathematics was a science, Wittgenstein once said, was like mistaking the broom for the furniture. Similarly, when you pick up the broom to clean the room – when you put the toolset to use – the confusion disappears.

Now Ainsworth’s assertion is closer to Wittgenstein than the math / science analogy implies, because he is saying that both philosophy and software engineering are toolsets of a kind. (Elsewhere, in an interesting take I might well return to, he describes software engineering instead as engineering in a computational medium.) Even keeping in mind that in another post software engineering is defined as entirely concerned with how the software works. “It neither changes what is wanted, nor what can possibly be computed,” … but it does change what is wanted – the articulation of a possibility in software changes its future iterations through the evolution of human understanding of that possibility. It is less like a broom and more like a paintbrush. Or a Japanese fan. Picking it up changes the room.

Or a dodgy second-hand chainsaw, which only works when you hold it at a fifteen degree angle and rev the crap out of the engine. The machine-nature of useful semi-broken software – or software engineering – seems to strain the very limits of the metaphor. “Software is clarity,” Ainsworth writes. I guess he hasn’t used Microsoft Word.

A Program Is Articulate

Rearing its head out of Helen’s corner of the twitter-sphere around the occassion of the great Austrian’s 112th birthday (and sixty years since his death) comes the Tractatus Digito-Philosophicus, a recasting of Wittgenstein’s landmark first book into software terms.

2.0122 […] (It is impossible for words to appear in two different roles: by themselves, and in programs.)

There are several appealing elements to this self-described “odd venture”. One is that the translation is to a degree automatic, based on a simple search and replace table found at the end. It is logical positivism via sed. Another is that the Tractatus was produced during and soon after Wittgenstein was working as an actual engineer – first as an aviation research engineer at Manchester University, and later supervising technicians in a supply depot in World War I. He was not temperamentally very well suited to engineering work. Biographers have traditionally downplayed this as an intellectual influence, though Susan Sterett explores interesting parallels and possible influences around the idea of engineering models in the well-titled and readable Wittgenstein Flies A Kite.

The Tractatus Digito has the virtue of poetry (metaphor, simile, and so on) in presenting the same information from a different perspective and so firing different connections in the brain. But it’s more systematic than poetry as well. It’s not just a martial arts metaphor, as rhetorically useful as they can be. To contrast with an example close to hand, attempting to describe software in Confucian terms is a project fuelled as much by juxtaposition and analogy as correspondence. The mapping to that world will always be a partial one.

Ainsworth, rather, has noticed what every undergraduate programmer should know: that programs are sequences of logical propositions. So Wittgenstein is necessarily writing about software, or perhaps more specfically, because there is no social dimension, about programs. Our thinking about software is intertwined with its origins in the 1920s. This partial recasting is valuable in the same way a Turing Machine simulator is valuable. Sure, some of the resulting sentences don’t really make sense. Yet bringing registers and sorting algorithms into the book that invented truth tables feels less like visiting a foreign land, and more like hearing a friend talk excitedly on their return to the old family home.

3.141

A program is not a blend of instructions. – (Just as a theme in music is not a blend of notes.)

A program is articulate.

XIII.3 Name Oriented Software Development

子路日:卫君待子而为政,子将奚先.子日:必也正名乎. 子路日:有是哉!子之迂也.奚其正.子日:野哉由也.君子于其所不知.蓋阙如也.名不正,则言不顺.言不顺,则事不成.事不成,则礼乐不兴.礼乐不兴,则刑罚不中.刑罚不中,则民无所措手足.故君子名知必可言也.言之必可行也.君子于其言,无所苟而已矣. — 论语 十三:三

Tzu-lu said, ‘If the Lord of Wei left the administration (cheng) of his state to you, what would you put first?’ The Master said, ‘If something has to be put first, it is, perhaps, the rectification (cheng) of names.’ Tzu-lu said, ‘Is that so? What a roundabout way you take! Why bring rectification in at all?’ The Master said, ‘Yu, how boorish you are. Where a gentleman is ignorant, one would expect him not to offer any opinion. When names are not correct, what is said will not sound reasonable; when what is said does not sound reasonable, affairs will not culminate in success; when affairs do not culminate in success, rites and music will not flourish; when rites and music do not flourish, punishments will not fit the crimes; when punishments do not fit the crimes, the common people will not know where to put hand and foot. Thus when the gentleman names something, the name is sure to be usable in speech, and when he says something this is sure to be practicable. The thing about the gentleman is that he is anything but casual where speech is concerned.’ — Analects XIII.3 (Lau)

If something has to be put first in programming, it is, perhaps, the rectification of names. Names are what place the system and the not-system in the same reality. They are the bridge between the externalized machine without use and the internalized emotion without expression.

What in Confucian philsophy we call the rectification of names we can in Confucian software call Name Oriented Software Development. This does not yet exist, but it can be defined simply. Name Oriented Software Development uses a toolset that promotes the continuous rectification of names across all the interstices between natural languages and machine languages in the system.

The nominalist toolset should span package, class, variable and method names. It should span library and project names. It should cover layers of code around the core system, including message protocol definitions and protocol dictionaries, configuration entities, unit and performance tests, and run scripts. The aim in managing machine facing names is to enforce consistency and coherence of names while making precision in naming, including type restriction, easy. The same name appearing in different machine-facing contexts, eg a message protocol field in a script and a Java class, should be linked in an automated and machine verified way. This might at first seem to make the internal technical dialect (namespace, one could say, if it were not taken) too rigid. This is not the intent, and if we look at the rename variable refactoring, not its effect in smaller scopes. It is because we can execute refactorings in a reliable, automatic way that it becomes viable as a low-risk change. This is the same across the entire internal technical dialect – enforced formal consistency allows mutability to be low risk.

By contrast, the aim in managing people facing names is to allow a consensus jargon to emerge backed by a literature of interaction and aspiration which is still moored to the technical reality of the system as it exists. This covers specifications, use cases, test documents (even and especially automated acceptance tests), application messages or labels for users or external parties, internationalization, log messages (ie, a UI for support) support and developer faqs, and user manuals and documentation. Changes to this shared understanding should be reflected as immediately as possible and not tied to a long software release cycle. A label, for example, is essentially a piece of simple key-mapped static data; changes to it can therefore be routine and implicit. When treating this sort of text as static data, it is essential to keep it automatically linked to the running widgets themselves – otherwise it is merely the domain of style guides and moral exhortation. A true dialect is owned by a community – a folksonomy – so the entire community must be able to use and contribute to it. The editors for these documents should be as broad as possible within organisational constraints. Where editing constraints exist (organisational not technical), annotation on these documents should be easy. Cross referencing within the docset and outside it to external sources of expertise (for instance on domain jargon) should also be easy to add and maintain.

Or, via Wittgenstein, Tractatus 7: Whereof one cannot speak clearly, one must damn well link to a wikipedia entry.

This approach owes more than a little to Knuth’s Literate Programming. A distinction is that instead of putting documentation with source code in a single artifact to be owned by a single philosopher-developer auteur, it puts editable, often executable content in the hands of a community of expertise.

Historically, the Confucians became increasingly sophisticated in their theory of names. I know of no record of Confucius addressing names changing over time, apart from a general openness to political reform (Analects IX.3). Indeed, as old Kongzi was often conservative, the quote above might reasonably be taken to advocate reverting to old names now in disuse. Xun Zi (荀子), who lived in the century after Confucius and was one of his major intellectual heirs, saw fit to reuse the Mohist (墨家) theory of names.

单足以喻则单,单不足以喻则兼; […] 名无固宜,约之以命,约定俗成谓之宜,异于约则谓之不宜。名无固实,约之以命实,约定俗成,谓之实名。名有固善,径易而不拂,谓之善名 — 荀子 – 正名 6-8

If a single name is enough to communicate, make it single; if not, combine. […] Names have no inherent appropriateness, we name by convention; when the convention is fixed and the custom established, we call them appropriate, and what differs from the convention we call inappropriate. No object belongs inherently to a name, we name by convention, and when the convention is fixed and the custom established, we call it the object’s name. Names do have inherent goodness; when straightforward, easy and not inconsistent, we call them good names. — Xun Zi – Rectification of Names 6-8 , AC Graham translation

AC Graham’s use of the word “combine” (兼) above is in the sense of “compound”. This is the term the Stanford Encyclopedia of Philosophy uses in preference. That entry points out Xunzi’s concern with names is also in rebuttal to the paradoxes of the Chinese sophists. Furthermore, Xunzi is rather more open to mutability and the pragmatic construction of language from a vernacular folksonomy. (The term 俗成, translated as convention, includes 俗 which now spans meanings including custom and vulgar.)

Computer science launched itself out of the western analytical tradition, though. A sometime description and criticism of Object Oriented design is that it is reheated Platonism. See, e.g., blogs by Vlad Tarko and Richard Farrar. ((Should the frequent light analogical treatment of Platonism and software sound a note of alarm for this very project? Perhaps. But there is heavier academic firepower behind us as well. Are we not grappling with code, which Berry and Pawlik call the defining discourse of our postmodernity? In an article that has more code metaphors than a house full of crack-addled Java-monkeys at teatime.))

The platonic analogy has legs. We do construct a parallel world of sorts in code. It is also revealing to think of classes as ideal representations of some external physical element. Isn’t that why we often fail as programmers? We critique the world for being less perfect than our ideal programs, for failing to match up to their strict conditions, for making them ugly, for crashing them. Code, and OO, can have a kind of brittleness that happens when we stop thinking of software as a model of the world and start thinking of it as the true world. We fit our shape to the name.

My suggestion is not to stop doing taxonomy – we could not navigate the world and construct alternative worlds out of software without it. We couldn’t even speak without it. Instead, we should use Xunzi’s advice and fit our names to the shape. We name by convention. We continually rectify names. If a single name is enough to communicate, make it single. If not, combine.

‘RenameClass’ is the most powerful refactoring. — Michael Feathers