7 Patterns to Refactor JavaScript Applications: Decorators

July 23, 2014 | By Michael Phillips, Engineer

On October 17, 2012, Bryan Helmkamp, founder of Code Climate, wrote a blog post outlining 7 patterns to refactor fat ActiveRecord models in Ruby on Rails. Here at Crush & Lovely, this post is a core reference for all Rails developers on how to separate concerns, write modular, concise and expressive code, and make testing exceedingly simple.

This series of posts demonstrates these concepts in the JavaScript environment; they are no less applicable to data models in JavaScript, and are equally as valuable. Each week, one of the seven patterns will be explained. This week, we’ll be talking about Decorators.

Patterns

  1. Service Objects
  2. Value Objects
  3. Form Objects
  4. Query Objects
  5. View Objects
  6. Policy Objects
  7. Decorators

Decorators

When a process has side effects that need to be executed only in certain situations, this functionality can be layered onto an existing operation using Decorators. A Decorator takes an object and wraps auxiliary functionality around it, letting you add on what you need when you need it and keeping the core procedure untouched.

Example

Let’s imagine a Service Object that generates report cards for each student in a class. A teacher can generate these report cards at any point, but there are some situations where those report cards should be mailed to the students’ parent.

One way to address this would be to have two separate Service Objects, GenerateReportCards and GenerateReportCardsAndEmailParent, but this creates duplication and is hard to maintain when there are many cases with many conditional steps.

Another way would be to put together callbacks, such as:

This isn’t bad, but it relies on the return value from the Service Object to be usable for the subsequent process. Additionally, the same process may need to happen in both procedures, such as generating the HTML for the report card.

This problem calls for a Decorator, which targets a specific method and layers on top of it, allowing us to tap into an existing operation and add auxiliary functionality. So, for this example, our Service object looks like this:

We could create a Decorator object that accepts an instance of the Service Object as its argument and returns that Service Object with the specified method wrapped with the added functionality.

One key goal of the Decorator pattern is that the returned object is the same object as the input object, both in terms of identity and API, but with an altered property. So the following should be true if the object is decorated properly.

With this pattern in practice, we can layer on any number of Decorators that decorate any number of methods on the original Service Object for much win.

Testing

When testing a Decorator, it is wise to test that the method is both decorating the original object properly and that the auxiliary method or methods are performing the right actions. A reasonably comprehensive test suite for the EmailReportCardToParent Decorator above could look like this:


This concludes the series on 7 Patterns for Refactoring JavaScript Applications. I hope these concepts have provided you with a core understanding of ways in which you can refactor your own applications. Each pattern has different implementations, approaches, and degrees of attraction to each engineer. However, these concepts have been battle-tested and proven successful in our applications at Crush & Lovely, and we are always trying to think of new and better objects to refactor our applications with.

What are some of your favorites of the patterns I’ve covered here? Are there others that I didn’t mention that you’ve used? Also, if you like these patterns and want to join a team of engineers that are constantly pushing to write better, more stable, and more readable JavaScript applications, check out our open positions!

Special thanks to Justin Reidy and Anisha Vasandani for editorial and code review.