The Architecture Anti-Astronaut
Ambitious software architecture is possible without the intellectual silliness that usually accompanies it.
Earlier I was scrolling Twitter and ran across a Tweet from Grady Booch about the (quite topical at the time) fall of Elon:
This term piqued my interest, and before even clicking through to find him citing it, I searched it up and found that, yes, it’s an established term!
When you go too far up, abstraction-wise, you run out of oxygen. Sometimes smart thinkers just don’t know when to stop, and they create these absurd, all-encompassing, high-level pictures of the universe that are all good and fine, but don’t actually mean anything at all.
Many programmers mistake my ambition for this sort of anti-pattern in software development leadership. I once worked on a team where in trying to explain my theoretical work, they would always jump too far to conclusions of complexity, because they assumed that the outcome of my work would necessarily involve catering to ‘the general case’, as I call it. That is not true.
My most impactful theoretical work—defining and applying mechanicalism—is concerned with eschewing abstraction as a direct lever of compartmentalisation. More precisely, it involves minimising coupling of data to the algorithms used upon it. Here is a dialogue between Charles and I about the new nimb concept coming in Hinterlib 2:
Alexander: does the prospect of nimbs excite you at all?
Charles: Nimbs?
A: https://github.com/aquefir/hinterlib/blob/v2/include/hn/nimb.h
C: So just BigInts? Also, why use an array of 16 bit ints? Use 64 bit ints and use adc/sbb ops to handle carry bits.
A: read the blurb at the top of the header
C: Just so you can encode them without an explicit size field?
A: there are no fields
these are not struct
s
they are to numerics what strings are to chars
A: using 64-bit integers on machines with <64-bit word size is confounding because we are already layering software propagation of arithmetic logic onto these things. such platforms would be confounded by the same process happening in two different layers, which is confusing and probably not optimal either
C: If you care so much about supporting old architectures, why break any mechanism by which they could use the adc/sbb ops that so many of them include explicitly for the purpose of arbitrary precision math?
A: because I’m not blindly motivated in my pursuit of function on those architectures. I need to be able to flex into small memory models in order to unlock greater ceilings of efficient computation.
A: >Just so you can encode them without an explicit size field?
this library takes no liberties about encoding, which is the entire point of laying things out in this way. I’m applying it immediately in my layout of the circular buffer module right now and it will soon be very clear how many liberties one can take without rendering these functions useless.
A: >If you care so much about supporting old architectures, why break any mechanism by which they could use the adc/sbb ops that so many of them include explicitly for the purpose of arbitrary precision math?
it’s a shame that architectures billing themselves as RISC so routinely deviate from their principles and couple themselves to the habits of software. this is actually something I am very interested in defying because of how it retards progress in ISA research.
A: The structure of data is as decoupled as can be from its layout in memory. you can do no better in service of that goal in the realm of Data-Oriented Design of software ABIs.
A: the more totally you can get your data down to have as few dimensions as possible, the more you can reserve the liberty of choosing the dimensionality relationships to the algorithm as it should be
A: the chips I design will be as efficient as can be while remaining as neutral as possible to the peculiarities of data layout. I will say that if anyone intends to take any kind of approach that imposes form in a general way upon data without the full context of a particular algorithm also in hand (i.e. fixed function or FSM type submodules), it is a mistake.
A: this sort of data structure is both self-evident in its form and extensibility as well as maximally neutral to the algorithms programmers may wish to use upon it. it is a mistake to design any chip that would disallow this kind of formation of data.
One particular excerpt I wish to highlight and reiterate:
The more totally you can get your data down to have as few dimensions as possible, the more you can reserve the liberty of choosing the dimensionality relationships to the algorithm, as it should be.
So, a pattern like this for a building block of data is a mistake:
struct a { int * a; int b; };
It couples the structure of the two data points so they must appear next to each other in memory. If the user needs serious performance, they will be forced to decouple the data from this struct
, and write a bunch of disgusting and meritless boilerplate for passing things back and forth since APIs will probably blindly use this struct
out of a purely aesthetic convenience.
Was it really worth saving appearances of an extra argument in function signatures? The Linux kernel coding style guide says opacity is bad in the context of typedef
s. By the same logic, opacity in struct
s can be just as bad for our users. More precisely, any rigorous use of structured data is necessarily decoupled in form. Database software doesn’t couple data like this, so why should you? It’s not any less obvious without the coupling if you write about your code at all.
Nimbs are a more semantically flexible way of solving the problem iterators solved in functional programming. Whereas it abstracts away the whole reality of addresses and limitations of pointer sizes, nimbs apprehend it directly and transparently, allowing many more optimisations to be made during compilation and much more informative analysis of program performance to be done.
With this tool, I can interact with databases larger than what fits into a 64-bit pointer, on machines like the Intel 286 that only have 16-bit pointers. On architectures of the future where 16-bit pointers are leveraged for their ease of saturation with entropy, these functions and all code using them will port over basically unmodified. Isn’t that incredible?
Most importantly, nimbs are among the first big examples I can finally show you of mechanicalism in action. Object-oriented programming and functional programming abstract away complexity with classes and type theory, respectively. Here, we leverage C to deal with data form directly, and take no prisoners from performance potential by leaving the larger form up to the user and their chosen algorithm. Doing this is absolutely fundamental to building performant, robust systems. This is how you write code that can last centuries without intervention.