The quickest way to simplify a complex function with lots of logic is to turn it into data. Here's what I mean.
Take this screen for example. It shows a list of consent forms for a medical appointment.
Nothing special. Checkmarks and links to PDFs. The submit button saves the list into a jsonb
field in Postgres so we have an exact immutable record.
But where does the list come from? 🤔
Is it a backend or frontend concern?
When I first built this 2 years ago, the list depended on:
- how this appointment happens – virtual and in-person appointments have different forms
- what kind of appointment is it – certain appointments have special forms, like acupuncture
- the latest PDF links – the URLs will change when/if the forms are updated
That sounded like a lot of contextual business logic to shove into the UI. Yes it knows all the data, but interpreting it felt like a step too far.
Plus if the PDF links change and you consent to a cached version of the list (if they're hardcoded in JavaScript), that could be a problem 🤔
I built the dumbest possible UI:
function ConsentForms({ appointment }) {
// makes an API call
const { forms } = useConsentForms(appointment.id);
return (
<ul>
{forms?.map((form) => (
<li>
<a href={form.url}>{form.name}</a> <Checkbox checked={form.checked} />
</li>
))}
</ul>
);
}
Make an API call to get list of consent forms, iterate and render. The surrounding code took care of saving.
We never had to touch this again. Run git blame
and it says "swizec 2 years ago" except where we made style tweaks and changed links to open in a new tab.
Business logic grows complex, always
2 years ago the team was small and doing lots. We added a basic function on the backend with a hardcoded list of forms:
const consentForms = {
default: [ ... ],
acupuncture: [ ... ],
virtual: [ ... ]
}
exports.getForms = (appointment) => {
if (isVirtual(appointment)) {
return consentForms.virtual
} else {
if (isAcupuncture(appointment)) {
return consentForms.acupuncture
} else {
return consentForms.default
}
}
}
Special forms for special appointments, defaults for the rest. Easy. Why didn't you do this on the frontend Swizec?
Here's why 👉 over the next 2 years, we:
- added 5 more "special" appointments
- added support for "special" appointments within virtual and in-person
- added support for checking whether you've consented to this version of this form and pre-filling the checkmark appropriately
That last one was a beauty of querying JSON data with SQL. Gotta love Postgres. Glad I wasn't the one figuring it out 😅
The function grew to 70 lines of code backed by a 120 line config object. But the frontend never changed.
Turn it into data!
As the business grew, they wanted to make this list depend on which city you're in. Health care is funny like that.
Our form logic would gain another dimension and explode in complexity. Too many combinations, too hard to test.
And they warned about new even crazier ideas coming soon!
We turned all our fancy business logic into a database table:
- appointment type
- location
- is virtual
- form id
Now you can get the list of forms with a single query:
select * from forms f, form_linkages fl where
fl.appointment_type = ?
fl.location = ?
fl.is_virtual = ?
fl.form_id = f.id
Bam. Done.
Analysts want to know which forms belong where? Query. Code needs a list of forms? Query. Business wants to update config? Query. New appointment type? Query. New location? Query. New form? Query. List of current forms in production? Query.
And this whole time the UI didn't change. Because we kept it dumb.
Cheers,
~Swizec
PS: this puts us on the path towards a CMS so engineering never has to think about consent forms again ✌️
Continue reading about Move your business logic into data
Semantically similar articles hand-picked by GPT-4
- Clever technical hackery can't solve the wrong design
- How better data modeling fixes your code
- 90% of performance is data access patterns
- Why you should build a form generator
- How to think of your business logic as data
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️