How Streamplace Works: No Microservices

The long-term vision for Streamplace involves millions of creators supported by a network of thousands of independently-operated Streamplace nodes all over the world. These nodes can syndicate each others' livestreams, clip and remix each others' content, broadcast everything to millions of viewers, and do all of this while respecting the creators' preferences for how their streams are handled. I talked a little about how that might work last week!

To make this happen, we need to make our software as easy to run, fork, and distribute as possible. And that means we build everything in the Streamplace node software itself: there are no microservices allowed at Streamplace.

But why?

I'm gonna pick on Livepeer a little bit here, because my experiences there were a direct input to this rule at Streamplace. Before I do, I want to clarify: the state of affairs I'm about to criticize a bunch is largely my fault. When I joined Livepeer, there was one core node software, go-livepeer, and almost no first-party infrastructure. By the time I left, uh...

😭

Everything started off innocently enough. It's 2019. Livepeer has some basically-working software for video transcoding, backed by a public network of orchestrators. (More on the background here.) We were starting to have some conversations with folks in the video industry, and they were interested in the idea of low-cost video transcoding but were having some trouble getting started. ("So the first thing you do, see, is load a wallet up with some Ether, then fund your deposit and reserve in the broadcaster smart contract..." is about as far as those conversations got.) So I was tasked with setting up a wee bit of first-party infrastructure to get them started.

I was in my first year at Livepeer and eager to help them flesh out some of this stuff. I had a background in JavaScript and Kubernetes and had worked at three different Seattle SaaS companies. Surely, it couldn't hurt to roll a little Node.js microservice that kept track of users' transcoding settings? And a cute little JSON API? This is just a quick demo for our first few users, it's not like we're building an entire product on top of this.

Oops.

Long story short, my one innocent Node.js API server became the foundation of the entire Livepeer.com Livepeer Video Services Livepeer.studio hosted product, still maintained this very day. The rest of the company's services weren't in Node.js, there was no particular reason to write it in JS, but I did anyway because that's what I came from and what I knew. It's a startup, I wanna ship fast!

Of course, the rest of the company then needed to interface with this system but they were writing Go, so that led to yet MORE microservices in Go, and then we scaled up because it was 2021 and there were more engineers and by this point we had an established pattern for microservices so of course the fastest way for people to get started was to add more. I tried to fix my mistake — here's a PR where I combined THREE different services! — but it was hard.

Make your software runnable

The point of this little parable: all of this software was open-source, but it was impossible for anyone outside of our team to run it. We did a good job on the service itself and built a great hosted streaming platform. And the fact it's open-source ended up being irrelevant.

And you see this pattern repeat elsewhere, of course. Why did it take until three months ago for someone to successfully set up a Bluesky-without-Bluesky stack? Could it perhaps have something to do with the fact you need to set up your own PLC, PDS, Relay, AppView, and social-app frontend? And that half of those services are written in Node.js and half are written in Go for some reason? With sadness in my heart, I have to hand this one to the ActivityPub community: if I boot up a Mastodon instance, I have everything I need in one place. How the heck do I do that for atproto?

But wait monoliths are bad though right?

Look, if you're Microsoft and you have tens of thousands of developers all over the world, you're going to need some microservices. You need lots of teams operating independently, with clear API contracts between them. Go right ahead. This article isn't for you.

If you're an open-source project maintained by a small team, you want everybody writing things in the same language, exercising the same development processes, and going through the same CI. You don't want everyone bringing their own favorite languages, databases, and frameworks to the party. Developers will chafe at this — I would have chafed at this in 2019 — but once you've got everyone in the same boat, now every feature goes out to every single one of your users.

Also, just because you're all working on one piece of software doesn't mean you can't deploy it as a microservice when it makes sense. I've got a little Streamplace node running on my personal server that does nothing but send pings for my livestreams to the Streamplace Discord server. When we eventually allow for VOD uploads, we'll probably need a bunch of "task runners" running on private servers somewhere that process them. But they'll all be running the same software behind the scenes with some different configuration.

Batteries Included

The target audience for the Streamplace node software (now on apt and Homebrew!) is a tech enthusiast — maybe someone that can spin up a Digital Ocean droplet and SSH into it, but not somebody that's writing an Ansible playbook or a Kubernetes deployment. We want to make it as easy as possible for them. And so:

Streamplace will always remain a single, statically-linked binary. One file, no dependencies, available on Windows, Mac, and Linux.

On top of that, we have a single React (Native) app for iOS, Android, and Web, and it gets bundled in that same binary.

Our documentation? Bundled and hosted by that same binary.

Our testing? We can run a full end-to-end test suite for the entire service on every single change, because everything is in one place. Microservices make this kind of thing very, very hard.

We also implement an Expo Updates server for serving new versions of the iOS and Android apps, and a Squirrel server for auto-updating the (WIP) Streamplace Desktop Electron apps.

One other benefit behind all of this is to maximize forkability. You're launching a new video service, and you need apps for iOS, Android, Windows, Mac, and Linux? Fork Streamplace; it's obvious. We're making it easy for you. And the greatest part: all of your content can still interact with every other Streamplace-compatible node out there through the magic of decentralized signing.

Our pitch to big Twitch streamers: don't switch from Twitch to Streamplace, switch from Twitch to your own app; have a direct relationship with your audience and your own presence on the App Store and Play Store. It's easy. But your Streamplace app can still interact with thousands of other Streamplace apps and nodes out there. And that's because we made it easy to run.