XP Practices in Detail¶
XP is defined by its practices, and they are designed to reinforce each other. Adopting one in isolation usually fails, because each practice covers a risk that another practice creates.
Test-Driven Development¶
The cycle is red, green, refactor:
- Write a failing test for the next small behavior.
- Write the simplest code that makes it pass.
- Refactor with the test as a safety net.
# 1. red: the test fails, which proves it exercises the new behavior
def test_reorder_copies_items():
cart = reorder(Order(items=["apple", "pear"]))
assert cart.items == ["apple", "pear"]
# 2. green: simplest thing that passes
def reorder(order):
return Cart(items=list(order.items))
# 3. refactor: only now, with the test protecting the change
Writing the test first matters because a test written afterwards has never been observed to fail, so it may pass for reasons unrelated to the code it claims to cover.
Pair programming¶
Two people, one keyboard. The driver writes, the navigator thinks one step ahead. Roles swap frequently.
| Gains | Costs |
|---|---|
| Continuous review, so defects are caught as they are written | Two people on one task, though not two people for twice as long |
| Knowledge spreads, and the bus factor rises | Tiring, and needs deliberate breaks |
| Design decisions are discussed before they calcify | Poor fit for trivial or mechanical work |
Mob or ensemble programming extends this to the whole team, typically for the hardest or most cross-cutting problems.
Continuous integration¶
Everyone integrates to the mainline at least daily, and an automated build plus test suite runs on every change. A broken build is the team's top priority.
The practice exists to kill integration risk. Long-lived branches accumulate divergence until merging becomes its own project, which is precisely the queue Lean calls inventory.
Refactoring¶
Continuous, small, behavior-preserving improvements to the design. Refactoring is only safe with a strong test suite, which is why it is paired with TDD, and it is only affordable if it happens continuously rather than as a quarterly cleanup project.
Simple design¶
The design should pass four rules, in order: all tests pass, reveals intention, no duplication, fewest elements. In practice this means YAGNI, build what is needed now, because speculative flexibility is usually the wrong flexibility.
Collective code ownership¶
Anyone may change any code. This removes the specialist bottleneck, and it depends on coding standards, CI and tests to stay safe.
Small releases and the planning game¶
Release in the smallest increments that deliver value. Planning is a negotiation: the customer decides scope and priority, the developers decide estimates and technical approach. Neither side overrides the other, which is what stops both death-march commitments and gold-plating.
Sustainable pace¶
Forty-hour weeks, or whatever the local equivalent is. Overtime is treated as a defect in planning, because tired developers produce defects that cost more than the hours gained.
How the practices support each other¶
graph TD
TDD[Test-Driven Development] --> REF[Refactoring]
TDD --> CI[Continuous Integration]
REF --> SD[Simple Design]
CI --> CCO[Collective Ownership]
PAIR[Pair Programming] --> CCO
PAIR --> SD
CCO --> REF
SD --> SR[Small Releases]
CI --> SR
Remove TDD and refactoring becomes dangerous. Remove CI and collective ownership becomes chaos. This interdependence is why partial XP adoptions so often conclude that "XP does not work here".
Check Your Understanding¶
Why is collective code ownership unsafe without continuous integration and a test suite?
In the planning game, who decides what gets built next and who decides how long it takes?
XP treats sustained overtime as what?