When I first started working with #ActivityPub, before #Fedify existed, it felt like writing web apps in Perl and CGI in the late '90s. Interesting, even exciting—but never comfortable. That era where your business logic and your protocol plumbing were just… the same thing:

print "HTTP/1.1 200 OK" print "Content-Type: text/html" print print "Hello, world!"

Decades of web development have given us layers of abstraction we now take for granted. Nobody hand-parses application/x-www-form-urlencoded query strings anymore. Nobody writes their own JSON codec, or manually constructs HTTP request/response messages. These things just aren't your problem when you're building an app.

ActivityPub development still feels like they are your problem. What do you do when the https://www.w3.org/ns/activitystreams#actor property comes in as a string instead of an array? What about when https://www.w3.org/ns/activitystreams#object is an embedded entity rather than a URI? How exactly do you implement HTTP Signatures? And wait—what's Linked Data Signatures, and do you need that too?

The real issue isn't that ActivityPub is complicated per se. It's that you can't get away with understanding it at a high level. You have to know it the way an implementor knows it—every edge case, every inconsistency in how different servers serialize JSON-LD, every signature scheme that exists in the wild. That's a lot to learn before you can even start thinking about your actual app. And when developers understandably cut corners on the protocol to focus on their product, it quietly becomes an interoperability problem for the whole ecosystem.

What I want ActivityPub development to feel like: you spend a day understanding the big picture, and then you just… build your app. That was the goal when I started Fedify, and honestly, we're not fully there yet. But it's where I want to get.

#fedidev #fediverse

Hi @hongminhee,
I feel you, but more often than not I see complexity not warranted by functionality but by what Fred Brooks called design by committee (In "The Design of Design").
Take the signatures https://doi.org/10.17487/RFC9421. Brings 0 benefit over cavage, could have been a FEP formalising it. But brings a lot of complexity.
This is a burden for indie implementors and benefits corporate ones.

I personally like implementing the whole stack and keeping it simple. That's what goes under the bus first when doing abstractions.

P.S.: admitted, CGIs on one server won't serve billions. But is that a good idea anyway? You can still do sound tiered architecture in a CGI. I can't ridicule a hello world for not being MVC.

Information on RFC 9421 » RFC Editor

@mro That's a fair point about design by committee, and I don't disagree that RFC 9421 added complexity without proportionate benefit. But I think it's a somewhat separate question from what I was getting at.

Even if every ActivityPub spec had been designed with ruthless simplicity—no committee sprawl, no redundant signature schemes—the DX problem would still be there. You'd still need to know what to do when a property arrives as a string instead of an array. You'd still need to handle embedded objects vs. URIs. The gap between “I understand ActivityPub conceptually” and “I can ship something that actually federates correctly” would still be wide.

My point isn't really about why the stack is complex. It's that the complexity, whatever its origin, currently falls entirely on the application developer. A framework should be able to absorb most of that—the same way web frameworks absorbed HTTP parsing and content negotiation—so developers can focus on what their app actually does.

(And yes, the CGI analogy was never meant to be architectural criticism! Just reaching for a feeling most of us remember.)

Hi @hongminhee,
as an aside, besides @aSeppoToTry being a #CGI done in 🐫 @ocaml #OCaml, my favorite one prbly being https://qr.mro.name, 30 lines of #bash - in essence

```bash

cat <<EOF
Content-Type: image/png

EOF

urldecode "$d" \
| cut -d = -f2 \
| qrencode -o - -t PNG -m 1 -s "$s" -l "$l"
}
```

QR Code Generator