Skip to main content
Clean Architecture 60 XP · 6 min

The Eisenhower Matrix in Development

Architecture is important but rarely urgent. Developers must defend good structure against short-term business pressure.

Showing
Ad (728×90)

Why this matters

The Eisenhower Matrix divides tasks into four quadrants based on urgency and importance. Robert C. Martin applies it directly to software development: architecture and good structure are important but almost never urgent. Urgent bugs, feature deadlines, and customer fires occupy the "urgent" quadrant — and they always crowd out the "important" work if developers let them.

Business stakeholders will always pressure developers to prioritize the urgent over the important. Martin's argument is that developers are the only people in the room who understand both dimensions — and therefore carry the professional responsibility to protect architecture even when it feels like it can wait. The mess created by letting urgent wins pile up compounds exponentially until the entire system grinds to a halt.

The problem

Code written under deadline pressure skips abstraction and tests. Every shortcut is a future tax paid with interest — the "urgent" feature becomes permanent technical debt.

Bad

def get_tax_rate(country: str) -> float:
    # TODO: load from config — no time, deadline tomorrow
    return 0.21  # hardcoded for Spain only

def calculate_invoice(subtotal: float, country: str) -> float:
    tax = subtotal * get_tax_rate(country)
    return subtotal + tax
function getTaxRate(_country: string): number {
  // TODO: load from config — skipped to hit deadline
  return 0.21; // breaks for every country except Spain
}

function calculateInvoice(subtotal: number, country: string): number {
  return subtotal + subtotal * getTaxRate(country);
}

The solution

Doing the important work right, even when it feels slower, keeps future change cheap. An abstracted, testable design costs little more up front and pays dividends forever.

Good

class ConfiguredTaxStrategy:
    def __init__(self, rates: dict[str, float]):
        self._rates = rates

    def rate(self, country: str) -> float:
        if country not in self._rates:
            raise ValueError(f"No tax rate for '{country}'")
        return self._rates[country]

class InvoiceCalculator:
    def __init__(self, tax):
        self._tax = tax

    def total(self, subtotal: float, country: str) -> float:
        return subtotal * (1 + self._tax.rate(country))

rates = ConfiguredTaxStrategy({"ES": 0.21, "DE": 0.19, "UK": 0.20})
calc  = InvoiceCalculator(rates)
print(calc.total(100.0, "DE"))  # 119.0
class ConfiguredTaxStrategy {
  constructor(private rates: Record<string, number>) {}
  rate(country: string): number {
    if (!(country in this.rates))
      throw new Error(`No tax rate for '${country}'`);
    return this.rates[country];
  }
}

class InvoiceCalculator {
  constructor(private tax: ConfiguredTaxStrategy) {}
  total(subtotal: number, country: string): number {
    return subtotal * (1 + this.tax.rate(country));
  }
}

const rates = new ConfiguredTaxStrategy({ ES: 0.21, DE: 0.19, UK: 0.20 });
const calc  = new InvoiceCalculator(rates);
console.log(calc.total(100, "DE")); // 119

Key takeaway

Urgent tasks feel pressing; important tasks build the future. Only developers understand the difference — and that makes defending architecture a professional responsibility, not just a best practice.

Done with this lesson?

Mark it complete to earn XP and track your progress.