TL;DR
- Contention in a shared org is a queue, and queue wait grows as rho/(1-rho). At 50% utilisation a change waits about one service time. At 90% it waits nine. At 95% it waits nineteen.
- That is why a tenth team feels nothing like a second. The pain is not proportional to headcount, and the cliff arrives without warning because the formula has a cliff in it.
- A branching strategy relocates the queue. It does not delete it. Trunk-based development over a tightly coupled runtime moves the wait out of Git, where you can see it, and into the deploy queue, where you cannot.
- The number of teams who can ship without queueing behind each other is
teams * (1 - coupling), floored at one. In a single Salesforce org coupling is 1.0, so that number is one, no matter how many repositories you own. - Coordination is the exception. It is not a queue. It grows as n(n-1)/2 pairwise links, which is Brooks, and it is the dimension that repository splits never touch.
What You'll Learn
- Why delivery pain in a shared org is superlinear in team count, stated as standard queueing results rather than as an opinion
- The three physical quantities that decide every wait, and what each one is in Salesforce terms
- Why splitting repositories fixes the merge queue and leaves the deploy queue exactly where it was
- How to price contention in the right currency, separating engineer hours from lead time
- Where this model stops being defensible, and what to calibrate before betting a programme on it
The Problem
A platform team adds its seventh delivery squad to a shared Salesforce org and delivery visibly degrades. Releases slip, the validation queue is never empty, and two teams are always waiting on a Full Copy sandbox. The retrospective produces process answers: tighten the change advisory board, add a release manager, ask people to communicate better.
Six months later the same org has nine teams and the same conversation happens again, only worse. Nothing in the process fixes it, because the process was never the mechanism.
Common questions this article answers:
- Why does adding one more team hurt so much more than the last one did?
- Will moving to trunk-based development, or splitting our repository, actually reduce contention?
- How many teams can share one Salesforce org before delivery breaks?
Quick Answer
Contention is a queue, and queues have a known shape. Utilisation, written rho, is the fraction of a step's capacity that arriving work consumes. Expected wait scales with rho/(1-rho), so it stays flat and unremarkable through the middle of the range and then goes vertical near the top. At 50% utilisation a change waits roughly one service time. At 90% it waits nine. At 95% it waits nineteen.
Teams describe this as a cliff that appeared overnight. It was in the arithmetic the whole time, and the org crossed a threshold.
Branching strategy decides which step saturates first. It cannot decide whether one saturates, because the count of independent deploy streams is a property of the runtime, not of your version control. In a single Salesforce org, every change eventually converges on one deployment target guarded by one Apex test run, so the number of teams who can ship without queueing behind another team is one. Splitting repositories genuinely splits the merge queue. It leaves the deploy queue untouched, and moving a queue is not the same as removing it.
Every wait is three quantities
The whole model rests on three numbers per step, and each is something you can measure in your own org rather than accept on authority.
- Arrival rate. How much work reaches this step per unit time. Six changes per team per week is a reasonable starting figure, so ten teams put sixty changes a week into the merge step.
- Service time. How long the step takes to handle one item. A validation deploy that runs the full Apex suite is measured in hours.
- Servers. How many of that step run in parallel. This is the quantity that makes platforms feel different from each other, and it is usually the one nobody writes down.
Servers is where platforms differ most, and it is the number that gets left out of the conversation. A Salesforce validation deploy serialises behind a full Apex test run, so it has one. A CI runner pool has four, or forty. Feed both the same arrival rate and the same service time and they behave nothing alike, for reasons that have nothing to do with how the teams work.
Expected wait comes from Sakasegawa's approximation for M/M/c, which reduces to the exact M/M/1 result at a single server. The model fits nothing and chooses no exponent. The superlinear shape everyone recognises is the rho/(1-rho) term doing what it has always done.
The dimension nobody can split their way out of
Four things queue in a delivery system: merge and integration, deploy, environments, and coordination. Three of those are queues in the strict sense. Coordination is not.
Coordination follows Brooks. Across n teams there are n(n-1)/2 pairwise links, scaled down by how much of the system is actually shared. Five teams have 10 links, ten teams have 45, and twenty teams have 190. At a modest 0.6 hours per active link per week, ten teams are spending most of a full-time equivalent on staying in sync, and no amount of repository surgery reduces it, because the coupling that creates the links lives in the object model and the order of execution rather than in Git.
This is the dimension that the org fracture plane argument attacks directly. Splitting orgs cuts links. Splitting repositories inside one org does not.
Coupling sets your deploy streams
The arithmetic is small enough to write down:
deployStreams = max(1, round(teams * (1 - coupling)))
Coupling is literally the fraction of the deploy path that is shared. Run five real platforms through it:
| Platform | Coupling | Deploy streams at 10 teams |
|---|---|---|
| Salesforce, single org | 1.00 | 1 |
| Mobile release train | 0.85 | 2 |
| Salesforce, multiple orgs | 0.55 | 5 |
| Kubernetes microservices | 0.22 | 8 |
| Fully independent runtimes | 0.20 | 8 |
At coupling 1.0 the result is one for any team count. That is Conway's law falling out of arithmetic rather than being asserted in a paragraph, and it is why the honest answer to "should we split the repo" is usually "yes, and it will not do what you are hoping".
Branch lifetime interacts with all of this. Trunk-based work integrates in about a day and ships batches of roughly 3 changes, a release branch model runs 10 days and 20, GitFlow runs 21 days and 30, and environment branches run 60 days and 45. Longer branches conflict more often, because branch duration is one of the strongest measured predictors of conflict, and bigger batches make each visit to a shared environment more expensive when it finally happens.
Over capacity is a state, not a score
When more work arrives at a step than it can clear, the queue never settles and the textbook wait is undefined. A model that reports a large number there is lying with precision.
The useful output is a state: this dimension is over capacity, the backlog grows every week, and here are the stages responsible. Ranking still works, through how much backlog a week of load builds, but the number stops pretending to be a wait. If your validation gate is saturated, no scalar score describes your situation, and the useful question changes from "how bad is it" to "which stage do we uncouple first".
Price it in the right currency
Contention costs are usually collapsed into one money figure, which makes three different things look like one. Three of them are payroll:
- Conflict rework, the hours engineers spend resolving conflicts
- Coordination, the hours spent keeping cross-team links alive
- Blocked waiting, time a team cannot use because it has no environment, net of whatever it successfully redirects elsewhere
The deploy queue belongs to none of them. A change queueing for production does not consume anyone's hours, because the team moves on to the next thing. It costs lead time, which is a time-to-market cost rather than a payroll one.
Keeping those separate is what lets you see the shape of the decision. Moving from one shared org to several barely moves engineer days and improves lead time by an order of magnitude. A single blended figure cannot express that, so it produces business cases that argue for the wrong change.
Where this stops being defensible
Two anchors come from published work rather than from assertion. A study of 143 open-source projects found roughly one merge in five conflicts, which sets the baseline conflict rate. A separate analysis of 182,273 merge scenarios across 80 projects found branch duration, changed file count and committer count to be the strongest predictors of conflict, which is why branch lifetime carries so much weight above.
Neither was measured on a ten-team Salesforce org. Treat both as order-of-magnitude anchors, not calibration.
Everything else is judgment, and the point of expressing it in physical units is that it becomes arguable. "Our branches live three weeks, not one" is a conversation a client can have with you. "Our exponent is 1.42" is not a conversation at all. One guess resists that treatment and should be named: how much blocked time a team successfully redirects to other work, currently assumed at 70%.
The absolute numbers have no external meaning. The ordering, the relative sizes and the shape are the defensible parts. Calibrate against your own merge conflict rate, deploy queue waits and environment booking data before you spend real money on the conclusion.
See it on your own numbers
The model above is implemented as Signal Box, a release strategy contention simulator that draws your topology as a railway board. Branches are tracks, environments are stations, merges are junctions, and contention shows up as signals at danger with changesets queued behind them.
Move the team count and watch which signal drops first. On a single-org board at eleven teams, ten changes stack up behind the validation gate. Kubernetes at the same arrival rate has none. Below about six teams neither queues at all. That knee is what the tool exists to show you.
Client-specific numbers load from a JSON context file through the drop zone. Those files are read in the browser and never leave the machine, there is no server and no storage, and while a context is loaded the link sharing feature switches off entirely so a client's real team count cannot escape in a copied URL.
Frequently Asked Questions
Q: Will trunk-based development fix our contention?
A: It will reduce merge contention, and the reduction is measurable, because it collapses branch lifetime to about a day and conflict probability rises with divergence. On a tightly coupled runtime it will also increase pressure on the deploy queue, because you are now sending small changes at a shared gate more often. The contention moves from a place you can see to a place you cannot. That is still frequently the right trade, but make it deliberately.
Q: How many teams can share one Salesforce org?
A: There is no universal number, because it depends on your validation deploy duration, your merge rate and your environment pool. There is a reliable shape: nothing much happens, then a threshold is crossed and delivery degrades quickly. In practice the knee tends to appear around six teams on a single org with a serialised validation gate. Measure your own utilisation rather than trusting six.
Q: We split our monorepo into per-team repositories and nothing improved. Why?
A: Splitting repositories splits the merge queue, which is real. It does nothing to the deploy queue, because deploy streams are set by runtime coupling and a single org has coupling of 1.0. You fixed one of four dimensions and left the one that was probably dominant. Coordination is likewise untouched, because the pairwise links come from the shared object model.
Q: Is this model validated against real Salesforce programmes?
A: No. The queueing mathematics is standard and the two literature anchors are real, but neither anchor was measured on a Salesforce org, and the input parameters are judgment. Use it to compare options and to find which dimension dominates. Do not quote its absolute figures to a steering group as though they were measurements.
Key Takeaways
- Contention is a queue. Wait grows as rho/(1-rho), which is flat then vertical, which is exactly how teams describe the experience.
- Branching strategy relocates the queue. It decides which step saturates first and never whether one does.
- Coupling, not Git, sets deploy streams. At coupling 1.0 the answer is one stream regardless of repository count or team count.
- Coordination follows Brooks rather than queueing. n(n-1)/2 links grow faster than hands, and no repository split reduces them.
- Separate payroll cost from lead time. Blending them hides the exact decision that multi-org strategies are usually trying to justify.
What's Next?
Recommended Reading:
- Team Topologies for Salesforce: The Org Is the Fracture Plane
- Salesforce Admin Git Basics
- Git difftool vs mergetool
Action Items:
- Measure the utilisation of your validation gate: arrival rate times service time, divided by how many run in parallel. If it is above 0.8, that is your bottleneck and no process change will move it.
- Count your active cross-team links and multiply by a realistic hours-per-week figure. Compare the total against the headcount you were about to add.
- Model your current and target topology in Signal Box, then replace its default parameters with your own measured merge rate, branch lifetime and validation duration.
Resources & References
- Signal Box, release strategy contention simulator
- Reinertsen, The Principles of Product Development Flow, on queueing and why contention is superlinear in team count
- Brooks, The Mythical Man-Month, for the n(n-1)/2 communication path result
- Forsgren, Humble and Kim, Accelerate, on short-lived branches and independent deployability as measured predictors
- Humble and Farley, Continuous Delivery, on the deployment pipeline and separating deploy from release
- Sakasegawa's approximation for M/M/c queue waiting time, which reduces to the exact M/M/1 result at a single server
Responses
Checking your session.
Loading responses.