hgrsd

Drawing boundaries

Introduction

I have often felt that there is a kinship between software design and conceptual analysis. Both practices are fundamentally about drawing boundaries; they are concerned with demarcation and categorisation. Software design, like conceptual analysis, requires grouping together things that, according to some intuition or heuristic, belong together; and separating those that do not.

Until now, this thought has been a pleasant and rather amorphous way of connecting two aspects of my life: a degree in philosophy, and a career in software engineering. I have never really interrogated or developed it.

In this article, I want to explore some this supposed kinship. In particular, I want to talk about the role of boundary-drawing and intuition in both software design and conceptual analysis.

Software design

We need to have a workable definition of "software design" to be able to draw parallels between it and conceptual analyis. The term is used relatively loosely in the industry and can denote multiple different things. When I speak of "software design", I refer to the way in which software systems are structured.

I am concerned with how systems are broken up into subsystems, components, and modules, in a way that lowers the cognitive load of someone working on that system.

In the words of Larry Constantine: software design is about the organisation of a software system from the perspective of "human beings trying to understand the code", not systems executing it.1

Conceptual analysis

Conceptual analysis is the philosophical practice concerned with defining the essence of concepts. This is generally done by formulating the necessary and sufficient conditions for something to be an instance of X, where X is the concept under investigation. Something is X if, and only if, it satisfies conditions Y and Z.

This is all quite abstract. Let me give an example. Imagine I want to define the concept of "sandwich". I claim that is a food made from meat and/or cheese and/or vegetables enclosed in bread."2 Then one of my objectors formulates a counterexample to test my definition: what about a hotdog? A hotdog is meat enclosed in bread, so it meets the criteria I have formulated. Yet, according to our intuitions, it is not a sandwich.

This kind of interrogation and refinement of a concept's boundaries, based on the language that we use and the intuitions that we hold, is characteristic of conceptual analysis.

Boundaries

Software design, like conceptual analysis, is a practice of boundaries. To build a well-designed software system, those boundaries must be drawn at the "right" places. Boundaries in software systems can take many shapes. They are drawn around functions, classes, modules, and services. Software engineers routinely ask themselves questions like: "does this belong in this function, or should I create a new one?", "does this class have too many unrelated responsibilities"?, or "should we create a new service for use case X, or does it fit with our existing service?".

Descriptive and inventive boundary-drawing

I want to make a distinction between two types of boundary-drawing: descriptive and inventive.

In the practice of conceptual analysis, the boundaries that are being drawn are almost always drawn around a concept that exists. I should note that the meaning of "exists" in this sentence is a deeply controversial subject in philosophy. Yet controversy aside, conceptual analysis is in the business of defining the content of concepts that are "out there in the world", for some definition of "being out there."

In software design, boundary-drawing is sometimes descriptive. This is true, for example, for a practice like Domain-driven Design (DDD). The key insight of that practice is that software is embedded in an pre-existing domain, about which bodies of knowledge already exist. A proponent of DDD would argue that a well-designed software system has boundaries that are aligned with relevant conceptual boundaries present in the domain in which the software operates. Although the collaboration between software engineers and subject-matter experts in the practice of DDD sometimes yields "novel" boundaries, the effort is by and large to unearth existing boundaries and to model those in software. This is a descriptive pursuit.

Inventive boundary-drawing is fundamentally different. Instead of deciding which things do and do not belong in a certain place, based on a given concept, inventive boundary-drawing involves the creation of a concept that unifies a set of phenomena. This kind of boundary-drawing is also commonplace in software design. Think of the well-known desire of software engineers to "abstract away" messy, complex, or often-recurring pieces of software, based on the realisation that those behaviours have something salient in common. Drawing a boundary around those behaviours and naming the resulting concept is an inventive act.

What makes a good boundary?

The factors that decide whether or not a given boundary is "good" are highly context-dependent. It is here that software design, as a much more practical pursuit than philosophy, departs markedly from conceptual analysis.

In conceptual analysis, a good boundary is one that accurately tracks the content of the concept that it tries to demarcate. (This is a reductionist statement. It deliberately glosses over the fact that it is unclear what "accurately track" means, or that some conceptual analysis is highly normative instead of purely descriptive).

In software design, a good boundary may be one that accurately tracks the content of a given concept. But what matters more is whether a certain boundary is useful. Recall the definition of software design as the attempt to structure systems in ways that lower cognitive load; making them easier to understand, maintain, and extend by others, or ourselves at a later point. Whether or not there is any kind of "truth" to a boundary in a software system is relevant only insofar as that "truth" makes the software feel more intelligible or natural.

In this sense, boundary-drawing in software design can perhaps be better thought of as an aesthetic rather than philosophical pursuit. (That said, it is a widely held belief that in order for something to be aesthetically pleasing, it should have some "truth" to it...)

The precedence of usefulness over truth is most clearly the case for inventive boundaries. A novel abstraction is only good if it makes the software easier to work with, understand, and maintain. If it does the opposite, it is a bad abstraction——even if, in some sense, it is "true".

Yet even for descriptive boundary-drawing in software design, the alignment of a piece of software's boundaries with some pre-existing concept is a matter of practicality——not truth. For example, the practices of DDD do not seek to build "true" software; rather, they are meant to achieve a common language between the software, its engineers, and the domain, with the purpose of making it easier to develop and maintain that software.

Intuition

Although the goals of drawing boundaries in software design (usefulness) and conceptual analysis (truth) are different, the strategies they employ are similar. I find this interesting, especially because in the field of software engineering there is limited introspection into the practices of software design, or acknowledgment that there are entire branches of philosophy that are concerned with similar questions of demarcation.

One key boundary-drawing strategy that is shared between conceptual analysis and software design is to appeal to intuition as a means of deciding which things should be in or outside of the boundary.

In conceptual analyis, such an appeal to intuition is often embedded in a counterexample: one may claim that "food made from meat" is a bad boundary for the concept of "sandwich", because it would include a hotdog which, according to our intuition, is not a sandwich.

Although this is rarely made explicit, the same happens in software engineering. Every so often there are attempts to formalise the drawing of good boundaries. An example is the notion of "architectural fitness functions", introduced in "Software Architecture: The Hard Parts",3 which score a system against a particular architecturally desirable quality.

But more often than not, when a software engineer argues that things belong together in a function, class, or module, they do so by reference to their intuition. "It feels that this is the right place for X", or "Y feels a little bit out of place here". Of course, these statements may be couched in jargon like coupling and cohesion, or SOLID principles. But once we have to define what makes a class cohesive, what it means to have a "single responsibility", or where to break up modules in order to reduce coupling, intuition will generally take over.

Is this a bad thing? In the realm of conceptual analysis, the use of intuitions to draw conclusions about boundaries is heavily cricitised: intuitions are unreliable, highly idiosyncratic, and always in flux. Surely, therefore, they cannot help us distil the essence of a concept.

But this does not mean that it is a problem for the practice of software design. Recall that in software design, what matters is the usefulness of boundaries. If intuitions lead to useful boundaries even though they do not yield "truth", then that is fine.

But what I do think is dangerous is the lack of acknowledgement of engineers engaged in software design that their intuitions play such a significant role in their work. It is only when we realise the crucial role the play that we can critically interrogate them: where do they come from? Are they shared with others? Are they useful? Why?

In order to encourage asking these types of questions it is important to show that software design is not an insular practice, but that it has a pedigree in other areas of human thought. I hope this blog article contributes a little to that goal.

Notes

1 See Larry Constantine's foreword to Kent Beck's "Tidy First?" (O'Reilly, 2023).

2 This example is taken from a public lecture delivered by Karen Bennett, the text of which is available here.

3 See Ford et al, "Software Architecture: The Hard Parts" (O'Reilly, 2021).

Tags: #philosophy #software