Beej's Bit Bucket

 ⚡ Tech and Programming Fun

2026-03-12

On Making

Nail in wood with hammer I made this!

TLDR: I gain a lot of fulfillment by making things. I don't consider things built by others at my request to be made by me, and are therefore much less fulfilling. And then I feel sad. This article starts strong and then heads off into the weeds.

There have been a lot of pieces written about what I'll call "the AI dev schism" And I think there's a lot of truth to those:

We'll just grant those as being correct for various developers. But there's something else that troubles me.

Backstory before we get going, so you can get a better idea of my perspective:

I'm going to use "AI" to mean "Generative AI and LLMs" in this essay. Sorry, veterans of so many AI winters.

Interlude!

Before we begin, I'd like to share with you a bit of my latest sci-fi novel. Some of you might unaware that, in addition to Beej's Guides, I also write science fiction.

Kael pressed his back against the shattered bulkhead, plasma scoring the air centimeters from his face. The Vorrkai assault drones had anticipated their route through the lower decks and now Rin was bleeding through her jacket sleeve and old Maret couldn't stop coughing from the vented coolant still hazing the corridor. Kael counted the pulse-intervals between shots. Three seconds. Maybe four. That was all the universe was offering him.

Then he saw it: the maintenance shaft behind the collapsed generator housing, its grate blown half-open by the same explosion that had caved in their original exit. It was tight. It was ugly. It ran directly over the Vorrkai's forward position, which was either the most dangerous path imaginable or the last one they'd ever think to watch. Kael grabbed Maret's collar and pointed without a word. The old man's eyes went wide, then hard. He nodded. Rin was already moving.

Kael came last, returning fire blind around the bulkhead corner, not to hit anything, just to make noise, and to give the drones something thermal to track while his people scrambled into the dark. A bolt caught the generator housing and the whole structure groaned, raining sparks down into the shaft on top of them. He hauled himself in, knees burning on the torn metal, and pulled the grate closed behind him with a sound he was certain every Vorrkai unit on the deck had heard. In the black ahead, Rin's hand found his wrist. Move, her grip said. Now. And so they did.

—Excerpt from The Vorrkai Interval, by Brian "Beej Jorgensen" Hall

And, in my now-copious spare time I make art! This is a woodcut, painted in pastels, showing some of my favorite subjects.

Dueling Wizard Hackers Mirrors of the Machine by Brian "Beej Jorgensen" Hall, $1300.

Carpentry? You bet I dabble! I rebuilt my front deck recently. The old one was rotting out, so I grabbed a bunch of cedar and put it together. I'd been meaning to do it for a while, but couldn't find the time.

And, finally, here's some of the code I wrote for a TUI adventure roguelike:

    fn try_move(&mut self, dx: i32, dy: i32) {
        let nx = self.player.x + dx;
        let ny = self.player.y + dy;

        // Check for monster combat
        if let Some(idx) = self.world.monster_at(nx, ny) {
            let result = {
                let monster = &mut self.world.monsters[idx];
                resolve_combat(&mut self.player, monster, &mut self.rng)
            };

            self.messages.push_many(result.messages);

            if result.monster_defeated {
                let monster = &self.world.monsters[idx];
                let xp = monster.xp_reward;
                let gold = monster.gold_reward;
                self.player.xp += xp;
                self.player.gold += gold;
                if gold > 0 {
                    self.messages.push(format!("You find {} gold!", gold));
                }
                if self.player.try_level_up() {
                    self.messages.push(format!(
                        "Level up! You are now level {}!",
                        self.player.level
                    ));
                }
            }

            if !self.player.is_alive() {
                self.messages.push("You have been slain! Rest in peace...");
            }

            self.advance_turn();
            return;
        }

        // Check terrain passability
        if self.world.is_passable(nx, ny) {
            self.player.x = nx;
            self.player.y = ny;
            self.advance_turn();
        } else {
            let terrain = self.world.terrain_at(nx, ny);
            self.messages.push(format!("The {} blocks your path.", terrain.name()));
        }
    }

I'm an extremely prolific polymath, I'm sure you'd agree!

I Am Uncomfortable

I don't like lying. And yet I feel, dear reader, I have misled you. Yes, all that has been created (including my deck) and I was the initiator of all that creation. But I don't really feel like I made any of it. I'm uncomfortable claiming that I did so.

Since you are certainly aware by now that all of the above is AI-generated (except my deck, which was created by skilled, paid craftsmen), perhaps you feel a little bit of discomfort with me claiming credit for doing those things, too.

However, I don't think everyone feels this way. I know many people who ask contractors to build things and they phrase it like they built it.

"I put in a new front deck," they'd say, even though other people did all the work. Personally, I feel that's misleading. I'm more of a "I had a new front deck put in" kind of person.

And when I do have Claude create something for me, I just can't say that I made it. Other people can, but I just can't. Again, I'm more prone to say, "I had this code built for me." I don't even feel comfortable MIT-licensing that (not-for-hire) work, if that's even legally possible. I just Unlicense it all.

As a manager, I'd never say that I built a product. "My team built this," I'd say. And as a manager of LLMs: "My Agents built this."

And that, for me, has very little weight in terms of making.

I don't feel like I did anything. And I like doing things. I find pride in doing things.

Completing projects is great. I love completing projects. Capitalists love completing projects. Real artists ship.

But having others complete projects I initiated is entirely less fulfilling to me.

It's not just the loss of the craft and the problem-solving challenge and whatever else. It's the loss of making.

What Did I Make Recently?

My wife wanted a no-frills flash card system for learning Spanish. "I just want a thing where I can put the words I want in a spreadsheet and then see it on flash cards." A prompt!

So I wrote it. By hand. I did use Claude to learn some basics, like the easiest way to get the data out of a Google Sheet (spoiler: it's the CSV endpoint), but I told it to generate no code.

--------------------------------------------
Language                     files      code
--------------------------------------------
JavaScript                       2       112
CSS                              1        33
HTML                             1        32
--------------------------------------------
SUM:                             4       177
--------------------------------------------

Didn't take long. Only about 50x longer than it would have taken Claude to do it.

But I can put my name on that code and say that I made it. Was it a lot of code? No. Was it groundbreaking and amazing? Certainly not. But I'm infinitely more proud of that code than anything I've had Claude write, because I'm not capable of being proud of the latter.

And my wife wouldn't go to her book club and say, "I wrote a flash card system to study Spanish." Admittedly, part of this would be because she didn't want to appear a geek, but mostly it's because it's untrue, even though she initiated the process.

What About The Art and Craft of Prompting?

After all, you create the prompts, don't you? You said you were proud of doing things. Isn't that doing a thing? And since so much got done, isn't it even more of doing a thing?

I don't disagree. And I do agree that there is skill here in some important ways.

Not all prompts are equally effective. Not all users of AI are as effective as one another. There's a very human contribution to be made here.

But the skill is in effectively asking someone to make something for you.

"Leadership is the art of getting someone else to do something you want done because he wants to do it."

          —Dwight D. Eisenhower

And I'm the kind of person who really misses the making of software. And prompting for software, to me, isn't the same as making the software. It's the same as asking someone else to make it.

What About Compilers, Smartypants?

Isn't it just turtles all the way down?

For any given C or Rust program, did I write that program? I wrote it in C. I didn't write any machine code. The computer wrote that.

There's something different in my mind about that. I'm not sure if it's the mathematically-precise relationship between the C and the machine code...? And yet that's not spelled out. I'm relying on some hacker's deep knowledge of the CPU to generate that magnificent set of optimized instructions when I stupidly divide something by seven. And it's not deterministic, strictly, in that Clang and GCC emit different instructions. What about different platforms? The C is portable and the machine code is not. Did I write that program that's running on Windows even though I personally only ever built it on Linux?

Going further in the murky gray, what if I instruct an LLM to be a C compiler and emit assembly code for some platform?

Let's try:

Convert this C program into x86_64 assembly for Linux.

#include <stdio.h>

int fib(int n) {
    if (n <= 1) return n;
    return fib(n-1) + fib(n-2);
}

int main(void)
{
    for (int i = 0; i < 10; i++)
        printf("%d: %d\n", i, fib(i));
}

Claude says:

# fib.s - Recursive Fibonacci, x86_64 Linux, AT&T syntax
# Build: gcc fib.s -o fib -no-pie

    .section .rodata
fmt:
    .string "%d: %d\n"

    .section .text
    .globl main

# ┌─────────────────────────────────────────────────────┐
# │  int fib(int n)          n in: %edi / return: %eax  │
# │  Stack frame:                                        │
# │    %rbp-8  = saved %rbx  (via push)                 │
# │    %rbp-12 = n  (spilled so it survives both calls)  │
# └─────────────────────────────────────────────────────┘
fib:
    pushq   %rbp
    movq    %rsp, %rbp
    pushq   %rbx                # callee-saved scratch
    subq    $8, %rsp            # 1 local (int n); keeps stack 16-byte aligned

    movl    %edi, -12(%rbp)     # spill n to stack

    cmpl    $1, %edi
    jle     .Lbase              # n <= 1 → return n

    # --- fib(n-1) ---
    movl    -12(%rbp), %edi
    subl    $1, %edi
    call    fib
    movl    %eax, %ebx          # %ebx = fib(n-1)

    # --- fib(n-2) ---
    movl    -12(%rbp), %edi     # reload n (call clobbered %edi)
    subl    $2, %edi
    call    fib                 # %eax = fib(n-2)

    addl    %ebx, %eax          # return fib(n-1) + fib(n-2)
    jmp     .Lret

.Lbase:
    movl    %edi, %eax          # return n

.Lret:
    addq    $8, %rsp
    popq    %rbx
    popq    %rbp
    ret

# ┌─────────────────────────────────────────────────────┐
# │  int main(void)                                      │
# │  Stack frame:                                        │
# │    %rbp-4  = int i  (loop counter)                  │
# └─────────────────────────────────────────────────────┘
main:
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $16, %rsp           # locals + alignment

    movl    $0, -4(%rbp)        # i = 0

.Lloop:
    cmpl    $10, -4(%rbp)
    jge     .Ldone              # i >= 10 → exit

    # fib(i)
    movl    -4(%rbp), %edi
    call    fib

    # printf("%d: %d\n", i, fib(i))
    movl    -4(%rbp), %esi      # arg2 = i
    movl    %eax, %edx          # arg3 = fib(i)
    leaq    fmt(%rip), %rdi     # arg1 = fmt  (RIP-relative)
    xorl    %eax, %eax          # AL=0: no XMM args to printf
    call    printf

    addl    $1, -4(%rbp)        # i++
    jmp     .Lloop

.Ldone:
    xorl    %eax, %eax          # return 0
    leave
    ret

OK, clanker, but does it work?

% gcc fib.s -o fib -no-pie
% ./fib
0: 0
1: 1
2: 1
3: 2
4: 3
5: 5
6: 8
7: 13
8: 21
9: 34

Well, holy golden ratios! It even used XOR to set exit status 0, the cheeky devil!

So did I write that program? Yes. I feel I did. (I actually did hand-code the Fibonacci thing just now—I've done it a million times for classes.) I feel I wrote the program even though I didn't write the assembly, which is the program that actually runs! The LLM wrote that!

Technically, it's the machine code that runs, but going from assembly to machine code now we're really getting into the land of strict, brainless, mathematically-precise translation, which I feel doesn't take away from the act of making any more than using a hammer to drive nails does.

What's the real difference in that gray area? I'm not sure. I think it hinges on something that has to do with making versus asking to be made, even if that line isn't particularly clear.

"I know it when I see it."

          —US Supreme Court Justice Potter Stewart

Things that I do:

Things that I ask others to do at my command (inspired by a nice capitalistic investment):

When I have ChatGPT create a painting, I don't feel like I painted it.

When I use the hammer, I don't feel like I'm asking the hammer to do something for me. Same with a C compiler or assembler.

And yet I just had Claude compile some C code right up there. Was that me writing C code and running it? Or was it asking something to write software for me? I have no doubt I could have prompted Claude with an English description of what I wanted and gotten the same output.

Is it because AIs seem human? You are asking them to do things in imprecise, human language. They respond in human ways and do the things you ask. And the relationship we are used to in those circumstances is more one of manager-report than one of colleague and peer. Whereas our relationship with a compiler is more similar to that of one with a hammer.

And yet... looking into that gray area makes me feel more confident that telling the AI to make something for me actually is an act of creation. What if I had an AI-powered hammer and asked it to hit a nail for me? What's the difference? But at that point, I can't say that I hammered it. It is important to me, this difference. Why?

By now, dear reader, I suspect we're both running out of steam and maybe we should leave it here to ponder.

I feel it's appropriate to conclude with some classic DNA:

"All I wanted to say," bellowed the computer, "is that my circuits are now irrevocably committed to calculating the answer to the Ultimate Question of Life, the Universe, and Everything." He paused and satisfied himself that he now had everyone's attention, before continuing more quietly. "But the program will take me a little while to run."

Fook glanced impatiently at his watch.

"How long?" he said.

"Seven and a half million years," said Deep Thought.

Lunkwill and Fook blinked at each other.

"Seven and a half million years!" they cried in chorus.

"Yes," declaimed Deep Thought, "I said I'd have to think about it, didn't I? And it occurs to me that running a program like this is bound to create an enormous amount of popular publicity for the whole area of philosophy in general. Everyone's going to have their own theories about what answer I'm eventually going to come up with, and who better to capitalize on that media market than you yourselves? So long as you can keep disagreeing with each other violently enough and maligning each other in the popular press, and so long as you have clever agents, you can keep yourselves on the gravy train for life. How does that sound?"

The two philosophers gaped at him.

"Bloody hell," said Majikthise, "now that is what I call thinking. Here, Vroomfondel, why do we never think of things like that?"

"Dunno," said Vroomfondel in an awed whisper; "think our brains must be too highly trained, Majikthise."

The Hitchhiker's Guide to the Galaxy, Douglas Adams

My Actual Contributions

As a post-script, here are my applied skills in the first part of this article.

Science fiction (honestly, the result was so vomitous I feel genuinely embarrassed having signed my name to it):

Write three paragraphs of sci-fi. Setting: We're in the middle of the novel at one of the pivotal fight sequences. The hero (choose a heroic sci-fi name) is leading two other refugees out under heavy laser fire from the baddies (choose an evil-sounding sci-fi name for this group). Our heroes have just been pinned down, but now see a way out.

What's the name of this novel?

Paintings and artwork:

Generate an image that shows the following: a woodcut, but with pastel coloring. Two wizardly computers hackers, one on the left of the frame and one on the right, facing each other, computers between them, both head down and focused. The left and right sides should be complementary and opposite colors to show that both sides are the same, yet different.

What's the name of this painting?

Ultima-likes:

I'm thinking of a game like Ultima I, except with a TUI. Visually, I was thinking of a 3x3 grid of characters per map cell. Some of them would be animated, e.g. the water on the ocean cells. And the map on the screen would be 7x7 map cells (or whatever Ultima I had)

It would be also like Ultima I in that it was fantasy.

The world should be procedurally-generated maybe with perlin noise. And the monsters should roam randomly, though they will be of prebuilt classes (no need to procedurally-generate monsters on the fly).

There should be some kind of DnD-ish stats, as well. No classes--just a general player is fine.

I'd like it in Rust using Ratatui. Color.

And I'd like the code well structured, with good separation between the UI and the game logic, as well as good code directory layout.

Carpentry:

Please replace my front deck.

Though I really did drive that nail into that piece of wood. I needed a picture to open with.

Uses of em dash within this piece are deliberate. Vim digraph: ^K-M.

Comments

View Comments Reply
Click on "View Comments" to see the comments.
Blog  ⚡  beej@beej.us  ⚡  Home page