Why Modern Software Is So Bloated: We Forgot There Are Many Ways to Program
MPSA - Make Programming Small Again. 2026-02-03
Remember when programs fit on floppy disks? When operating systems measured in kilobytes rather than gigabytes? Something fundamental changed between the 1980s and today, and it wasn’t just that we got better at programming.
We forgot that computers are fundamentally Reprogrammable Machines—RMs, as I’ve started calling them—that need not be centrally controlled by a single CPU paradigm.
The Monoculture Problem
Here’s an uncomfortable truth: nearly all modern programming languages are essentially the same. They’re variants of CPU assembler—synchronous, sequential, and built around the function call paradigm. Whether you’re writing Python, Java, JavaScript, C++, Rust, or Go, you’re working within the same fundamental model.
We’ve dressed this up with type checkers, which we’ve hard-wired directly into our languages. But type checking is just a tool—a way to catch certain classes of bugs faster. There’s no inherent reason it needs to be baked into the language itself. Prolog and other relational languages would be perfect for type checking as a separate linting step, yet we keep Greenspunning type systems into every new language.
The Function Call Straightjacket
Our insistence on function-based calling conventions has ruled out entire categories of programming paradigms. Try building a bare-metal Forth using a modern programming language—it’s nearly impossible. You have to drop down to assembler.
This isn’t a failure of Forth. It’s a failure to recognize that functional programming—even the imperfect FP of languages like C—comes with severe restrictions. FP works beautifully for calculators and compute-heavy tasks, but it’s mediocre for anything that isn’t inherently synchronous and sequential: the internet, robotics, IoT, or systems involving mutation.
What Pure Functional Programming Actually Looks Like
Want to see truly pure functional programming? Look at Sector Lisp: 436 bytes total, including a 40-byte garbage collector. That tiny size isn’t just assembler tricks—it’s what happens when you embrace genuine functional purity. Sector Lisp doesn’t allow assignment at all.
That’s the real functional paradigm. If you need assignment, control flow, or state, you need another programming language alongside it. Forth, StateCharts, PBP, Drakon—these are some of the complementary tools pure FP needs. (These are only the ones that pop to mind at this moment - one should assume that there are many others).
Imagine a Forth that offered three choices instead of two:
Indirect threaded pointers to code
Direct threaded assembler code
Pointers to Sector Lisp snippets with a “docol”-like mechanism that handles return values.
This is programming with appropriate notation for each task.
The Memory Crisis We Don’t Talk About
Our casual attitude toward memory—assuming infinite RAM, relying on caches and cache coherence—has produced bloatware measured in megabytes and gigabytes instead of kilobytes. We use algorithms that assume unbounded memory, like ASTs in compiler development, when staged compilation techniques (pioneered by PT Pascal and its successors like Concurrent Euclid and Turing+) can accomplish the same goals with a fraction of the footprint.
Turbo Pascal proved this point decades ago: small, fast, and remarkably capable. It didn’t need gigabytes of RAM to be productive.
The same principle applies to modern transpilation approaches. Consider Forth-Haiku: it uses Forth-like syntax to describe shader code, then transmogrifies it to JavaScript—treating JavaScript as a lower-level “assembler.” This demonstrates that we can use appropriate high-level notations for specific problem domains, then compile down to whatever target makes sense, rather than writing everything directly in the target language’s paradigm.
We don’t need to bloat our source code with the target platform’s assumptions. We can think at the right level of abstraction, then transpile.
The Operating System Trap
Here’s the vicious cycle: our insistence on warped functional programming requires operating systems. Then we write library code as functions that depend on those operating systems, creating a self-fulfilling prophecy. Libraries require operating systems, which require the functional paradigm, which requires libraries, which require operating systems...
This incestuous dependency chain isn’t inevitable. It’s a consequence of paradigm lock-in.
Missing the Signs
When we hit “callback hell,” it should have been a signal that our paradigm was wrong for the problem. Instead, we added more band-aids—promises, async/await, reactive programming—rather than stepping back and asking whether synchronous, sequential thinking was appropriate for inherently asynchronous systems.
The Historical Weight
The concept of “functions” was invented millennia ago for capturing thought with quills on papyrus. Then it was warped again to fit Gutenberg’s typesetting paradigm 500 years ago. We’re still carrying that conceptual baggage, force-fitting modern computational problems into frameworks designed for fundamentally different media.
A Way Forward
The solution isn’t to perfect functional programming further. It’s to remember that there are many ways to program a Reprogrammable Machine. We need to match our notation and paradigm to the problem structure, not force every problem into the same sequential, synchronous mold.
Different problems deserve different paradigms: message-passing for distributed systems, state machines for control flow, pure functional for calculations, Forth-like approaches for systems programming. You can’t cram all of that into one programming language and still get something that isn’t milquetoast. Instead of picking one language for a project, pick one language for each paradigm within the project. Create the solution in pieces, then glue them all together into a coherent whole.
The goal isn’t to twist the functional programming paradigm further by force-fitting other paradigms into it—it’s paradigm appropriateness.
See Also
Email: ptcomputingsimplicity@gmail.com
Substack: paultarvydas.substack.com
Videos: https://www.youtube.com/@programmingsimplicity2980
Discord: https://discord.gg/65YZUh6Jpq
Leanpub: [WIP] https://leanpub.com/u/paul-tarvydas
Twitter: @paul_tarvydas
Bluesky: @paultarvydas.bsky.social
Mastodon: @paultarvydas
(earlier) Blog: guitarvydas.github.io
References: https://guitarvydas.github.io/2024/01/06/References.html


