That's why I'm building Concise Encoding [1], which is a twin text/binary format that can be 1:1 converted back and forth. You do everything in binary, and only convert to/from text in the few places where a human needs to be involved (like debugging or configuration).
The type field is almost always 1 byte long, except for typed arrays (which would generally in aggregate be long enough to offset the cost) and two uncommon types/variations. These have an effective 2-byte type field (0x94 selects a secondary type plane, and the next byte selects the specific type from there).
The most common integer values (-100 to 100) are encoded directly into the types 0x9c to 0x64 (wraparound), such that interpreting them directly as signed 8-bit signed integers yields their actual value (type 0x00 = integer 0, type 0x64 = integer 100, type 0x9c = -100, etc).
Strings are also optimized such that types 0x80 - 0x8f are used for the most common string lengths (0 to 15) so as not to require a separate length field.
The rest have a 1-byte type field. There are also 3 reserved type codes left in the first plane in case something big comes up in the future. You can see the chart here: https://github.com/kstenerud/concise-encoding/blob/master/cb...
Anyway, it's all great programming but it seems to me a symptom or a larger social failure, where we are making bad protocols faster instead of making the protocols better.