ABC Metric (Assignments, Branches, Conditions)
Also Known As
TL;DR
Explanation
The ABC metric (Jerry Fitzpatrick, 1997) measures method complexity using three independent counts: A = assignments (state changes), B = branches (function/method calls and control transfers), and C = conditions (boolean expressions). The final score is computed as the vector magnitude: sqrt(A^2 + B^2 + C^2). Unlike cyclomatic complexity, which focuses on decision paths, ABC captures how much a method mutates state and delegates work. High A suggests excessive state manipulation, high B indicates heavy delegation or deep call chains, and high C reflects complex logic. Tools like PHPMetrics and PHPLoc report ABC per method. Scores above ~20 should be reviewed; above ~50 typically indicate methods that are difficult to test, reason about, and maintain.
Common Misconception
Why It Matters
Common Mistakes
- Reducing ABC by splitting methods without reducing actual logic complexity.
- Ignoring high assignment counts — excessive state mutation is a major maintainability risk.
- Treating all branches equally — external calls and control flow both increase B but have different implications.
- Using ABC thresholds blindly without considering domain complexity.
Avoid When
- Evaluating very small methods where ABC adds little insight.
- Comparing across different domains without normalising expectations.
When To Use
- Identifying overly complex or state-heavy methods.
- Enforcing maintainability thresholds in CI pipelines.
Code Examples
// ❌ High ABC — excessive state + branching
function processOrder($order, $user, $coupon, $tax) {
$total = 0; $discount = 0; $shipping = 0;
if ($order && $user && $coupon) {
if ($coupon->valid && $coupon->amount > 0) {
$discount = $coupon->amount;
}
$total = $order->subtotal - $discount + $tax + $shipping;
}
return $total;
}
// ✅ Lower ABC via decomposition and reduced state
function processOrder($order, $user, $coupon, $tax) {
if (!$this->isProcessable($order, $user, $coupon)) {
return 0;
}
$discount = $this->calculateDiscount($coupon);
return $this->calculateTotal($order, $discount, $tax);
}
private function isProcessable($order, $user, $coupon): bool {
return $order && $user && $coupon;
}
private function calculateDiscount($coupon): float {
return ($coupon->valid && $coupon->amount > 0)
? $coupon->amount
: 0;
}
private function calculateTotal($order, $discount, $tax): float {
return $order->subtotal - $discount + $tax;
}