IT EN

The big meeting: how a list of customers to call became a seven-month project (and then went back to being a query)

Half an hour in the Everest room, taking turns as the business and the tech side: AI requested instead of a list, the "while we're at it", the "what if someday", a seven-month Gantt. Then a stupid question, seven lines of SQL and one line of cron.

Seven-month Gantt chart with Kafka, data lake, AI and an iOS app; at the bottom a tiny bar, a 7-line SELECT, circled in red: one afternoon

Thursday, 18 September 2025, 9:52. An invite is blinking in your calendar: "Requirements alignment – Customer Reactivation Project". 10:00 to 10:30, Everest meeting room. Fourteen attendees, six of them "optional", and all six will turn up, because there's a tray of pastries. Attachments: none. Description: "as agreed".

You walk into this meeting twice, taking turns. Some of the time you are the business: you have a problem and need to get it across. Some of the time you are the tech side: you have to build the solution. Last week we added subtitles to a meeting like this one, to translate between the two languages. Today we put it on a stopwatch, minute by minute, to watch a small need turn into a huge project. Spoiler: nobody is acting in bad faith, and that is exactly the problem.

9:55 · You, the business: the real need

You run sales. Every Monday morning you do the same thing: you open the ERP, scroll through the customer list and check each one's last order date. If it's more than two months old, you copy the name and phone number onto a sheet. Then you hand the sheet to the sales reps, who spend the week on the phone: "Everything all right? Anything you need?" It works: plenty of customers, if called in time, start ordering again. But it costs you three hours, every Monday.

So the real need fits in one line: on Monday morning I want the list of customers who haven't ordered in 60 days, with their phone numbers, without losing three hours.

Except that's not what you wrote in the meeting invite. You wrote: "We need a predictive customer churn dashboard, powered by AI." Why? Because at the trade fair in June, three speakers out of three said "AI". Because "churn" sounds much better than "people who stopped buying from us". And mostly because you know from experience that if you ask for "a list" you end up at the back of the queue, while if you ask for "a platform" you get a budget, a sponsor and the Everest room.

You have just made the first move that complicates everything: instead of describing the problem, you asked for a solution, the one already in your head. On technical forums this has a name, the XY problem: you have problem X, you imagine the solution is Y, and you ask for help with Y. Everyone will do a great job on Y, and nobody will ever hear about X.

10:01 · You, the tech side: the brain takes off

Now you're on the other side of the table. You hear "dashboard", "predictive", "AI", and before the projector has warmed up your brain has already filled the whiteboard:

# whiteboard, 10:03 — "Customer Reactivation Platform" v0.1
services:
  - api-gateway
  - auth-service          # SSO + MFA, obviously
  - ingestion-service     # reads orders from Kafka
  - kafka                 # three brokers, "for resilience"
  - data-lake
  - feature-store
  - churn-model           # the AI that was asked for
  - model-registry
  - notification-service  # email, push, SMS, "WhatsApp someday"
  - dashboard-frontend
teams: 3
estimate: "7 months, not counting sprint zero"

You don't do it out of malice. You do it because the last time you delivered "a simple thing", that thing became the heart of the company and you maintained it with nobody beside you for four years, with comments in three languages. You do it because a big architecture protects you: if something goes wrong, nobody can say you didn't see it coming. And you do it, let's whisper this, because "Kafka" weighs more on a CV than "a query". Nobody will ever say that out loud in the Everest room.

Here's the second move that complicates everything: you took the business's proposed solution seriously, instead of taking the business seriously.

10:06 · You, the business: "while we're at it…"

Back in your own seat, you see the whiteboard full of boxes and arrows and feel something new: they're taking you seriously. And when people take you seriously, you feel like asking for more.

  • "While we're at it, can it export to PDF?"
  • "While we're at it, an iPhone app?" You updated yours to iOS 26 on Monday, the one with the new "Liquid Glass" look, and it seems a shame not to use it.
  • "While we're at it, a notification when a customer becomes at risk."
  • "While we're at it, a view for management, with charts."
  • "While we're at it, multiple languages: someday we'll open in Germany."

Each "while we're at it" costs you one sentence. It costs whoever builds it weeks. Nobody in the room is holding the price tag, and without a price everything looks free. It's the XY problem's twin: there you hid the need under a solution, here you bury it under extras.

10:10 · You, the tech side: "what if someday…"

You pay back in the same coin. "What if someday we have ten million customers?" Today there are 3,200, growing 4% a year: at that pace, reaching ten million takes about two hundred years. But the architecture, quite rightly, must be ready. "What if someday we change ERP?" Here's an abstraction layer. "What if someday the reps want the list on their watch?" The frontend will be headless.

"What if someday" is the tech side's "while we're at it": insurance against an imaginary future, paid for today with real money. In 1998 Ron Jeffries, one of the fathers of Extreme Programming, put it like this: "Always implement things when you actually need them, never when you just foresee that you need them." That's where the acronym YAGNI comes from: You Aren't Gonna Need It. It's almost always true. And when it isn't, adding the thing later costs less than maintaining it unused for years.

10:15 · Both of you: the estimate

The security person asks about GDPR, and rightly so: names and phone numbers are involved. Whoever is acting as project manager puts up a Gantt chart: seven months, three teams and a "sprint zero" to decide how to run the sprints. The cost has more digits than the yearly budget for the coffee machines.

Silence. You, the business, think: "All this for three hours on a Monday?" But you don't say it, because by now the predictive dashboard has become a project, and projects aren't taken apart out loud. You, the tech side, think: "Seven months is optimistic." And you don't say it either.

10:18 · The stupid question

At the far end of the table sits someone who joined the company two weeks ago: the only person in the room with no reputation to defend and no CV to pad. They half-raise a hand.

"Sorry, this might be a stupid question. But in the end, what do you do with the list?"

You, the business, answer without thinking: "I print it and give it to the reps on Monday morning. They call."

"And how do you do it now?"

"By hand. It takes me three hours."

"And what if at seven on Monday you found a ready-made Excel file in the shared folder?"

A pause. A long one. "…That would be perfect, actually."

In three questions, the AI, the data lake, the Liquid Glass app and the ten million customers of the twenty-third century have all disappeared. It's the meeting-room version of an old Toyota tool: Taiichi Ohno, the father of the Toyota Production System, taught people to ask "why?" five times in a row until they reach the real cause of a problem. For requirements two or three are often enough, with a twist. Not "why?", which puts people on the defensive, but "what do you do with it afterwards?" and "how do you do it now?". They are neither technical questions nor business questions. They are about what happens after the software, which is the only thing that matters.

10:20 · You, the tech side: seven lines

You open your laptop. The ERP runs on PostgreSQL, with a customers table and an orders table. You type:

SELECT c.company_name, c.phone, c.sales_rep,
       max(o.order_date) AS last_order
FROM customers c
JOIN orders o ON o.customer_id = c.id
GROUP BY c.id
HAVING max(o.order_date) < current_date - 60
ORDER BY c.sales_rep, last_order;

Line by line: for each customer (GROUP BY) take the date of the latest order (max), keep only those idle for more than 60 days (HAVING, which is WHERE for groups) and sort by sales rep, so each rep finds their customers together. Customers who never ordered don't show up, and rightly so: they're not customers to reactivate, they're contacts to activate. Different meeting, different room.

I actually ran it, on a test database with PostgreSQL 17: 3,200 customers and about 57,000 orders. Result: 322 customers to call, in 32 milliseconds. On the other side, seven months of Gantt chart.

Then the list has to arrive by itself. One line of cron, the Unix program that runs commands at fixed times, is enough:

# every Monday at 7:00
0 7 * * 1  psql -d erp --csv -P csv_fieldsep=';' -f /opt/report/dormant.sql > /srv/shared/to-call-$(date +\%F).csv

The --csv option of psql has existed since PostgreSQL 12. The semicolon separator is for Excel: with many European regional settings it expects one, and with commas it crams everything into the first column. But the trickiest detail of the whole project is the backslash before %F. In a crontab the % sign, unless escaped with a backslash, becomes a newline, and the command silently breaks in two. There you go: now you have your own "complexity" too, and it fits in one character.

Total: one afternoon, tests included.

10:24 · Why it's so hard to accept

It should end here, with applause. Instead the resistance arrives, from both sides.

You, the business, think: "Is that all? It feels like too little." That's understandable: we're used to measuring the value of something by what it cost. If it takes an afternoon, it seems worth an afternoon. A seven-month project, on the other hand, can be presented to management, put in a slide, celebrated at go-live. But do the maths: three hours times fifty-odd Mondays a year is about 150 hours, almost a month of work given back. And the list arrives every week, not just when you have time. The value isn't in the lines of code but in what changes on Monday morning.

You, the tech side, think: "It doesn't scale. It isn't elegant. It won't look good on a CV." And underneath, deeper down, there's a less admissible thought: if the job takes an afternoon, what am I for? You're for exactly this: finding the one-afternoon version. In 1980, accepting the Turing Award, Tony Hoare said it better than anyone. There are two ways of constructing a software design: "One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies." And right after that he added: "The first method is far more difficult."

Genuinely difficult, and not only in software. In 1657, in the sixteenth of his Provincial Letters, Blaise Pascal apologised like this: "I have only made this letter longer because I have not had the time to make it shorter." The line also circulates under Mark Twain's name, though he had nothing to do with it. Making things simple takes time and, above all, courage: in the Everest room it took eighteen minutes and someone unafraid of asking a naive question.

One clarification, so we don't throw away the valid concerns too: simple doesn't mean sloppy. The query goes into version control as if it mattered, because it does. The file goes into a folder only the sales reps can see (the security person nods). And someone writes three lines on what the report does and whom to call if the file isn't there on Monday. If one day there really are ten million customers, you'll rewrite everything, with the money earned in the meantime.

10:29 · Both of you: it ends on time

For the first time in the history of the Everest room, the meeting ends on time. There are pastries left over. The project manager files the Gantt chart in a folder called "Future", and nobody has the heart to delete it.

Three months from now, want to bet?

A few months from now, we bet, you, the business, will come back with a new request: "Could we add the last product they bought? Then the reps know what to offer." Notice the difference: this request doesn't come from a trade fair, it comes from use. The reps will have called three hundred customers and discovered what's really missing. It's a real need, and nobody could have designed it in September.

And you, the tech side, will add it in half an hour:

WITH latest AS (
  SELECT DISTINCT ON (c.id)
         c.company_name, c.phone, c.sales_rep,
         o.order_date AS last_order, p.name AS last_product
  FROM customers c
  JOIN orders o   ON o.customer_id = c.id
  JOIN products p ON p.id = o.product_id
  ORDER BY c.id, o.order_date DESC, o.id DESC
)
SELECT * FROM latest
WHERE last_order < current_date - 60
ORDER BY sales_rep, last_order;

DISTINCT ON is a PostgreSQL speciality: for each customer it keeps only the first row according to the sort order, that is, the most recent order. The o.id DESC bit breaks ties when there are two orders on the same day. Same 322 customers, one more column.

That's how systems that work grow. In 1975 John Gall, a paediatrician, published a tongue-in-cheek book on systems called Systemantics. It contains a sentence that programmers now call "Gall's law": "A complex system that works is invariably found to have evolved from a simple system that worked." It also works the other way round: a complex system designed from scratch never works and cannot be patched up to make it work. You have to start over with a simple system that works. A seven-line query, for example.

The anti-big-meeting kit

Print it and bring it to the next invite with fourteen attendees and no attachments.

If you're the one asking (business)

  • Describe what you do today, not what you'd like to buy. "Every Monday I lose three hours on…" is worth more than "we need a platform".
  • Bring an example of the output you want: even a handwritten sheet, even a photo of a whiteboard.
  • Say what happens next: who uses it, when, and to do what.
  • For every "while we're at it", ask what it costs. If nobody knows, it isn't free.
  • Accept the ugly version that works by Friday. The pretty one will come, if it's needed.

If you're the one building (tech)

  • Before touching the whiteboard, ask "what do you do with it afterwards?" and "how do you do it now?".
  • Often the solution is the existing process, automated. Start there.
  • Count the data, for real. Three thousand rows aren't big data, and often neither are three million.
  • For every "what if someday", ask: when? How likely is it? How much would it cost to add later?
  • Offer the version you can deliver this week, and treat it as real code: versioned, documented in three lines, with the right permissions.

For both of you

  • The stupid question is the most expensive one not to ask.
  • If a requirements meeting ends without anyone having seen an example of the output, it hasn't ended: it's only been postponed.

15:40 · The next invite

In the afternoon another invite arrives, for tomorrow: "Requirements alignment – Invoice Export Project". 10:00 to 11:30, Everest room, seventeen attendees, no attachments. Before accepting, you reply with a single line: "Could you send me an example of the file you need, and tell me what you do with it afterwards?"

Twelve minutes later an Excel sheet with four columns arrives, along with an answer: "We upload it to the bank's portal on the 5th of every month." The meeting is cancelled. Somewhere, in a folder called "Future", a Gantt chart weeps quietly.

Sources