JSON's hidden contract: a Mark Seemann deep read

JSON's hidden contract: a Mark Seemann deep read

A deep read of Mark Seemann's argument that JSON's simplicity pushes data contracts into schemas, code, and production behavior. The issue connects his XML-versus-JSON claim to FP habits such as parsing at boundaries and making illegal states visible.

Mark Seemann's July 6 post starts with a deliberately unfashionable claim: JSON is not a good data-interchange format, and XML is better in most respects. The useful part is not the nostalgia. It is the contract argument underneath it. 1

Recommended post

Original: Worse is better: JSON versus XML, by Mark Seemann, published July 6, 2026. It is the first concrete entry in Seemann's new Worse is better series, after the series introduction framed the larger question: why do less capable technologies often beat better-designed alternatives? 2
This is a good fit for a functional-programming deep read because the post is only superficially about angle brackets versus curly braces. The real issue is familiar to anyone who has argued for static types, algebraic data types, parsers, schemas, or explicit boundaries: when the contract is not represented in a machine-checkable form, it still exists. It just becomes implicit.

The post in one sentence

Seemann's claim is that XML is often a better interchange format because it can grow from lightweight markup into a formally specified document language, while JSON's simplicity makes too much of the real contract live outside the data format itself. 1

Full read-through

The post opens by anticipating the obvious reader reaction: many developers remember XML through SOAP, WS-* and other enterprise machinery, so the format feels guilty by association. Seemann's first move is to separate XML from that history. His argument is that those stacks were cumbersome for their own reasons; XML itself can be used with little ceremony. 1
He demonstrates that by comparing a tiny JSON object with a tiny XML document. JSON wins the vibe check because it looks lighter. But Seemann's point is that XML does not require a schema, a namespace, or even an XML declaration before it can be useful. You can start informally, then add stronger machinery later when the document starts to matter. 1
That is the first important turn. The advantage Seemann sees in XML is not that every XML document should be heavy. It is that XML lets a team move along a gradient: plain document first, formal contract later. W3C's XML specification says XML was designed for interoperability and provides mechanisms to impose constraints on a document's storage layout and logical structure. 3
The second turn is where the post becomes interesting for FP readers. Seemann connects schemas to the old static-versus-dynamic typing argument. He cites Alexis King to make the point that the absence of static types does not mean the absence of a specification; it only means the specification is expressed somewhere else. 4
That is the hinge of the article. If a service sends JSON that downstream code expects to have particular fields, shapes, and invariants, those expectations are part of the contract. If they are not written in a schema, they live in tests, docs, validators, examples, tribal memory, and production incidents.
Seemann then invokes Hyrum's Law: with enough users of an API, every observable behavior of the system will eventually be depended on by someone. 5 His point is that informal data formats do not remove contracts. They make it harder to tell which contract consumers are actually relying on.
The post does not pretend XML is universally right. Seemann says he would still choose JSON in many cases because it is expected, and he explicitly calls out modern browser-facing applications as a place where JSON makes sense. 1 That concession matters. The argument is not "XML good, JSON bad" as a rule. It is "JSON's default ergonomics are not the whole engineering trade-off."
The last section handles the size objection. Seemann admits XML is more verbose, even giving a tiny example where the XML representation is more than twice the character count of the JSON representation. His reply is pragmatic: size is often not the deciding factor, and when it is, JSON may be too large as well. 1
He closes with the claim that XML's mature standards ecosystem, including schemas and support for sum-type-like structures, is the thing JSON keeps trying to reconstruct. JSON Schema's own site makes the same need visible from the other direction: it describes JSON Schema as the vocabulary that enables data consistency, validity, and interoperability at scale. 6

The important technical detail

The most important detail is the distinction between syntax and contract.
RFC 8259 defines JSON as a lightweight, text-based, language-independent data interchange format with a small set of formatting rules. Its grammar covers structural characters, strings, numbers, objects, arrays, and the literal values false, null, and true. Comments are not part of that grammar. 7
That minimalism is JSON's strength. It is easy to emit, easy to parse, easy to eyeball, and easy to adopt across languages. It also means JSON by itself says almost nothing about the shape a particular application expects.
XML made a different bet. XML itself is also a document syntax, but the ecosystem around it includes formal schema machinery. XSD's own specification says its purpose is to define and describe classes of XML documents by constraining and documenting their parts: datatypes, elements, content, attributes, values, usage, and relationships. 8
In FP terms, this is the difference between passing a loose map around and parsing it into a domain type at the boundary. The loose map is flexible, but the program still assumes something about it. The parsed type makes the assumption explicit.
That does not automatically make XML pleasant. It does make Seemann's argument sharper than a format preference. He is saying that interchange is not only about the cost of writing payloads. It is also about the cost of discovering, evolving, and checking the contract those payloads imply.

What the post gets right

Seemann is strongest when he treats schema as a tool for managing social scale, not just machine validation.
Small teams can get far with examples and conventions. The trouble starts when a payload has multiple producers, many consumers, long-lived versions, generated clients, archival data, regulatory constraints, or external partners. At that point, the format has to answer questions humans stop being able to answer reliably from memory.
Which fields are optional? Which variants are legal? Can the consumer ignore unknown values? Is order meaningful? Can the producer add a new case without breaking old readers? Are duplicate names allowed? What happens if the value is present but null?
JSON can answer these questions with JSON Schema, OpenAPI, protobuf, application code, or hand-written documentation. Seemann's point is that this means the format's winning simplicity is partly bought by pushing the specification elsewhere.
That is why the post belongs in this channel. It is the same argument FP developers make when they prefer total functions, typed errors, algebraic data types, and parsers over unchecked dictionaries. The value is not academic neatness. The value is making illegal or ambiguous states harder to smuggle across a boundary.

Where I would be careful

The post underplays one reason JSON won: it fits the everyday shape of web programming. JavaScript object literals made JSON feel native on the client, and the surrounding tooling compounded that advantage. Seemann acknowledges this when he says he would use JSON for modern single-page applications and backend-for-frontend services. 1
There is also a cost to XML's power. A mature standards ecosystem can be a gift, but it can also become a menu of features nobody on the team wants to own. If a team reaches for XML because it wants schemas but accidentally imports a whole culture of heavyweight document processing, the cure can feel worse than the disease.
So the practical lesson is not "switch back to XML." It is stricter than that: decide where the contract lives, and make that decision explicit.
If JSON plus JSON Schema gives your team a checked, versioned boundary that people actually maintain, Seemann's critique has been answered. If JSON is only a bag of examples and tolerant parsers, the contract has probably moved into production traffic.

How to apply it

Use Seemann's post as a boundary-design checklist:
  1. Ask whether the payload is only syntax or also a contract. If multiple teams depend on it, the answer is almost always contract.
  2. Write down where the contract is enforced. Schema, parser, generated type, test suite, API gateway, consumer code, or human convention are not interchangeable.
  3. Model variants explicitly. If the payload has cases, states, or alternatives, make those cases visible somewhere machine-checkable.
  4. Treat examples as tests, not specifications. An example shows one legal value. It does not describe the whole space.
  5. Prefer boring adoption when the boundary is local. For a small internal endpoint or browser-facing JSON API, the mainstream format may still be the right trade-off.
The FP-flavored rule is simple: parse at the edge, keep the domain small, and do not confuse a convenient wire format with a reliable model of the problem.

Lines worth keeping

Seemann's cleanest summary is the opening thesis:
"JSON is not a good data-interchange format."
The more important version is this:
"XML allows gradual enhancement."
The static-typing bridge is the strongest sentence in the piece:
"Only, as suggested by Hyrum's law, the contract is implicit."
And the pragmatic escape hatch keeps the argument honest:
"To be clear, I would pragmatically choose JSON in lots of cases today, simply because that's the expected format, and having to defend a less popular choice is rarely worth it." 1

Bottom line

This is not a call to revive every XML stack the industry worked hard to escape. It is a reminder that data interchange is a type-design problem wearing a file-format costume.
JSON made the common case easy. XML kept more of the contract machinery close to the format. The right lesson is to stop treating that machinery as optional once the boundary matters. Whether you use XML, JSON Schema, OpenAPI, protobuf, or a hand-rolled parser, the contract exists. The only real choice is whether it is explicit enough for the next maintainer to find before production does.

Related content

  • Sign in to comment.
More from this channel