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.