Programming Through Composition
Building complete systems from proven tools rather than accumulating unnecessary layers of complexity.
FIG 1.0 - Every system is composed of pieces.
Assembling specialized tools rather than relying on a monolithic ecosystem. Every task can be broken down into simple pieces.
Related Insights
Cody in the file
Our studio's inauguration
Current Trend Market
MXI.STUDIO EDITORIAL
Innovation | Platform | Software | Design
The MXI.Studio Editorial is a collection of articles, ideas, and reflections written by the people behind MXI.Studio. We explore emerging technologies, innovation, industry trends, and the current challenges of an ever-evolving world.
Proven, modern tools
A lot of software projects do not really need more complexity. They need clarity, a narrower scope, and a better way to connect the pieces they already depend on. That is the basic idea behind what is called amalgamation pattern: start with mature tools that do one thing well, keep the internal structure simple and lean, and build the specific parts you actually need on top of that foundation.
This is not really about chasing novelty. It is more of a practical habit. In the age of AI, it has become much easier to work with libraries and existing systems without getting buried under their internals. You can understand a package, ask questions about how it fits into your project, and implement it with far less inconsistency than before. That changes the way a project can be assembled.
"It becomes less about writing everything from scratch and more about composing reliable pieces into something you actually control then building on top of it."
At the same time, there is another reality that often gets overlooked: many modern frameworks and large-scale libraries are built to solve thousands of possible use cases simultaneously. They are impressive engineering achievements, but they also tend to impose architectural assumptions, dependencies, abstractions, and workflows that may not actually align with the project being built.
FIG 2 - A complex tool for all uses
A very complex tool can cover multiple needs, but it does not always replace the efficiency of a well-composed toolbox.
From this point onward, the project gradually begins to be built around the framework, rather than the framework serving the project.
TAB 1 — Comparison between a compositional approach and an approach based on complex tools
This is one of the reasons we tend to increasingly prefer smaller and more focused systems. There are cases where rebuilding a feature from the ground up using simpler mature components is not only more understandable, but also cleaner architecturally. Not because rewriting everything is inherently better, usually it’s not, but because many problems become unnecessarily inflated once they are absorbed into generic ecosystems trying to accommodate every possible scenario.
The difference is especially noticeable when working with highly modular libraries.
-
Mature parser JSON
-
Compact network library
-
Lightweight Browser
-
Specialized math libraries
-
Targeted competitive tool
A carefully limited selection of libraries often provides exactly the necessary functionality without bringing an entire ecosystem along with it. Instead of inheriting a massive stack of abstractions, the project can remain relatively close to its actual operational logic.
"That closeness matters."
When the internal structure of a program remains understandable, it becomes easier to debug, optimize, refactor, and extend over time. The codebase feels less like an opaque environment that needs to be navigated and more like a system deliberately assembled around a clear objective.
Systems fusion
That is where a “fusion” aspect really comes in.
The idea is not to build a giant framework attempting to solve everything. It is to assemble a precise system out of smaller, dependable components, then fuse them together into a cohesive architecture that remains owned by the developer. Instead of adapting your project to an external ecosystem, you construct a lean internal engine specifically for the problem you are trying to solve.
Interestingly, this is not a particularly new philosophy. Modern software already operates this way to a large extent. Most large systems today are built across multiple libraries, multiple runtimes, and sometimes multiple programming languages simultaneously. The difference is that these layers are often hidden beneath increasingly complex tooling and infrastructure.
Recent work around multilingual programming systems explores this idea directly by attempting to coordinate different programming languages under unified type systems and interoperable workflows. Similarly, work surrounding Python bindings for large-scale C++ robotics libraries demonstrates how high-performance native systems can remain accessible through higher-level environments without sacrificing flexibility or control.
What’s interesting is not necessarily the research itself, but the broader direction it reflects. Software is increasingly becoming compositional. Different languages excel at different tasks, and modern tooling makes it possible to connect them together much more fluidly than before.
Separation of contexts
Assembling simple, precise, and manageable modules.
One tool, one role
Each tool keeps a clear function. Nothing is mixed; everything can be tracked, replaced, and recomposed.
Controlled building blocks
Building with simple, mature components chosen for their real usefulness within the project.
FIG 3 — Building better often begins by choosing more specialized tools.
"This is where separation of context becomes extremely important."
Not every part of a project needs to live inside the same environment. A low-level layer may handle performance-critical systems, memory-sensitive operations, rendering pipelines, simulation logic, or networking infrastructure. A higher-level layer may handle orchestration, scripting, experimentation, interfaces, or rapid iteration. The bridge between those layers is not a workaround; it is part of the architecture itself.
A very simple example would be using C++ to implement the lower-level systems that require tighter optimization and explicit control, then exposing those systems as bindings within Python. From there, the higher-level application can coordinate multiple mature libraries together while still relying on a highly controlled native core underneath.
The result is interesting because it preserves both sides:
-
the efficiency and precision of low-level development;
-
the flexibility and speed of interpreted environments.
This also changes the role AI can play during development. AI becomes genuinely useful when it helps reduce hassle around integration, understanding APIs, generating bindings, navigating documentation, or assembling boilerplate between mature systems. This is where it provides the most practical value. Not as a replacement for engineering decisions, but as a tool that makes compositional development significantly easier.
The important distinction is that the architecture still belongs to the developer. AI may help explain how to expose a native library to Python, generate basic wrapper code, debug an integration issue, or explain how a particular dependency behaves internally. But the overall structure, how the project is divided, how contexts are separated, which systems remain low-level, and which abstractions are acceptable, remains an intentional choice of the developer.
Controlled complexity
That intentionality is important because modern software environments tend to accumulate layers very quickly. Build systems grow larger, dependencies become deeply nested, frameworks expand to accommodate increasingly generic needs, and eventually projects inherit complexity that no longer directly contributes to the actual product.
Coding by composition is essentially an attempt to move in the opposite direction.
The goal is not to chase minimalism or rewrite every tool from scratch, but rather to eliminate technical debt, fully understand the codebase, effectively meet our objectives, use mature and reliable libraries where they make sense, rebuild selectively when doing so produces a cleaner and more controlled architecture, separate contexts clearly, keep the source code understandable. And then connect the pieces deliberately instead of inheriting an entire ecosystem by default.
In many ways, it is less a strict methodology than a mindset
The objective is not to eliminate complexity entirely, complex systems will always exist, but to ensure that the complexity inside a project is understood and identifiable, rather than complexity inherited accidentally from oversized abstractions and generalized frameworks.
That is really the core of the idea:
build closer to the foundation, keep the moving parts understandable, and assemble systems in a way that remains coherent to the people actually building them.