Programs, Not Objects: How I Stopped Designing Architecture and Started Writing a 3D Editor – Alex on software development
Skip to content
July 11, 2026
Programs, Not Objects: How I Stopped Designing Architecture and Started Writing a 3D Editor
Today’s post is a bit different from my usual deep dives into mesh geometry. It’s a story about architecture – and about going back to the beginning.
Think back to how you learned to program. Almost certainly, you started with procedural code: a program was a sequence of steps, maybe split into functions. Input, transformation, output. Simple.
Then someone opened the door to a whole new world: object-oriented programming. Everything is an object! Objects have state and behavior! Model the real world! And we believed it. We spent years – years – learning how to carve reality into classes. Is a Circle an Ellipse? Should Document own View, or observe it? Composition or inheritance?
Then we discovered that plain OOP doesn’t really scale, and we fell into the world of patterns: MVC, MVVM, Observer, Dependency Injection, service locators, factories of factories. Each pattern solved a real problem – and each added a layer of indirection between "what the program does" and "what the code says."
The result is familiar to anyone who has maintained a large application. You open the codebase and the actual behavior is nowhere. It’s scattered across a dependency graph that exists only at runtime, wired together by a DI container, held up by callbacks and event buses. To answer the question "what happens if this value changes?" you do archaeology: grep, breakpoints, tracing through callbacks.
To be fair, AI made this archaeology much cheaper. I can point a model at a legacy codebase, ask "who reacts to this event?", and get a decent answer in seconds. But AI made understanding bad architecture cheaper – it didn’t make designing good architecture any less of a craft. That part is still on us.
The task: a 3D editor, quickly
Some time ago I needed to write a 3D mesh editor. Not a toy – a real application: load meshes, run geometric operations on them (clipping, stitching, simplification), undo/redo, a UI for parameters, and, critically, the ability to keep adding operations for years without the whole thing collapsing.
With a task like this, the first question is always architecture. Extensibility, maintainability, easy feature growth – everything we want so the project can evolve for years without a rewrite.
The classical move is obvious: decompose into objects. Mesh, Scene, Operation, Command, Tool, ToolManager, Selection, SelectionChangedEvent… I’ve built systems like that. I know exactly how it goes: six months in, the object graph is a living organism that nobody fully understands, and adding a feature means negotiating with it. So this time I didn’t do that. Instead, I went back to the very beginning – to the mental model we all started with.
The model: processes, programs, and tables of cells
Here is the entire architecture, in four sentences:
A process is a set of programs.
A program is a table of named variables with declared dataflow between them (I call it a sheet of cells).
Some cells hold plain values; some are computed from other cells. The dependency graph between them is declared explicitly, as data.
Computed cells come in two kinds: formulas , which produce a value from their inputs, and actions , which perform an effect – mutate geometry, run a transaction – when the user says so.
That’s it. Sounds almost primitive, right? A program is literally a table: names on the left, values on the right, plus computed cells wired to their inputs.
If this reminds you of a spreadsheet – good. The names Sheet and Cell are not an accident. Excel is the most successful reactive programming environment ever created. Hundreds of millions of people build working "applications" in it without ever drawing a class diagram. You look at a cell, you see its formula, you see its inputs – the dependency graph is the program. Even the formula/action split is Excel’s: formulas recalculate, macros run when you press the button. Nobody considers the button a failure of the model.
The same idea lives in Grasshopper and similar node-based tools: a program is a dataflow graph, each node has inputs and outputs, and the wiring between nodes is the application. My editor is essentially that, expressed in C++ instead of boxes and wires.
And the pattern reaches well beyond software. Look at how complex manufacturing is organized – the PLM/PDM world, where things like rockets get built. Thousands of people, departments that know almost nothing about each other: one team develops fuel, another designs fasteners. Nobody holds the whole product in their head. What holds it together is decomposition into programs – in the wider sense: a method of reaching a defined goal within the production chain – each with declared inputs and outputs, connected by a digital thread, so that a change...