DEV Community

Discussion on: Elegant patterns in modern JavaScript: RORO

Collapse
 
billsourour profile image
Bill Sourour • Edited

Thank you for your feedback Dian.

I first encountered the concept of receiving a single object rather than individual parameters back when jQuery ruled the world. Some functions in jQuery – especially those related to $ajax – received a so-called options object.

Back then, I didn't like this pattern at all for the exact reasons you mentioned; I found that it made functions more opaque and added complexity that could only be overcome by adding more documentation.

Since then, two things happened which changed my mind. The first is the advent of destructuring syntax. The second, equally important change, is in the sophistication of our code editors.

For example, here is how VS Code treats my findUserByRole function. No extra documentation needed.

Collapse
 
dmfay profile image
Dian Fay

I use options objects myself in Massive -- it's the only way to keep signature size under a sane maximum when you have a dozen different things that can affect the shape of your results and don't want to move to a builder-style pattern. The tradeoff is that I have to be very careful with documentation; that and the fact that the options are a known set applied consistently across the API are why it's usable at all.

Destructuring is more a convenience than a compelling argument for working like this. You could always pass objects and return objects; now you can express it a bit more elegantly, but it's still the same concept. What really enables you is your editor, and that's not something I'd be willing to depend on. People use other editors with different featuresets, and even if everyone standardized on VSCode, syntax tree analysis isn't available when you're reading diffs or browsing an open source codebase on the web. Readability as plain text is critical, and sacrificing that to achieve an architecture that actually increases local complexity seems like a bad trade for most cases.

Thread Thread
 
billsourour profile image
Bill Sourour • Edited

Thanks again for your feedback.

I would argue that we are actually increasing plain text readability rather than diminishing it.

In terms of reading the function signature, I don't think the extra curly braces impede readability. And, in terms of reading code that consumes our function, I think a destructured parameter object has the advantage.

Imagine coming across the following examples in plain text...

findUsersByRole('admin', true, true)
findUsersByRole({
  role: 'admin',
  withContactInfo: true,
  includeInactive: true
})

...isn't the second one clearer? Especially when we are in a plain text environment that can't easily navigate to the function's signature.

Thread Thread
 
dmfay profile image
Dian Fay • Edited

Essentially what you have with this example is a criteria object. This is another instance where the idea works out okay, because you're approaching the unary argument as criteria, not as a discrete role and flags. You don't even really need destructuring to work with it: you can just iterate Object.keys and pop the values into your prepared statement parameters or analogous structure.

Where the real problems start to pop up is when you bundle information that shouldn't be bundled. Think dispatchMessage('channel', 'message', true) versus dispatchMessage({channel: 'channel', message: 'message', emitOnReceipt: true}). It's true that you can make an educated guess as to what emitOnReceipt does without having to look at dispatchMessage's signature. But are there other behaviors? Can message itself be a complex object? What happens if I pass a "meta-message" object that contains x, y, z other fields (even if the function destructures arguments immediately, arguments is still around to make things interesting)?

A well-formed signature does as well with some of these kinds of questions as what's arguably an abuse of anonymous objects, and does better with others; notably, the possibility of pollution is obviated. If you're going to operate on a "meta-message" concept that ties these disparate values together, it should be a proper class. And sometimes it's worth doing that! But throwing anonymous objects around is something that really needs to be considered carefully.