You find a bug on line 47. You fix it. Tests pass. Monday morning: two new tickets. The PDF header shifted. The chart labels are off. Neither is anywhere near line 47.
The method reads top to bottom. Sections are commented. It looks clean. But there's a let yOffset at the top that threads through every section — header, table, charts. Fix the table's column widths, yOffset shifts by a few pixels, and the charts render in the wrong position.
// Before — one shared variable ties everything together
function generateReport(data: ReportData): void {
const doc = new PDFDocument({ layout: "landscape", size: "A4" });
if (data.header) {
doc.fontSize(18).text(data.header.title, 50, 40);
if (data.header.logo) {
doc.image(data.header.logo.src, 400, 30, { width: 100 });
}
}
let yOffset = data.header ? 80 : 40;
if (data.rows?.length) {
for (const [i, row] of data.rows.entries()) {
let x = 50;
for (const [j, cell] of row.entries()) {
doc.text(String(cell), x, yOffset, { width: 80 });
x += 90;
}
yOffset += 20;
}
}
if (data.charts) {
yOffset += 30;
for (const chart of data.charts) {
doc.image(renderChartToBuffer(chart), 50, yOffset, { width: 500 });
yOffset += chart.height + 20;
}
}
doc.end();
}
// After — each section owns its own offset
function generateReport(data: ReportData): void {
const doc = new PDFDocument({ layout: "landscape", size: "A4" });
let y = 40;
if (data.header) y = renderHeader(doc, data.header, y);
if (data.rows?.length) y = renderTable(doc, data.rows, y);
if (data.charts?.length) y = renderCharts(doc, data.charts, y);
doc.end();
}
Each function takes a position, does its job, returns the next position. Fix a bug in renderTable? It can't affect renderHeader. Add a footer? One function, one line. The blast radius of any change is one function, not the entire report.
The test: find the longest method in your codebase. Count the let variables declared at the top that are mutated further down. Each one is a hidden wire connecting sections that look independent.
Full breakdown with more examples at mvpforstartup.com.
What's the method in your codebase that everyone avoids touching? Drop it in the comments — I pick Problem #3 from what developers actually deal with.
Top comments (0)