5 Programming Patterns I Like

John Stewart on May 20, 2019

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... [Read Full]
markdown guide
 

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.

 

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
};
 

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')

 

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

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

 

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?

 
 

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!

 

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';
}
 

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
}
 

3. One loop two arrays

Is reduce really necessary here? Wouldn't it be so much clearer to do this with a forEach?

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

5. Nested ternaries

The same flow you used in the ternaries can be applied to the if statements:

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

And if you used the same flow as in your if statements but with ternaries, they'd also look weird:

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

Also, I find ternaries formatting to be more readable this way:

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

HA! I posted the almost the exact same else-if logic before realizing you had!

 

Personally, I don't like the nested ternary conditions.

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

Instead of the nested if..else, I would prefer the "Early assignment" like "Early Exits"

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

// instead

let result = "";

if(!conditionA) result = "Not A";
if(!conditionB) result = "A"
result = "A & B"
 

Nice post!

Re #1: Rubocop calls them "guard clauses" and I tend to prefer that style as well.

But if there are only two branches, I sometimes prefer the symmetry of if / else. Especially when if is an expression (as it is in Ruby).

Either way, IMO it's usually clear enough when input validation is being done, however it gets written. It's one of those places where obscuring the intent takes real talent :P

Re: #2: agree with @nepeckman that putting the switch statement in a function is usually a good option. Especially if multiple cases map to the same output value, because there you can use switch fallthrough to "stack" the tests and avoid repeating yourself.

Re: #3: reduce (fold) is so powerful 😍... map and filter can both be written in terms of it, and many more things as well. Many "indexed" loops can be translated into a function folded over a range of integers.

Also, I haven't seen it formalized, but it seems like a lot of tail-recursive code can be translated to "reducer style" as well -- it's a good option if the inputs can be easily generated as some sort of collection.

If the fold implementation allows early termination (a la Clojure's reduced, it becomes even more useful.

 

Oh yeah, in case you haven't seen it in action, you might be interested to know that a side-effect-free series of map calls can be refactored similar to your #3. map distributes across function composition, so

map(g, map(f, coll)) == map(compose(g, f), coll)

The latter form only walks the collection once, obviously. You can compose the functions manually or borrow compose from a library like Ramda.

 

Early exits keep indentation sane which contributes a lot to readability.

Nested ternaries are great and very clear if you lay them out like:

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

so the structure of each line is exactly the same.
(Don't try this in PHP by the way - you need parens to fix the broken associativity).

 
  1. No 'foo' variables should be called: "The Shakespeare Naming Convention" or SNC.
 

Part of our coding standard is no acronyms (with a very few specific exceptions for industry terms). It is amazing how much easier it is to read code from 5+ years ago when it isn't littered with little three letter shibboleths.

 
 
 

I think nesting ternaries makes things more difficult to change later without scratching your head. The linked article says it simplifies the conventional if

const withIf = ({
  conditionA, conditionB
}) => {
  if (!conditionA) return valueC;
  if (conditionB) {
    return valueA;
  }
  return valueB;
};

but it doesn't go all the way:

const withIf = ({
  conditionA, conditionB
}) => {
  if (!conditionA) return valueC;
  if (!conditionB) return valueB;
  return valueA;
};

At this point the if and the ternary are nearly identical, with the exception that the if statement blocks can contain anything they like without breaking the layout. Imagine if instead of returning a simple value they were all returning a long string or a calculation? I mean, you can say that these sorts of things should be factored into their own functions, but that's true of both techniques.

 

There is a very unfortunate drawback of using a function for "if" or ternary... the conditions are always evaluated and that often means dereferencing null or undefined...

 

You're right. I have found it is exactly easy to understand the ternaries because the priority level is default satisfying what I want it to be. But One loop two arrays I don't agree. I code the following code and it is more elegant:

const validTrolley = result.filter(item => item.inventoryCount && item.putShelvesFlg)
const invalidTrolley = result.filter(item => !(item.inventoryCount && item.putShelvesFlg)).map((item, index) => {
            item.isInvalid = !index;
            return item;
          })
 

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" :-)

 

When using reduce, I prefer to always return a new pure array rather than pushing to an existing array. Keeping reduce stateless has resulted in less debugging for me.

const exampleValues = [2, 15, 8, 23, 1, 32];
const [truthyValues, falseyValues] = exampleValues.reduce(([truthy, falsey], value) => {
  if (value > 10) {
    return [truthy.concat(value), falsey];
  } else {
    return [truthy, falsey.concat(value)];
  }
}, [[], []]);
 

I really appreciate and identify with this article.

But... Not the nested ternaries. The example used as the "bad nested if" feels to me like those commercials for cracking eggs and how no one can do it (meaning, it's actually easy, but we want to sell you a thing)

First, let's kill the unneeded semicolons, because, yuck. Second, reverse the first logic and use else if for the second and you have yourself some pretty simple logic that can also be multiple lines long... but... for the sake of this example we don't need curly braces either. So apples to apples if code would be below. Honestly, the nested ternary functions I've seen are a HUGE mess, not at all as simple as the example provided. Especially while returning JSX and returning blocks of JSX-HTML...shudder

if (!conditionA)
  result = 'Not A' 
else if (conditionB)
  result = 'A & B'
else
  result = 'A'

Multi-line Version

if (!conditionA) {
  result = 'value: Not A' 
  console.log('not A')
} else if (conditionB) {
  result = 'A & B'
  console.log('value: A & B')
} else {
  result = 'A'
  console.log('value: A')
}
 

These patterns are so useful in day to day work!

In the 'one loop two arrays' pattern for partitioning I like to emphasize what is the essential, minimal difference in each condition. In this case, it's really just 'what array do I append to?'

var target =
  arrays[
    predicate(example) ? 1 : 0];
target.push(example);
 

I love nested ternaries, shortens the code. A real world example, simple Vue-router meta controlling;

    const accessControl =
      to.meta.abKey === 'default'
        ? true
        : to.matched.filter(x => abKeys.includes(x.meta.abKey)).length > 0
        ? true
        : false;
 

cond1 ? true : cond2 ? true : false

is the same as

cond1 || cond2

 

Nested ternaries can be tricky for their operator not having the same priority between programming langages :

a='a',b='b',c='c',d='d',e='e',a?b:c?d:e; // ==='b'
$a='a';$b='b';$c='c';$d='d';$e='e';echo $a?$b:$c?$d:$e; // ==='d'

Also using spaces or multiple lines may mislead the programmer, suggesting priority :

a?b:c ? d : e;
a?b:c
  ?
    d
  :
    e;

To me, it is always better to use parenthesis, on one line of code. If the line goes too long you should use variables (as in pattern 4 "No 'foo' variables") :

const result1 = !conditionA ? "Not A" : (conditionB ? "A & B" : "A");
const result2 = (!conditionA ? "Not A" : conditionB) ? "A & B" : "A";

Still my preference goes to a non nested if/elseif/else blocks (i find it a lot clearer) :

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

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

 

πŸ˜…

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

 

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

 

For nested ternaries we can use self-executable loops:

{ (() => {
if(x) {
//do something...
console.log(''x')
}
if(y) {
//do something...
console.log(''x')
}
if(z) {
//do something...
console.log(''x')
}
}
)()
}

 

Instead of switch to object literal I suggest the facade pattern. Going with facade pattern, your IDE will be able to resolve function definition. If this object resolution grows in complexity it will be harder to understand why this generic function refers to and only your debugger can help you.

 

The details of this would be an interesting topic for a follow-up article.

 
 

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

 

:D

Definitely not, just things I noticed I do sometimes.

 

I liked the first two and use very often.

I kind of feel nested ternary is more confusing though mileage varies person to person.

 

Great post! We both use the first concept you mentioned in the post. I'll explore the others and see how I can incorporate them also.

 
 

The Early Exits I know them as "Quick Fails" and its the best patter I learned recently.

 
 
 

hi,
someone can give me advice which book about programming patterns to buy ? I'm interested in this.
thanks

 
 

It's very relatable, have been doing almost all of them in my code (except the two arrays pattern, which is a great idea as well).

 

Omitting the else and else ifs when you do the early return always seems dangerous.

code of conduct - report abuse