Square peg, round hole
I think there’s been an inflection point recently in NIPs that are being proposed. Some examples:
- Products with pubkeys: https://github.com/nostr-protocol/nips/pull/1225
- Shared-ownership events: https://github.com/nostr-protocol/nips/pull/1192 and https://github.com/nostr-protocol/nips/pull/1015
- Spreadsheets: https://github.com/nostr-protocol/nips/pull/1189
- Relational databases: https://github.com/nostr-protocol/nips/pull/1168
- Relay-specific notes: https://github.com/nostr-protocol/nips/pull/1146
- Editable notes: https://github.com/nostr-protocol/nips/pull/1090
- Restricted events: https://github.com/nostr-protocol/nips/pull/1083
- Relay-based access control: https://github.com/nostr-protocol/nips/pull/1030
- Protected events: https://github.com/nostr-protocol/nips/pull/1029
- Closed groups: https://github.com/nostr-protocol/nips/pull/875
Some of these I like, some I don’t. But most of them go beyond adding new features to nostr (for example audio, video, speedruns, resumes, etc), and begin to change how nostr actually works.
Nostr can be an everything app, but I think that means something very specific. Nostr can represent data types from pretty much any domain, but it can’t actually support all the semantics needed to build any arbitrary system.
I would suggest conservatism in what we build on nostr, but of course anyone can build whatever they want. But I do think it’s possible to identify things that nostr is good at, and things it’s bad at, and play to nostr’s strengths.
Nostr’s strengths:
- Being able to model any data type orthogonally to the rest
- Single-owner, self-authenticating, atomic data types
- Potential for robust content dispersal and retrieval if we can flesh out NIP 65 etc.
Nostr’s weaknesses:
- Mutable state, non-atomic state
- Shared ownership, key delegation/rotation
- Privacy — metadata will always leak, lack of consistency makes key rotation harder
- Consistency — not everyone has the same view of the world
- Transactionality — nostr isn’t good for updating multiple pieces of data in lockstep
It happens that the original use case of nostr — public broadcast social media — benefits greatly from nostr’s strengths, and isn’t bothered by any of nostr’s weaknesses. Blob storage like what blossom is building also works well in this paradigm. A lot of the use cases @PABLOF7z has identified work beautifully well because of the single-owner public-read nature of nostr, which makes forks easy to model.
But things like access control, relational data, collaborative document creation, heavier datasets, or anything that requires a solution to the double-spend problem become very awkward (or impossible) to model on pure nostr. A simple example of this is lists. Not only is it common for a single user to mess up his follow lists because of a lack of consistency between clients or devices, but commonly requested features like shared ownership lists immediately result in a huge increase of complexity, either on the key management side or on the data structure side. Both of these problems are difficult to solve on nostr due to lack of consistency — keys can’t always be reliably or safely shared, and linked data structures spanning multiple events by different authors can be hard to assemble reliably.
I think the danger here is that if we as a developer community fail to realize the limitations of nostr and try to adapt the protocol to fit every possible use case, on an ad-hoc basis, we’re going to end up with a tragedy of the commons, where no developer can comprehend what must be done to get his work done, and all kinds of weird artifacts appear for end users that no one can explain.
Here are some suggestions I have for preventing this from happening. I realize no one is going to follow them. But maybe they can be helpful for avoidance of wasted time.
- Don’t overload event kinds. Many people (including myself) have tried to extend kind 0 with attributes for forms, products, and groups, but that leads to madness. Instead, create a new metadata event signifying a different kind of agent.
- Don’t model things as replaceable events if you can avoid it. This creates the problem of shared mutable state, which nostr doesn’t have a good story for resolving. They also have a hard limit on how big they can be.
- Use different keys for different things. For domains where some kind of access control needs to be implemented, not tying everything to your main pubkey makes it possible to create and burn keys as needed. Incidentally, this can help users maintain better privacy. An example of this is private groups, which have a dedicated key separate from the group creator’s own key.
- Event ownership should always be (is) single-key. If you need shared ownership, figure out a way to share keys. More work needs to go into key invalidation and rotation for this to really work.
- Explore the fork model — this is “my” version of the same thing, and coexists with rather than supersedes the original. This has potential not just for groups or wiki entries.
- Distinguish between different ways to use relays. Relays may be used as indexers (holding specific event types or supporting different features like search/count), repositories (holding many diverse events, to be used with filters), or curated feeds (to be used without filters, or with only a few filters).
These are just suggestions, and many of them may be wrong. Nostr development is hard, and getting harder. Keep it simple.