DEV Community

Discussion on: 4 Dangerous Problems in JavaScript Easily Solved by The Builder Design Pattern

Collapse
 
willsmart profile image
willsmart • Edited

Thanks for a great post!
It's a great discussion of why the builder pattern is worthwhile, separating construction details from objects' behaviours once it's been set up.

Adding my 2c worth of JS style advice though (nothing specific to builder patterns btw): let's move away from methods like constructor(name, gender, eyes, legs, scent, tongue, heart, weight, height) outright.

In JS if you have a bag of arguments they're better placed in an argument object. Use multiple arguments when there couldn't be any confusion about which param is which when looking at some code that calls the function (i.e. when there's a natural ordering or when order doesn't matter).
So

addThreeNumbers(a,b,c); // no confusion here
log(a,b,c); // logs in order I'd assume
new Frog(a,b,c,d,e,f,g); // um, Brad, we need to talk about your variable naming, I'm heading out for a breather
new Frog({
  name: a,
  eyes: b,
  heart: c,
  gender: d,
  tongue: e,
  scent: f
}) // Brad, we still need that talk but at least I could figure out your code, btw you forgot the legs.

For the Frog thing I'd use something like:

constructor({name, gender, eyes, legs, scent, tongue, heart, weight=undefined, height=undefined}) {....}

(the =undefined is not required but is a note to callers that these are optional)

This adds a whole two characters and no complexity to the code but comes with big wins:

  • The biggest is that it's much harder to make arg ordering mistakes.
  • Notable mention is that arg labels end up following their values around, allowing for easier calls and robustness against additional details, eg:
function buildBobTheFrog() {
  const frogAttributes = {
    ... defaultFrogAttributes,
    name: "Bob",
    gender: "Non-binary",
    pronouns: "It",
    eyes: "Like summer rain",
    legs: "1.5 (don't ask)"
  }

  if (foo) frogAttributes.heart = "bar"

  // ... other code as you see fit to set up the frog's bits

  // The next line is simply intended to create the frog 
  // -- i.e. it does one simple thing introducing one new detail, the class name 
  // -- so the actual line of code should have one basic detail in it: `Frog`.
  // It shouldn't be expected to understand what attributes a frog expects,
  // -- or intricacies of how they are ordered in that particular piece of code.
 return new Frog(frogAttributes);
}