Incremental Implementation

- Any time you're tempted to write more than ~100 lines before testing

What Is Incremental Implementation?

Incremental Implementation is a disciplined software development technique that emphasizes making changes to a codebase in small, manageable, and testable units. Rather than attempting to build an entire feature, refactor a large part of the system, or implement a multi-file change in one go, this skill encourages breaking down work into thin vertical slices. Each slice should represent the smallest piece of end-to-end functionality that can be implemented, tested, and verified independently before moving on to the next segment.

The core idea is to avoid the risks associated with "big bang" integrations, where large, untested code changes can introduce hidden bugs, complicate debugging, and slow down the overall delivery process. With Incremental Implementation, the system remains in a working, testable state after each change, making both progress and problems visible as soon as possible.

Why Use Incremental Implementation?

Large features and multi-file changes are inherently risky. Implementing too much at once can lead to several problems:

  • Difficulty in Isolating Bugs: If something breaks, it is harder to identify which part of the change introduced the issue.
  • Complex Code Reviews: Reviewing hundreds of lines of code at once is error-prone and time-consuming.
  • Increased Merge Conflicts: Longer-lived branches with big changes are more likely to diverge, leading to difficult merges.
  • Delayed Feedback: If the work is not tested until the end, effort may be wasted on changes that do not fit or work as expected.

Incremental Implementation addresses these issues by making each change small enough to be easily understood, tested, and integrated. This approach:

  • Reduces the risk of introducing critical bugs
  • Enables rapid feedback loops for both automated and manual testing
  • Simplifies code reviews, allowing reviewers to focus on specific, meaningful changes
  • Keeps the main branch in a deployable, production-ready state

How to Use Incremental Implementation

Adopting Incremental Implementation involves a specific workflow that can be summarized in the following cycle:

┌──────────────────────────────────────┐
│                                      │
│   Implement → Test → Verify ──┐      │
│       ▲                       │      │
│       └───── Commit ◄─────────┘      │
│              │                       │
│              ▼                       │
│          Next slice                  │
└──────────────────────────────────────┘

Step-by-Step Process

  1. Break Down the Task: Identify the feature or change you need to implement. Decompose it into the smallest possible vertical slices, each providing a complete, testable piece of functionality. A vertical slice often touches multiple layers of the application (UI, API, database) but accomplishes a single, user-visible outcome.
  2. Implement the First Slice: Write just enough code to achieve that slice. Avoid the temptation to scaffold or stub out the rest of the feature.
  3. Test Immediately: Run the existing test suite to verify nothing broke. If there are no tests, write new ones targeting the new slice. Automated tests are preferred, but manual verification is better than none.
  4. Verify Outcomes: Confirm that the intended behavior works as expected and does not negatively impact other areas.
  5. Commit and Push: Once the slice is working and tested, commit your changes. Push to the repository and, if your workflow allows, merge to the main branch.
  6. Repeat for the Next Slice: Move on to the next smallest unit of work, following the same process.

Example

Suppose you are adding a "favorite" feature to a blog platform.

Do not:

  • Build the entire backend API, database migrations, UI components, and tests before running anything.

Do:

  • First, add a button to the UI that visually toggles between "favorited" and "not favorited," using mocked data. Test and verify the UI change.
  • Next, connect the button to a local state. Test and verify.
  • Then, wire up the button to call a stubbed backend endpoint. Test and verify.
  • Afterward, implement the backend endpoint and make sure it works with the UI. Test and verify.
  • Finally, add database storage, update tests, and verify the full end-to-end flow.

Each step is small, testable, and leaves the system in a working state.

// Initial slice: UI toggle with mock state
function FavoriteButton() {
  const [favorited, setFavorited] = useState(false);

  return (
    <button onClick={() => setFavorited(!favorited)}>
      {favorited ? 'Unfavorite' : 'Favorite'}
    </button>
  );
}

Commit and test this before connecting to the backend.

When to Use Incremental Implementation

Apply this skill in the following situations:

  • When implementing features or changes that span multiple files, components, or layers of your system
  • When a task feels too large or complex to land in a single step
  • When refactoring code, especially if the change affects more than one function or module
  • Any time you are tempted to write more than about 100 lines of code before running tests or verifying the application

Do not use Incremental Implementation for trivial, one-line, or single-file changes where the scope and risk are already minimal.

Important Notes

  • Discipline is Key: It takes conscious effort to limit your changes to a single slice. Resist the urge to get ahead of yourself or skip tests.
  • Each Slice Must Be Working: Never leave the system in a broken or untested state after a commit.
  • Communicate with Your Team: Make sure everyone understands the incremental approach, especially in collaborative environments or when using pull requests.
  • Automate Testing: The value of this skill is maximized when changes are continuously tested, preferably using an automated CI pipeline.
  • Avoid Over-Slicing: While small increments are good, do not artificially split changes so much that they lose meaning or context.

Incremental Implementation is a foundational skill for delivering robust software at scale. By working in small, testable steps, you minimize risk, speed up feedback, and make even the largest features manageable.