Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Wednesday, August 1, 2012

Enterprise-class Javascript, part III


The third episode is dealing with global variables and encapsulation. Let's start with globals. Global variables have been a curse in almost every programming language for decades, but many Javascript developers (most of them I know) still use global variables and functions all the time. Some of them may accidentally define functions which are not global (especially with jQuery), but don't really understand the difference. Why do they use globals? I think there are multiple reasons to it. First of all, it's because many web developers don't have real programming background, but instead they were once forced to widen their view of world from plain HTML to Javascript. Secondly, JavaScript has implied global variables and you may be using global variables by accident; if you do not explicitly declare a variable, a global variable is implicitly declared for you. And last but not least, Javascript has been written this way in the past; writing Javascript was considered just a mandatory plague and typically it was written by copycats without straining their brains too much.

In Javascript the global object is the global namespace that holds the top level functions and global variables. Variables which are not explicitly defined are implied global variables, and their names are also kept in the global object. Writing functions to global scope is roughly the same thing as writing Java classes to default package or C#'s global namespace. This inevitably leads to collisions and that's why many programming languages and markup languages have packages (e.g. Java) or namespaces (C#, XML, C++, ...). It's also the reason why global functions do not lead into reusable code which could be published as a library. In reality you must use global variables and functions, but don't put your own stuff there. I found a really nice depiction of global scope by Dmitry Baranovskiy. He compared JavaScript’s global scope to a public toilet: “you can’t avoid going in there, but try to limit your contact with surfaces when you do.”


As an example, let's assume for a second that jQuery and Underscore would have been implemented as a set of global functions. They share so many names of functions that you couldn't use them together. Everything would blow up instantly. Fortunately they are not reserving nothing but one or two slots from the global object: jQuery exposes 'jQuery' and '$', underscore.js just '_'. It doesn't matter how the functions and variables are named in the context of exposed global variable. If you are looking for a trouble, try using '$' as your global variable name. On the other hand, (sh)it also happens sooner or later when you use names like database, db, application, app and alike; the moment you start using another ill behaving library (in addition of yours) you are screwed.


In addition of keeping your stuff out of global scope, you should also embrace encapsulation. One particularly easy way to achieve this is to use RequireJS, which implements module pattern for you. Now it's time to show how to do something without global variables and keep your module internals hidden. First we define a module without any global vars. Here it is:

define( function( ) {
var counter = 0;

function incr( ) {
counter++;
}

return {
getAndIncrement : function( ) {
var tmp = counter;
incr( );
return tmp;
},
reset : function( ) {
counter = 0;
}
};
} );

Why aren't the functions and variables global in example above? That's because they are defined in the scope of anonymous factory function, the one and only parameter to define. They cannot be referenced from outside of their enclosing scope. The object literal returned from the factory function is going to be the public interface of your module and thus the consumer side of our module could look like this:

<script type="text/javascript">
require( [ 'counter' ],function( cnt ) {
alert( cnt.getAndIncrement( ) );
alert( cnt.getAndIncrement( ) );
cnt.reset( );
alert( cnt.getAndIncrement( ) );
} );
</script>

The series of calls show values 0, 1, 0, leaving counter to value 1. If you use the same module again (maybe another script block later in the same page), you can see that counter variable is shared between those scripts. The reason is that module loader executes the factory function (a function passed to define) just once and thus the counter variable declared inside the module is allocated and initialized just once. If this is not what we want, we can modify our module a little bit, so that it returns constructor function instead. This makes it possible to create multiple instances of our world-famous counter object. The new version now looks like this:

define( function( ) {
function incr( self ) {
self.counter++;
}

function Counter( ) {
this.counter = 0;
};

Counter.prototype.getAndIncrement = function( ) {
var tmp = this.counter;
incr( this );
return tmp;
};

Counter.prototype.reset = function( ) {
counter = 0;
};

// Return constructor function
return Counter;
} );

while the consumer could look like this:

<script type="text/javascript">
require( [ 'counter2' ],function( Counter ) {
var c1 = new Counter( );
var c2 = new Counter( );
alert( c1.getAndIncrement( ) );
alert( c2.getAndIncrement( ) );
alert( c1.getAndIncrement( ) );
alert( c2.getAndIncrement( ) );
c1.reset( );
alert( c1.getAndIncrement( ) );
} );
</script>

This time the series of alerts show values 0, 0, 1, 1, 2. Oops, what just happened? Why didn't the reset function work? Because the code is missing this-keyword in front of counter. Also, because there's no var keyword it actually sets a global variable called counter to value 0. To fix it we just add this-keyword, and now the code of function reset looks like this:

Counter.prototype.reset = function( ) {
this.counter = 0;
};

The series of alerts now show values 0, 0, 1, 1, 0. That's what we expected.

In conclusion, if you are writing nothing but random shit I would suggest you do it right. It doesn't mean huge overhead neither in performance nor productivity and then you in the right track from the beginning. Read these Global domination and JavaScript module-pattern in depth for more information.

At least one more episode is still coming, and it's about optimizations.

Tuesday, July 31, 2012

Enterprise-class Javascript, part II


My previous post was about modularity and dependency management using AMD based RequireJS. While modularity and dependency management form a basis for re-usable software development, it's not all. In the world of Web-based applications there's one special feature; if you application runs on browser it means all your HTML, CSS and Javascript files must be accessible in source format. Especially with Javascript it means your precious source code doensn't have any theft-protection. Legal or not, but anyhow the source code can be stolen just like that and I know people are doing it a lot. Now you may think "thank god we only allow clients who have signed on", but it really means "only signed-on clients can steel your source code". How do you control which of your clients has stolen your potentially valuable source code? If you don't care, how about donating all your server side code, too? On the other hand, most Javascript files I've seen are such big piles of steaming shit that nobody actually wants them even for free (wait for episode 3 of this series). I've contributed those piles too before I decided to get some real understanding about Javascript. And even if you don't mind about your source code being stolen, having your source code accessible and in readable format also opens it security vulnerability. For example, one can check from source code your field validation rules and use that information to enter illegal data.

So, if this is a real problem, somebody must have solved it already, right? Yes, it has been solved but it's not used as much as one would expect. Since I'm still in the middle of studying RequireJS, right now I'm suggesting Google's Closure Compiler. You can find a web version here. Google Closure Compiler will optimize and mangle your code. One of the episodes to come will dive into optimizations, but for now we are just fine with the mangling. I use my "fancy" memory game  as a sample. It contains just a couple of placeholder divs and mangled, optimized Javascript code. It's not optimized as much as it could, but it's a good start. You can find the associated Javascript content here.

Now a simple function like this:

function funnel( n,fn ) {
return function( ) {
if( --n == 0 )
fn.apply( null,arguments );
};
}

has become this:

function l(b,a){return function(){--b==0&&a.apply(null,arguments)}}

That's not very far from the original, so let's try a little bit more complex function like this:

function animateText( $objects,text,then,delay,classesToRemove,classesToAdd ) {
if( delay != undefined )
$objects.delay( delay );
$objects.fadeOut( delayInTurning,function( ) {
var $this = $(this);
$this.text( text );
if( classesToRemove != undefined )
$.each( classesToRemove,function( idx,cssClass ) {
$this.removeClass( cssClass );
} );
if( classesToAdd != undefined )
$.each( classesToAdd,function( idx,cssClass ) {
$this.addClass( cssClass );
} );
} ).fadeIn( delayInTurning,then );
}

It becomes this:

function n(b,a,c,f,d,e){f!=h&&b.delay(f);b.fadeOut(p,function(){var b=$(this);b.text(a);d!=h&&$.each(d,function(a,c){b.removeClass(c)});e!=h&&$.each(e,function(a,c){b.addClass(c)})}).fadeIn(p,c)}

While you have all the functionality in the mangled version, you understand it? Can you make any changes to it? What if you have lots of functions which all look like this? At least it makes a lot harder to understand and maintain this kind of code. How about reversing the mangling, reverting original sources back with another tool? Is it possible? If you put a donkey to the mincer, can you reincarnate the donkey by putting the minced meat to another machine?

Monday, July 30, 2012

Enterprise-class Javascript, part I



Recently a friend of mine asked my opinion about library called RequireJS. I have done lots of Javascript but still I haven't even heard about it. Shame on me. As an execuse I'm just saying I'm mostly server-side programmer and Javascript is just my hobby. After going through the RequireJS documentation I noticed that it's not just a regular Javascript library, but a Javascript module loader instead. I always overlooked CommonJS and things alike and thus I didn't even know about AMD (Asynchronous Module Definition). OMG, how it's possible I didn't know about it? So far I've thought that jQuery, maybe mated with underscore.js is enough. Just use things like namespaces, avoid globals at any cost, add JSDoc comments to your code and mangle it through Google Closure Compiler. With this approach you can have some kind of intellisense, loads faster and your code is theft-protected at least to some extent. But something was missing ...


After initial shock I did some tests with RequireJS. Worked as expected and I was really happy since I used to take care of namespaces and Javascript module pattern by myself. No more, since RequireJS takes care of it on my behalf. It was just what I've been looking for a while. Somehow it remainded me about OSGi. And just like with OSGi, it kind of forces you make modular code. Also, if you follow good programming practices you can hide your dependencies right to the place where belong and keeping your private functions private. Let's take an example. If the module is dependent on, let's say, underscore.js, I really don't care as far as it fullfils its contract. Or let's say a module is using backbone.js, which in turn is using underscore.js and jQuery. With traditional approach I have to have zillions of script-tags in my page using any of those libraries and they have to be in correct order. With RequireJS my module now looks like this:

// file uploader.js
define( ['jquery'],function( $ ) {
// Do this and that with jQuery
} );

and my module consumer now looks like this:

<script src="require.js"></script>
<script>
require( ['uploader'],function( Uploader ) {
var u = new Uploader( ... );
...
} );
</script>

Notice that I only have one script tag (besides my own inline script), which is loading require.js. If my consumer side code is using jQuery, I would also have jquery as depedency. Now it looks like this:

<script src="require.js"></script>
<script>
require( ['uploader','jquery' ],function( Uploader,$ ) {
$(document).ready( function( ) {
var u = new Uploader( ... );
...
} );
} );
</script>

But why load jQuery again? Isn't jQuery already loaded? Yes, maybe it is, but even though my uploader is using jQuery, it's just an implementation detail. You should always list all your dependencies and RequireJS takes care of asynchronously loading it just once (unless you want multiple versions).


Hiding dependencies to where they belong is really important thing. Think about adding a dependency to common code referenced by hundreds of pages. With RequireJS it's just a matter of telling the dependency and dropping a Javascript file to correct location.


And finally, if you think about how seriously you should take AMD, look inside your jQuery 1.7+. The AMD module definition is there.


This was just the beginning and more will come about manglers, optimizers, using globals, ... Meanwhile you should visit RequireJS site.