Clients rarely arrive with a specification. They arrive with a description of their week and a sense that software should be able to help.
That is not a problem to be fixed by demanding requirements. It is the normal starting point, and getting from there to a schema is a large part of the job.
Start with what goes wrong
The first request usually describes a solution someone has already imagined. “We need a dashboard.” “We need an app where parents can log in.”
Underneath is a problem, and the problem is more useful:
- What happens today, step by step?
- What goes wrong, and how often?
- Who notices when it does?
- What do you do about it now?
The music school I built for opened with “we need a scheduling system”. The actual problem was that teachers were coordinating lesson changes through personal phone numbers, and nobody had a record of anything. Scheduling was part of it. The messaging and the audit trail mattered more, and neither was in the original request.
Listen for the nouns
Once someone describes their week in their own words, the entities are sitting there in the transcript. Write down every noun they use more than twice.
For the music school: student, parent, family, teacher, lesson, term, invoice, course.
Now ask about each one. Not “what fields does it have”, which nobody can answer, but questions in their language:
- Can one exist without the other? Can a lesson exist without a teacher assigned? If yes, the relationship is optional and your schema needs to say so.
- How many? Does a student have one parent or several? Can a parent have children at different levels? This is where one-to-many and many-to-many get decided, and it is much cheaper to decide now.
- Does it change over time, and do you need the old value? If a lesson price changes, do past invoices keep the old price? If yes, the price belongs on the invoice line, not only on the lesson.
- What must never happen? “Two lessons in the same room at the same time.” “A teacher seeing another teacher’s families.” These are constraints, and writing them down now means they get enforced instead of discovered.
The decision that mattered most
For the music school, the obvious model is a table of students. The correct model was a family account with several students attached.
I got there by asking how billing worked. One invoice per family, not per child. That single answer changed the shape of the schema, and it meant that later requests like “move all of the Hendersons to Thursday” were a query rather than a feature request.
The obvious model is often right. It is worth ten minutes to check.
Write it back in their words
Before any code, I write a short summary and send it over. Not a schema diagram. Something like:
A family has one or more students and one billing contact. Each student takes lessons with one teacher per subject. Lessons happen in a room at a time, and two lessons cannot share a room. Invoices go to the family monthly and keep the price that applied when the lesson happened.
Clients correct this. Reliably. The corrections are the valuable part, and they cost nothing at this stage. The same correction after the schema is built and seeded costs a migration and a week.
Only then, the schema
Now the tables write themselves, the constraints are already known, and the API contract follows from the schema.
Framework choice comes last and matters least. I have never regretted time spent on the data model. I have regretted, more than once, starting to code before I understood what the nouns actually were.