How I Write Code That Reads Like English 👨🏼💻
Feb 04, 2023 4:01 pm
Read Time: 5.0 minutes
New Email 📢
"A task has been assigned to you!"
Let's check it out:
Feature: Only show active job listings
Simple!
Let's open the code base and make the change.
Yikes. 😬
The code change might be easy.
Just add another filter function that filters by active status:
jobs = jobs.filter(j => j.is_active === true);
But we know better.
This function could be way easier to read.
You can assume the Job interface is defined like this:
And that getJobsFromDatabase() returns an array of Job objects
Let's fix it.
Here are my three steps for writing code that reads like English.
(or as close to english as I can get it)
No Lazy Names 🥱
function getJobs()...
let jobs = ...
const result = ...
ugh
These names might make sense to you but don't forget the golden rule for avoiding confusion:
✨ Make no assumptions ✨
The only thing safe to assume is that the reader knows Typescript.
Don't assume they know what we are doing.
Let's change the names to describe what's going on:
Okay, so the code got longer...
But this has a huge benefit:
We don't make the reader figure out what is happening
When it comes to code:
Clear code > Less code
For example by changing the name from
result -> jobsGroupedByCompany
We give the reader a heads-up for what they are about to read.
Before:
"Variable named result? what are they storing here?"
After:
"Variable named jobsGroupedByCompanyName. Let's see how they do that."
It makes a world of difference when reading code.
But we are far from done.
There are two more changes to make.
Functions do 1 thing ☝️
Our function is called getJobsByLocation()
When I read that I expect the function to:
get jobs by location
But inside the function we are:
filtering by location...
grouping by company...
sorting by post date...
Filtering by location is what getJobsByLocation() says it does so we can leave that there.
But grouping by company_name and sorting by post_date?
I wouldn't expect that to happen in the getJobsByLocation()
unless it was called:
getJobsByLocationAndGroupByCompanyAndSortByPostDate()
But let's not do that.
Remember:
Every function does one thing
All we did here was:
- Take a unique block of logic
- Move it to its own function
- Return the output
Nothing special.
But even with this simple change, it is much easier to understand the getJobsByLocation() function.
We are safe to assume that groupJobsByCompanyName() and sortJobGroupsByPostDate() work as expected.
all we would have to do is add another .filter() call for checking if the job is active, write a unit test, and call it a day.
But we can take it even further...
Humans read language. Not logic. 📖
Let's focus on the sort function for a moment:
Maybe I'm crazy... but sort functions can be confusing.
However, the sort function just takes in a function...
So what if we name a function and describe exactly what it does?
Always go for clarity:
It's a small change, but it makes a big difference to me.
Just move the sort logic to its own function and give it a descriptive name.
In general, when you are passing functions into functions this can help clean things up. Simple cases like filter(j => j.location === location) are fine on their own, but if it gets complicated I find it easier to break out.
We could keep going further with this, but these three have the biggest impact;
These are the 20% of changes that make up 80% of the impact.
_______________________
As always if you have questions feel free to shoot me an email at swdlodonnell@gmail.com
This is week 6 of this newsletter and we passed 20 subscribers! 🎉
I appreciate all of 20 you.
Until next week 👋