Jan 21, 2022
Ten years against division of labor in software


"Software libraries suck. Here's why, in a sentence: they promise to be abstractions, but they end up becoming services. An abstraction frees you from thinking about its internals every time you use it. A service allows you to never learn its internals. A service is not an abstraction. It isn't 'abstracting' away the details. Somebody else is thinking about the details so you can remain ignorant.

"Programmers manage abstraction boundaries, that's our stock in trade. Managing them requires bouncing around on both sides of them. If you restrict yourself to one side of an abstraction, you're limiting your growth as a programmer.1 You're chopping off your strength and potential, one lock of hair at a time, and sacrificing it on the altar of convenience. "

"Division of labor is a relationship not to be gotten into lightly."


"I think software finally gives us a way to avoid division of labor."

"I think namespaces and modules are socially counter-productive even when implemented in a technically impeccable manner, because they encourage division of labor. In even the smallest of projects, without thinking about it, we often start out with the goal of working with someone, and proceed to do so by defining an interface and then working apart. That is no fun, and it is gradually self-limiting. I think we do this because it's so easy to create interfaces and silos, to isolate ourselves from each other's changes using namespaces and similar constructs. By creating these constructs, by making them too easily available, we forget to ask if we should use them. This is, I think, an example of taking the human out of the loop. But even here, the only way I can think of to do a rollback is by trying to build a software stack from scratch."


"For the past couple of years I've been researching ways to write software that make it easier for newcomers to understand rather than for insiders to maintain. In this quest I built a toy OS and Basic-like language called Mu which tries to “rhyme with” the design process by which Unix was coevolved with C. The big additional design constraint compared to Unix+C is to make the OS primitives testable. I want to be able to pretend in tests that we run out of memory or disk, that a context switch happens between these two instructions, and so on. My hypothesis is that having the ability to easily write such tests from day 1 would radically impact the culture of an eco-system in a way that no bolted-on tool or service at higher levels can replicate: it would enable new kinds of tests to be written and make it easier to be confident that an app is free from regression if all automated tests pass. This would make the stack easy to rewrite and simplify by dropping features, without fear that a subset of targeted apps might break. As a result people might fork projects more easily, and also exchange code between disparate forks more easily (copy the tests over, then try copying code over and making tests pass, rewriting and polishing where necessary). The community would have in effect a diversified portfolio of forks, a “wavefront” of possible combinations of features and alternative implementations of features instead of the single trunk with monotonically growing complexity that we get today. Application writers who wrote thorough tests for their apps (something they just can't do today) would be able to bounce around between forks more easily without getting locked in to a single one as currently happens."


"The lesson I draw for software from https://creators.vice.com/en_uk/article/animator-hand-draws-film-in-4-years-nova-seed isn't about collaborating or not, it's about avoiding division of labor. When working with someone on a project don't "design an interface" and then work alone on either side of it. Work together all over it."

"It is undeniably useful to be able to put off learning about some parts of the system until we feel the urge. The golden mean may be to be on a stack that isn't 'lumpy', where between you and machine code are many gossamer-thin layers, any one of which can be easily peeled back to understand how it works.

"I started out mocking NPM for the left-pad debacle, but over time I've actually grown more sympathetic to left-pad. The problem isn't that somebody wrote a library for left-pad. It is that even something as trivial as left-pad has triggered our division-of-labor instincts. A library like left-pad is just begging to be saved into projects that use it so users have one less moving part to worry about at deployment time. Turning it into a first-class dependency also ensured that a lot less people looked inside it to understand its five lines of code or whatever."

"One of the benefits of my scheme is that calling programming languages abstractions is almost always obviously incorrect. Libraries are also never abstractions. Clarifying this wording immediately cuts through a bunch of confused discussions online."

"Libraries with non-trivial functionality take a long time to get right, and in the meantime they are produced more like guilds of craftsmen than factories. (Even if the products themselves permit factory-like operation at scale.) In that initial bake-in period we are ill-served by conventional metaphors of software components, building blocks, etc. We should be dealing more in vertically-integrated self-contained systems rather than plug-and-play libraries. More OpenBSD, less `gem install`."

"Division of labor is an extremely mature state for a society. Aiming prematurely for it is counterproductive. Rather than try to imitate more mature domains, start from scratch and see what this domain ends up needing."


"Confusingly, I've been calling Iverson's notion of subordination of detail "abstraction", and Iverson's notion of abstraction "service" or "division of labor". Though lately I try to avoid the term "abstraction" entirely. That seems on the right track. Regardless of terminology, this is a critical distinction."

"I consider an example of exemplary library use to be how I copied the termbox library into Mu, periodically merged commits from upstream, gradually cleaned it up to fit better with my project, and gradually stripped out code from it that Mu does not require.

"In the process I made some wrong turns, deleting features that I later decided I wanted and created bugs for myself. But when it did things I didn't want, I was now empowered to change them. One of my patches was useful upstream, so I submitted it. I would be in no position to submit that patch if I hadn't taken the trouble to understand termbox's internals. And that shows a final benefit of copying and privately forking libraries: it makes you a better citizen of the open source world, because open source depends on eyeballs, and using a library blindly helps nobody except your (extremely short-term) self."

"I've been thinking about the problem with division of labor for 7 years now, and I think I've boiled it down to two sentences. Why division of labor is disempowering:

1. (the setup) Power = capability - supervision.

2. Division of labor tends to discourage supervision."


"Let's assume code reuse is a mirage. What can we achieve if we stop aiming for it? In this I think I'm close to the Forth aesthetic."

"Division of labor discourages learning from your complements."


  • The only way to guarantee you won't run afoul of Hyrum's Law is to make no updates.
  • As a consequence, I don't care about Hyrum's Law. I make updates to the best of my ability, trying not to break others, but I don't/can't guarantee they won't break others.
  • If my updates can break others, I can't push them to others without explicit consent. Others have to pick them up on their own schedule, when they have the time to test them for their own context.
  • If my updates can break others, others may have to make changes to them for themselves.

Rather surprisingly, these baby steps lead to a world entirely different from the one I live in. One where we don't have interchangeable parts yet, where software is often tweaked for a specific situation.


  • Lin Pengcheng, 2022-01-23: 10 Principles:

    1. Division of tasks
    2. Single Leader and Unified Scheduling
    3. Empowerment and Management by Objective
    4. Single form (pipeline fractal system)
    5. Concentration and decentralization
    6. Level chain
    7. Definiteness
    8. Order
    9. Standardization
    10. Exception handling


    The Math-based Grand Unified Programming Theory: The Pure Function Pipeline Data Flow with Principle-based Warehouse/Workshop Model

Comments gratefully appreciated. Please send them to me by any method of your choice and I'll include them here.

RSS (?)
twtxt (?)
Station (?)