Maintainable Javascript carsonified

Post on 06-May-2015

5.057 views 1 download

Transcript of Maintainable Javascript carsonified

Maintainable JavaScript

Chris&an HeilmannCarsonfied online conference, September 2010

JavaScript is awesome!

Nowadays writing JavaScript is wonderfully easy.

Libraries patch the support holes in browsers.

Pure JavaScript environments allow us to really play with the language.

JavaScript is dead easy to learn and the first steps are already very rewarding.

This is also the problem of JavaScript.

The web is not a closed environment where we can dictate the technologies people use.

Some of the things I will talk about today will seem outdated or overly cautious.

The reason is that I want to build a web that works.

For far too long we have built a mess that barely functions and is hard to change.

So here are a few ideas and concepts you should follow if you write JavaScript.

★ Using, not abusing libraries

★ Separation of concerns

★ Building for extensibility

★ Documenting your work

★ Planning for performance

★ Avoiding double maintenance

★ Live code vs. development code

Libraries fix browsers and make the complex simple.

They make web development predictable.

Building without libraries means constant catch-up with the browser market.

Do not mix and match libraries though.

Stick with one and use it to its strengths.

If the library totally re-invents JS as we know it, this is fine.

But: writing in an abstraction syntax is not writing JavaScript.

Quick two-liners do not replace architecting and planning.

Professional libraries come as a pick and mix solution.

Include what you need and when you need it - not the kitchen sink approach.

One big danger of libraries is to tie the markup and your scripts far too close to each other.

Small looking loops can actually be very slow.

Long CSS selectors are dangerous.

Pick your plugins by how well they are documented, how well supported and how easy they are to extend.

Not by how flashy they are.

★ Using, not abusing libraries

★ Separation of concerns

★ Building for extensibility

★ Documenting your work

★ Planning for performance

★ Avoiding double maintenance

★ Live code vs. development code

This is old news.

Take each technology on the web and use it for what it was meant to.

HTML that works without JavaScript should not be aded using JavaScript.

HTML that only makes sense when JavaScript is available should be added with JavaScript.

Instructions that describe functionality that is dependent on JS should also be added by it.

Text, classes and ID names are very much prone to change.

So don’t spread them all over your scripts but keep them in one place for maintenance.

Public configuration objects are a great idea.

Most underused element:

<button>

Buttons by definition are there to trigger script functionality - so use them instead of links.

Links should point to a real resource - a url, a server endpoint or an anchor.

Empty links, void(0) # and other hacks don’t make any sense.

Styling should be done in CSS, not in your JavaScript.

Calculated positions are of course the exception to that rule.

Adding and removing classes makes sure designers have a handle and you don’t have to worry.

By adding a class to a parent element you can swiftly hide a lot of elements you’d otherwise have to loop over.

Adding a “js” class to the body means CSS designers can define two views easily.

Make maintainers not have to know JS or change yours!

★ Using, not abusing libraries

★ Separation of concerns

★ Building for extensibility

★ Documenting your work

★ Planning for performance

★ Avoiding double maintenance

★ Live code vs. development code

Using libraries means using a lot of anonymous functions.

Most of the time at the end of a massive chain of methods or for every click().

Naming and calling these methods makes more sense as you create a single space to maintain.

Never think your script is done and you thought of all use cases.

This is why we have dozens of lightbox plugins in jQuery all doing almost the same thing.

Instead of building a “one size fits all” solution, split it up into small solutions that do one thing and allow for mixing and matching.

Think about firing off custom events at interesting moments.

This allows people who want to extend your solution to do so without having to touch the main code.

Don’t limit anything to a fixed size or amount. Instead make it a variable in the configuration object.

★ Using, not abusing libraries

★ Separation of concerns

★ Building for extensibility

★ Documenting your work

★ Planning for performance

★ Avoiding double maintenance

★ Live code vs. development code

Documentation is what we rely on when we get lost.

People think documentation replaces good code examples.

The issue is that as developers, we almost never start with the documentation.

Instead we dive into the code and mess about with it.

We read the documentation when we get stuck.

Which is why code comments and descriptive variable and function names make your code easy to maintain.

Comment the special case, not the obvious.

Keep function and variable names short and to the point.

Your documentation should explain applying and extending the code, not the code itself.

Don’t worry about the size of comments - a good process deals with that.

GitHub and Google Code is the new View-Source, so add value, not only solutions.

★ Using, not abusing libraries

★ Separation of concerns

★ Building for extensibility

★ Documenting your work

★ Planning for performance

★ Avoiding double maintenance

★ Live code vs. development code

You can find a lot of great performance tricks on the web when it comes to JS.

Read those with the use case in mind.

Tricks necessary to make Google Mail on mobiles run smooth are edge cases.

Performance is a specialist topic and can be handled a lot in build processes.

If a performance change means re-educating a whole team of developers it is probably not worth it.

Scripts can convert and change code written in a predictable fashion.

Hacks and shortcuts need to be fixed by humans.

The performance of JS itself is not really the issue you should be concentrating on.

Slowness of the DOM and reflow of the interface is where users get hurt.

So use DOM access sparingly.

Assemble HTML as as string and use innerHTML once instead of adding to it.

Use Event Delegation instead of hundreds of event handlers.

Store information in JS objects instead of HTML attributes.

Make your code easy to understand and clean and add a performance review and refactoring step at the end.

★ Using, not abusing libraries

★ Separation of concerns

★ Building for extensibility

★ Documenting your work

★ Planning for performance

★ Avoiding double maintenance

★ Live code vs. development code

Double maintenance of code is a bad idea.

Validation rules might get out of sync.

This is always the killer argument of enemies of progressive enhancement.

I spend a lot of time doing form validation in JavaScript - why should I repeat the same on the server side?

Because there is no security in JavaScript!

If all you do is validate in JS, attackers will have a field day with your server.

Besides, there is no need to repeat validation rules.

That way you validate on the server and you can use the same rules for your JS...

Form validation scripts are annoying.

You need to access the right parts, read and write from the DOM, change styles and and and...

You can leave it all to the server and still save your users a full page reload.

Request type switching is the answer.

JavaScript libraries add a special footprint to the server request when calling content via Ajax.

(so should your own Ajax solutions, btw)

You can use this to send content to Ajax requests and other content to normal requests.

You can use this to render a form completely server side and just send a string back for each request.

http://github.com/codepo8/validationdemo

Filter inputs for nasties and include the rules.

If the form has not been submitted, include the form code.

Otherwise loop through the rules and check the data that was sent against them.

this is like /pattern/.test($(name).value)

If there was an error - show the form again. Otherwise say thanks.

The form itself is a simple HTML form doing all the dynamic rendering with PHP...

Check for the error array and if there is an error, show it. Otherwise show a * to indicate required field.

Check if the form was sent via Ajax - if not, render the form element.

If there was an error, say so. At the field show the error or the * SPAN.

And all you then need to do in JavaScript is to override the form submission.

And instead replace the innerHTML of the form on every submit.

An example using YUI3...

Load the IO and Node module.Define the configuration for the Ajax call.

On submission of the form load the validate.php file with the config and don’t send off the form.

If the Ajax call was a success, replace the innerHTML of the form with the HTML returned from validate.php

In addition to that, focus on the first element with an error message - this helps with assistive technology.

If the Ajax call failed, send the form.

Subscribe to the Ajax events.

Writing lots of HTML with JavaScript is painful.

So if you can avoid it, avoid it :)

You can take this concept further.

Make the backend render HTML to use with include() in PHP and load the same with Ajax.

Using Node.js you can move that later on to a pure JavaScript solution.

★ Using, not abusing libraries

★ Separation of concerns

★ Building for extensibility

★ Documenting your work

★ Planning for performance

★ Avoiding double maintenance

★ Live code vs. development code

Live code is not development code.

If you really get to a high traffic level with your scripts you should have a build process.

A build process should do a few things for you.

★ Remove comments★ Remove whitespace★ Bundle lots of files into one★ Pack the code★ Version, add the author and

date.★ Validate + Lint

Some examples of great practices in the wild.

Give browsers what they can do and use what they do better!

Easing the use of web fonts for better typography.

Simply adding a link doesn’t give you feedback though...

Using JS to load the fonts on the other hand does.

http://code.google.com/apis/webfonts/docs/webfont_loader.html

Classes added to the root element by the Google WebFont loader

.wf-inactive

.wf-active

.wf-tangerine-n4-inactive

.wf-tangerine-n7-active

.wf-droidsans-n4-inactive[...]

n4 - normal i4 - italicn7 - bold i7 - bold italic

http://code.google.com/apis/webfonts/docs/webfont_loader.html

<style type="text/css"> .wf-inactive p { font-family: serif; font-size:12px; } .wf-active p { font-family: 'Tangerine', serif; font-size:20px; } .wf-inactive h1 { font-family: serif; font-size: 16px } .wf-active h1 { font-family: 'Cantarell', serif; font-size: 35px }</style>

WebFontConfig = { google: { families: [ 'Tangerine', 'Cantarell' ] }, typekit: { id: 'myKitId' }, loading: function() { }, fontloading: function(family, info) {}, fontactive: function(family, info) {}, fontinactive: function(family, info) {}, active: function() {}, inactive: function() {}};

And that’s that. A lot about writing maintainable JavaScript is to avoid writing it yourself :)

Christian Heilmann http://wait-till-i.com http://developer-evangelism.com http://twitter.com/codepo8

Thanks!