One Product, Many Surfaces
Model the application once, and each new channel becomes a projection instead of another implementation.
For most of the web’s history, “shipping the app” meant shipping a website. If you had budget, you added an iOS build, maybe an Android one, and a public API so partners could pull data. The list of ways someone could touch your product was short, and it stayed short for years. A team could hand-build each entry because there were three or four of them and they rarely changed.
The surface count keeps growing
That list isn’t short anymore, and it changes every quarter. You still have web and mobile. You have a REST API and probably a GraphQL one beside it. You have webhooks. You have an MCP server now because your users want their agents to reach your product without a human clicking through a UI. You have a Slack app, a browser extension, a CLI, and an embeddable widget that lives inside someone else’s dashboard. Each of these is a surface: a distinct way a human or a machine touches the same underlying product.
Most teams treat each surface as its own project. The web app has its own state management, its own notion of what a “project” is and which buttons should be disabled when. The mobile app reimplements that logic in Swift and Kotlin. The API has its own serializers and its own idea of which fields are writable. The MCP server, bolted on last quarter, has a third interpretation of the same rules. Five teams, or five sprints, each building a slightly different model of the same business.
The second change is where you pay
The cost of that isn’t the first build. It’s the second change. A product manager decides that an archived project can be restored within thirty days but not after. That’s one rule. Now it has to be re-expressed in the web client’s state machine, the mobile view models, the API’s permission checks, the MCP tool’s input schema, and the Slack command handler. Five implementations of one idea, written by different people at different times werre tested to different standards. They drift. The web app enforces the thirty-day window; the API forgot; the agent calling your MCP server happily restores a project from last year and corrupts a report. Nobody decided that behavior. It’s the residue of five surfaces each owning a copy of logic that should have lived in one place.
One state, many projections
The alternative is a single canonical representation of what your application is and what it can do, with each surface as a thin projection of that representation. The state lives in one place: what entities exist, what fields they carry, which transitions are legal, and who’s allowed to perform them. No surface owns any of that. A surface is a view onto it. The web client renders the state as HTML and interactive controls. The API renders it as JSON over HTTP. The MCP server renders the same legal transitions as tools an agent can call, with the same permission checks the web UI runs. When “restore within thirty days” becomes a rule, you define it once, against the canonical model, and every surface inherits it the moment you deploy. The agent can’t restore the year-old project because the state machine it’s projecting through won’t allow the transition. Not because someone remembered to add a guard in the MCP handler.
This sounds like ordinary good architecture, and at a small scale you can argue it’s premature. You can’t anymore. The objection used to be “you’re building an abstraction for surfaces you don’t have yet.” But you do have them, and you’re getting more whether you plan for them or not. MCP didn’t exist before Anthropic published it in November 2024. By 2026 it’s a surface your users expect, the same way they expected a mobile app in 2012 and a public API in 2016. You’re going to pay the cost of supporting these surfaces regardless. The only decision left is whether you pay it once, against a shared model, or N times, once per surface, plus the compounding tax of keeping N copies in sync forever.
New surfaces are distribution channels
That’s the defensive case. The offensive case is where this turns into an actual advantage, and it’s about speed.
Every surface is a distribution channel. It’s a place your product can be reached that it couldn’t before, by a kind of user or a kind of software that wasn’t in the room last year. When agents became real buyers of software functionality in 2025, the products that already exposed their capabilities as clean, callable transitions got reached. The products whose logic was trapped inside a React bundle did not. An agent can’t click a button that only exists as a rendered component with three hundred lines of event handlers behind it. It can call a tool. If your capabilities are already modeled as transitions on a shared state, exposing them as tools is a projection you write in days. If they’re scattered across client code, it’s a quarter of untangling, and you ship the integration after the moment that mattered has passed.
Speed on surfaces compounds. The architecture that makes your fifth surface cheap makes your eighth surface nearly free because the expensive part (deciding what your app actually is and means) is already done and reused. The team that can light up a new surface in a week while a competitor takes two quarters isn’t just faster. It’s present in places the competitor is absent: inside the agent that became the default way a customer segment gets work done, inside the partner’s dashboard, on the platform that didn’t exist when either company wrote its first line of code. Being early to a surface is worth what being early to the App Store was in 2009 or early to having any web presence was in 1996. The norms get set, the integrations get built, and the default gets chosen while the latecomers are still refactoring.
One place to reason about the product
There’s a quieter benefit too. When the state is canonical and surfaces are projections, you can reason about your whole product from one place. You can answer “who can do what” by reading the model, not by auditing five codebases and hoping they agree. New surfaces become a question of how to render existing truth, not what the truth is. That separation is what lets a small team behave like a large one: the work of defining the product happens once and the work of exposing it scales out cheaply.
Prepare for the surface without a name
The next surface is already coming, and you don’t know its name yet. Two years ago nobody was provisioning for MCP; two years from now there’s a channel we’re not describing here because it hasn’t shipped. The question that decides whether you reach it in time isn’t how clever your web app is. It’s whether your product is one thing with many views or a pile of views pretending to be one thing.


