Work on Features, Not Repositories
Why organizational boundaries shouldn’t change where development happens.
Recently on Twitter, Kent C. Dodds asked:
Hey folks who have a decoupled client-server application (no server rendering, server is just an API server). Where is your client code and server code located?— Kent C. Dodds (@kentcdodds) September 1, 2018
It’s an interesting question, as we often have various reasons to split projects into multiple repositories. (e.g. if I don’t share code between the client & server, then they should be separated, right?)
In my experience, a repository should house all of the code necessary to make developing & shipping features relatively frictionless.
Software is like Jello: poke it in one place, and another place jiggles.
A Real-World Example
Starbucks’ Progressive Web App (PWA) is basically a single-page React app managed within a single repository. The GraphQL API is in another repository.
In practice, working on the UI that requires API changes means:
npm linkour API to our PWA.
Working on the UI changes until real data is needed, then…
Working on the API changes, until the UI is working again.
Pushing 2 pull-requests for approval.
Once approved, bumping & releasing the API first.
Finally, bumping & releasing the UI.
There are a lot of places this process breaks down, especially on large teams with a lot of work in-progress.
But the real problem is that the repositories are splitting up features based on implementation.
Ideally, I’d like to see:
Working on the UI & API simultaneously. (In practice, this expedites discovery & turnaround!)
Pushing a single pull-request can be reviewed, approved, and tested.
Once approved, the UI & API is shipped as a single feature slice.
A single repository, properly structured, can deploy to multiple hosts, as separate NPM packages, or as a single monolithic app.
How code is shipped does not have to mirror how it is developed.
But We’ve Known This Already.
Just Look At React Components
When I first started working with React, it was normal for separation of concerns to mean separation of file types.
But overtime, possibly expedited thanks to CSS-in-JS, we began to encourage natural coupling of technologies around features.
If you want to touch the UI and it means the API has to change, that’s perfectly natural. Self-imposed splitting of code into repositories is a form of premature optimization.
Instead, make adding value easy. And when it’s not easy, split up your code, change your tools, re-architect your app, or whatever.
It’s much easier to blow something up than to piece it back together.
For more content on co-locating files with their features, check out Kent C. Dodds’ “What code comments can teach us about scaling a codebase”.