Respect The Javascript

Posted by by

Yes, it’s true. Javascript is so popular it can now be a full-time job. Many people used to coast through their daily jobs as a PHP, Rails, Java developer with a few $(..) statements, maybe a $('#message').hide() ( or a $('#message').slideUp(); if you were hip).

But these days, Javascript is coming of age. It’s grown from being a scrappy little toy we have loved and abused with code like onclick="alert('...')" , to be something that has grown up with us, and now appreciate. It is the only runtime language I can think of that will run on any modern processing device. It’s ubiquitous and the ecosystem has evolved beyond what anyone could have imagined, with many implementations (Rhino, V8, now Nashorn) and it’s very own matching server-side equal, node.js

Ok, so Javascript’s big. So what?

We need to stop treating Javascript like we did 5 years ago, pay it some respect and treat it like the 1st class language it now is. Web development is fragile – the difference between a website that works and one that doesn’t can be a single line of Javascript. Avoiding problems – or at least catching them early – is the key to reliable deployments.



How do I do that?

Simple. Remember all those requirements in your delivery document for testing? Well, JUnit / PHPUnit / NUnit may be all 100% green for your server side code, but you know what? In modern apps, up to 80% of code is on the frontend, written in Javascript.

Hang on – did you just say I haven’t written tests for 80% of my code?

Depends – if you haven’t got unit tests for them, you probably test the code somehow – whether it’s integration testing (people loved Selenium for this – but it’s not ideal) or manual regression testing.

But I’ve been doing it like this for years, why should I change?

If you’re happy with how it’s been going, don’t change a thing. But consider why we write tests in the first place. Not just so that the code works. It’s so that we know it will keep working, or so we get told when it doesn’t (by a broken build, or a red light). You know, when you leave and someone else picks up your code to insert a cool jQuery animation (or take it out because they don’t understand how to chain deferred animations) they can have a level of confidence that they haven’t broken any other functionality.

Ok, you’ve convinced me. I want to be a better Javascript developer. But i’m on a project with zero Javascript tests and main.js has 11,000 lines of code. Where do I start?

Most blogs talk about fresh projects – I think that’s unrealistic. It’s always easier to set up standards for greenfields vs. a legacy app. So here’s what i’d suggest:

1. Get your team onboard with your views.

If you can’t do this, you may have an uphill battle with the rest of the team – ideally it is a democratic choice. Or if you’re the lead, you could force it upon them – that works well 😉

2. Start using "use strict";

Put it at the top line of all your Javascript files. And watch everything break. Seriously.

Strict mode has intentionally different semantics.

Ok, so that was fun. But now my app is broken. The good news is "use strict"; is interpreted at a block-level scope, so you can add it within a method declaration, which turns on strict mode only for code that follows. This will let you add strict mode to new code, without breaking your legacy code, until you have felt out the pain points of strict mode all the bad practices you have adopted over the years. It’s a great way to learn how to write better Javascript. "use strict"; is a tiny badge of honor that says the Javascript should execute consistently across implementations. More about strict mode here.

If you re-test your app and it’s all working, then well done! Just for fun, you can try adding "use strict"; to the top of any of your Javascript library plugins you use. This (apart from reading the plugin source code itself) gives a good idea of how well written the plugin(s) are that you use in your codebase. Many worthwhile plugins will already have this in their source code, along with JSHint options in comments (and tests!).

3. Start concatenating / minifying your Javascript

You may be doing this already – although many people are not – Gasp! This may highlight some problems, or your next deployment may break. Most often this highlights dependency ordering issues or code quality issues with Javascript due to the parsing in the minification process.

This step should be easy to convince your team / product owner(s) as it is an accepted good practice (you could argue CDNs are better for common libraries) and *should* give perceivable performance benefits to users. It is easily measurable as an improvement and your tracking code page load time should reflect this improvement too.

Minifying can help catch many small issues with your code, including the #1 mistake: dangling commas of death in IE: var arry = [1,2,3,4,5,];

The other reason is that this is a huge enabler for modular code in your codebase. If you had everything in one big monolithic main.js file, you can now separate out your concerns into modules, eg. user.js, item.js, cart.js and structure your Javascript codebase like you already do in the main codebase, which makes it easier to locate, easier to understand and easier to test.

Legacy Java projects seem to be the main culprit in this space. Rails and Node.js guys have been doing this forever. I can’t comment on PHP and .NET stacks.

I have personally used WRO4J on a Spring-MVC app, although it took some time to configure and tweak, we could rely on it for production builds. As an upgrade path on the JVM – consider Play 2 or Grails since these have much better static asset support built-in.

4. Use JSHint

This is a bit more of an investment. Since you are now minifying and using strict mode, you should be using better practices in your Javascript code. Now you can make it even better. You can cut down on the number of bugs in your code by enforcing good practices and a coding format (which makes it more consistent and easier to read)

Make JSHint part of your build pipeline and tweak the warning flags to suit your project. Just make sure you run JSHint before your minify, otherwise you won’t get far 🙂

Now you want to faster feedback with JSHint, between the time you write the code to the time you verify it with JSHint. If you run a local build task as part of a pre-check-in process to source control, you may only do that once a day and you could spend 30 minutes fixing the errors it finds, long after writing the culprit code.

Ideally, you want to find a way to run JSHint over your code as you write it – either in the IDE as a highlighter (IntelliJ does this well and Sublime too) or using Guard or a background process to monitor Javascript file changes.

This way you get fast feedback about the issues, and soon learn never to do them in the first place!

5. Write tests

This is the hardest to transition to, if you’re not doing it now. I prefer Jasmine but there are plenty of test frameworks out there, just do some research.

Pick something that will integrate with your build pipeline and use it. Start small, otherwise you will give up trying since your code will not be structured to be easily testable. Read up about mocks, stubs and fixtures and find a DRY way to define them in your tests. Also, don’t test everything, but that’s another story 😉

6. Refactor

Like spring-cleaning, refactoring keeps the codebase lint-free and removes dead weight or changes in design that have accumulated. Pragmatic refactoring is probably the best indicator of a strong developer. How do you know when you’ve done a good refactor?

The tests don’t break: Now that you have tests, you can use them to ensure the business logic your tests cover still work as expected.Test coverage should be the same or greater than when you started the refactor.

Now that you have tests, you can use them to ensure the business logic your tests cover still work as expected.Test coverage should be the same or greater than when you started the refactor. The app still works: A green build is great, but it’s a false negative if the app is broken. If this happens, try to look for an opportunity to add a testcase which covers whatever failed.

A green build is great, but it’s a false negative if the app is broken. If this happens, try to look for an opportunity to add a testcase which covers whatever failed. The code is easier to read: This is important. If it’s harder to read, what have you achieved?

This is important. If it’s harder to read, what have you achieved? The code is not significantly slower than before: This is more subjective, but you want confidence that you haven’t introduced any performance regressions due to the refactor. If anything it should be faster if you have removed redundant code / decreased the complexity of an algorithm.

7. Monitor code coverage

I wouldn’t say this is required, but it is a best practice.

I recommend Istanbul as it gives a beautiful report, runs on any environment (uses Node.js), works with Require.js / AMD modules, produces a cobertura coverage report and can fail the build if it doesn’t meet your specified thresholds for line / statement / branches / function coverage.

Conclusion

As our web apps become more and more Javascript-heavy, skipping practices like refactoring and automated unit testing can lead you into a Javascript-tinged world of pain.

Respect the Javascript, or you’ll get punished.

If anyone has any further improvements or recommendations on tools they use, i’d love to hear about them. You only get better by learning, experimenting and refining your knowledge.