Friday, August 28, 2026

How I shamed the slop machine

AI tech bros try to convince us that the slop machines are able to write good code, and that they will be able to inspect it for bugs and vulnerabilities. This is not my experience at all.

Here I have my own implementation of a slab memory allocator in C. Less than 1k LoC, I originally wrote it circa 2012. This is tricky code for a custom data structure with a relatively simple high-level interface - initialise a slab with the desired size of the objects, allocate an object from the slab, free an object from the slab, destroy the whole slab. Behind those seemingly simple operations is a lot of pointer manipulation and chasing, and bit-twiddling.

github.com/bbu/cart/blob/master/slab.h

github.com/bbu/cart/blob/master/slab.c

I am intimately familiar with this code because I wrote it. I know what each branch is supposed to do, and what the expected state of the data structure is in those branches. I asked Gemini to find any bugs and vulnerabilities:

...

...

...

...
...
...

Friday, August 14, 2026

Code is the hard part

You've probably heard the opposite from those annoying corporate types with a shiny and popular LinkedIn profile. Guess what? They don't have a clue because they have never evaluated a system for its technical merits. They are the "product owners" in an ever more enshittifying world.

Code represents the data transformations and data dependencies in a system. Code has formal syntax and well-defined semantics, and is mostly non-ambiguous. Whatever you call "architecture" is an abstract, reduced and conceptualised view that is derived from the very fabric of code. True no-nonsense knowledge about a system is in the code, and in the code of the subsystems it interacts with. Architecture exists even at the micro level of a single function - it embodies decisions on what the inputs/outputs are, how those inputs are manipulated, and whether such a function needs to exist at all in the wider scheme of things. Writing the code for a particular problem is an exploratory process where you gradually unveil the nature and the constraints of the problem as you type it in. It takes a certain shape and starts living an animated life in your head. Code is self-correcting and tells you that you need handle a particular edge case; it also tells you to reduce complexity by removing these 2 redundant states from your state machine implementation. Not because you are following "patterns", but because you understand the flow of your own code.

Code makes the difference between the application that corrupts your data and exits abruptly with "unhandled exception occurred", and the one that is able to exit gracefully and prevent such a situation altogether with a sensible message like "your input doesn't satisfy conditions A and B". This is the very foundation of security. Intuition for performance also comes from understanding what your code does, and not by treating it as a side artifact.

Code is here to stay and will be the backbone of the stuff that matters. Eventually, the accumulation of throwaway slop specified by "architects" and "domain experts" in a markdown file won't be worth the storage medium it is stored on. Programmers who understand their code will be the true architects.

Thursday, July 23, 2026

Are we living in an age of statistical mediocrity?

Almost every piece of text you can consume online is now having this syntactically-shiny, perfectly-spelled package with a rather shallow and unoriginal semantic core. You probably wanted to read something about a place or a culture you've never encountered, and it reads like something you've read hundreds of times before. You probably watched a YT video about a hobby you practise, and it follows a very formulaic presentation and vocabulary. Averaged conventional experiences and conventional wisdom, regurgitated in a non-offensive, plausible-looking package. Where's the subjective lived human experience, the personal judgement, the slightly odd and difficult sentence structure, the touch of originality?

It's not only about LLM-generated content. Even interactions with real people online produce a very narrow and predictable set of reactions. The ideas and concepts we operate with are shockingly limited. You probably don't like a product for some valid particular reasons, and you get the prefabricated "it's not about you, it's what the market dictates". You probably have a personal issue in a very particular personal situation, but you get prefabricated advice that it's a "you issue".

How can one stay sharp in such an environment? Detach from the online world and read old-fashioned books from the pre-LLM era. Have dinner conversations with honest, morally-integral, intellectually deeper people from diverse backgrounds. Do not trade your inner self for a "popular profile" in the property of the techno-feudal landlords.

Friday, April 3, 2026

LLM coding is the wrong layer of abstraction

Conventional wisdom tells you that LLMs are good at automating the generation of boring, repetitive boilerplate code. I can agree, but why do we need to write that boilerplate again and again in the first place? Isn't that a failure of our industry as a whole? Why do we need to translate short sentences of lousy and imprecise human language to thousands of lines of syntactically-correct formal language with inscrutable hidden behaviours and semantic anomalies? Wasn't the point of high-level computer languages for humans to express computation in an unambigious and ergonomic manner? I don't want a probabilistic mumbo-jumbo machine as an interface between me and the computer.

I want to express my intent clearly and concisely in a formal language, using abstractions that are sound for the problem at hand. Where could these abstractions live? They could be in the kernels of operating systems, in middleware, in libraries, in language semantics and runtimes. We don't need to recreate them in every sloppy LLM-generated project that tries to become a million-dollar business. LLMs don't help us disentangle the mess that is the software world. They are a tool that aggravates the problem, while their proponents feel productive and enthusiastic.

Friday, December 12, 2025

The choice between Rust and C-derived languages is not simply a matter of memory safety

Rust encourages a rather different "high-level" programming style that doesn't suit the domains where C excels. Pattern matching, traits, annotations, generics, and functional idioms all sound great on paper, but when you're building low-level systems, they create an environment where everything becomes verbose, ceremony-driven, and semantically dense. You write more code about the code than about the actual work being done.

This is a consequence of Rust's "killer" feature: prevent entire classes of bugs at compile time. An ambitious goal, and when it works, it's magic. But the price is that the language must express more information than the actual algorithm demands. That extra information becomes noise in domains that already prize simplicity – bare-metal firmware, packet parsers, high-performance I/O loops. These are ecosystems where adding structure just because the type system encourages you to is not a virtue; it's overhead.

C, by contrast, is a different kind of animal. The language rewards terseness and economy of expression. You write exactly what you mean, and almost nothing else. Once you understand how pointers, lifetimes, and data layouts behave, it's like the compiler stops being a gatekeeper and becomes a quiet workhorse. It translates what you wrote into something very close to what the machine executes. No lifetimes to annotate. No type-level gymnastics to appease the borrow checker. No compiler front-end that feels like an argumentative partner.

The philosophical split between C-derived languages and Rust is deeper than "safe vs unsafe". It's about the role of the programmer in approaching a problem. Rust's mental model is rich, layered, and session-typed. It demands you to think in terms of ownership semantics, region constraints, and type traits. Even a simple data structure can grow a halo of metadata: derives, macros, lifetimes, Send/Sync bounds, feature gates. And while all of this scales well for large teams building complex asynchronous systems, it’s overkill in tight, performance-critical loops where the ideal number of moving parts is as few as possible.

C's mental model is brutally direct: bytes go here, pointers point there, and you control the boundaries. Unsafe? Yes. But also minimal. The clarity it provides in low-level domains isn't a side effect; it's the design goal. The language does not enforce guard rails, and therefore it does not require you to encode a novel's worth of constraints in your types. Good C codebases look simple not because they lack abstractions, but because they avoid abstractions that don't directly express the computation. And that's the thing Rust struggles with.

None of this means Rust is "bad" or that C is "better". It means they optimise for different values. Rust optimises for correctness and maintainability under heavy abstraction. C optimises for transparency and minimalism under extreme constraints.

Sometimes you don't want a language that keeps you safe. Sometimes you want one that simply gets out of your way.

LLMs are not a means to an end

We use these tools as know-it-all assistants that can answer questions in all areas of human knowledge. Their answers are never grounded in the empirical world of the senses. They don't have "skin in the game" and will happily change their opinion diametrically if you present the same question from a different light. They reinforce conventional wisdom by offering generic solutions to local problems with local variables. Our over-reliance on them will atrophy our reading and writing skills. We also use them as "rephrasers" to make ourselves sound better, supposedly. This is destroying genuine human connection and communication.

Friday, February 23, 2024

The pitfalls of pure rationality

Being rational with regards to the surrounding natural and physical world is undeniably good for our survival. We learn the effects of touching a hot stove and never attempt to do it consciously once we are older than 4. We know that driving on ice makes a vehicle hardly controllable, and tend to avoid it. This cause and effect paradigm is incredibly helpful for navigating the natural world. We don't need constant empirical proof for stuff like that. We don't need to deconstruct any social constructs.

However, I believe that this paradigm, when applied abstractly to human-made institutions and enterprises, skews our social understanding and navigation abilities. It fabricates toxic conventional wisdom and explanatory models that supress basic reasoning in a local, context-sensitive manner. The Scottish philosopher David Hume famously said that "reason is a slave of the passions". Once you start viewing the world through deterministic mega power structures and institutions, you are no longer sensitive to your local environment. You stop seeing a window of possibilities and the particular qualities of the people around you. Many of these assumptions are time- and region- sensitive and can become even less relevant with time.

If you become overly hooked on formalisms like behavioural economics, cognitive psychology, evolutionism or the geopolitical power struggles, you are no longer an ingenious free-acting agent. You attempt to explain the behaviour of your neighbour with theories developed by distant academics. You start taking decisions symbolically and in a virtue-signalling manner – "I will buy from another brand because I believe that someone I don't know 5000 miles away is a creationist".

What would the cure be? Develop social intuitions. Observe your local surrounding environment and the people around you. Try to listen to their personal stories. Tell them yours. Then you can probably figure out what's valuable for them, what drives them every day. Applying that knowledge in the economic realm might change the world for the better.