Programmers early in their careers often latch onto building “high performance” software. I was certainly drawn into that trap early on my programming career. High performance is a fun problem because it targets the dopamine feedback loops that make programming fun. Most of the time, trying for high performance isn’t detrimental, but in protocol design, it definitely is. Networking protocols are built to allow communication between two necessarily different pieces of software so interopability and correctness should take center stage over performance. New services should be HTTP first–if you don’t at first need all the features, your successful service eventually will and you’ll end up maintaining a variant of HTTP.

  • Draft
    • Errors - a robust way to represent different statuses and classes of errors. These should include user errors, client errors, server errors, and temporary errors.
    • Version - Include a way to version your protocol.
    • Representation - Your protocol should include the description of the way data representation will occur.
    • Client and server implementation - Your protocol should include a client and server implementation.
  • MVP
    • Encryption - this is a must in any modern protocol. If you design a new protocol without on by default encryption that supports well-tested, well-known algorithms you’re either lazy, incompetent, or malicious. You care about the privacy of your users, right?
    • Authentication - your protocol should include a way to authenticate users. Ideally, it will support multiple ways for good integration with external authentication systems (tokens, username/password combos, public/private keys).
    • Reverse proxy support - while this isn’t a necessity to build yet, your protocol should be able to support proxying traffic based on DNS hostnames. Supporting this means you’ll be able to run multiple instances behind a single IP:Port combination. This opens up opportunities to:
      • Easily run a managed service.
      • Use wildcard DNS addresses to dynamically spin up new instances.
      • Make administration easier (single IP/port open for firewall rules), cheaper too.
  • Post-MVP
    • Format negotiation - your service will likely go through different versions of formats and development will benefit from being able to negotiate different protocols e.g. maybe the first version was textual, but future versions were binary to avoid expensive parsing.
    • Compression - your protocol should support compression and negotiation of compression protocols.
    • Client library generation - your protocol should be usable by a wide variety of clients. In order to keep them in-sync, they should be generated.
    • Testing tooling - your protocol should have debugging tooling and test suites to validate client and server compatibility.
    • Multiplexing - your protocol may want to support multiplexing connections to avoid the overhead of establishing multiple connections.
    • Persistent connections - your protocol may want to support reusing connections to avoid the overhead of establishing a new connection for each request from a single client.
    • Binary representation - your protocol should have an efficient binary representation to reduce speed on the wire.
    • Caching and partial requests - the most efficient way to transfer data is to avoid transferring it altogether.