Thesis
This is the (unofficial) thesis I stumbled into for my computer science master's at Portland State University which ended up being about: authoring software history. The proposed method binds together two histories into a single narrative. Those histories are: 1. source code history (revisable) and 2. design decision history (immutable).
1. Problem Statement
1.1. AKM-centric
1.1.1. v1
The following is limited to application-level software architecture decisions (not system-level).
[1], [2]
(1 application-level architecture decisions are often amenable to change)
- have multiple acceptable trajectories
- are intended to change in future circumstances
and thus are not natively represented by the medium of code. [3]
(2 in other engineering disciplines, decisions manifest physically)
[4]
(3 software engineering decisions can be ambiguous)
[1], [3]
Artifacts involved in a sequence of changes to an application often do not contain references to architecture decisions. [3], [5]
(4 software architecture decisions often not made explicit) [6]
- on-boarding, understanding history & evolution of the code
- refactoring, maintenance, code health
- updates to & implementation of requirements, increasing complexity
- maintaining engineering standards, enforcing practices
- analyzing tradeoffs, future trajectories
[1], [2], [7], [8], [9]
(5 architecture decisions are useful)
- completeness, explainability, trustworthiness, quality
- low cognitive load of human interface, ease of exploration, adaptability
- modifiability, ease of maintenance, consistent value & relevance over time
[10]
(6 how might software architecture decisions be accessible)
To address this "architecture decision gap" in the software development life cycle
we propose "structured decision records".
[3], [5]
(7 how can we represent decisions in software)
1.1.2. v2
When software applications are architectured in dynamic, ill-defined environments: design decisions are often made with the intention of revision. [1, p. 2], [2, p. 1]
Yet, design records are rarely accessible and without understanding of previous and current design decisions, revisions in the software life cycle becomes increasingly expensive. [3, p. 1], [5, p. 2]
Unlike engineering disciplines for which static, well-defined environments lend to rigorously established decision criteria which are naturally manifested in a physical design artifact [4, p. 1]: software decision criteria is often ambiguous and continuously evolving (is stateful in nature) which is not naturally by software design artifacts (the code) which can only represent the current, single state. [1, p. 2], [3, p. 1]
- entropy as knowledge is lost to time [7], [9, p. 2]
- agentic workflows which lend towards weaker human understanding [11, p. 5], [12, p. 10]
- agent instantiation requiring context injection [12, p. 10], [13, p. 3]
1.1.3. v6
The process of creating & maintaining software architecture design records is tedious, expensive, sensitive to entropy, and resulting artifacts are of limited continued use. [7], [9, p. 2], [14, p. 4]
In environments of rapid change and uncertainty, decisions are made with the intention of revision. [1, p. 2], [2, p. 1] Yet, when previous design decisions are inaccessible (skipped, implicit, or lost) [3, p. 1], [5, p. 2], [6, p. 1] revisions become increasingly difficult and expensive. [7], [8, p. 3], [15, p. 20]
Agentic workflows simultaneously worsen the design "decision gap" while benefitting from context of previous decisions. [11, p. 5], [12, p. 10], [13, p. 3]
This paper aims to re-define architecture design records as active artifacts and a primary step in the software development life cycle.
1.1.4. v10
In environments of uncertainty and change, software architecture designs are decided with the intention of revision. [1], [2]
Yet, when knowledge of design decisions is incomplete, revisions become increasingly difficult and expensive to implement. [3], [5], [8], [15], [16], [17], [17]
Documentation of such decisions typically produces passive artifacts which are quickly outdated. [7], [9], [14]
Agentic workflows widen this "decision-implementation gap" while simultaneously benefitting from context of previous design decisions. [11], [12], [16], [18]
This paper aims to promote decisions to active artifacts in the software development life cycle which act as a foundation and primary step for generating a changeset.
1.1.5. v11
The day I die is the day I stop deciding.
Collective indecision may surpass corruption as the greatest enemy.
- inability to make timely decisions
- can't take action; paralysis
- action without quality decision
- can take action, but long-term decision context is incomplete
Yet, environments of uncertainty and rapid change demand quality decision making ability. [1], [2]
Rapid change demands rapid change. Uncertainty demands maintaining context to analyze & revise decisions. [5], [7], [8], [9]
Modern software infrastructure enables rapid, incremental, measureable, revertable updates from an application's codebase. [19] Of course, long-term decision making ability is not to be solved… but, there is much help to be had in the process. Most help is to be had in software, where we can make decisions an active instrument in the continuous integration and deployment of a software application.
1.1.6. v12
Throughout the life cycle of a software application, many architectural decisions are made. [20]
These decisions are often made in rapidly changing and uncertain environments. [1]
Rapidly changing environments demand rapid updates to previous decisions. Modern software infrastructure enables methodical delivery of updates. [2], [19]
Uncertain environments, in addition to demanding quick responses, demand context of previous decisions. When you respond in an uncertain environment, you must, at the very least, know what you decided before. Lastly, uncertain environments demand quality decisions over long periods of time. Long-term decision quality remains requiring of hybrid intelligence. One should not generally rely on machine inference.
In practice, maintaining a close to context of prior architectural knowledge is rarely accomplished or at great expense. [5], [9], [21]
Architectural decisions and knowledge are subject to many forms of degradation. Incomplete Architectural Knowledge (AK) results in challenges which quickly compound. [22]
Maintaining AK is naturally an open-ended task, and additionally varies from organization to organization to individual project. Thus, it is an ill-defined task in terms of what is required, when it is done, and if it is done well.
Maintenance of AK is thus a continuously evolving definition & process — but this does not mean it is intractable. And so, in order to enforce maintenance of AK, a decision must be elevated to a first class artifact; ensuring maintenance of AK through time in response to a stimulus, a decision is the origin point of interaction with a codebase.
This AK-implementation gap is worsened by agentic workflows naively bolted onto existing software development processes. [11]
Agentic workflows may also be able to bridge the gap. [12]
Relative to code, AK is a secondary artifact. Yet, much literature about Architectural Knowledge Management (AKM) indicates that AK should be considered first-class artifacts. [3], [14], [23], [24], [25], [25]
Promoting AK to a first-class artifact is under-explored. [20]
1.1.7. v13
Throughout the life cycle of a software application, many architectural decisions are made. These decisions often occur in rapidly changing and uncertain environments. [1], [2]
Rapidly changing environments demand rapid updates to previous decisions. Modern software infrastructure enables methodical delivery of updates. [19]
Uncertain environments, in addition to demanding quick responses, demand context of previous decisions. In practice, maintaining a complete context of prior architectural knowledge is rarely accomplished or at great expense. [5], [9], [21]
Architectural knowledge is subject to many forms of degradation. Incomplete AK results in challenges which quickly compound. [20], [22]
This AK-implementation gap is worsened by agentic workflows naively bolted onto existing software development processes. [11]
Agentic workflows may also be able to bridge the gap. [12]
Creation and maintenance of AK is naturally an open-ended task: interpretations may vary between organizations and projects. Thus what is required, if it is quality, and when AK is complete does not have a clear definition. This makes a first-class representation difficult and why, relative to code, AK has remained a secondary artifact. Yet, much literature about AKM indicates that AK should be considered first-class artifacts. [3], [14], [23], [24], [25], [25]
Architectural knowledge lacks the infrastructure and tooling dedicated to code. Promoting AK to a first-class artifact to be operationalized by the core infrastructure and tooling (CI/CD) in a software development lifecycle is under-explored. [20]
1.2. Decision-centric
1.2.1. v1
Decisions are hard, we make a lot of them, we sometimes revise them (with irreversible consequences), and, crucially, they are of compounding importance over time.
Decisions are shaped by an environment. Yet, environments often develop aspects which negatively impact decision making. Avoiding these detrimental interactions requires new perspectives on the many facets of decisions.
Software engineering has a deep literature to aid us in making quality architecture decisions, documenting architectures effectively, and on.
Quality decision making benefits from such expert knowledge, but requires an intuition of a codebase's circumstances. As intuition weakens, decision making ability follows.
Intution is developed through the friction of work. When the work to generate code becomes frictionless, intuition for the architecture & implementation does not naturally develop.
To facilitate continued quality decisions, intuition for a codebase must be developed and maintained. Without the development of intuition through the authoring of code, friction must be added elsewhere in the software development life cycle.
1.2.2. v2
Decisions are hard, [26], [27] we make a lot of them, we sometimes revise them with irreversible consequences, and they are of compounding importance over time. [28], [28], [29], [30], [31]
Decisions are shaped by the environment in which they are made. [32], [33], [34], [35] When that environment degrades, so does the quality of the decisions it produces. [36], [37]
Software engineering has built a deep literature around this problem: how to make quality architecture decisions, and how to preserve the knowledge behind them. [20] That literature assumes a practitioner with hard-won intuition about their codebase - intuition developed through the friction of directly authoring it. [38], [38], [39], [39], [40]
When code generation becomes frictionless, that intuition does not naturally develop. The environment changes; decision quality follows. [41], [41], [42], [43]
The literature's tools remain valuable. But they were not designed for an environment in which the practitioner's intuition can no longer be assumed. [44], [45] Sustaining decision quality in such an environment requires deliberately reintroducing the friction that frictionless code generation removes. [46], [47]
1.2.3. v3
A software system can be thought of in terms of its form but equally of the underlying decisions. [3], [48] Those decisions shape architecture, tooling, constraints, interfaces, deployment strategies, and future change. Some decisions are revised quickly without much consequence. Others remain embedded for years. Their effects compound over time. [7], [28], [28], [49], [50]
Code is well supported by software infrastructure. It is versioned, tested, reviewed, deployed, and tracked through mature tooling. Decision state is not. The context behind important changes is often scattered across issue threads, diagrams, design notes, chat logs, and individual memory. [3], [51], [51] Put plainly: implementations are reliably preserved in a standardized manner, yet preservation of rationale may vary and only contains fragments. [3], [52]
This "decision-implementation" gap matters because software development depends not only on the ability to generate changes, but on the ability to make and revise decisions under changing conditions. [53] Those conditions are often poor: incomplete information, moving requirements, time constraints, shifting ownership, fatigue, and on. [2], [36], [37], [54] More recently, code generation has changed the relationship between implementation work and architectural intuition. [41], [41], [43] When implementation becomes easier to produce, the understanding once developed naturally through the direct friction of authoring and revising code no longer arises in the same way. [38], [39], [40], [45], [46]
1.2.4. v4
If only a software architect could bend time… to preserve past rationale by broadcasting into the future to those who need it. Best we can do is write our history and try hard to make it discoverable; the ideal of a perfect history is an illusion.
The question is not: did we capture the intent, traces, tickets, diagrams, ….
The question is: how can we interact with each decision in our architecture as it collides with reality?
[cite: sw-arch-is-decisions]
History is not a mere linear timeline of events, yet we track our software evolution as a simple sequence. The events of software architecture's evolution form a topology of decisions. It is possible to build a model to represent this. Additionally, we can incorporate into topology the ability to define structural warning signals and other functions.
1.2.5. v5
The progression of codebase's lifecycle surfaces as a sequence of snapshots in time, yet underneath is a rich and complex structure of relationships between decisions past. From the surface one can read and parse a history, while below the surface interdependent decisions are a structure to be queried. Remediation to the codebase bubbles up as additional events occurred, yet each bubble may represent a reconsideration of entire branches of decisions. The surface-level history is calm, still, dead; below lives living, interlinked forests of decisions capable of sensing their collision with reality in the present. [25], [50], [55], [55], [56], [57], [58]
This does not imply replacing git, but building on top (or, to follow the analogy: below). Specifically, an event-sourced Command/Query layer which implements a "decision-gated" protocol in between snapshots. This mechanism links changes in decisions to changes in the code. Additionally, the decision event feed into a topological structure that is configurable, stateful, can be computed on, can define computations, can be inherited, and on. [25], [59]
1.2.6. v6
A simple sequence of changes (actions), , can mathematically define the states of a codebase's history. The decisions which accompany each change, however, embody a much richer space in terms of structure, relationships, and interactions.
You may imagine the top of an iceberg… you can see the shape exposed above the surface of the water, but that's it.
For a codebase, what's exposed above the surface is the latest state of the code (the sum of all actions).
In git, this is referred to as the HEAD. git allows us to go back in time to see how the surface once was.
From a back in time, it's easy to see the difference in states (the difference, or, the result of a sequence of actions).
However, when we try to look below (at the decisions), we can't see as clearly. We do our best to keep the docs up to date, write the Architecture Decision Records (ADRs), capture the traces, the specs, create diagrams, etc. This helps, but the clarity when we look below pales in comparison to the of the surface… Down below, there may even be shadows (stale or incorrect information) which we have to ignore in order to see the true shape. You'll most likely have to rely on your hard earned intuition or do some exploration.
Even more difficult: to look underneath and back in time!
Wouldn't it be nice to immediately see the entire topology of decisions that once existed?
Imagine if you could directly compare against the present decisions… a decision diff!
What if we could go even further and know the circumstances of how those decisions came to be and even which lines of code they apply to?
The question I am asking is… in software, can we elevate "decisions" to elements of near equal citizenship as expressions in code? To achieve this, we can mathematically link changes in code to changes in decisions. These first class decisions may have a formal structure, topological relationships, computable warning signals, a stateful protocol, and on.
1.2.7. v7
When humans try to model, navigate, and ultimately affect reality through language, is “decision” a useful general-purpose primitive for organizing that work?
This paper explores whether a decision-first system can function as a general coordination substrate across domains
Such a system may serve not only as a record of decisions, actions, and commitments, but also as a navigable model of a decision space: its adjacent possibilities, trajectories, and contradictions within a domain.
This work sits at the intersection of design rationale, design space analysis, collaborative decision support, and decision provenance, but extends them toward a decision-first execution model in which decisions act as a general coordination substrate across domains.
1.2.8. v8
Machine learning of language has let one generate code at super-human speed while relaxing the necessary precision… the same assistance shadows, pollutes or erodes (union, not xor) the hard-earned & embodied : skills & decison-making intuition (2^2) that cultivate quality codebases, a threat this paper calls "decision mode collapse."
If a software system is most truthfully represented as the set of decisions behind it, then preserving decision quality and intuition across the SDLC requires first-class tooling for decisions themselves, not just the code (a rigorous projection).
- an event-sourced communication protocol,
- a graph data structure whose nodes enumerate scenarios (questions to be decided on) carrying an immutable progression of stances (decision choices), and
- accompanying tooling to manifest as a general interactive medium for organization and collaborative decision-making;
- core libraries
- a CLI
- a self-hostable image for real-time collaborative software development
- boilerplate repositories of decision environment examples (an enumeration of decision-space trajectories
- and an indempotent set of instructions for reverse-cultivating a decision environment from seeded commits
The contribution sits at the intersection of human-machine interaction, collaborative decision support systems, and software engineering principles, while aiming to generalize to any organization designing "forcing functions" to uphold quality decisions in any domain.
1.3. History-centric
1.3.1. v1
How might we tell a richer story of the progression of a codebase's lifecycle? Currently, we track the chronological history of the code from state to state. But, what of the underlying decisions which determined each state?
Version control systems such as git provide us with a chronological timeline of states of the code, and, by definition, the action (changeset) that occurred between each state. This project proposes interleaving (into that timeline of actions and states) an event-based protocol. The protocol's primary objective: a mathematical link between the decisions made prior to each action.
You may wonder: "Code is code… what is the representation for a decision?" That answer is: "It depends." It's configurable. The proposed protocol only enforces "how to carry decisions alongside actions", not "what decisions look like". Just as one may write poor code, one's code may link to poor underlying decisions.
- a scenario description
- an action (changeset), and
- a sign off from someone.
You may again wonder: "what's the point?"
While one could define a decision so minimally…
at the other end of the spectrum, a decision object may act as a living substrate for all that software engineering has to offer:
tradeoff matrices, plans & specs, ADRs, telemetry, and on.
The introduction of this "decision protocol" primarily enforces the formal "carrying of decisions" alongside our existing formal practices of carrying the state of our code. And, as we will see, opens up a new world of functionality for and ways to interact with our codebase. Lastly, in the face of isolating & frictionless methods of generating code, these first-class decisions can also act as collaborative Cognitive Forcing Functions (CFFs).
2. Abstract
We have principles for managing complexity; we can design our code well. But what about the design of the source code history itself? How important is a well structured history?
Our interactions with the world are immutable. Time goes on, history is written. Source history is revisable. Return to earlier and make a change.
When a revision to the source is needed, you and other participants interact. Your future interactions may revise an earlier source state. These two histories are on different timelines. Proposed is an approach for binding a unified history.
Software is susceptible to a runaway effect where continued work becomes increasingly slow, difficult, risky, or stops. While this can be prevented by good design and maintenance, this work considers the importance of a software's history.
Software… we are writing constantly. Softwares are shooting out of the printer, approaching light speed! The software's are combining together to make a giant ball! Now the ball's surface is growing… in weird directions… the surface is becoming extremely complex!
2.1. PNSQC g doc
2.1.1. Decision based
Abstract Over a software’s development life cycle (SDLC), many decisions carry responsibility for the source code over its history. Sustaining understanding of prior decisions is tedious and difficult. However, without clear decision awareness, naive modification is susceptible to a runaway effect, known as architectural erosion or compounding technical debt, where change becomes increasingly expensive, risky, unsafe, or blocked. When design rationale is preserved in passive artifacts with weak links to code, isolated changesets may drift. This paper instead models decisions as formally tangled with source code history through a “Decision Environment” composed of three connected spaces: (1) a source space combining versioned history with hierarchical source code artifacts; (2) a question-decision space (a directed acyclic graph, often tree-shaped); and (3) a programmable temporal observation space. The spaces respond in tandem to changing circumstances. Participants act within and observe the environment through a communication protocol. We present an event-based protocol, including core libraries, CLI/API/web tooling, integrations, explanation/annotation mechanisms, and workflows for interacting with the decision environment during regular development and onboarding established code bases. The protocol acts as a cognitive forcing function: links from changed lines to prior decisions act as an inertial resistance which requires changesets to be reconciled with the prior environment.
2.1.2. Questioning the Source History: Decisions and Revisions
Abstract Over a software’s lifecycle, the source history is cultivated within a field of questions and decisions. Sustaining understanding of our [design] decision history is not easy. However, repeated modification of software, without a clear history, is susceptible to a runaway effect where change becomes increasingly expensive, difficult, risky, unsafe, or eventually freezes (often: architectural erosion, compounding technical debt). When source history and design history are preserved in isolation, a changeset (a next step in source history) can drift, or become isolated, from the design. It is proposed to instead model these histories in tandem: the revisionist source code history, joined by, two immutable temporal histories: a question-decision history and a programmable observation history. The use of the proposed tandem history does not make drift impossible, only gives a structure of resistance against it by maintaining “responsibility” links from decision points to lines of code. Decisions can change, questions are still. Including questions in the model gives structure to the decision space. Participants interact within a “question-decision environment” via a protocol to read, write, and revise “chapters” of the tandem history. Proposed is an event-based protocol, including core libraries, CLI/API/GUI, explanations & annotations, integrations, extensibility, and tutorials for regular development and onboarding established code bases. Question the Source: A Tandem History
2.1.3. Question the Source: A Questionably Explainable History
Abstract Over a software’s lifecycle, the source code is cultivated within the field of questions and decisions. Sustaining understanding of our [design] decision history is not easy. However, without a clear history, software is susceptible to a runaway effect where change becomes increasingly slow, expensive, difficult, risky, unsafe, or eventually freezes. When source history and design history are recorded in isolation, new work can drift from the intended design. It is proposed to instead model these histories in tandem: a revisable, sequential source code history paired with an immutable, temporal question-decision history. Decisions can change, questions stay. Modeling questions gives an exploratory structure to the decision space. The proposed model acts as a forcing function: upfront effort is demanded in order to maintain relationships between decision history and source history, but, in turn, hunks of code are stabilized by an inertial resistance of linked prior decisions (preventing drift). Changes are reconciled with prior decision points before the tandem history can move to the next state. The model does not prevent bad code nor poor decisions; it only provides a method for authoring code and decision histories as one.
3. Introduction
3.1. v1
Application-level decisions in a SDLC are not "high-stakes" as in health or education domains. (Ignoring costs and assuming expertise) Decisions in software may be: implemented many ways, changed later, evaluated ahead of time, incrementally rolled out, automatically rolled back, etc.
Application-level decisions (not: multi-application system wide architecture & physical infrastructure) in a given project's SDLC involve choices and tradeoffs between common frameworks, architecture patterns, database integrations, etc. Popular application-level practices in popular languages are reasonably represented in Large Language Models (LLMs) [60] and implementation by agentic systems is reasonable with enforceable guardrails. [61], [61] However, decision making ability in such agentic workflows is lacking on many dimensions. [12], [12], [44], [44]
Current approaches for integrating agentic workflows into the SDLC augment existing practices. [13], [13] This paper also wonders about augmenting an existing workflow, namely, the ADR, however, the proposed method in the paper molds the ADR into a "structured decision" of which may be able to be adopted widely if it brings meaningful benefits to the SDLC in terms of maintainability, safety, engineering, ethics, trust, cognitive load, education, collaboration, and lastly, by establishing a comprehensive enumeration of software project starting points to be used by anyone (boilerplate repositories to be forked).
Previous approaches of documenting decisions in a codebase have been faced with tediousness, consistent team onboarding and alignment, enforcement difficulty, staleness, high cognitive load, low continual value, isolation, etc. [14], [14], [17], [17]
This paper attempts to mold the idea of the ADR into a set of structured files that lives alongside code and tests. While fundamentally different, these "structured decisions" share one similar aspect: much like lines of code may be covered by a test, many "structured decisions" may cover many lines of code and/or their tests. Do not be fooled: the "coverage" of a "structured decision" is much weaker (to the point that it should not be called coverage) in that it does not actually "cover" a line of code by actually interacting with, or, executing it, and to the further detriment of the definition of "cover", a "covering decision" must additionally manually maintain a one-way verifiable link from decision to code and/or test (a tedious, error-prone task). The creation and maintenance of these manual one-way relationships at least fits with the function of structured decisions: they are the pre-cursor to code and tests and so the creation of these one way relationships will be ahead of time and revised as each decision is made – to change the code you must first make a decision and it will be part of that decisions "plan" which files are interacted with. The difficult part is including all previously defined implicitly included decisions, but some deterministic and semantic rules can be made to ease this burden.
In the SDLC, these structured decisions are at the opposite end of the pull request, hence "PrePR". Structured decisions also function as: parents to multiple variations of plans and their changesets, definitions for reconsideration of a decision, an immutable history of the code evolution, an entry point for code exploration, and on.
5. Method
5.1. sMDP Lens
- each state, , as a commit on the main branch
- an action, , is a changeset applied to reach a new state
The transition probability tensor, , doesn't apply to code - a valid changeset is always applied deterministically. The reward, , can also be ignored for now (although is potentially interesting to think about over long time horizons). The discount factor, , can also be ignored for now.
Playing off the MDP and incorporating our aforementioned "decisions", we have a semi-MDP, .
It is then proposed that a base model for decisions, , might be question centered.
9. References
10. Acronyms
AKM Architectural Knowledge Management 1, 2
AK Architectural Knowledge 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
AI Artificial Intelligence 1, 2
ADR Architecture Decision Record 1, 2, 3, 4, 5
CFF Cognitive Forcing Function 1
LLM Large Language Model 1, 2, 3, 4
MDP Markov Decision Process 1, 2, 3
MAS Multi-Agent System 1
PR Pull Request 1
RLHF Reinforcement Learning from Human Feedback 1
11. Glossary
Cognitive forcing function somethin' that makes you think 1