Many enterprise software teams use a product requirements document (PRD) to move an idea from one group to another.
A product manager writes the document. An engineering team reads the document and gives an estimate. A design team makes a model that does not fully match the document. The product manager changes the document. The engineering team gives a new estimate. The design team changes the model.
This sequence can continue for many weeks. The software that the team then makes is often different from the first idea.
This sequence is not a failure of the people. The people do the work that the tools permit. The gap between an idea and software that operates is large. A document does not close that gap. A document describes the idea. Description loses information.
The person who has the idea cannot show the idea in the software. That person can only describe the idea. The engineer who receives the description must interpret the description. Each step away from the first idea causes more loss of information.
| Sequence that uses a document | Sequence that uses a branch |
|---|---|
| Write a PRD | Make a feature branch |
| Request a design | Make a user interface with typed fixtures |
| Give an estimate | Put the branch on a server and open a preview URL |
| Change the document again | Receive approval from the stakeholder |
| Make the software | Make the software safe for production |
| Release the software | Release the software |
Some teams try to decrease this loss with better procedures. Examples include design sprints, prototype sessions, and user story maps. These procedures improve the description. The gap stays.
An alternative sequence
A different sequence is possible when the software architecture permits it.
A product manager has an idea. That person:
- Makes a copy of the monorepo and makes a feature branch
- Makes a user interface in the presentation layer. The user interface uses typed fixtures. It does not use API code or a database.
- Puts the branch on the server. A preview environment starts automatically.
- Gives a URL to the stakeholder on the same day.
Some ideas receive approval on that day. Some ideas do not. An idea that stops at this step would often stop many weeks later in a sequence that uses a document. The team learns this result with less work.
When the preview is approved, the engineering team takes the branch. The work of the engineering team is to make the implementation safe for production:
- Move reusable components into the shared component library
- Make the API handlers and the database schema
- Make the validators and replace the fixtures with real API calls
- Make the end-to-end tests
The engineering team does not interpret a vision. The engineering team hardens an implementation that the stakeholders already approved.
The question of whether this is the correct thing to make is already answered. The remaining question is how to make this correctly. That is the question that engineers are trained to answer.
The product manager did not write a specification as a document. The product manager wrote a branch. The branch is the specification.
Safety limits
A feature branch is not production software. A person who is not an engineer can make errors in the presentation layer. The architecture must contain those errors.
The presentation layer cannot change tenants, permissions, or stored data. Preview environments stay behind a review step before a merge. The engineering team still decides what enters production.
If these limits are not in place, a feature branch is not a safe specification. It is unreviewed code.
The architecture
This sequence needs a monorepo that contains a presentation layer, a business and API layer, a shared schema package, a component library, and end-to-end tests. The layers are separated by purpose. They are not separated by deployment boundary.
graph LR PL["Presentation"] -->|API calls| BL["API Layer"] PL & BL -->|imports| SP["Shared Schema"] BL --> DB[(Database)] CL["Component Library"] -.->|used by| PL
- Presentation layer. This layer does rendering and user interaction. This layer calls the API. This layer does not know about tenants, permissions, or data storage. A person who is not an engineer can work here without a change to the layers below.
- Business and API layer. This layer is headless. It serves the presentation layer, mobile clients, third-party integrations, and public API users through one surface. Multi-tenancy, role-based access control, and compliance limits are applied here. Clients above this layer do not see those controls.
- Shared schema package. This package holds the type definitions for each data shape. Both layers validate against this package. The fixtures in the prototype use the same types. The team has one source of truth in one repository.
- Component library. This library holds shared parts of the user interface.
- End-to-end tests. These tests validate the full path after the engineering team connects the real API.
The specific tools can change. The necessary conditions do not change. The system must have shared types. The API must not contain the user interface.
Agents as one more client
Enterprise applications must now give capabilities to agents.
Some teams treat this as a new system. They make a new surface, new authentication, new schema definitions, and a dedicated team. That approach does the same work two times.
graph LR WEB["Web"] & MOB["Mobile"] & MCP["MCP Server"] & PUB["Public API"] --> BL["API Layer"]
The presentation layer is one client among several. If the business layer is headless and the schemas are shared, an MCP server is an addition. It is not a new structure.
The MCP server uses the same handlers, the same validators, and the same authorization guards. The agent receives the same multi-tenant interface as the web client. It receives that interface because it is the same interface.
The schema package that defines API responses also defines MCP tool signatures. An agent that uses these capabilities uses the same contract that a product manager used in a prototype.
The schema as a contract
Fixtures are not false data. Fixtures are typed statements about the shape of real data.
When a product manager makes a feature branch with fixtures, that person writes a specification. The API must return data in this shape. The user interface must behave in this way when it receives that data.
The engineering team then makes that specification real. When the engineering team makes the endpoint, it satisfies a contract that the prototype already showed to stakeholders. The data shape does not contain surprises. The user interface and the API cannot disagree about types, because both import one schema package.
The knowledge of the organization about its data shapes exists in one place. The system applies that knowledge in all clients. Humans and agents can read it.
The cost of distribution
Teams often divide an API into microservices to increase scale and team independence. The cost of that division is less often measured.
If the API is divided into services, the prototype sequence fails:
- Fixtures must span service boundaries
- Schemas change independently. After some months, the fixture of the product manager does not match what any service returns.
- A preview environment must start many services and their dependencies
- The product manager cannot make a prototype without infrastructure support. That support becomes a ticket. The ticket waits in a sprint. The idea is then many weeks from a test.
There is also an operational cost. A change to a shared type in a distributed system is not one change. The team must make the change. Then the team must wait for CI to publish a package. Then the team must go to another repository to increase the version. Then the team must wait for that pipeline. The team must do this again for each consumer.
A change that takes minutes in a monorepo can take days across services. Each handoff is a location where an error can occur. A secret can be incorrect. A version can be incorrect. A pipeline can fail at the end of the week.
The monorepo reduces this work to one CI run, one secret store, and one pull request that contains the full change. When a failure occurs, there is one place to look.
Enterprise teams often describe a monolith as a scale risk that they manage. A distributed system is a complexity cost that they often do not measure.
Enterprise constraints
A frequent objection is that enterprise requirements force this complexity. Multi-tenancy, SOC 2, HIPAA, many client types, public APIs, and mobile applications look like reasons for dedicated services.
These requirements do not force dedicated services:
- Multi-tenancy is a concern of the API layer. Middleware and guards apply it. The presentation layer does not see it.
- Compliance boundaries are applied at the same layer.
- Web, mobile, and agent clients use the same headless API.
- A public API is one more consumer of the business layer. It can have its own authentication and rate limits. It does not need its own codebase and CI pipeline.
The team can divide the monolith later, at a specific bottleneck, with evidence. The team does not need to divide it first as coordination infrastructure for a problem that does not exist yet.
Pre-emptive division feels like architecture. It also has the cost of architecture.
Conclusion
When a person who is not an engineer can make a feature branch, the work of the organization changes.
Product managers do not write requirements that lose information in transfer. They do not wait for engineering time to learn if an idea has value. They can learn this in days. Engineers who receive branches do not interpret documents. They decide what to extract, what to harden, and what to remove.
The time between an idea and a released feature decreases. An agent can also operate in this loop on the same codebase with the same contract.
The limit is not the skill of the product manager or the engineer. The limit is whether the architecture lets a person show an idea as software before the team agrees to make it.
If a person who is not an engineer cannot make that branch, the team will continue to move ideas through documents. Documents will continue to lose information.
Further reading
- MonoRepo — Martin Fowler on the case for keeping all your code in one place
- Trunk-Based Development — the branching strategy that keeps prototyping fast and merges cheap
- Model Context Protocol — the open standard for connecting language models to tools and data sources