codeintelligently
Back to posts
Codebase Understanding

Code Ownership: Who Should Own What and Why It Matters

Vaibhav Verma
7 min read
code ownershipengineering cultureteam managementcodebase understandingbest practices

Code Ownership: Who Should Own What and Why It Matters

A 2019 study by Microsoft Research analyzed 3.4 million code changes across dozens of projects and found a clear correlation: files with more contributors had more bugs. Specifically, files with 9+ contributors were 16 times more likely to have defects than files with 1-2 contributors.

That sounds like a slam-dunk argument for strong ownership. One person owns each module, they know it deeply, and the code stays clean. Except there's a catch: strong ownership creates knowledge silos, increases your bus factor, and can turn senior engineers into bottlenecks.

I spent three years arguing for strong ownership. Then I spent two years arguing for collective ownership. Both were wrong. The answer is a hybrid model that I call Stewardship, and it took me five years of mistakes to figure it out.

The Three Ownership Models

Model 1: Strong Ownership

One person (or a small team) owns each module. All changes go through them. They set the conventions, review every PR, and are responsible for quality.

Pros: Consistent code style. Deep expertise. Fast code review because the reviewer knows the codebase intimately. Lower defect rates within the module.

Cons: Bottleneck on the owner. Knowledge silo. The owner burns out or becomes a single point of failure. Changes that cross module boundaries require coordination between multiple owners, which slows everything down.

Model 2: Collective Ownership (XP Style)

Everyone owns everything. Any developer can change any code. The codebase is the team's shared responsibility.

Pros: No bottlenecks. No knowledge silos. Maximum flexibility for task assignment.

Cons: Inconsistent conventions (everyone has different preferences). Diffuse responsibility (if everyone owns it, nobody owns it). Higher defect rates because changes are made by people with less context. "Tragedy of the commons" for code quality.

Model 3: Stewardship (The Hybrid)

Every module has a steward, but anyone can make changes. The steward's job isn't to gatekeep. It's to guide. They set conventions, review PRs (but aren't the only reviewer), mentor others on the module, and ensure architectural consistency.

The critical difference from strong ownership: the steward actively transfers knowledge. Their goal is to make themselves replaceable, not indispensable.

Why Stewardship Works

Stewardship gives you the quality benefits of strong ownership without the bottleneck and silo risks. Here's how it differs in practice:

Situation Strong Ownership Stewardship
PR review Owner must approve Steward reviews OR another qualified reviewer
Bug in module Owner fixes it Anyone fixes it, steward reviews
New feature Owner designs + implements Anyone proposes, steward guides architecture
On-call incident Owner is paged Rotation includes 2-3 people, steward available for escalation
Steward goes on vacation Work stops or quality drops Backup steward covers, work continues

Setting Up Stewardship

Step 1: Map Your Modules

List every significant directory or service. For a monorepo, this might be:

src/
  auth/         -> Steward: Sarah, Backup: James
  orders/       -> Steward: Marcus, Backup: Sarah
  payments/     -> Steward: James, Backup: Priya
  inventory/    -> Steward: Priya, Backup: Marcus
  notifications/ -> Steward: Marcus, Backup: James
  shared/       -> Steward: Sarah, Backup: All

Every module must have a steward and a backup. No exceptions.

Step 2: Configure CODEOWNERS

GitHub's CODEOWNERS file automates review assignment:

# .github/CODEOWNERS
/src/auth/          @sarah @james
/src/orders/        @marcus @sarah
/src/payments/      @james @priya
/src/inventory/     @priya @marcus
/src/notifications/ @marcus @james
/src/shared/        @sarah

The first name is the steward, the second is the backup. GitHub will request reviews from these people automatically. But here's the key: configure it so that only one approval is required, not all listed owners. This prevents the bottleneck that kills strong ownership.

Step 3: Define Steward Responsibilities

Document what being a steward means. Here's the charter I use:

A steward is responsible for:

  1. Reviewing PRs in their module (or delegating to the backup with context)
  2. Maintaining a 1-page module guide: what it does, key patterns, known issues
  3. Ensuring test coverage stays above the team-agreed threshold
  4. Mentoring at least one other person to the point where they can be the backup
  5. Presenting the module's architecture in a quarterly team session

A steward is NOT responsible for:

  1. Writing all the code in their module
  2. Being the only person who can make changes
  3. Being on-call 24/7 for their module
  4. Blocking PRs from other contributors

Step 4: Rotate Stewardship

This is the most important and most commonly skipped step. Rotate stewardship every 6-12 months. The backup becomes the steward. The steward becomes a contributor. A new backup is trained.

Rotation prevents the exact problem that stewardship is meant to solve: knowledge concentration. If Marcus is the payments steward for three years, you're back to strong ownership in all but name.

My Contrarian Take: The Shared Module Needs the Strongest Ownership

Most teams apply strong ownership to business-critical modules (payments, auth) and collective ownership to shared code (utilities, common components, infrastructure). I think this is backwards.

The shared module is the one that needs the strongest stewardship. Here's why: shared code affects everyone. A bad abstraction in a utility function propagates across the entire codebase. An inconsistent pattern in the shared component library creates confusion in every team that uses it.

I've seen shared modules become dumping grounds. "I don't know where to put this function. I'll put it in utils." Nobody pushes back because nobody owns utils. Over time, utils grows to 3,000 lines of unrelated functions with no consistent naming, no tests, and no documentation.

Assign your best architect as the steward of the shared module. Give them veto power over additions. Require that every function in the shared module has tests and JSDoc comments. The shared module should have the highest quality bar in the codebase, not the lowest.

Measuring Ownership Health

Track these metrics monthly:

1. Review latency by module. How long does it take for a PR in each module to get its first review? If one module consistently takes 3x longer than others, its steward might be a bottleneck.

bash
# Using GitHub CLI to check average review time for a path
gh pr list --state merged --json number,reviews,files --limit 50 | \
  jq '.[] | select(.files[].path | startswith("src/payments/"))'

2. Contributor diversity. How many different people have committed to each module in the last 3 months? If it's just the steward, knowledge isn't being distributed.

bash
git log --since="3 months ago" -- src/payments/ --format="%aN" | sort -u | wc -l

3. CODEOWNERS coverage. What percentage of your codebase is covered by CODEOWNERS? Uncovered directories are no-man's-land where quality degrades.

4. Backup readiness. Can the backup steward handle a production incident in their module without the primary steward? Test this by having the backup take on-call for one sprint.

The Code Ownership Decision Framework

Use this to decide the right ownership model for each part of your codebase:

Factor Strong Ownership Stewardship Collective
Regulatory/compliance code Yes
Core business logic Yes
Feature modules Yes
Shared utilities/libraries Yes (senior steward)
Internal tools Yes
Prototypes/experiments Yes
Documentation Yes

Regulatory code (payment processing, healthcare data, financial reporting) benefits from strong ownership because compliance requires accountability. Feature modules benefit from stewardship because they need both quality and velocity. Internal tools and prototypes benefit from collective ownership because speed matters more than consistency.

Common Mistakes

Mistake 1: CODEOWNERS without a process. Adding a CODEOWNERS file without defining what ownership means leads to confusion. Are owners gatekeepers or advisors? Define it explicitly.

Mistake 2: Too many owners. If a file has 6 owners, it has zero owners. Keep it to 2-3 per module: one steward, one or two backups.

Mistake 3: Never rotating. If the same person has been the steward for 2+ years, they've become a knowledge silo regardless of your ownership model.

Mistake 4: Ownership without authority. If the steward is responsible for quality but can't block a PR that violates the module's conventions, they're a figurehead. Give stewards the authority to match their responsibility.

Mistake 5: Confusing ownership with blame. When a bug is found in a module, the steward's job is to fix it or delegate the fix. It's not their fault the bug exists. If ownership is tied to blame, nobody will volunteer to steward anything.

Ownership is a social contract, not a technical configuration. CODEOWNERS files and review policies are the mechanism. The culture of stewardship, mentoring, and knowledge sharing is what makes it work.

$ ls ./related

Explore by topic