DEV Community

Cover image for 5 Programming Patterns I Like
John Stewart
John Stewart

Posted on • Originally published at johnstewart.dev

5 Programming Patterns I Like

In this post I get into some patterns I try to use while programming. These patterns are observations I've made about myself recently while working as well as a couple I stole from coworkers over the years.

These patterns are in no particular order just a simple collection.

1. Early exits

function transformData(rawData) {
  // check if no data
  if (!rawData) {
    return [];
  }

  // check for specific case
  if (rawData.length == 1) {
    return [];
  }

  // actual function code goes here
  return rawData.map((item) => item);
}

I call this pattern 'early exits' but some also refer to this as 'the Bouncer Pattern' or 'guard clauses'. Naming aside, this pattern takes the approach of checking for invalid use cases first and returning out from that function otherwise it continues onto the expected use case of the function and executes.

For me, this approach has some positives that I really like:

  • encourages thinking around invalid/edge cases and how those cases should be handled
  • avoids accidental and unnecessary processing of code against an unexpected use case
  • mentally allows me to process each use case much more clearly
  • once adopted, you can quickly glance at functions and understand the flow and execution which typically follows a top down approach going from - invalid cases -> small cases -> expected case

More info:

2. Switch to object literal

// Switch
let createType = null;
switch (contentType) {
  case "post":
    createType = () => console.log("creating a post...");
    break;
  case "video":
    createType = () => console.log("creating a video...");
    break;
  default:
    createType = () => console.log('unrecognized content type');
}

createType();

// Object literal
const contentTypes = {
  post: () => console.log("creating a post..."),
  video: () => console.log("creatinga  video..."),
  default: () => console.log('unrecognized content type')
};

const createType = contentTypes[contentType] || contentTypes['default'];
createType();

Next up is removing the switch. I often make mistakes when writing each case and very often forget a break. This causes all kinds of fun issues. The switch statement doesn't add a whole lot of value when I'm writing code. It seems to get in the way.

I prefer using an object literal instead, here's why:

  • don't have to worry about case or break
  • easier to read and quickly understand what's happening
  • object literals are easy enough to write
  • less code

More info:

3. One loop two arrays

const exampleValues = [2, 15, 8, 23, 1, 32];
const [truthyValues, falseyValues] = exampleValues.reduce((arrays, exampleValue) => {
  if (exampleValue > 10) {
    arrays[0].push(exampleValue);
    return arrays;
  }

  arrays[1].push(exampleValue);
  return arrays;
}, [[], []]);

This pattern is nothing really special and I should have realized it sooner but I found myself filtering a collection of items to get all items that matched a certain condition, then doing that again for a different condition. That meant looping over an array twice but I could have just done it once.

Turns out this has a name (bifurcate) and I stole it from 30secondsofcode.org. If you've never checked out that site I suggest going there. So much good information and useful code.

I know reduce can be kind of daunting and not very clear what is going on but if you can get comfortable with it, you can really leverage it to build any data structure you need while looping over a collection. They really should have called it builder instead of reduce.

More info:

4. No 'foo' variables

// bad
const foo = y && z;

// good
const isPostEnabled = isPost && postDateValid;

This one may seem kind of obvious but I'm sure we all have seen code that does this. Take the time and do your best to name something appropriately.

This is especially important for working professionals or people who are in a position where they are educating others. Variable naming should be used to help explain and give context to what is going on within the code.

Someone should be able to read your code and loosely begin to understand what is trying to be solved.

More info:

5. Nested ternaries

let result = null;
if (conditionA) {
  if (conditionB) {
    result = "A & B";
  } else {
    result = "A";
  }
} else {
  result = "Not A";
}

const result = !conditionA
  ? "Not A"
  : conditionB
  ? "A & B"
  : "A";

I'll admit, in the beginning the idea of nesting ternaries was off-putting. It just seemed like a clever way to write conditionals. Then I started writing business logic and found myself with nested if else clauses and some pretty questionable conditional logic.

I think if and else are much easier to read as they are actual words but when these become nested I start to really have a hard time following what is going on and mentally keeping track of everything.

I started deferring to ternaries and nested ternaries and I found I was able to quickly understand at a glance what was happening.

I think this pattern is really up to you and your team and your preferences. I have worked in codebases that do both well and can see both sides to this, but personally nested ternaries are really growing on me.

More info:

Oldest comments (59)

Collapse
 
nepeckman profile image
nepeckman

Personally, my favorite way to do JavaScript switches is to isolate them to their own function. If you're doing a simple dispatch, a function is already an appropriate abstraction, and return gives you the ability to avoid the break mess.

// Object literal
function createContent(contentType){
   const contentTypes = {
     post: Post,
     video: Video,
     default: Unknown
   };
   const createType = contentTypes[contentType] || contentTypes['default'];
   return createType(); // or new createType() if its a class constructor
}

// Switch
function createContent(contentType){
  switch(contentType){
    case "post": return Post() // or new Post() if its a class constructor
    case "video": return Video()
    default: return Unknown()
  }
}

Utilizing the switch statement also dodges the biggest drawback of the object literal: the location of the object. If you put the object literal in your dispatch function, you're creating the object every time you run the function. If you create the object once outside of the function, now your dispatch logic is in a different place than the actual dispatch call.

I wish JavaScript had a built in pattern matching construct, but a well used switch statement isn't all that bad.

Collapse
 
thejohnstew profile image
John Stewart

I like that switch versus the one I wrote. :D

I recently discovered pattern matching via Scala and enjoyed using it!

Collapse
 
evanplaice profile image
Evan Plaice

Why not wrap the whole thing in one function. Use it as a closure to store the type data then return the switch function to access it?

Collapse
 
kleene1 profile image
kleene1

Cool post ! :)

Collapse
 
geompse profile image
Geompse

Example with no object creation in the function:

// Object literal
const createContent = function(contentType){
   const contentTypes = createContent.contentTypes;
   const createType = contentTypes[contentType] || contentTypes.default;
   return createType(); // or new createType() if its a class constructor
}
createContent.contentTypes = {
  post: Post,
  video: Video,
  default: Unknown
};
Collapse
 
ecancino profile image
Eduardo Cancino • Edited

I love this solution, very simple;

I usually do this:

const  fromTypes = (types, def = null) => type => (types[type] || def)

const createContent = fromTypes({ post: Post, video: Video }, Unknown)

createContent('post')

Thread Thread
 
jaytailor45 profile image
Jay Tailor

This is how redux architecture works ;)

Collapse
 
keevcodes profile image
Andrew McKeever

Love seeing these posts! I just recently used a switch in my code and didn't like the overall bulk the switch created. Nice ideas on how to clean it up!

Collapse
 
thejohnstew profile image
John Stewart

Googled and found this:

I like it.

Collapse
 
thejohnstew profile image
John Stewart

Where are these terms?

Collapse
 
verrigo profile image
Radu Caprescu

I'm sorry, but if you like nested ternaries you are either a bad man or someone who didn't have a 4 or 5 nested ternary that made you scream with pain. Or both :D

Collapse
 
thejohnstew profile image
John Stewart

πŸ˜…

I haven't done 4 or 5 nested. That seems a bit much lol

Collapse
 
verrigo profile image
Radu Caprescu

Well, I have PTSD with using ternaries. I once did some work in Jasper Reports and their scripting language used only ternaries. Now every ternary that is longer than 1 line (max 2 at the most) gives me the creeps and is an instant code smell for me

Collapse
 
steffenpedersen profile image
Steffen Pedersen

Are you thinking about specific programming patterns, when you are programming? Like "Oh, I gotta use 1. Early exits right now." πŸ˜€

Collapse
 
thejohnstew profile image
John Stewart

:D

Definitely not, just things I noticed I do sometimes.

Collapse
 
maciekgrzybek profile image
Maciek Grzybek

Awesome article mate πŸ‘Œ

Collapse
 
nuculabs_dev profile image
Nucu Labs

JavaScript X.X

Collapse
 
pinotattari profile image
Riccardo Bernardini

I use mostly Ada and very sparingly JavaScript, but...

(1) I agree with the "no foo" suggestion (although when I am really in a hurry I throw in a "Tmp" with the idea of choosing a better name later...). I always try to use fully readable names for my variables and functions.

(2) About the nesting of ternary operator, my preference goes to the "ternary Ada style," similar to the ?: but with full verbose "if", "then", "else" and, if needed, "elsif" :-) oh, yes, and "case..when" :-)

Collapse
 
adam_cyclones profile image
Adam Crockett πŸŒ€ • Edited

Everything else looks fine but the nested turn ops.. not for me, clarity can go a long way over terse for the sake of others. Besides there are alternatives to nested conditionals. Boolean array .every or .some spring to mind.

// similar to x && y
const criteria = [
   user === 'logged-in',
   hasCardDetails
]
if ( criteria.every(isTrue => isTrue) ) {
   // do a thing if all are true
}
// similar to x || y
const criteria = [
   user === 'logged-in',
   hasCardDetails
]
if ( criteria.some(isTrue => isTrue) ) {
   // do a thing if some are true
}
Collapse
 
adamgerthel profile image
Adam Gerthel

Clever! Gonna remember this one

Collapse
 
adam_cyclones profile image
Adam Crockett πŸŒ€ • Edited

Your most welcome πŸ˜„, this is functional programming at it's finest. The only thing I don't like is the need to return the result by lambda. I haven't tried it but perhaps the Boolean constructor could sit where isTrue => isTrue is currently? I am afk so can't test.

Thread Thread
 
adamgerthel profile image
Adam Gerthel

I haven't tried it but perhaps the Boolean constructor could sit where isTrue => isTrue is currently?

This sentence went "swoosh" over my head.

I also had to google what a lambda was - had never heard that name for an anonymous function before (but I'm an autodidact which could explain it..) πŸ˜‚

Could you elaborate in an ELI5 way? :D

Collapse
 
vycoder profile image
yev

As a personal preference I just try to avoid nesting in any form as much as possible because it really obscures the logic.

Say, this code snippet,

let result = null;
if (conditionA) {
  if (conditionB) {
    result = "A & B";
  } else {
    result = "A";
  }
} else {
  result = "Not A";
}

into:

function getResult() {
  if (!conditionA) {
    return 'Not A';
  }
  if (conditionB) {
    return 'A & B';
  }
  return 'A';
}

or even:

function getResult() {
  if (!conditionA) {
    return 'Not A';
  }
  return conditionB ? 'A & B' : 'A';
}