Dark Code
4 minute read
Phase 1 - Foundations | Scope: Team
Dark code is the default technique for integrating incomplete work. It costs nothing to maintain and requires no cleanup, because the code never runs until you decide to connect it.
What Is Dark Code?
Dark code is new logic that is fully built, tested, and deployed to production, but not yet reachable. No route, UI trigger, or message consumer points to it. It sits inert in the running binary until the final commit connects it.
This is sometimes called “connect tests last” or a “dark launch,” because the implementation is complete; only the wiring is missing.
What Dark Code Is Not
- It is not dead code left behind after a change. Dark code is temporary and has a defined moment it becomes live.
- It is not a feature flag. There is no runtime check and no conditional branch. The only cleanup is the wiring commit itself, which is not cleanup at all.
- It is not untested. The code has full unit and integration test coverage before it deploys; only production traffic hasn’t reached it yet.
What Dark Code Improves
| Problem | How Dark Code Helps |
|---|---|
| A feature takes multiple days or weeks to build | Each piece integrates and deploys daily; only the last commit exposes it |
| Feature flag sprawl | No flag is created, so there’s nothing to track or remove later |
| Fear of half-built features reaching users | Code with no caller cannot be reached by any user, regardless of deployment frequency |
| Large, risky final pull requests | The final change is a small wiring commit, not the whole feature |
Building Behind Dark Code
Step 1: Build the implementation
Write the domain logic, service, or component with its own unit and integration tests, exactly as you would if it were shipping today. Commit and deploy continuously as you go.
Step 2: Deploy without wiring
Each commit ships to production. The code compiles, is tested, and runs inside the deployed artifact, but nothing calls it. There is no behavior change for users, because there is no path to the new code.
Step 3: Wire it in as the final change
Once the implementation is complete and reviewed, the last pull request adds the entry point: the route, the UI trigger, or the consumer binding.
This commit is small and easy to review, because all the risk was already tested and deployed in the commits before it.
When Dark Code Is Not Enough
Dark code works when you control every caller and can wait to wire the last one in. It does not work when:
- You need to compare the new logic against production behavior before trusting it. Use parallel run instead.
- You are replacing an implementation that already has live callers. Use branch by abstraction instead.
- The business needs the release timed independently of when the code is ready, such as a coordinated launch or a gradual percentage rollout. Use a feature flag instead.
Key Pitfalls
1. “We wired it in early to test in production”
If you need production traffic to validate the new code before trusting it, that is a parallel run, not dark code. Wiring in an unfinished path to see what happens exposes users to unfinished work.
2. “The dark code sat unwired for three months”
Dark code should be wired in within days, not months. If the entry point keeps slipping, the feature isn’t actually close to done, and calling it dark code is hiding that from the team.
Measuring Success
| Metric | Target | Why It Matters |
|---|---|---|
| Time from first dark commit to wiring | Days | Confirms dark code isn’t a substitute for finishing the feature |
| Size of the final wiring commit | Small: a route or binding, not logic | Confirms the risk was already tested and deployed incrementally |
| Feature flags created per sprint | Decreasing as dark code adoption increases | Confirms flags are reserved for cases dark code can’t cover |
Next Step
When you’re replacing an implementation that already has live callers instead of adding a new one, use Branch by Abstraction.
Related Content
- Evolutionary Coding Techniques - the full decision hierarchy
- Trunk-Based Development - the practice dark code makes safe
- Feature Flags - the alternative to reach for once dark code doesn’t apply
- Small Batches - deploying each piece of a feature continuously