docs: add ADR 0035, move SDK application crates into a product repository - #861
docs: add ADR 0035, move SDK application crates into a product repository#861coroiu wants to merge 1 commit into
Conversation
…tory Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deploying contributing-docs with
|
| Latest commit: |
00b9b1b
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://f0271e58.contributing-docs.pages.dev |
| Branch Preview URL: | https://docs-adr-0035-product-reposi.contributing-docs.pages.dev |
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE This PR adds a single new file, Code Review Details
|
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 560" fontFamily="ui-sans-serif, system-ui, sans-serif"> | ||
| <text x="120" y="70" fill="#1a1a1a" fontSize="30">SDK</text> | ||
| <text x="472" y="66" fill="#888" fontSize="26">NPM</text> | ||
| <text x="800" y="70" fill="#1a1a1a" fontSize="30">Clients</text> | ||
|
|
||
| <line x1="500" y1="110" x2="500" y2="490" fill="none" stroke="#888" strokeWidth="2" /> | ||
|
|
||
| <g fill="none" stroke="#1a1a1a" strokeWidth="3" strokeLinecap="round"> | ||
| <path d="M70,120 L290,120 C360,120 380,300 450,300" /> | ||
| <path d="M70,165 L240,165 C330,165 370,300 450,300" /> | ||
| <path d="M70,210 L190,210 C300,210 350,300 450,300" /> | ||
| <path d="M70,480 L290,480 C360,480 380,300 450,300" /> | ||
| <path d="M70,435 L240,435 C330,435 370,300 450,300" /> | ||
| <path d="M70,390 L190,390 C300,390 350,300 450,300" /> | ||
| <path d="M70,300 L450,300" /> | ||
| <path d="M550,300 C650,300 700,210 810,210 L930,210" /> | ||
| <path d="M550,300 C630,300 660,165 760,165 L930,165" /> | ||
| <path d="M550,300 C620,300 640,120 710,120 L930,120" /> | ||
| <path d="M550,300 C650,300 700,390 810,390 L930,390" /> | ||
| <path d="M550,300 C630,300 660,435 760,435 L930,435" /> | ||
| <path d="M550,300 C620,300 640,480 710,480 L930,480" /> | ||
| <path d="M550,300 L930,300" /> | ||
| </g> | ||
|
|
||
| <path d="M450,300 L550,300" fill="none" stroke="#1a1a1a" strokeWidth="3" strokeLinecap="round" strokeDasharray="2 14" /> | ||
| </svg> |
There was a problem hiding this comment.
♻️ DEBT: Diagram is inline SVG rather than Mermaid, and carries no perspective caption
Details and fix
The diagram standard adopted in ADR-0033 states rule 1 as "Diagrams are Mermaid source text, nothing else" and rule 4 as "Every diagram carries a perspective caption: audience, intent, and scope", attached as an italic blockquote below the diagram. This is the only inline <svg> in docs/; the two remaining SVGs are the autofill assets that ADR-0033 records as a tracked deviation until replacements ship, and this site is meant to be the standard's reference implementation.
There is also a concrete rendering consequence: the strokes and text are hardcoded to #1a1a1a (and #888). docusaurus.config.js sets no colorMode override, so the default dark-mode toggle is available, and in dark mode near-black lines on the dark background make the diagram effectively invisible. Mermaid inherits the site theme automatically, and markdown.mermaid is already enabled.
A flowchart LR with the contributing teams fanning into a single publish node and out to the consuming clients would carry the same "serialized pipeline" message, in theme-aware, diffable source.
🎟️ Tracking
No Jira ticket. This ADR came out of a cross-repo breaking-changes investigation.
📔 Objective
Adds ADR 0035 (status: Proposed): move the SDK's application-logic crates into a product repository so they compile together with the clients that consume them, while keeping the core infrastructure crates as a separately published, versioned library shared across products.
The ADR records the problem (breaking changes serialized through the npm/Maven publish pipeline, worsening as more teams contribute to the SDK), the options considered (do nothing, additive-only, coordinated merge gate, plain monorepo, product repository), and the decision with its consequences, plan, open questions (mobile), and follow-ups (the server circular dependency).
Proposed for discussion.
If you prefer you can also look at the hand-written version/starting point
Input for ADR
Ever since we introduced more teams into the SDK we've had a continuous challenge: Breaking changes.
Developers want to move fast, and the best way of doing that is using breaking changes, because of this
we've continuously tried to find ways of enabling this. An example of this is the breaking changes detection
workflow which coordinates with the
clientsmonorepo to build the latestmainclientscommit againstSDK PRs (this actually started with a purely static analysis of the TypeScript types on the SDK repo alone).
The goal of this workflow was to encourage and guide developers to have fix PRs for the breaking changes reviewed and ready for merge. Unfortunately, it hasn't achieved this to the degree that we were hoping for as we've seen breaking changes increase even with the workflow. I argue that not doing anything is not an option, as the situation will continue to deteriorate as more and more features and development moves to the SDK.
What is the problem with breaking changes?
The issues with breaking changes can be traced back to the SDK living in a separate repository and pulled into the clients as a published NPM package because of how it collapses the flow into a serialized delivery pipeline. In other words, it creates a bottleneck.
<style> .rail { fill: none; stroke: #1a1a1a; stroke-width: 3; stroke-linecap: round; } .dash { fill: none; stroke: #1a1a1a; stroke-width: 3; stroke-linecap: round; stroke-dasharray: 2 14; } .npm { fill: none; stroke: #888; stroke-width: 2; } .label { fill: #1a1a1a; font-size: 30px; } .npmlabel { fill: #888; font-size: 26px; } </style>SDK
NPM
Clients
Think of this in another way, every breaking change in the SDK adds to a queue of fixes that then need to be merged on the clients repo, in the same order as they were merged in the SDK. So if Team A merges a breaking change into the SDK, then every other team needs to wait for the corresponding clients fix until they can start pulling in SDK features merged after the breaking change.
I did some research by asking Claude to look at the previous 12 months. When reading it it's important to note that, while research may show a median breaking change on clients only taking a couple of hours to fix, that is a couple of hours where nobody else can merge. It's one thing to look at it from the perspective of absolute time, and another from the perspective of total person-hours affected. Here is what the research found: [claude: insert your research and conclusions here].
Side-note on Server - SDK breaking changes
These also present a challenge because of how we automatically generate API bindings from server commits.
However, this relationship is a bit different and can be split into two parts:
Compile time breaks
These are the ones that are most similar to the SDK - Clients breaks. If a breaking change is merged on the server then
a fix needs to be merged on the SDK before any additional changes after the break can be pulled in. The research shows [claude: insert research here (these are not as common)].
Run time breaks
These come from the fact that running SDK instances are not physically tied to a server version (SDK is client side, Server is server), meaning that the SDK needs to combine static type safety with the ability to handle unknown data coming from an unknown server version. This is fundamentally different from SDK - Client where the SDK is physically bundled with each client at compile time. We need to follow-up on this separately, but it is just a matter of implementing better support for these scenarios, and not an architectural re-design.
Alternatives considered
Coordinated merge gate (cross-repo/meta-repo)
Keep the repos separate, but link a breaking sdk-internal change to its clients/mobile
fixesand merge them together as one gated change set, essentially a distributed atomic merge. This would probably be implemented as an extension of the automations we already have.Advantages
Disadvantages
package.jsonversionBan breaking changes
Exactly what it says, ban breaking changes and force every update to be backwards compatible.
Advantages
Disadvantages
Do nothing - improve what we can
Continue allowing breaking changes, don't move any repositories, don't add any gates.
This actually turns into a collection of smaller solutions, some examples:
Advantages
Disadvantages
Monorepo
The solution that was chosen for
jslib: move the SDK into theclientsrepo.Advantages
Disadvantages
Product repository
Similar to the monorepo but taking Bitwarden's ambition of becoming a true multi-product company into account. The core idea here is: Move closely related code together to address the most frequent breaking changes but keep the core infrastructure separate and available for other products. There is a fundamental assumption being made here: Products will not need to share application logic at the SDK level.
Advantages
clientsrepo, e.g. Secrets Manager.Disadvantages
Solution chosen: Product repository
This solution combines a few key traits that makes it stand out as the best solution: Fastest development time, smallest maintenance cost. It's a one time effort, one that we've done before with
jslib, which results in an environment that lets us write any type of changes as often as we want without having to worry about compatibility.Some additional points [claude: try to merge these into flowing text with the section above]:
Open question
mobilenow? Or leave it as a standalone repo for now?Follow ups