Engineering

Our engineering principles.

Eight rules we use to write code, ship features, and decide when to deploy. They are not novel and they are not universal. They work for us, at our size, on this kind of product. The cases where we have broken each rule are also in the post.

We wrote these down because we were tired of re-deriving them in every design review. The list is short on purpose; longer lists do not get read. Each principle has a short rationale, a concrete example, and the case where we broke it.

1. The data layer is the product

Most of what looks like product work, on this product, is actually data-layer work. If the schema is wrong, the UI is wrong. If the indexes are wrong, the performance is wrong. If the permissions are wrong, the security is wrong. I treat the data layer like it is the user interface, because it is.

Example: the work graph (the long version is here) gets treated as its own product, separate from any user-facing surface. The schema, the planner, the indexes, the audit log are the deliverable. Everything else depends on getting them right.

Where I broke it: early on, I treated the data layer as plumbing. I built module features first and tried to make their schemas talk to each other afterward. The integration cost compounded. The course correction was to stop feature work and write the graph layer properly before going any further.

2. Ship the smallest correct version

We default to the smallest version that is correct end-to-end, with a path to expand. "Correct end-to-end" is the key constraint: a feature that demos but does not pass the eval set is not shipped. A feature that passes the eval set but is missing the cosmetic polish, can ship.

Example: when we added INR and SGD to pricing, we shipped the currencies first, the regional tax rules in the next release, and the per-region invoice templates two releases later. Each step was correct on its own.

Where we broke it: Documents launched with eighteen of the planned features. The first three releases after launch were spent finishing the original list, not adding new features. In retrospect, we should have shipped twelve features and called it done.

3. Defaults are decisions

Every default we ship is a choice on behalf of the customer. We treat defaults like product copy: argued, reviewed, never set absently. A default that is wrong for 60 percent of customers is worse than no feature.

Example: the assistant's default approval threshold for outbound actions is $250. We argued about it for three weeks. We picked $250 because it covers the long tail of small actions (book a meeting, send a recap) without covering the actions that should always be approved (send a contract, charge a card).

Where I broke it: I shipped a default that made every Doc public-to-the-workspace, on the theory that "find-ability" was the dominant need. That was the wrong call for most real use; privacy mattered more than I had weighted it. I changed the default later, but a default like that is the kind of decision people live with from the first invite, which is exactly why defaults deserve the scrutiny.

4. The eval set is the spec

For features that involve a model, we write the eval set before we write the prompt. The eval set is the spec. If the eval set passes at a rate above the threshold, the feature ships. If it doesn't, the feature doesn't ship, regardless of how good the demo looks.

Example: for a feature like contract redline, the eval set is drawn from real contract language and scored against how a careful reviewer would mark it up. The threshold is set before the prompt is written, and the feature does not ship until it clears that bar, however good the demo looks.

Where I broke it: an early version of the meeting-recap feature shipped with a thinner eval set than it needed. The edits it required in practice were higher than I expected, so I rebuilt the eval set using those corrected recaps as ground truth.

5. Every deploy is a roll-forward

We do not ship features behind a flag and never turn it on. If a feature ships, it ships to 100 percent within four weeks of the first percent. Either it works and we roll forward, or it does not and we roll back to nothing. There is no "permanent beta."

The reason: feature flags accumulate. A flag that is on for some customers and off for others doubles the code paths we have to maintain. After a year, you have hundreds of flags and you cannot reason about the product. We keep the flag count under 25, by retiring flags aggressively.

Where I broke it: the BYO-model feature stayed a partial roll-out far longer than this rule allows, because its failure modes were complicated and I was not ready to commit either way. Carrying both code paths was exactly the tax the rule is meant to avoid.

6. Read the audit log

The audit log is the most-honest source of truth about how the product is used. I read it for each module regularly. The patterns there inform the roadmap more than any survey, NPS score, or "voice of customer" exercise.

The audit log shows what people did. Surveys show what people remember doing. The two diverge.

Example: I removed a confirmation step from the Tasks "complete" action after the audit log showed that the overwhelming majority of confirmations were on tasks the user had created themselves, where the extra tap bought nothing. I kept it for tasks created by someone else.

Where I broke it: for a while I stopped reading the log for the search module, because the query was painful to write. The fix was to make the per-module audit query a one-click thing in the internal admin. Once the friction was gone, I actually used it.

7. Boring infrastructure

We pick the boring choice for infrastructure unless we have a strong reason to pick the interesting one. Postgres over the trendy database. Go for backend services unless the case for something else is overwhelming. AWS over the multi-cloud abstraction layer. Attention is the scarce resource; it goes to the product, not the stack.

Example: the work graph runs on Postgres with custom extensions. We considered a graph database; we ran a four-week prototype; we picked Postgres because the operational cost of the alternative was higher than the engineering cost of building on Postgres.

Where I broke it: the columnar tier is not a boring choice. It is a less-mature piece of the stack. I took the risk because the analytical workload demanded it, and I paid for it with a handful of hard debugging sessions while I learned its failure modes.

8. The hardest path is sometimes correct

The rules above bias toward simplicity. They are not rules to avoid hard work. Sometimes the right answer is the hard answer, and the rules above are not an excuse to dodge it.

Example: permission-aware retrieval at query time, not at index time. The easy version is to filter results post-retrieval. We picked the hard version because the easy version leaks data. The hard version took two quarters; we still ship it.

Example two: the assistant runtime is a state machine on top of a model, not a chat-plus-tools loop. The chat-plus-tools loop was the easy version. The state machine took four months of rework. The result is a runtime we can reason about, audit, and ship.

How we ship, day to day

Beneath the principles are practices. The ones we care most about:

  • Continuous deploy for services. Every commit on main that passes checks goes out. There is no separate staging environment; staging is production with a different feature flag set, and the flag count stays low.
  • Tagged releases on a predictable cadence for the platform. Real names, changelog entries, release notes. The cadence is regular, the content is not artificial.
  • A written postmortem for anything serious enough to be user-visible. Done properly, before moving on, rather than as theater. The discipline is the point.
  • Stay close to how the product is actually used. In the user's own words, not a summary of them. The moment you start working from summaries, you start building for a user who does not exist.

What we don't say but mean

Two things that are not in the formal list, but inform how we work:

Avoid the heroic. A heroic late-night save is a failure of system design, not a success of operator skill. The right response to one is not a medal, it is making sure the situation cannot recur. Anything that runs on heroics eventually burns out the hero.

No rule here is sacred. Every principle above has been rewritten at least once as the product taught me something. The rules are a starting position. They are not a religion.

If any of this resonates and you want to talk about how it would translate to your team, drop a note: hello@wrxstack.com. We read every one.

F

Farhan

Farhan is the solo builder of wrxstack. He designs, writes, and ships Atlas and Portfolio on his own, and writes here about product, engineering, careers, and the craft of building software as one person.