Tari Ibaba

Tari Ibaba is a software developer with years of experience building websites and apps. He has written extensively on a wide range of programming topics and has created dozens of apps and open-source libraries.

How to write “natural” code everybody will love to read

The biggest reason we use languages like JavaScript and Python instead of Assembly is how much closer to natural language they are.

Or how much they CAN be!

Because sometimes we write code just for it to work without any care about demonstrating what we’re doing to other humans.

And then this backfires painfully down the line. Especially when one of those humans is your future self.

Parts of speech: back to basics

You know your code is natural when it resembles English as much as possible. Like an interesting, descriptive story.

It means you’ve intelligently made the entities and actions in the story to powerfully express the code flow from start to completion.

Nouns

What entities are we talking about?

  • Variables
  • Properties (getters & setters)
  • Classes & objects.
  • Modules

Every character has a name, so we describe them with expressive nouns and noun phrases.

Not this:

JavaScript
// ❌ do-examples.ts // ❌ Cryptic const f = 'Coding'; const l = 'Beauty'; // ❌ Verb const makeFullName = `${f} ${l}`; class Book { // ❌ Adjectival phrase createdAt: Date; }

But this:

JavaScript
// ✅ examples.ts // ✅ Readable const firstName = 'Coding'; const lastName = 'Beauty'; // ✅ Noun const fullName = `${firstName} ${lastName}`; class Book { // ✅ Noun phrase dateCreated: Date; }

Verbs

What are the actions in your codebase?

  • Functions
  • Object methods

An action means an entity is doing something; the naturally way to name them is with descriptive verbs and verb phrases.

Not this:

JavaScript
class Product { constructor(name, price, quantity) { this.name = name; this.price = price; this.quantity = quantity; } // ❌ Noun total() { return this.price * this.quantity; } } const product = new Product('Pineapple🍍', 5, 8); console.log(product.total()); // 40

But this:

JavaScript
class Product { constructor(name, price, quantity) { this.name = name; this.price = price; this.quantity = quantity; } // ✅ Verb getTotal() { return this.price * this.quantity; } } const product = new Product('Banana🍌', 7, 7); console.log(product.getTotal()); // 49

Methods are for doing something. Properties are for having something.

So better still:

JavaScript
class Product { constructor(name, price, quantity) { this.name = name; this.price = price; this.quantity = quantity; } get total() { return this.price * this.quantity; } } const product = new Product('Orange🍊', 7, 10); console.log(product.total); // 70

Adverbs

Remember an adverb tells you more about a noun or verb or another adverb.

In JavaScript this is any function that takes function and returns another: a higher-order function. They upgrade the function.

So instead of this:

JavaScript
// ❌ Verb function silence(fn) { try { return fn(); } catch (error) { return null; } } const getFileContents = (filePath) => silence(() => fs.readFileSync(filePath, 'utf8'));

It’ll be more natural to do this:

JavaScript
// ✅ Adverb function silently({ fn }) { // or "withSilence" try { return fn(); } catch (error) { return null; } } const getFileContents = (filePath) => silently({ fn: () => fs.readFileSync(filePath, 'utf8') });

It’s like saying, “Get the file contents silently“.

Natural inputs

Coding and computing are all about processing some input to produce output.

And in natural code the processing is action and the input + output are entities.

Let’s say we have a function that calculates a rectangle’s area and multiplies it by some amount.

Can you see the problem here?

JavaScript
const area = calculateArea(2, 5, 10); // 100

Which argument is the width and height? Which is the multiplier?

This code doesn’t read naturally; In English we always specify objects of an action.

How to fix this? Named arguments:

JavaScript
// Inputs are entities - nouns✅ const area = calculateArea({ multiplier: 2, height: 5, width: 10 }); function calculateArea({ multiplier, height, width }) { return multiplier * height * width; }

This is far easier to read; we instantly understand what inputs we’re dealing with.

Even when there’s just 1 argument I recommend using this.

Natural outputs

And we can be just as explicit in our outputs:

JavaScript
const { area } = calculateArea({ multiplier: 2, height: 5, width: 10, }); function calculateArea({ multiplier, height, width }) { return { area: multiplier * height * width }; }

Which also allows us easily upgrade the function later:

JavaScript
const { area, perimeter } = calculateArea({ multiplier: 2, height: 5, width: 10, }); console.log(area, perimeter); // 100 60 function calculateArea({ multiplier, height, width }) { return { area: multiplier * height * width, perimeter: (height + width) * 2 * multiplier, }; }

There’s no time for magic

Coding isn’t a mystery thriller! It’s a descriptive essay; be as descriptive as possible.

Not this cryptic mess:

JavaScript
function c(a) { return a / 13490190; } const b = c(40075); console.log(p); // 0.002970677210624906

What do all those numbers and variables mean in the bigger picture of the codebase? What do they tell us – the human?

Nothing. They tell us nothing. The entity & action names are either non-existent or of terrible quality.

It’s like telling your friend:

Yeah I went to this place and did this thing, then I did something to go to this other place and did something of 120!.

This is nonsense.

Natural code describes everything. Nice nouns for entities, great verbs for the actions.

JavaScript
const speedstersSpeedKmPerHr = 13490190; const earthCircumferenceKm = 40075; function calculateSpeedstersTime(distance) { return distance / speedstersSpeedKmPerHr; } const time = calculateSpeedstersTime(earthCircumferenceKm); console.log(time); // 0.002970677210624906 ~ 11s

Now you’ve said something.

Yeah I went to the restaurant and ate a chicken sandwich, then I drove to the gym and did bicep curls of 120 pounds!.

Create “useless” variables

Variables in natural code are no longer just for storing values here and there.

They’re also tools to explain what you’re doing:

That’s why instead of doing this:

JavaScript
if ( !user.isBanned && user.pricing === 'premium' && user.isSubscribedTo(channel) ) { console.log('Playing video...'); }

We’ll do this:

JavaScript
const canUserWatchVideo = !user.isBanned && user.pricing === 'premium' && user.isSubscribedTo(channel); if (canUserWatchVideo) { console.log('Playing video...'); }

We’re going to use the variable only once but it doesn’t matter. It’s not a functional variable but a cosmetic variable; a natural variable.

Final thoughts

Code is for your fellow humans too, not just compilers.

Can someone who doesn’t know how to code understand what’s going on in your code?

This is no doubt a powerful guiding question to keep your code as readable an natural as possible.

5 unexpected ways coding upgrades your life — beyond making money

I could code for many hours straight but I usually couldn’t say the same about writing!

And I always wondered why.

But I knew it was because of certain underlying emotions and values I felt when coding but didn’t quite feel for writing.

Eventually, I discovered at least 5 things about coding that make it so enjoyable and meaningful.

Things that can make any activity more pleasurable and fulfilling.

1. Purpose

There’s a deep sense of purpose in coding that gives us constant drive & passion.

A reason to wake up in the morning.

Every massive coding project is a brand new mission in itself with lots of exciting goals & milestones.

It’s an endless adventure.

Imagine creating an endless runner game like Subway Surfers from scratch:

You will have so many invigorating things to do:

  • Download & install the game engine: like Unity
  • Create the sprites: characters, hoverboards, costumes, etc.
  • Create the algorithm for the endless running…

Every milestone gives you a strong sense of accomplishment & direction.

2. Growth: of people & code

You

Growing as a person makes life feel new and exciting.

You grow when you gain more of something valuable:

  • Strength: Levelling up at the gym
  • Freedom: Beating an addiction: alcohol, porn, etc.
  • Knowledge: Becoming more fluent in a language

As you improve your coding knowledge & skills you feel like you’re making focused progress as an individual.

You get better at:

  • Solving problems: and designing algorithms
  • Writing clean, readable code
  • Writing modular cohesive code with minimal coupling

Your code

You nurture when you help something else grow:

  • Raising children
  • Body transformation coaching
  • Gardening

When you code, you nurture programs.

Every new line and every new commit upgrades the system with new capabilities.

At a high level:

  • You give it more features
  • You make it faster
  • You improve the UI

Low-level:

  • You refactor: greater readability
  • You fix bugs
  • You create tests: greater stability

3. Cognitive challenge: and mental stimulation

No secret that coding makes your brain work!

Just like:

  • Chess
  • Philosophy
  • Debating & solving math proofs

You need lots of logical processing and memory retrieval to create problem-solving algorithms.

Especially for complex games and backend-heavy apps.

You stretch your cognitive abilities and enter into an enjoyable state of flow — keeping you glued to the chair for hours.

And when you’re done you feel a deep sense of accomplishment.

It’s a key reason why we created Coding Beauty Play — regular puzzles to test your memory and make you think!

Just see all the processing needed to go from the formatted string to the number:

4. Power: of creation & automation

Coding transforms you into an all-powerful digital god.

You can autonomously create a brand new world of your own with nothing but your thoughts.

It’s a major reason why game programming and front-end UI design can be so exciting.

And where did all the millions of games & apps we use every day come from?

They didn’t come from the investor money or the code editors; these were just tools.

They came from the minds of the creators and developers.

It all started with an idea — ideas that go on to revolutionize the world and generate billions.

Making an impact on both the virtual and physical world.

Of automation

With coding, you complete unbelievable amounts of work in fractions of a second.

Think of all the work Google Search does every day:

  • 99,000 queries every second
  • 8.5 billion searches per day
  • 2 trillion global searches per day

This is simply out of the bounds of manual human ability, to put it lightly.

With automation I finally stopped those annoying Windows Updates.

By creating a tiny app to constantly stop the services any time Windows auto-restarted them.

5. Unity: of code & humans

Of code

Coding brings you face-to-face with the beauty of collaboration.

You experience the magnificence of various components of a complex system cohesively working together towards a common end.

Like carefully connected pieces on a chessboard working in harmony.

You see this when you split up your files into modules and objects.

Every single module plays its role in achieving the overall goals of the larger system.

They have the opportunity to be part of a community; of something bigger than themselves.

Of humans

And so do we when we work as a team.

We feel a shared sense of belonging as we strive toward a common goal together.

We are energies by the connection and fulfilled by our contributions towards the group and the mission.

Join the community on Discord for more engaging & free-flowing discussions on these things, and tips for leveling up and earning more as a developer.

10 must-have skills to become a top 1% web developer

10 essential skills every web developer should have…

From web basics you may be familiar with already; then going on to crucial skills like working with browser dev tools and coding rapidly with AI.

Notice how the focus is on real-world action instead of just theoretical knowledge — because that’s what matters.

1. HTML essentials: Create a basic functional web page

All about the core skeleton of a website.

How to:

  • Create an HTML page in an editor & open it in the browser
  • Set page title & icon
  • Create paragraphs of text
  • Create headings
  • Create links to other pages
  • Display images
  • Display tabular data
  • Show lists of elements
  • Handle input with forms
  • Create comments & comment out code
  • Make your page more meaningful with Semantic HTML

Some people think semantic HTML is useless because of CSS but they’re wrong.

It’s still crucial for accessibility and explaining your page to search engines to rank high on the results page.

JavaScript
<!-- tells search engine that the "AI singularity" is a time --> <time datetime="2025-01-07">AI singularity</time> is coming sooner than you think!

Without this you end up like those devs who use <div> for everything.

2. CSS essentials: Style the web page

That’s how you can go from this:

To this:

Enriching the skeleton with life.

How to:

  • Add styles to a page
  • Add colors: Fills, gradients, opacity, foreground vs background colors
  • Customize fonts: Font family, size, styles, weight, web-safe fonts, Google Fonts
  • Create layouts: Margin & padding, visual stacking, relative alignments
  • Add and customize backgrounds
  • Add flair with animations and transitions
  • Style particular states and parts of elements: Pseudo-selectors and pseudo-classes
  • Customize shape: outline & borders, height, width,
  • Reuse styles: CSS variables
  • Make your page look great for all screen sizes: breakpoints, responsive images,
  • Style faster with frameworks: Tailwind, Sass

3. JavaScript essentials

How to add interactivity to your web pages and make things happen:

Basics

If you’re new to coding:

How to:

  • Think about programming
  • Add JavaScript code to a page
  • Print output: alert(), innerHTML, console logging
  • Manage data — Create, use, update, and print variables: data types, scopes
  • Create comments & comment out existing code
  • Reuse actions: Create & call functions: syntax, parameters & arguments, return values, types, scopes
  • Create objects to represent real-world entities: data & variables, actions & methods, nested objects
  • Select and manipulate elements on a page: getElementById, querySelector, use methods & properties, etc.
  • Handle input & events: on a web page, etc.
  • Manipulate text with strings: multiline, substrings, case, concatenate, interpolate, split & join, trim & pad, search & replace, regex
  • Use lists: initialize, add, update, remove, iterate, transform, search, filter, sort, reverse
  • Use date and time: Create, update, format & display
  • Get data or do action conditionally: if/else, switch, ternaries, dictionary selection
  • Indefinitely do action conditionally: while, do while, for, break, continue
  • Upgrade your dev experience with TypeScript: types, generics, interfaces, transpiling, configuring, etc.

Develop for the client-side

You may know coding basics in & out but can you write JS code specifically for the browser?

How to:

  • Make network requests to a server: fetch() API, HTTP verbs, send & get data
  • Handle UI states: empty, loading, error, partial, ideal
  • Store data locally: cookies, Local Storage, Session Storage, etc.
  • Organize and package code: modules & module bundlers
  • Handle form input
  • How to code faster with NPM packages

4. Improve quality of life with dev tools

How to:

  • Create, inspect, & filter console logs: info, errors, warnings
  • Add temporary scripts & actions
  • Inspect, select & debug HTML elements
  • Inspect & temporarily modify styles
  • Monitor network requests
  • Test your pages on multiple screen sizes
  • Install editor extensions to develop faster
  • Customize editor themes, fonts, and settings to enjoy development more
  • Use an integrated debugger
  • Code faster with snippets: including Emmet
  • Develop faster with keyboard shortcuts
  • Use AI to develop faster

5. Improve site performance

How to:

  • Measure performance
  • Improve perceived performance
  • Improve Core Web Vitals: LCP, CLS, INP
  • Optimize general resource delivery: caching,
  • Optimize images: compressing, WebP
  • Lazy load images & video
  • Optimize CSS
  • Optimize web fonts: compressing, swapping, etc.

6. JavaScript framework: Develop faster

Whether it’s React, Angular, or Vue, they all have the same fundamental concepts:

How to:

  • Create and reuse components
  • Accept & display data in components: data binding, conditional rendering, etc.
  • Manage state in a component
  • Display & update list data
  • Handle events from components
  • Handle side effects and external data changes & state changes
  • Manage app-level state — independent from components
  • Handle form input
  • Style components
  • Handle SPA navigation with frontend routing

7. Version control: Track changes

Version control makes it easy to track changes across your codebase and experiment.

How to:

  • Create a local repo to store code & assets
  • Stage and commit files & changes: best practices, etc.
  • Ignore files with .gitignore
  • Check out previous commits
  • Create new branches: from latest or previous commits
  • Merge branches: resolving merge conflicts, etc.

Git & GitHub

How to:

  • Create your own GitHub repo: README.md, licenses, etc.
  • Use remotes: Create, push, pull, remove
  • Clone a repo from GitHub
  • Fork a GitHub repo
  • Make pull requests to a GitHub repo

8. Manage data in a database

Even if you’re dedicated to frontend, knowing these will refine your understanding of data processing & manipulation.

How to:

  • Design a schema for the data
  • Implement schema: tables, keys, data types, foreign keys, collections (NoSQL)
  • Add data to the database
  • Read data: joins, filter, sort, search, aggregate
  • Update data
  • Delete data

9. Develop for the server-side

How to:

  • Respond to a request: URLs, using the header & body
  • Manage logs: Create, inspect
  • Create a RESTful API: HTTP verbs, status codes
  • Fetch data from other APIs
  • Send requests to a database: Create, read, update, delete

10. General but crucial

How to:

  • Learn rapidly on demand
  • Solve problems independently from code
  • Communicate: with designers, clients & other devs
  • Debug: and be patient
  • Search for information on demand: and process it for your needs

Final thoughts

Once you learn all these you’ll be able to build 99% of web apps and sites from start to finish with great speed and high quality of life.

The 5 most transformative JavaScript features from ES8

ES8 was packed with valuable features that completely transformed the way we write JavaScript.

Code became cleaner, shorter, and easier to write.

Let’s check them out and see the ones you missed.

1. Trailing commas

Trailing commas used to cause a syntax error before ES8!

❌ Before:

JavaScript
const colors = [ '🔴red', '🔵blue', '🟢green', '🟡yellow', // ❌ not allowed ]; const person = { name: 'Tari Ibaba', site: 'codingbeautydev.com' // ❌ nope };

But this caused some problems:

But this made things inconvenient when rearranging the list:

Also we always had to add a comma to the last item to add a new one — cluttering up git diffs:

So ES8 fixed all that:

✅ Now:

JavaScript
const colors = [ '🔴red', '🔵blue', '🟢green', '🟡yellow', // ✅ yes ]; const person = { name: 'Tari Ibaba', site: 'codingbeautydev.com', // ✅ yes };

The benefits they bring also made tools Prettier add them by default after formatting:

2. async / await

This was where it all started with async/await!

No more annoying nesting with then():

❌ Before:

JavaScript
wait().then(() => { console.log('WHERE ARE YOU?!😠'); }); function wait() { return new Promise((resolve) => setTimeout(resolve, 10 * 1000) ); }

✅ After:

JavaScript
// 💡 immediately invoked function expression (IIFE) (async () => { await wait(); console.log('WHERE ARE YOU?!😠'); })(); function wait() { return new Promise((resolve) => setTimeout(resolve, 10 * 1000) ); }

The difference is clear:

❌ Before:

JavaScript
function getSuggestion() { fetch('https://api.example/suggestion', { body: JSON.stringify, }) .then((res) => { return res.json(); }) .then((data) => { const { suggestion } = data; console.log(suggestion); }); }

✅ After:

JavaScript
async function getSuggestion() { const res = await fetch('https://api.example/suggestion'); const { suggestion } = await res.json(); console.log(suggestion); }

10 lines 3 lines.

With async/await we could finally use our native try-catch for async code:

❌ Before ES8:

JavaScript
startWorkout(); function startWorkout() { goToGym() .then((result) => { console.log(result); }) .catch((err) => { console.log(err); }); } function goToGym() { return new Promise((resolve, reject) => { if (Math.random() > 0.5) { reject(new Error("I'm tired today!😴")); } resolve("Let's go!🏃‍♂️👟"); }); }

✅ Now:

JavaScript
startWorkout(); function startWorkout() { try { goToGym(); } catch (err) { console.log(err); } } function goToGym() { return new Promise((resolve, reject) => { if (Math.random() > 0.5) { reject(new Error("I'm tired today!😴")); } resolve("Let's go!🏃‍♂️👟"); }); }

3. Powerful Object static methods

Object.values()

A brilliant static method to extract all the values from an object into an array:

JavaScript
const person = { name: 'Tari Ibaba', site: 'codingbeautydev.com', color: '🔵blue', }; const arr = Object.values(person); // ['Tari Ibaba', 'codingbeautydev.com', '🔵blue'] console.log(arr);

Awesome for data visualization:

JavaScript
const fruits = [ { name: 'Banana', pic: '🍌', color: 'yellow', }, { name: 'Apple', pic: '🍎', color: 'red', }, ]; const keys = Object.keys(fruits.at(0)); const header = keys.map((key) => `| ${key} |`).join(''); const rows = fruits .map((fruit) => keys.map((key) => `| ${fruit[key]} |`).join('') ) .join('\n'); console.log(header + '\n' + rows);

Object.entries()

Bunches each key-value pair in the object to give a list of tuples:

JavaScript
const person = { name: 'Tari Ibaba', site: 'codingbeautydev.com', color: '🔵blue', }; const arr = Object.entries(person); /* [ [ 'name', 'Tari Ibaba' ], [ 'site', 'codingbeautydev.com' ], [ 'color', '🔵blue' ] ] */ console.log(arr);

Great for data transformations using both the object key and value:

Object keyed by ID list of objects:

❌ Before:

JavaScript
const tasks = { 1: { title: '👟HIIT 30 minutes today', complete: false, }, 2: { name: 'Buy the backpack🎒', complete: true, }, }; const taskList = Object.keys(tasks).map((id) => ({ id, ...tasks[id], })); console.log(taskList);

✅ Now:

JavaScript
// ✅ cleaner const taskList = Object.entries(tasks).map( ([id, task]) => ({ id, ...task, }) ); console.log(taskList);

4. Native string padding

On the 22nd of March 2016, the popular NPM package left-pad broke several thousands of software projects after the creator took it down as a form of protest.

It made a lot of people worried about our possible over-dependence on external modules — even something as simple as string padding.

But luckily ES8 brought native string padding to JavaScript with the padStart and padEnd string methods:

JavaScript
const name = 'tari'; console.log(name.padStart(9, ' ')); // ' tari' console.log(name.padEnd(10, '🔴')); // 'tari🔴🔴🔴'

We no longer needed to rely on yet another 3rd party dependency.

5. Object.getOwnPropertyDescriptors()

Semi-fancy name but effortless to understand.

Descriptors are properties of properties — one of these:

  • value
  • enumerable
  • get
  • set
  • configurable
  • enumerable
JavaScript
const person = { name: 'Tari Ibaba', color: '🔵color', age: 999, greet: () => console.log('Hey!'), }; console.log( Object.getOwnPropertyDescriptors(person) );

Final thoughts

Overall ES8 was a significant leap for JavaScript with several features that have become essential for modern development.

Empowering you to write cleaner code with greater conciseness, expressiveness, and clarity.

95% of users will never use your app again without this JavaScript feature

Without this JaaScript you will waste thousands of dollars and users will hate your app.

1. They will hate your app

They will be irritated by the horrible user experience and never return.

So imagine you’ve created an amazing AI writing assistant giving helpful suggestions for writing engaging stories:

You’ve got your API all set up for requests in handleChange:

JavaScript
export function AssistantUI() { const [suggestions, setSuggestions] = useState(''); const [loading, setLoading] = useState(false); const handleChange = async (event: any) => { const value = event.target.value; setLoading(true); const res = await fetch( 'https://api.writer.example.com/suggestions', { method: 'POST', body: JSON.stringify({ text: value }), } ); const json = await res.json(); setSuggestions(json.suggestions); setLoading(false); }; return ( <div className="flex flex-col justify-center flex-wrap content-start"> <textarea onChange={handleChange} className="mt-2 mb-4" cols={40} rows={10} /> { //... } </div> ); }

But unfortunately there’s a serious problem — can you spot it? 👇

I just started writing and immediately your AI is telling me nonsense about wrong spelling!

Where is my breathing space? Can’t you at least allow me to stop typing?

Oh no, I’m done — You ruined my day and I’ll never return.

But luckily that was just you in an alternate reality — the real you already knew that such UX would be annoying at best and infuriating at worst.

You’re so thoughtful and empathetic — that was why you knew this was a much better way to write handleChange:

JavaScript
export function AssistantUI() { const [suggestions, setSuggestions] = useState(''); const [loading, setLoading] = useState(false); const timeout = useRef<NodeJS.Timeout | null>(null); const handleChange = async (event: any) => { const value = event.target.value; setLoading(true); // restart delay clearTimeout(timeout.current!); // ✅ 1-second delay before fetch timeout.current = setTimeout(async () => { const res = await fetch( 'https://api.writer.example.com/suggestion', { method: 'POST', body: JSON.stringify({ text: value }), } ); const json = await res.json(); setSuggestions(json.suggestions); setLoading(false); }, 1000); }; return ( // ... ); }

Now the AI waits for 1 second before giving suggestions!

Everybody is in love with your app now – we could even stop using it if we tried…

In programming, we call this technique debouncing.

And it shows up everywhere…

  • Google Search: Any time you search, you’re experiencing debouncing in action.

Notice the delay between typing and the autocomplete update. It’s not latency, it’s debouncing.

  • Conversation: When we’re debating and you let me make my points before responding, you’re debouncing.

You didn’t interrupt and start screaming — you made sure I was done by constantly setting a subconscious timeout until I finally stopped speaking:

JavaScript
let silenceTimeout; let silenceDelay = 1000; function opponentKeepsTalking() { clearTimeout(silenceTimeout); silenceTimeout = setTimeout(() => { reply('Your fallacious premises have no basis in reality'); }, silenceDelay); }

2. You lose thousands of $$$

Your users are not the only ones getting overloaded — your servers are crying out for help.

❌ Before debounce:

1,000 users typing 10 times a second = 10 x 60 x 1000 = 600,000 requests a minute!

This load isn’t a functional issue with cloud computing but what about the costs?

Especially since you’re probably using an expensive AI service like OpenAI or GCP Vertex.

✅ Now after debounce:

Typing frequency no longer matters — if they pause typing 10 times every minute that’s

10 x 1000 = 10,000 requests a minute! A 98.3% reduction in requests and costs!

You were spending $1000 a day but now you’re spending less than $170 (!)

What took you a day to spend now takes you a week. Thanks to debounce.

But you can do better

Okay but that’s still like $5,000 a month — can’t we do better?

90% of your users are free and we need to keep their usage at a bare minimum.

Luckily you’re really smart so you quickly came up with this:

JavaScript
const timeout = useRef<NodeJS.Timeout | null>(null); const ignoring = useRef<boolean>(false); const handleChange = async (event: any) => { if (plan === 'free') { // ✅ still ignoring so nope if (ignoring.current) return; // ✅ start ignoring for 20 seconds ignoring.current = true; setTimeout(() => { ignoring.current = false; }, 20 * 1000); } // after throttle debounce(); const value = event.target.value; setLoading(true); const res = await fetch( 'https://api.writer.example.com/suggestion', { method: 'POST', body: JSON.stringify({ text: value }), } ); const json = await res.json(); setSuggestions(json.suggestions); setLoading(false); };

You ignore free users for 20 seconds after getting their last suggestion.

So only 3 suggestions per minute for them.

900 free users, 100 paying.

900 x 3 + 100 x 10 = 3,700 requests a minute — from $5,100 to $1900.

Killing two birds with one stone:

  • Massive 63% savings
  • Incentivize free users to upgrade for unlimited suggestions.

This is another technique we call throttling.

And it shows up anywhere you have periodically limited access to something:

  • GPT-4o model: Only allow 80 messages every 3 hours for Plus users, as of May 13th 2024.
  • Eating: You can only gobble up so much food at a time

Recap from our earlier debate:

  • Debounce: You wait for me to finish talking before responding and vice versa.
  • Throttle: We both have 5 minutes max at a time to talk.

With this powerful combo, what lasted only one day now lasted 3 weeks.

600,000 requests became 3,700, everyone loves your app, and you’re going to be a billionaire.

This is how functional try-catch transforms your JavaScript code

How common is this?

JavaScript
function writeTransactionsToFile(transactions) { let writeStatus; try { fs.writeFileSync('transactions.txt', transactions); writeStatus = 'success'; } catch (error) { writeStatus = 'error'; } // do something with writeStatus... }

It’s yet another instance where we want a value that depends on whether or not there’s an exception.

Normally, you’d most likely create a mutable variable outside the scope for error-free access within and after the try-catch.

But it doesn’t always have to be this way. Not with a functional try-catch.

A pure tryCatch() function avoids mutable variables and encourages maintainability and predictability in our codebase. No external states are modified – tryCatch() encapsulates the entire error-handling logic and produces a single output.

Our catch turns into a one-liner with no need for braces.

JavaScript
function writeTransactionsToFile(transactions) { // 👇 we can use const now const writeStatus = tryCatch({ tryFn: () => { fs.writeFileSync('transactions.txt', transactions); return 'success'; }, catchFn: (error) => 'error'; }); // do something with writeStatus... }

The tryCatch() function

So what does this tryCatch() function look like anyway?

From how we used it above you can already guess the definition:

JavaScript
function tryCatch({ tryFn, catchFn }) { try { return tryFn(); } catch (error) { return catchFn(error); } }

To properly tell the story of what the function does, we ensure explicit parameter names using an object argument – even though there are just two properties.

Because programming isn’t just a means to an end — we’re also telling a story of the objects and data in the codebase from start to finish.

TypeScript is great for cases like this, let’s see how a generically typed tryCatch() could look like:

TypeScript
type TryCatchProps<T> = { tryFn: () => T; catchFn: (error: any) => T; }; function tryCatch<T>({ tryFn, catchFn }: TryCatchProps<T>): T { try { return tryFn(); } catch (error) { return catchFn(error); } }

And we can take it for a spin, let’s rewrite the functional writeTransactionsToFile() in TypeScript:

JavaScript
function writeTransactionsToFile(transactions: string) { // 👇 returns either 'success' or 'error' const writeStatus = tryCatch<'success' | 'error'>({ tryFn: () => { fs.writeFileSync('transaction.txt', transactions); return 'success'; }, catchFn: (error) => return 'error'; }); // do something with writeStatus... }

We use the 'success' | 'error' union type to clamp down on the strings we can return from try and catch callbacks.

Asynchronous handling

No, we don’t need to worry about this at all – if tryFn or catchFn is async then writeTransactionToFile() automatically returns a Promise.

Here’s another try-catch situation most of us should be familiar with: making a network request and handling errors. Here we’re setting an external variable (outside the try-catch) based on whether the request succeeded or not – in a React app we could easily set state with it.

Obviously in a real-world app the request will be asynchronous to avoid blocking the UI thread:

JavaScript
async function comment(comment: string) { type Status = 'error' | 'success'; let commentStatus; try { const response = await fetch('https://api.mywebsite.com/comments', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ comment }), }); if (!response.ok) { commentStatus = 'error'; } else { commentStatus = 'success'; } } catch (error) { commentStatus = 'error'; } // do something with commentStatus... }

Once again we have to create a mutable variable here so it can go into the try-catch and come out victoriously with no scoping errors.

We refactor like before and this time, we async the try and catch functions thereby awaiting the tryCatch():

JavaScript
async function comment(comment: string) { type Status = 'error' | 'success'; // 👇 await because this returns Promise<Status> const commentStatus = await tryCatch<Status>({ tryFn: async () => { const response = await fetch<('https://api.mywebsite.com/comments', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ comment }), }); // 👇 functional conditional return response.ok ? 'success' : 'error'; }, catchFn: async (error) => 'error'; }); // do something with commentStatus... }

Readability, modularity, and single responsibility

Two try-catch rules of thumb to follow when handling exceptions:

  1. The try-catch should be as close to the source of the error as possible, and
  2. Only use one try-catch per function

They will make your code easier to read and maintain in the short- and long-term.

Look at processJSONFile() here, it respects rule 1. The 1st try-catch is solely responsible for handling file-reading errors and nothing else. No more logic will be added to try, so catch will also never change.

And next try-catch in line is just here to deal with JSON parsing.

JavaScript
function processJSONFile(filePath) { let contents; let jsonContents; // First try-catch block to handle file reading errors try { contents = fs.readFileSync(filePath, 'utf8'); } catch (error) { // log errors here contents = null; } // Second try-catch block to handle JSON parsing errors try { jsonContents = JSON.parse(contents); } catch (error) { // log errors here jsonContents = null; } return jsonContents; }

But processJsonFile() completely disregards rule 2, with both try-catch blocks in the same function.

So let’s fix this by refactoring them to their separate functions:

JavaScript
function processJSONFile(filePath) { const contents = getFileContents(filePath); const jsonContents = parseJSON(contents); return jsonContents; } function getFileContents(filePath) { let contents; try { contents = fs.readFileSync(filePath, 'utf8'); } catch (error) { contents = null; } return contents; } function parseJSON(content) { let json; try { json = JSON.parse(content); } catch (error) { json = null; } return json; }

But we have tryCatch() now – we can do better:

JavaScript
function processJSONFile(filePath) { return parseJSON(getFileContents(filePath)); } const getFileContents = (filePath) => tryCatch({ tryFn: () => fs.readFileSync(filePath, 'utf8'), catchFn: () => null, }); const parseJSON = (content) => tryCatch({ tryFn: () => JSON.parse(content), catchFn: () => null, });

We’re doing nothing more than silencing the exceptions – that’s the primary job these new functions have.

If this occurs frequently, why not even create a “silencer” version, returning the try function’s result on success, or nothing on error?

JavaScript
function tryCatch<T>(fn: () => T) { try { return fn(); } catch (error) { return null; } }

Further shortening our code to this:

JavaScript
function processJSONFile(filePath) { return parseJSON(getFileContents(filePath)); } const getFileContents = (filePath) => tryCatch(() => fs.readFileSync(filePath, 'utf8')); const parseJSON = (content) => tryCatch(() => JSON.parse(content));

Side note: When naming identifiers, I say we try as much as possible to use nouns for variables, adjectives for functions, and… adverbs for higher-order functions! Like a story, the code will read more naturally and could be better understood.

So instead of tryCatch, we could use silently:

JavaScript
const getFileContents = (filePath) => silently(() => fs.readFileSync(filePath, 'utf8')); const parseJSON = (content) => silently(() => JSON.parse(content));

If you’ve used @mui/styles or recompose, you’ll see how a ton of their higher-order functions are named with adverbial phrases — withStyles, withState, withProps, etc., and I doubt this was by chance.

Final thoughts

Of course try-catch works perfectly fine on its own.

We aren’t discarding it, but transforming it into a more maintainable and predictable tool. tryCatch() is even just one of the many declarative-friendly functions that use imperative constructs like try-catch under the hood.

If you prefer to stick with direct try-catch, do remember to use the 2 try-catch rules of thumb, to polish your code with valuable modularity and readability enhancements.

?? vs || in JavaScript: The little-known difference

At first glance you think you can just swap in anyone you like right?

JavaScript
let fastest = undefined; console.log(fastest ?? 'The Flash⚡'); // The Flash⚡ console.log(fastest || 'The Flash⚡'); // The Flash⚡

Wrong. They’re not what you think.

And we must learn the difference once and for all to avoid painful bugs down the line.

And what’s this difference?

It’s the incredible contrast in how they treat truthy and falsy values.

What are these?

Falsy: becomes false in a Boolean() or if:

  • 0
  • undefined
  • null
  • NaN
  • false
  • '' (empty string)

Truthy: every single thing else:

Now see what happens when you create a || chain like this:

JavaScript
const fruit = undefined || null || '' || 'banana🍌'; const color = '' || 'red🔴' || null; const num = 0 || NaN || 100 || false; console.log(fruit); // 'banana🍌' console.log(color); // 'red🔴 console.log(num); // 100

It keeps going until it hits the first truthy!

But what about a ?? chain? 👇

JavaScript
const fruit = undefined ?? null ?? '' ?? 'banana🍌'; const color = '' ?? 'red🔴' ?? null; const num = 0 ?? NaN ?? 100 ?? false; console.log(fruit); // '' (empty string) console.log(color); // '' console.log(num); // 0

Do you see the clear difference?

One looks for truthy, the other looks for anything that isn’t null or undefined.

When to use ?? vs ||

Initializing extra lives in a video game, where 0 means something?

?? 👇

JavaScript
const data = loadData(); const player = initPlayer(data); function initPlayer({ extraLives }) { const extraLives = extraLives ?? 20; console.log(`Player extra lives: ${extraLives}`); }

Paginating a response, where 0 limit makes no sense?

|| 👇

JavaScript
function paginate(options = {}) { return ['a', 'b', 'c', 'd', 'e'].splice(0, options.limit || 3); } paginate(1); // Output: ['a'] paginate(); // Output: ['a', 'b', 'c'] paginate(0); // Output: ['a', 'b', 'c']

User must have a name, so no spaces and definitely no empty strings?

|| 👇

JavaScript
function getUsername(userInput) { return userInput || 'Guest'; } function getProfilePic(userInput) { return userInput || 'profile-pic.png'; }

Did the user enter an invalid number or did they enter a number at all?

Find out with ?? 👇

JavaScript
function getUserAge(input) { if (!input) { return null; } else { return Number(input); } } console.log(getUserAge('') ?? '❌'); console.log(getUserAge('314') ?? '❌'); console.log(getUserAge('green🟢') ?? '❌');

?? and ?. are friends

Is someone there? not null or undefined?

Yes:

  • ?? — alright I’m done here
  • ?. — So let’s check out what you’ve gone

No:

  • ?? — So who’s next?
  • ?. — Um… bye!
JavaScript
console.log(''?.length); // 0 console.log('' ?? '❌'); // '' console.log('Tari Ibaba'?.length); // 10 console.log('Tari Ibaba' ?? '❌'); // 'Tari Ibaba' console.log(null?.length); // undefined console.log(null ?? '❌'); // '❌' console.log(undefined?.length); // undefined console.log(undefined ?? '❌'); // '❌'

Final thoughts

?? is a gullible child who will believe anything.

|| is a detective in search of the truthy and nothing but the truthy.

5 amazing new JavaScript features in ES15 (2024)

2024: Another incredible year of brand new JS feature upgrades with ES15.

From sophisticated async features to syntactic array sugar and modern regex, JavaScript coding is now easier and faster than ever.

1. Native array group-by is here

Object.groupBy():

JavaScript
const fruits = [ { name: 'pineapple🍍', color: '🟡' }, { name: 'apple🍎', color: '🔴' }, { name: 'banana🍌', color: '🟡' }, { name: 'strawberry🍓', color: '🔴' }, ]; const groupedByColor = Object.groupBy( fruits, (fruit, index) => fruit.color ); console.log(groupedByColor);

Literally the only thing keeping dinosaur Lodash alive — no more!

I was expecting a new instance method like Array.prototype.groupBy but they made it static for whatever reason.

Then we have Map.groupBy to group with object keys:

JavaScript
const array = [1, 2, 3, 4, 5]; const odd = { odd: true }; const even = { even: true }; Map.groupBy(array, (num, index) => { return num % 2 === 0 ? even: odd; }); // => Map { {odd: true}: [1, 3, 5], {even: true}: [2, 4] }

Almost no one ever groups arrays this way though, so will probably be far less popular.

2. Resolve promise from outside — modern way

With Promise.withResolvers().

It’s very common to externally resolve promises and before we had to do it with a Deferred class:

JavaScript
class Deferred { constructor() { this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); } } const deferred = new Deferred(); deferred.resolve();

Or install from NPM — one more dependency.

But now with Promise.withResolvers():

JavaScript
const { promise, resolve, reject } = Promise.withResolvers();

See how I use it to rapidly promisify an event stream — awaiting an observable:

JavaScript
// data-fetcher.js // ... const { promise, resolve, reject } = Promise.withResolvers(); export function startListening() { eventStream.on('data', (data) => { resolve(data); }); } export async function getData() { return await promise; } // client.js import { startListening, getData } from './data-fetcher.js'; startListening(); // ✅ listen for single stream event const data = await getData();

3. Buffer performance upgrades

Buffers are tiny data stores to store temporary data your app generates.

They make it incredible easy to transfer and process data across various stages in a pipeline.

Pipelines like:

  • File processing: Input file buffer process new buffer output file
  • Video streaming: Network response buffer display video frame
  • Restaurant queues: Receive customer queue/buffer serve customer
JavaScript
const fs = require('fs'); const { Transform } = require('stream'); const inputFile = 'input.txt'; const outputFile = 'output.txt'; const inputStream = fs.createReadStream(inputFile, 'utf-8'); const transformStream = new Transform({ transform(chunk) { // ✅ tranform chunks from buffer }, }); const outputStream = fs.createWriteStream(outputFile); // ✅ start pipeline inputStream.pipe(transformStream).pipe(outputStream);

With buffers, each stage process data at different speeds independent of each other.

But what happens when the data moving through the pipeline exceeds the buffers capacity?

Before we’d have to copy all the current data’s buffer to a bigger buffer.

Terrible for performance, especially when there’s gonna be a LOT of data in the pipeline.

ES15 gives us a solution to this problem: Resizable array buffers.

JavaScript
const resizableBuffer = new ArrayBuffer(1024, { maxByteLength: 1024 ** 2, }); // ✅ resize to 2048 bytes resizableBuffer.resize(1024 * 2);

4. Asynchronous upgrades

Atomics.waitAsync(): Another powerful async coding feature in ES2024:

It’s when 2 agents share a buffer…

And agent 1 “sleeps” and waits for agent 2 to complete a task.

When agent 2 is done, it notifies using the shared buffer as a channel.

JavaScript
const sharedBuffer = new SharedArrayBuffer(4096); const bufferLocation = new Int32Array(sharedBuffer); // ✅ initial value at buffer location bufferLocation[37] = 0x1330; async function doStuff() { // ✅ agent 1: wait on shared buffer location until notify Atomics.waitAsync(bufferLocation, 37, 0x1330).then((r) => {} /* handle arrival */); } function asyncTask() { // ✅ agent 2: notify on shared buffer location const bufferLocation = new Int32Array(sharedBuffer); Atomics.notify(bufferLocation, 37); }

You’d be absolutely right if you thought this similar to normal async/await.

But the biggest difference: The 2 agents can exist in completely different code contexts — they only need access to the same buffer.

And: multiple agents can access or wait on the shared buffer at different times — and any one of them can notify to “wake up” all the others.

It’s like a P2P network. async/await is like client-server request-response.

JavaScript
const sharedBuffer = new SharedArrayBuffer(4096); const bufferLocation = new Int32Array(sharedBuffer); bufferLocation[37] = 0x1330; // ✅ received shared buffer from postMessage() const code = ` var ia = null; onmessage = function (ev) { if (!ia) { postMessage("Aux worker is running"); ia = new Int32Array(ev.data); } postMessage("Aux worker is sleeping for a little bit"); setTimeout(function () { postMessage("Aux worker is waking"); Atomics.notify(ia, 37); }, 1000); }`; async function doStuff() { // ✅ agent 1: exists in a Worker context const worker = new Worker( 'data:application/javascript,' + encodeURIComponent(code) ); worker.onmessage = (event) => { /* log event */ }; worker.postMessage(sharedBuffer); Atomics.waitAsync(bufferLocation, 37, 0x1330).then( (r) => {} /* handle arrival */ ); } function asyncTask() { // ✅ agent 2: notify on shared buffer location const bufferLocation = new Int32Array(sharedBuffer); Atomics.notify(bufferLocation, 37); }

5. Regex v flag & set operations

A new feature to make regex patters much more intuitive.

Finding and manipulating complex strings using expressive patterns — with the help of set operations:

JavaScript
// A and B are character class, like [a-z] // difference: matches A but not B [A--B] // intersection: matches both A & b [A&&B] // nested character class [A--[0-9]]

To match ever-increasing sets of Unicode characters, like:

  • Emojis: 😀, ❤️, 👍, 🎉, etc.
  • Accented letters: é, à, ö, ñ, etc.
  • Symbols and non-Latin characters: ©, ®, €, £, µ, ¥, etc

So here we use Unicode regex and the v flag to match all Greek letters:

JavaScript
const regex = /[\p{Script_Extensions=Greek}&&\p{Letter}]/v;

Final thoughts

Overall ES15 is significant leap for JavaScript with several features essential for modern development.

Empowering you to write cleaner code with greater conciseness, expressiveness, and clarity.

structuredClone(): The easiest way to deep copy objects in JavaScript

Deep copying is a regular programming task for passing or storing data.

  • Shallow copy: Only copies the first level of the object
  • Deep copy: Copies all levels of the object
JavaScript
const obj = { name: 'Tari', friends: [{ name: 'Messi'}]}; const shallowCopy = { ...obj }; const deepCopy = dCopy(obj); console.log(obj.friends === shallowCopy.friends); // ❌ true console.log(obj.friends === deepCopy.friends); // ✅ false

But all this while we’ve never had a built-in way to perfectly deep copy objects and it’s been a pain.

We always had to lean on third-party libraries for deep copying and keeping circular references.

All that changes now with the new structuredClone() — an easy and efficient way to deep copy any object.

JavaScript
const obj = { name: 'Tari', friends: [{ name: 'Messi' }] }; const clonedObj = structuredClone(obj); console.log(obj.name === clonedObj); // false console.log(obj.friends === clonedObj.friends); // false

Cloning circular references with ease:

JavaScript
const car = { make: 'Toyota', }; // 👉 Circular reference car.basedOn = car; const cloned = structuredClone(car); console.log(car.basedOn === cloned.basedOn); // false // 👇 Circular reference is cloned console.log(car === car.basedOn); // true

Something you could never do with the JSON stringify/parse hack:

Go as deep as you want:

JavaScript
// ↘️ const obj = { a: { b: { c: { d: { e: 'Coding Beauty', }, }, }, }, }; const clone = structuredClone(obj); console.log(clone.a.b.c.d === obj.a.b.c.d); // ✅ false console.log(clone.a.b.c.d.e); // Coding Beauty

Limitations you should know

structuredClone() is very powerful but it has important weaknesses you should know:

Can’t clone functions or methods

Because of the special algorithm it uses.

Can’t clone DOM elements

Doesn’t preserve RegExp lastIndex property

I mean, no one’s cloning regexes but it’s one to note:

JavaScript
const regex = /beauty/g; const str = 'Coding Beauty: JS problems are solved at Coding Beauty'; console.log(regex.index); console.log(regex.lastIndex); // 7 const regexClone = structuredClone(regex); console.log(regexClone.lastIndex); // 0

Other limitations

Important to be aware of them to avoid unexpected behavior when using the function.

Clone some, move

This is a more sophisticated one.

You transfer inner objects from source to clone instead of copying.

Which means there’s nothing left in source to change:

JavaScript
const uInt8Array = Uint8Array.from({ length: 1024 * 1024 * 16 }, (v, i) => i); const transferred = structuredClone(uInt8Array, { transfer: [uInt8Array.buffer], }); console.log(uInt8Array.byteLength); // 0

Overall structuredClone() is a valuable addition to a developer’s toolkit and makes object cloning easier than ever in JavaScript

How to guarantee a coding job by writing the perfect cover letter

So who told you nobody reads cover letters?!

If you really believe that then prepare for a massive shock…

83% of hiring managers absolutely DO read cover letters.

And they’re not just skimming through — 60% of hiring managers spend at least 2 minutes reading your resume!

Cover letters are the unique selling point that gets you chosen over people with dangerously similar qualifications.

Learn the perfect to write them once and stand out in every job application. Every job platform: Upwork, Indeed, and so much more.

Blind mass applying leads to failure

Don’t behave like those irritating email spammers.

Sending the same old generic message to thousands of addresses hoping for 2 replies.

Your cover letter needs to be personalized to:

  • The job description
  • The company’s mission and values.

It shows you’re genuinely interested.

Make sure to include these gems

1. Attention-grabbing intro

If you mess up the intro everything that follows is automatically worthless.

Get straight to the point without using so much formal baggage.

Recommended: Quickly state your niche and intentions to “learn more” about the company 😉

Example:

I’m a passionate full-stack web developer with over 6 years of experience interested in learning more about the Coding Beauty team.

2. What have you achieved recently?

Solutions before features.

Recruiters care more about concrete real-world achievements than the dry technical details behind them.

Example — for the full-stack web developer role:

Over the past 3 years, I helped my company generate over $2 million in additional revenue by spearheading the development a new e-commerce web platform.

Wow, amazing achievement! Who is this guy?

Then leading up to your experience, you say:

And now I’m thrilled to continue my journey by contributing and growing with Coding Beauty. These are three things that make me a perfect fit for this position:

3. Experience

Alright, I’m now much more curious to see the skills & experience you gained to help you reach such majestic heights:

Firstly, at XYZ Corp, I spearheaded the migration from AngularJS to React, enhancing the user experience and improving performance by 30%. My focus was on creating reusable components, which streamlined the development process and fostered collaboration. I believe in writing clean, maintainable code and mentoring junior developers, which I did by conducting weekly code reviews and workshops.

Secondly, while at ABC Solutions, I led a project to integrate a Node.js backend with a MongoDB database, reducing data retrieval times by 50%. I am passionate about efficient architecture and robust security practices, which I implemented by designing a comprehensive API and setting up automated testing, ensuring a seamless and secure application.

Notice how they state something about themselves in relation to the experience they gained in both cases.

Making it unique to the individual — rather than some random generic rambling no one cares about.

4. Why this company?

Why do you want to work here?

Show how you resonate with the mission and values of the company:

Example:

Finally, I’m drawn to Coding Beauty’s mission because it aligns perfectly with my belief in empowering developers to reach their fullest potential. By fostering personal growth, promoting the enjoyment of coding, and facilitating avenues for financial success, Coding Beauty embodies values that resonate deeply with me.

5. Strong conclusion

Confident but not too brazen:

Example:

I’m sure my background aligns sufficiently with Coding Beauty and this role. I am enthusiastic about leveraging my expertise to contribute meaningfully to Coding Beauty’s objectives and look forward to hearing back.

Putting it together

I’m a passionate full-stack web developer with over 6 years of experience interested in learning more about the Coding Beauty team.

Over the past 3 years, I helped my company generate over $2 million in additional revenue by spearheading the development a new e-commerce web platform.

Firstly, at XYZ Corp, I spearheaded the migration from AngularJS to React, enhancing the user experience and improving performance by 30%. My focus was on creating reusable components, which streamlined the development process and fostered collaboration. I believe in writing clean, maintainable code and mentoring junior developers, which I did by conducting weekly code reviews and workshops.

Secondly, while at ABC Solutions, I led a project to integrate a Node.js backend with a MongoDB database, reducing data retrieval times by 50%. I am passionate about efficient architecture and robust security practices, which I implemented by designing a comprehensive API and setting up automated testing, ensuring a seamless and secure application.

Finally, I’m drawn to Coding Beauty’s mission because it aligns perfectly with my belief in empowering developers to reach their fullest potential. By fostering personal growth, promoting the enjoyment of coding, and facilitating avenues for financial success, Coding Beauty embodies values that resonate deeply with me.

I’m sure my background aligns sufficiently with Coding Beauty and this role. I am enthusiastic about leveraging my expertise to contribute meaningfully to Coding Beauty’s objectives and look forward to hearing back.

Thanks,

Coding Masters

Keep it short

Don’t write a book — everything we’ve gone should be done in 4 or 5 paragraphs.

No need to impress with fancy vocabulary or formal language.

Lean towards a conversational, semi-formal tone.

Follow these tips and tricks and you’ll drastically improve the quality of your cover letters for Upwork, Indeed or general job listings.