intermediate

Repository pattern

Expose collection-like persistence operations while hiding query details and keeping service code testable.

A repository exposes collection-like persistence operations for an aggregate: `findById`, `save`, `listActiveForUser`. It hides ORM or SQL details from application services when contracts stay use-case oriented.

					interface OrderRepository {
  findOpenForCustomer(customerId: string): Promise<Order[]>;
  save(order: Order): Promise<void>;
}
				

Good repositories model business queries, not every possible column filter. They sit at a boundary — not a magic layer that removes the need to think about SQL.

On interviews: mention aggregate ownership, pagination, filtering, transactions, and when a query builder is clearer than a repository method explosion.

Common pitfalls: generic `findByAnyField` repositories that leak the database; repositories that become thin ORM wrappers with no design value; hiding needed query semantics behind vague method names.

The trade-off is clearer service code and test doubles versus extra abstraction when the domain is only CRUD.

Checklist:

  • Model use-case-oriented methods.
  • Avoid hiding needed query semantics.
  • Keep transactions explicit at the right layer.
  • Use query builder when joins or locks need control.