Don’t initialise Javascript automagically

The problem with looping over behavioural HTML attributes

Adam Silver
Simple = Human
5 min readJan 5, 2017

--

I used to write Javascript that initialises components automagically. Don’t worry I’ll explain what I mean. Take a look below:

The technique works by looping over every element with a particular behavioural class name. If the Document contains the class name several times, the script creates several instances. With no Javascript changes at all. That’s the automagical bit.

Developers commend this technique because there’s only four lines of code. Less if using a library. And it never needs updating. If you want another date picker, just add a class of date picker. Job done.

This approach is problematic for many reasons. Here’s why:

1. It’s harder to understand the codebase at a glance

To understand the codebase at a glance, you need to know what behaviour exists and where.

The loop doesn’t tell you how many date pickers there are. There could be a thousand instances or there could be one (or none) — in which case the loop is misleading. Either way you don’t know.

2. You might apply behaviour by accident

If you happen to use a class that corresponds to a component, then you might accidentally initialise behaviour.

3. It’s difficult to estimate stories

If you can’t document what you’re changing and where, it’s difficult to define and estimate a story.

4. It’s difficult to QA

After modifying a date picker, a tester will ask you what parts of the system you’ve affected. The loop doesn’t help you answer this question.

5. It’s harder to debug

If there’s a problem with one date picker, finding and debugging it is more tricky. You will have to find the problematic instance by searching the HTML templates. Then you will need to step through the loop until you find the erroneous one.

6. It’s harder to delete

As you don’t know where the loop is executing, you can’t delete code in confidence. Thus, the code stays in the codebase for a long time.

7. It’s hard to determine behaviour

This approach forces you to store behaviour in HTML attributes. This isn’t an elegant way to define behavioural relationships. HTML becomes bloated and hard to read. Every attribute value is a string, when you might, for example, want a number.

8. It’s painful to customise

When you need to use models and XHR etc, it becomes painful to work with this approach.

I’ll give you an example. Imagine you have a form with two date pickers: a start-date and end-date.

When the user chooses a start-date, the end-date values update. This is to ensure the end-date is always after the start-date.

This is hard to define in HTML. In Javascript it’s easy:

9. It’s painful to infer behaviour from HTML

The loop doesn’t allow you to customise an instance by passing in options. Instead, you have to store behaviour in HTML. When you change behaviour, you must update the HTML. This goes against recommended​ practices.

10. It’s painful to override behaviour

To override behaviour, you will need to add an extra class to the HTML. Then the date picker (or the loop) will determine the override by checking for this extra class. At this point, the component (or the loop) is no longer generic.​

11. It’s hard to destroy instances

It’s easy to store the instances during initialisation. But, determining and retrieving one later so you can destroy it, is harder this way.

12. It increases the chance of performance issues

This approach means the Javascript has to crawl the DOM a lot more than is otherwise necessary. First to find elements that need enhancing, and second to determine behaviour from attributes.

Touching the DOM is expensive, which increases the risk of performance issues. The risk increases further when you have many components and many instances of a component.

13. It’s harder to unit test

It’s difficult to unit test behaviour when you store behaviour in HTML. You might then decide to use HTML fixtures. But they are slow and you’re no longer writing unit tests. You could mock the DOM but this is tedious and problematic. The less you store in HTML the easier it is to test.

14. It’s harder to initalise at different times

This technique often assumes that we want to initalise everything when the Document is loaded. But sometimes we need more sophistication. For example, we may want to initialise a component once it’s loaded later with AJAX. This approach makes this hard.

15. It exposes a security hole

You can read about the security hole here.

16. It increases the size of HTML

Putting Javascript in HTML increases the HTML. But unlike Javascript, it can’t typically be cached because HTML is likely to contain personalised and dynamic content.

“But I don’t want to update Javascript every time I want a new instance?”

I fail to see why updating Javascript is a problem. In fact, I would expect you to change Javascript when updating behaviour. Updating HTML instead of Javascript is not better.

“Is this necessary—it feels like code bloat?”

If code is valuable, it’s not code bloat.

“But the Javascript will have a lot more code.”

Maybe. Maybe not. It depends on your architecture and your requirements. Even if it did, good code is not just determined by the number of lines.

“But let’s at least use it for simple components.”

Even if it did work for simple components, you have to draw a line between simple and complex. This is arbitrary and having two ways of doing the same thing makes code inconsistent.

“It’s easier for backend developers to add behaviour in HTML.

You need to decide whether backend developers should be writing Javascript or not. If they should be writing it, then help them do it right. They are software engineers. Trust them.

Summary

Good code is not about number of lines.

Good code is not about how easy it is to write the first time.

Good code is easy to reason about.

Good code is easy to update.

Good code is consistent.

Good code is easy to unit test.

Good code is easy to delete.

Bad code is easy to write but hard to delete. Bad code is magical. Magic is entertaining. Code shouldn’t be entertaining.

Automagical loops obfuscate complexity. They make things appear simple when they’re not.

Help future-you by writing Javascript that doesn’t suffer from these problems. HTML isn’t good at defining behaviour. But Javascript is.

Please ♥ the article if you found value in it.

If you sign up for my newsletter I’ll send you other articles about designing and developing simple, human and inclusive experiences on the web.

--

--

Adam Silver
Simple = Human

Former frontend dev, turned designer. I talk about how to design simple and accessible products (without the BS).