|
| 1 | +# Versioned Binary Application Record Encoding (VBARE) |
| 2 | + |
| 3 | +Fearless schema migrations at theoretical maximum performance |
| 4 | + |
| 5 | +VBARE is a tiny extension to BARE |
| 6 | + |
| 7 | +## Preface: What is BARE? |
| 8 | + |
| 9 | +- https://baremessages.org/ |
| 10 | +- https://www.ietf.org/archive/id/draft-devault-bare-11.html |
| 11 | + |
| 12 | +## Project goals |
| 13 | + |
| 14 | +- fast -- self-contained binary encoding, akin to a tuple -> |
| 15 | +- simple -- can rewrite in under an hour |
| 16 | +- portable -- cross-language & well standardized |
| 17 | + |
| 18 | +non-goals: |
| 19 | + |
| 20 | +- data compactness -> that's what gzip is for |
| 21 | + |
| 22 | +## Use cases |
| 23 | + |
| 24 | +- Defining network protocols |
| 25 | +- Storing data at rest that needs to be able to be upgraded |
| 26 | + - Binary data in the database |
| 27 | + - File formats |
| 28 | + |
| 29 | +## At a glance |
| 30 | + |
| 31 | +- Every message has a version associated with it |
| 32 | + - either pre-negotiated (via something like an http request query parameter/handshake) or embedded int he message itself |
| 33 | +- Applications provide functions to upgrade between protocol versions |
| 34 | +- There is no migration in the schema itself, just copy and paste the schema to write the new one |
| 35 | + |
| 36 | +## Migration philosophy |
| 37 | + |
| 38 | +- declare discrete versions with predefined version indexes |
| 39 | +- manual migrations simplify the application logic by putting complex defaults in your app code |
| 40 | +- stop making big breaking v1 -> v2 changes, make much smaller changes with more flexibility |
| 41 | +- reshaping structures is important -- not just changing types and names |
| 42 | + |
| 43 | +## Code examples |
| 44 | + |
| 45 | +## Current users |
| 46 | + |
| 47 | +- Rivet |
| 48 | + - Network protocol |
| 49 | + - All internal communication |
| 50 | + - All data stored at rest |
| 51 | +- RivetKit |
| 52 | + - Protocol for communicating with clients |
| 53 | + |
| 54 | +## FAQ |
| 55 | + |
| 56 | +### Why not include RPC? |
| 57 | + |
| 58 | +- why the fuck does your protocol need to define an rpc schema |
| 59 | +- keep it simple, use a union |
| 60 | + |
| 61 | +### Why is copying the entire schema for every version better than using decorators for gradual migrations |
| 62 | + |
| 63 | +### Isn't copying the schema going to result in a lot of duplicate code? |
| 64 | + |
| 65 | +- yes. after enough pain and suffering of running production APIS, this is what you will end up doing manually, but in a much more painful way. |
| 66 | +- having schema versions also makes it much easier to reason about how clients are connecting to your system/the state of an application. incremental migrations dno't let you consider other properties/structures. |
| 67 | +- this also lets you reshape your structures. |
| 68 | + |
| 69 | +### Why copying instead of decorators for migrations? |
| 70 | + |
| 71 | +- decorators are limited and get very complicated |
| 72 | +- it's unclear what version of the protocol a decorator takes effect -- this is helpful |
| 73 | +- generated sdks become more and more bloated with every change |
| 74 | +- you need a validation build step for your validators |
| 75 | +- things you can do with manual migrations |
| 76 | + |
| 77 | +### Don't migration steps get repetitive? |
| 78 | + |
| 79 | +- most of the time, structures will match exactly. most languages can provide a 1:1 migration. |
| 80 | +- the most eggrarious offendors will be deeply nested structures, but even that isn't terrible |
| 81 | + |
| 82 | +## Comparison |
| 83 | + |
| 84 | +- Protobuf (versioned: yes) |
| 85 | + - unbelievably poorly designed protocol |
| 86 | + - makes it your problem by making everything optional |
| 87 | + - even worse, makes properties have a default value (ie integers) which leads to subtle bugs with serious concequenses |
| 88 | + - tracking indexes in the file is ass |
| 89 | +- Cap'n'proto (versioned: yes) |
| 90 | + - simplicity |
| 91 | + - quality of output languages |
| 92 | +- cbor/messagepack/that mongodb one (versioned: self-describing) |
| 93 | + - requires encoding the entire key |
| 94 | +- Flatbuffers (versioned: yes) |
| 95 | + - still uses indexes like protobuf, unless you use structs |
| 96 | + - structs are ass |
| 97 | + - cdoegen is ass |
| 98 | +- https://crates.io/crates/bebop & https://crates.io/crates/borsh (versioned: TODO) |
| 99 | + - provides cross platform |
| 100 | + - TODO: more complicated than i'd like |
| 101 | + - bebop includes an extra ??? step |
| 102 | +- rust options like postcard/etc (versioned: no) |
| 103 | + - not cross platform |
| 104 | + |
| 105 | +## Implementations |
| 106 | + |
| 107 | +| Language | BARE | VBARE | |
| 108 | +| --- | --- | --- | |
| 109 | +| TypeScript | X | X | |
| 110 | +| Rust | X | X | |
| 111 | + |
| 112 | +[Full list of BARE implementations](https://baremessages.org/) |
| 113 | + |
0 commit comments