Polymer anti-patterns: Prevent leaking internals between components

Data binding and event bubbling might couple your components much closer than you expect.

Ronny Roeller
NEXT Engineering
3 min readJul 10, 2017

--

How decoupled are your components?

Lately, we refactored two larger Polymer applications. These refactorings turned out to be considerable more time-consuming than expected. Hence, we went back to understand what caused the unforeseen complications.

Here are the two anti-patterns that we identified:

Anti-pattern 1: Leak data structure via data binding

The problem

Our application contains mini apps, which are supposed to be decoupled from the rest of the application. The mini apps only need some state information when they get started (e.g. profile information about the current user) and could cause some data changes in the application when they finish (e.g. an update to the profile information).

We wired up the mini apps by directly passing e.g. the current user:

<mini-app user="[[user]]"></mini-app>

And then naively used the passed user within the mini app, e.g.:

<div>Hello [[user.name.givenName]]!</div>

The problems started when we simplified the data model in our application: For example: Storing the given name in user.given_name instead of user.name.givenName required to adjust every single mini app, all physically “decoupled” in separated Github repositories.

Solution

Every decoupled component (being stored in a separated Github repository is a sure indicator) must own its data structures. The component’s data structure should only consider the domain of the component itself— not how data is stored in the embedding component.

For example, our mini app might require the user property to be in a format like this example:

{
firstName: 'Joe',
email: 'joe@company.com'
}

The calling component has to create then the required data on the fly, e.g.:

<mini-app user="[[_convert(user)]]"></mini-app>...convert(user) {
return {
firstName: user.given_name,
email: user.primary_email,
}
;
}

Now, whenever the data model of the application changes, we only need to adjust the convert methods. No knowledge about the inner workings of the mini app is required.

As a positive side effect, we also avoid leaking additional data points that the mini app shouldn’t know about (e.g. the security role might be stored in the user object).

Anti-pattern 2: Leak event structure via event bubbling

The problem

Our mini apps signalize via events noteworthy state changes, e.g. when a mini app gets closed:

this.dispatchEvent(new CustomEvent('closed', {
bubbles: true,
composed: true,
}));

The embedding application would listen for these events, and change e.g. the view:

ready() {
super.ready();
this.addEventListener('closed', e => this._toAppSelection(e));
}

It felt like an elegant solution: we have one central part that listen to closed events, and then anything within any mini app can trigger the central code.

But what we had really done was introducing a dependency from the mini app to the embedding component: The mini app knew about the magic closed event within the embedding application. So, when we wanted to refactor an event in the embedding application, we had to immediately reflect the change in every single mini app!

The solution

Every decoupled component must own its events. The component’s event structure should only consider the domain of the component — not how events are handled in the embedding component. A translation layer connects the component events to the central event handling code.

For illustration, the mini app fires now a finalized event when it’s done, which gets translated by a mini app-specific wrapper:

<mini-app on-finalized="onFinalized"></mini-app>...class MiniAppWrapper extends Polymer.Element {  onFinalized(e) {
this.dispatchEvent(new CustomEvent('closed', {
bubbles: true,
composed: true,
}));
}
...

If we now want to refactor the events in the application, we only need to adjust all the wrappers — instead of touching the mini apps itself.

Happy coding!

Want to learn more about Polymer? Have a look to all our Medium posts on Polymer.

--

--

Ronny Roeller
NEXT Engineering

CTO at nextapp.co # Product discovery platform for high performing teams that bring their customers into every decision