October 09, 2024 · 3 min read

From 0 to Production in a Startup Environment

Abstract. Engineering lessons from building production systems when speed, ambiguity, and maintainability all matter.

Startup engineering is not about moving fast by ignoring engineering. It is about choosing which engineering problems deserve attention now and which ones can safely wait.

That distinction is hard. Early systems are built under uncertainty: the product may change, the customer may change, the team may change, and the architecture may need to survive decisions that were made before the problem was fully understood.

Architecture early on

The first architecture should be easy to change.

That usually means:

  • simple deployment;
  • few services;
  • clear module boundaries;
  • boring databases;
  • explicit integration points;
  • logs that explain what happened.

The mistake is not starting simple. The mistake is starting vague.

A monolith can be a good decision if the boundaries inside it are clear. A set of microservices can be a bad decision if the team does not yet understand the domain boundaries.

When not to build microservices

Microservices add coordination cost. They require service ownership, API contracts, deployment discipline, observability, and operational maturity.

In an early product, the bottleneck is often not service scalability. It is learning. Splitting the system too early can slow that learning down because every product change becomes a distributed change.

I would rather start with a modular monolith and extract services only when there is pressure that justifies the extraction:

  • different scaling profile;
  • different reliability requirement;
  • clear ownership boundary;
  • separate deployment cadence;
  • external integration isolation.

Without one of those reasons, a service boundary is often just a tax.

Speed versus maintainability

Speed and maintainability are not opposites.

The fastest teams I have seen are not fast because they ignore structure. They are fast because the structure is understandable. Engineers can find the right place to make a change, understand the side effects, and ship without negotiating the entire system each time.

Useful maintainability work in a startup is usually practical:

  • naming things consistently;
  • keeping data models legible;
  • writing the runbook after the first incident;
  • adding tests around critical flows;
  • making external integrations replaceable;
  • deleting code paths that no longer matter.

This kind of work compounds.

Technical debt

Technical debt is not automatically bad. Some debt is the price of information.

The dangerous debt is debt that hides:

  • unclear ownership;
  • duplicated business logic;
  • implicit state;
  • unknown failure modes;
  • manual processes that nobody remembers;
  • integrations that cannot be safely changed.

The useful habit is to label shortcuts when they are taken. A shortcut that is visible can be managed. A shortcut that becomes part of the culture becomes architecture.

Production changes the product

A system becomes different after users depend on it.

Once the product is in production, the engineering problem includes migration, support, observability, backward compatibility, and incident response. These are not secondary concerns. They are part of the product.

The best early systems are not perfect. They are understandable enough that the team can improve them while the product is moving.