Skip to content

product

A deployed build every Friday

8 min read

Every Friday there is a URL, and the thing behind it runs. Not a screenshot, not a status update, not a branch that is nearly ready. That is the visible half of the arrangement. The invisible half is the set of engineering decisions it forces, and those are the more interesting part.

Vertical slices, not horizontal layers

The comfortable way to build is by layer. Schema first, then the API, then the interface. It groups similar work, it reads well on a plan, and nothing is deployable until the last layer lands. Every integration bug in the project is then scheduled for the same week, which is also the week before the deadline.

A vertical slice is one use case, end to end, with everything around it missing. For a child growth tracking application the first slice is one parent, one child, one weight measurement, written to Postgres, read back, drawn on a chart, deployed. No roles, no second locale, no immunization records, and a session that is hardcoded.

What that buys is early contact with the boring seams: serialization, timezone handling, error surfaces, the deploy configuration, and the difference between the date a measurement was taken and the timestamp the row was written. A timezone disagreement found in week one is a fix. The same disagreement found in week six, after three layers have each quietly picked their own assumption, is a schema change with a data migration attached to it.

The cost is real: some code gets written twice. The hardcoded session becomes real authentication. A stub becomes a service. We take that trade every time, because rewriting a stub you always intended to rewrite is cheap, and reconciling three layers that disagree about what a date is costs whatever it costs.

Continuous deploy before there is anything to deploy

The first deployment happens before there is a feature, and it deploys almost nothing: a page with the name of the application on it, pushed through the pipeline that will carry the next six months of work. In week one that is worth more than a feature running on a laptop.

Environment drift compounds, and it never accumulates in one place. A Node version. An environment variable that exists in one environment. A Postgres extension somebody enabled by hand while debugging. A build step that passes because of a file in one developer's home directory. Three weeks of divergence is a bad afternoon. Three months of it is a project inside the project.

The specifics we hold to: one container image promoted between environments rather than rebuilt per environment, configuration injected as environment variables, and migrations run as an explicit step in the deploy pipeline rather than at application boot. The last one matters more than it looks. A migration at boot turns a bad migration into a crash loop across every instance. A migration as a deploy step turns the same mistake into a failed deploy with the previous version still serving traffic.

Week one deployment also finds out that nobody has the cloud permissions they believed they had. That is a good week to find out.

Build toward the riskiest assumption

Sequence by risk, not by the order things appear in the specification and not by which part is pleasant to write. The question at the start of each week is which assumption, if it turned out false, would change the plan.

It is usually one of three: an integration behaves differently from its documentation, the real data has a shape nobody described, or a query that is fine on a thousand rows is not fine on ten million.

So if the plan rests on a legacy endpoint returning something usable, the first slice goes through that endpoint even when the interface it feeds is an unstyled list. If the plan rests on a query being fast enough, week one loads production-shaped volume into Postgres and runs the query, and the deliverable is a number with a row count beside it.

The failure this avoids has a recognizable rhythm: four productive weeks on well-understood work, a good feeling in every meeting, then a wall in week five that was visible on day one to anyone who looked at it. Doing the comfortable work first is not a schedule, it is a deferral with a chart attached.

Weekly delivery is what makes risk-first sequencing socially possible. Building the ugly thing first is a hard sell against a document, because the client watches a month of unattractive progress and has to take the reasoning on trust. It is an easy sell against a deployed slice they can click, because the reason is visible in the thing itself.

What the cadence forces you to automate

Anything manual and weekly gets automated by roughly week three, because nobody can stand doing it a fourth time. This is the most reliable side effect of the cadence and it happens whether or not it was planned.

  • Migrations, run the same way in every environment.
  • Seed and test data, because a demo needs a database that resembles something.
  • A preview environment per branch, which stops review from being a conversation about a screenshot.
  • Rollback as one command. Nobody writes this until the week they need it, unless the cadence drags it forward.
  • A smoke check that runs after deploy against the real URL and fails loudly. Deploy succeeded and application works are two different claims.
  • Release notes assembled from merged pull requests, because writing them by hand on a Friday afternoon is how they stop being written.

The rule we use is dull and it works: the second time a step gets done by hand on a Friday, it goes into the pipeline on the following Monday. Not the third time. Twice is enough evidence.

The compounding effect is that Friday becomes boring. Deployment risk is roughly proportional to the time since the last deploy, so a team deploying weekly is running the least dangerous version of the thing most teams find frightening.

Where weekly delivery goes wrong

Three failure modes, all of which we have had to build something around.

The cadence pulls work toward demos

A polished screen with hardcoded data looks finished. The same screen with a real query, an empty state, an error state, and pagination looks identical and takes three times as long. Under weekly pressure the first one is always tempting, and a project assembled from those is ninety percent done for months at a time.

Two countermeasures. A slice is not complete unless its unhappy paths ship with it, so the empty state and the error state are part of the definition rather than follow-up work. And whatever is not real gets named out loud in the demo and in writing: this list is live, this number is hardcoded, this button does nothing yet. A demo without that sentence is not a demo, it is a claim.

The third check is cheap. A slice counts as shipped when someone other than its author has walked through it in the deployed environment. Not on a branch, not on a laptop.

Some work genuinely does not slice

A data migration, a protocol implementation, and a compliance review all contain long stretches with nothing user-visible in them. Forcing those into a weekly demo produces theatre, and everyone in the room can tell.

The fix is to change the artifact rather than the cadence. For a migration, Friday's deliverable is the migration run against a production-sized copy of the data with a row-count diff and a wall-clock duration. For a protocol implementation, it is a conformance suite going from twelve passing cases to forty, in CI, visible to anyone who wants to look. For a compliance review, it is the control list with evidence attached and the count of controls that now have it.

The requirement was always that something checkable ships every week. It was never that something clickable ships every week. Conflating those two is exactly how a delivery cadence turns into a performance.

Weekly visibility invites feature-by-feature management

A client who sees something every week can start assigning next week's tasks. That is driving rather than steering, and it usually happens without anyone deciding to do it. The symptom is a Friday conversation that has stopped being about what the product needs and is entirely about what should be in next Friday's build.

Our response is structural. The Friday session has two halves and they stay apart. The first is what shipped and what we learned from it, including the parts that came out worse than expected. The second is what the next slice is and which assumption it tests. Feedback on details goes into the backlog in writing rather than reordering the plan live, and anything that does reorder the plan has to name what it displaces, because a week holds one slice and the arithmetic is not open to negotiation.

This is a genuine cost of the cadence rather than a client problem. Weekly delivery buys correction speed and charges for it in perspective. Somebody has to keep the six week view in the room, out loud, every week, or the project optimizes itself into a pile of individually sensible small decisions.

The rule for whether a piece of work can be sliced at all is a sentence test. Describe the smaller version in one sentence that contains the words for and only: export works, for one report type, for administrators only. If that sentence is honest and someone could actually use what it describes, it is a slice. If the sentence needs the word eventually, it is not a slice, it is a fragment with a screen in front of it, and the right move is to change what ships on Friday rather than to build something that merely looks finished.

Working on something similar?

Tell us what you are running into. We are happy to compare notes.