Defensive coding is an important lesson from Pragmatic Programmer, although not my favorite. It says that you should validate your inputs. Don't trust anyone!
This is a good principle.
Your software should validate inputs. A client may have bugs, an API could spazz out, a database or hard drive can get corrupt, a user might do something silly. Hell, sometimes clients and users are downright malicious trying to break your code.
But on a team with lots of moving pieces and little big-picture understanding, defensively coding all the things leads to bload. Does every function in a chain really need to validate its inputs?
How defensive coding goes wrong
We once built an API that ran 29,000 database queries for every request. Thanks to defensive coding and what looked like clear sensible separation of concerns.
The easiest way to write unreadable code is by splitting your functionality across 20 clean small functions.
โ Swizec Teller (@Swizec) November 12, 2021
That example can't fit in a post you'll read. Too much background info and context required.
Here's an example from a different part of that project ๐ we built a UI that sorts the same array 5 times ๐คจ
Designed by engineer ๐ช
The UI lets you update and manage a person's schedule. You bulk upload a new list of availabilities via CSV, verify the update, and see the result in a calendar component off-screen after saving.
Because we work as a team, each portion was built by someone else. Because we have good engineers, they all thought "Oh wait, I gotta validate my inputs!"
You end up with a date range function that looks like this:
function getDateRange(dates) {
const sorted = dates.sort();
return `Updating between ${sorted[0]} and ${sorted[sorted.length - 1]}`;
}
A component that lists updates like this:
function DateList({ dates }) {
const sorted = dates.sort();
return (
<ol>
{sorted.map((date) => (
<li>{date}</li>
))}
</ol>
);
}
A calendar that lists events like this:
import groupBy from "lodash.groupby";
function Calendar({ events }) {
const sorted = events.sort();
// groups preserve sort order internally
const byDay = groupBy(sorted, (event) => event.day);
return; // render UI
}
And a few others here and there.
What's going on?
Every engineer is following the Validate Your Inputs principle. When they need a sorted array and aren't sure if it's sorted โ sort all the things!
This makes sense when you think of each piece of code as a unit. Which they do because that's what they're currently working on and thinking about.
Everything outside your function becomes The Untrusted Outside and you code accordingly.
Repeat across time and engineers and you create a bloated codebase that spends half its time validating and re-validating the same data. ๐ฉ
This tendency can lead to swallowed promises when functions handle their own errors instead of propagating them back up the stack.
Solution: Validate the edges, trust the insides
The solution is to more carefully design your units and agree on where the edges are.
Where does new data enter your system? Validate there.
- API request
- user input
- database or file read
- URL params
Validate inputs at those entry points and the rest of your code can assume they're valid. A type system can help you communicate that to other engineers.
Cheers,
~Swizec
PS: better unit definitions help with testing too! You can avoid the cult of TDD by testing the interfaces, not the implementation โ๏ธ
Continue reading about How defensive coding leads to bloat
Semantically similar articles hand-picked by GPT-4
- My favorite lessons from Pragmatic Programmer
- Don't neglect your upgrades
- Better tooling won't fix your API
- Make mistakes easy to fix
- Smart core, thin interfaces
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 โค๏ธ