$(..) statements, maybe a
$('#message').hide() (or a
$('#message').slideUp(); if you were hip).
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
How do I do that?
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.
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
Strict mode has intentionally different semantics.
Ok, so that was fun. But now my app is broken. The good news is
If you re-test your app and it’s all working, then well done! Just for fun, you can try adding
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.
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
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.
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 ;)
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.
- 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.
- The code is easier to read: 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.
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.