Source of Truth in SWE

Discussion of a common thought pattern

1048 words

v1

Originally published on eighttrigrams.substack.com on December 6th, 2025

A common pattern in software engineering is that of the Source of Truth. One of the simplest examples of it is that of two datastores, where one contains data derived from the other, which are possibly further manipulated because the purpose of the second datastore is to provide the data in a certain way which is different from how the original datasource could do it. To be concrete, we could have a database and a cache for faster access, or a database and a search index, for quicker search. Or we could have database followers in distributed systems.

File:2019 - Wiener Karlskirche mit Teich und Hill Arches Skulptur am Abend.jpg
2019 - Wiener Karlskirche mit Teich und “Hill Arches” Skulptur am Abend. [commons]

Apart from datastores, the other main area where we speak of Source of Truth is that of code, which is commonly considered as one. Software by its nature is extremely complex. It is built over time, often in collaboration with many individuals. The intention at any given time when modifying an existing piece of software is focused on a specific change of behaviour, as contrasted to its current behaviour; which means each change is a “diff” limited in time and (architectural) scope, when seen in the context of the whole lifecycle and expanse of the codebase of the software.

When someone is interested in why the software reacts in a certain way under certain circumstances, or, like maybe a product manager would, inquires about the behaviour of the software under certain hypothetical circumstances, The Code is often cited as the ultimate source of truth. That is, whatever the originally stated, collected or documented requirements may be—whether those happen to be bigger vision documents or those focused on smaller changes (usually captured in tickets) as described above.

When a question about the system has to be answered for stakeholders, code being the source of truth can mean that one reproduces a certain state inside the system to demonstrate how it works under certain circumstances. But this implies already that the behaviour looked at is determined by the code which produces it. So this is in a way the same as looking at the code directly, which often needs to be done anyways, when certain behaviours cannot be easily reproduced. To repeat, code itself is usually seen in software systems as the source of truth.

Which brings us to the question of tests. Historically, the case has been made that tests, which suggest on the basis of material world intuitions that they are something which happens after something is built and before it is shipped, and specifications, which are something that is written before building, are essentially the same in software engineering.[1] There exists a spec/test duality, about which people have felt so strongly at times that you see it in “spec” file endings, where other frameworks say “test”.

So here things get interesting, because this puts the source of truth quality of code in question. There exists a deterministic relationship between (functional) tests and the code they cover. The pragmatic case for code being the source of truth is that in the field you never find 100% test coverage, although it is possible.

But, by triangulation[2], all code could theoretically be produced from tests/specs. Specs, to see it from another angle, are after all the requirements, formulated in the most unambiguous way possible (exactly as unambiguous as code itself). In short, the argument here is that with 100% test coverage you could scrap all the code and re-create it from the tests.

The motivation for performing such supposedly “mental gymnastics” (of flipping things on their head) is justified, though, namely that one could want to preserve the original (functional) behaviour while changing the underlying or emerging non-functional characteristics of a system. Examples:

  1. Re-factor the code, to improve its structure,[3] readability, maintainability, extensibility.

  2. Re-factor the code for speed, reliability, security, …

  3. Port the system or parts of it into another programming language or platform.

So, as we see with the test/spec duality, there are valid reasons to question the seemingly obvious primacy of code as source of truth. And although nothing comes close to the unambiguous status of tests, this opens up the question again of whether design documents of various sorts (as produced in requirements gathering phases as well as later on during development) should be kept up to date.

I would argue tendentially, yes. I mean, in the lightest form this just would mean keeping the tickets and records and not deleting artifacts afterwards. The catch here, though, is that these are of limited use, since they describe more often than not a specific behaviour change, as I explained at the beginning. We also have automated change tracking, of course, in the form of version control. And then, for completeness, for bigger decisions we also have architectural decision records and requests for comments, which both document why certain decisions have been made.

What is missing, I found, are often dedicated efforts to keep designs up to date, or actual comprehensive documentation of features. I remember once, for lack of a designer in our team, I (an engineer) produced all the screens and the flow between them. The feature in question was itself quite complex, in terms of flows, and also because for the feature to become visible, the application had to be brought into a certain state, which was not easy to bring about for everyone. So I thought it would be handy to update the screens and the flows after I implemented the feature.

I was quite pleased and wished to have seen such efforts more often, but the reality is that, like all documentation, we are dealing with secondary artifacts. This is precisely the reason why in “code quality” books it is often said that when you are explaining too much in function docstrings, you should try to improve the function name first to reflect what you are trying to say. The understanding is that docstrings inevitably go out of date.

Which brings us full circle. The source of truth pattern is specifically that you have a clear understanding of which artifacts are disposable and which are not. That is, which artifacts can be faithfully re-created from the other artifacts.

Footnotes

  1. In software engineering, tests, as tests, are usually seen as regression tests, by which we ensure that previously intended functionality does not get broken when we add new functionality on top of existing one.

  2. See my earlier article The Triangulation Method here: link.

  3. Especially when it comes to code structure, I think, the argument for seeing the test as source of truth is strong. For code of wildly varying quality can “pass the tests.” And, when the architecture is good, that is, when a good relationship between loose coupling and high cohesion prevails, it is an option to accept lower code quality on a piece of relatively isolated code as long as it passes the tests; a consideration which is especially relevant in the age of AI-assisted coding. To be clear, though, when code needs to be extended, a necessary pre-cleanup has to be performed to avoid things becoming really difficult to maintain. The point here is that one can defer such cost into the future, and thereby possibly avoid it entirely, should subsequent changes to that code never happen.

# Comments

Leave a comment