27.11.06

Metaprogramming in JavaScript

Several months ago, I was working on an interface for form elements. The idea was to create an API for easy manipulation, since our old API was growing out of control and it was hard to use.

Compared to the old one, this new API was object oriented, with methods like "validate", "initialize" and "clone". Experience taught us that there would be a lot more than these methods, so a structure was needed that would allow the API to be maintainable and scalable.

First thing to do was to transpose the approach to the common OO API (the justification is beyond the scope of this post). Methods would not be piled together under one class (or input type), but the other way around: each method would be a "class" and each input would be a "method". This prevented a problem we had in the past: someone added new functionality to text and textarea, but didn't bother doing it for date. (these are not regular HTML inputs but inputs as a user perceives them)

The next issue was to make the API load effortlessly, without having to add the definition into a massive, unreadable file or redundantly in more than one. One of the reasons things are not maintained well is because it's not easy to maintain them. With this in mind, we had to ensure that developers would have a minimum amount of code to write to add the desired functionality. This is where metaprogramming steps in.

Metaprogramming, as defined on a piece of paper tucked away in a shirt pocket that I forgot to check before chucking it into the washer, is a technique that allows a program to spew programs. In other words, this code will create code. Specifically, the methods will be defined separately in files and our framework will suck them up and construct an API. Automatically.

This is nothing new to Java, for example. You create a Java class and it's magically picked up and read from some path. Well, I wanted that simplicity in my JavaScript, so I promptly whipped:
function generateInterface(obj) {
// This is an external XHR function that calls the
// server and returns an array of file names
// in a given path, for example ('/api')
// returns: ['/api/clone.js', '/api/validate.js',
// '/api/init.js']

var definitions = loadUrl(path);

// Iterating through the paths to get the name of the file
for (var i, url=definitions[i=0]; url; url=definitions[i++]) {
var method = url.match(/\/([\w]+)\.js$/)[1];

// Note the anonymous function to avoid calling the

// wrong function at runtime
(function (method) {
obj[method] = function () { route(method); };
})(method);
}
return obj;
}
Ok, so now I just have to write the route function, which gets the source from the paths, caches it for subsequent calls and calls the appropriate methods. Oh, I also have to write the code that will return me all the files in a particular path...

Hold on.

Does this seem complex to you? It certainly does to me. Why try to replicate something that exists in another language? Is this language really that weak? A typical blunder among Java/JavaScript programmers is to try to replicate Java functionality in JavaScript.

Well, that's just great. All this yadda-yadda for nothing. How should it be done, then? Include your files with regular <script src=""></script> tags and use prototypes to tie your functions to the appropriate object.

Now, I know you might feel crossed because I made you go through all this code for nothing, but that's not true. The metaprogramming example is still a good one, it's just the justification what sucks. However, I hope my three readers understand that if they whip up some JavaScript and it seems a bit too verbose, there's probably something wrong with it. Pay special attention to code that doesn't do "DHTML", "DOM manipulation" or something like that. Controller logic must remain in the controller, that is, on the server in Java, Perl, PHP or whatever you're using back there.

There's a simple reason to stick to simplicity: maintaining all that code in JavaScript will be your demise.


20.11.06

AOP + JavaScript

This weekend a "friend" asked me to support my claim that Aspect Oriented Programming is easy in JavaScript. I wrote this based on someone else's post back in September, to deal with a situation I was having with jQuery's plugins. I would've used his code, but being the code nazi that I am (thanks for my nickname, Max) I changed it to my liking:
/**
* Provides the ability to execute functions (advices) before,
* after or around any other method, without having to
* change the source of such methods
*
* @author Francisco Brito
* @example
* new Advice(jQuery.fn).before('write', jQuery.fn.validate);
* new
Advice(jQuery.fn).after('validate',
* function (){ alert('foobar!'); });

* @yields
* $(node).validate();
* anonymous(); // alerts 'foobar!'
* $(node).write();

*/
function Advice(object) {
return {
/**
* Executes function 'f' before 'method'.
* @example
* new Advice(node).before('onchange', function (){
* alert('executes before the onchange');
* return true;
* });
*
*/
before : function(method, f) {
var original = object[method];
object[method] = function() {
if (f.apply(object, arguments) != Advice.BREAK){
return original.apply(object, arguments);
}
};
},
/**
* Executes function 'f' after 'method'.
* @example
* new Advice(node).after('onchange', function (){
* alert('executes after the onchange');
* });
*
*/
after : function(method, f) {
var original = object[method];
object[method] = function() {
if (original.apply(object, arguments) != Advice.BREAK) {
return f.apply(object, arguments);
}
}
},
/**
* Executes function f, from where "this.yield()" can be
* called to wrap the original
* @example
* new Aspect(jQuery.fn).around('validate', function (){
* alert('foo');
* this.yield();
* alert('bar');
* });
*/
around : function(method, f) {
var original = object[method];
object[method] = function() {
object.yield = original;
return f.apply(object, arguments);
}
},
BREAK = 'Aspect.BREAK'
};
}

A few things to note:
  • There's no way to unattach the advice (undo the code)
  • The "new Advice" is attached to an object. This can be a node, a prototype or any object with methods.
  • The "after" method doesn't keep the return value. I didn't need it.
  • The methods you're replacing must exist before the advice is defined. I bet this doesn't have to be like this but for now it is.
  • Don't get confused
For the jQueryans out there, this might help you organize the functions on your multiple-inherited nodes. Yes, I know it's object composition, not multiple inheritance, but for people more familiar with OOP, it's close enough.

14.11.06

Executing scripts with XmlHttpRequest

In the spirit of all that is Ajaxy, you may or may not have encountered yourself in a situation where you dynamically load content from the server into a container. In more advanced applications, this content also contains some JavaScript to be executed. It's not uncommon for people to be confused by scripts not executing this way.

Well, you have to explicitly execute them. A browser will only execute scripts loaded with the page or written to the page, not loaded dynamically. I'll show you the easy way and you'll never wonder again:

First, get all the scripts from your source and put your HTML where you want it.

var re_scripts = /<script([^>]*?)>([\w\W]*?)<\/script>/g;
var scripts = [];
myXhrSourceText.replace(re_scripts, function(match, attributes, script){
scripts.push(script);
});
myDiv.innerHTML = myXhrSourceText;

Note that I'm using the replace method to iterate through the matches, since I'm assuming there can be more than one. This method is quite handy because it doesn't require another for loop to iterate since it's using a visitor.
You can also remove the scripts from your innerHTML by assigning the return of the replace function to the innerHTML, your call.

Then, execute. It's that easy.

eval(scripts.join('\n'));


Oh wait, it's not. If your script has functions and variables intended to be used by other parts of your application, they need a scope:

self.eval(scripts.join('\n'));


That's easy. Oh wait, it's not. IE doesn't work. You have to use a super special secret command "execScript":

(window.execScript || self.eval)(scripts.join('\n'));


Given the usual IE-doesn't-work-so-I-gotta-hack-this problem, the result is small and functional. Sweet!

7.11.06

Scripting is scripting

Last night, aliens abducted me and implanted a memory about visiting the Perl and the Ruby pages on Wikipedia.

To clarify, neither of those languages have been previously implanted on me, so I was just looking at the syntax and realized that I like those languages for the same reason I love JavaScript. There's so much potential for creativity! To contrast, compare to Java. There's soooo much to learn, and chances are, you'll never EVER learn all about the existing libraries, practices, policies, etc. It's massive and not very flexible. I have the impression that the C family is similar.

Javascript, on the other hand, is easy to learn. I mean, there's not that much regarding syntax BUT there's a myriad ways to write your code in crazy creative ways. It's precisely that lack of restrain that loosely-typed scripting languages provide that give you the freedom to get creative.

Sure, it's a double-edged sword. I've seen enough Java developers writing in JavaScript and thinking that's all there is to it. They don't realize that it's because it's flexible enough that you can somehow simulate Java with it.

I really want to try my hand at Perl. I already had significant respek for it just because of its regular expressions (isn't that a language by itself?), but last night I seriously wondered if I could get to be as good with Perl and enjoy it as much as JavaScript. Ruby is also looking very red and shiny.

What do I think is the secret? Being multi-paradigm. It's truly giving you the choice to implement the pattern that suits you best. It's not locking you into OOP; about allowing you to pass around everything and anything (functional); or to simply jot something down (procedural). If you think about it, all these three languages do that.

I'll post again in the future, when I've mastered those two and see if I still think so highly of them. Hopefully the aliens will save me the time and just implant that in me tonight.

6.11.06

Good Management, Bad Management

Management, in general, can be oversimplified as follows:

When things are operating as they should, nobody notices. However, when things are poorly managed, everyone can tell. Why is this? Things go wrong, that's a fact. A door handle breaks. A good building manager notices and gets it fixed quickly. A bad manager will either not notice, not fix it quickly, or fix it poorly and it breaks again. With bad management, it's just more likely that people will spot the flaws, because they'll be visible for longer. More people are exposed to them or repeatedly exposed to them, so it becomes harder to forget that the door handle was broken a week ago.

I figure that managing employees is no different. If one complains about something and nothing is done, this person won't forget and will just get more frustrated. It's also likely that someone else notices and so on.

Of course, this is just one aspect of managing. We're all managers, at least of our own lives. If we don't fix what's broken and fix it right (and right away), it will remain broken and whatever it is we're managing will degrade, very likely getting worse in time.

For people who like lists, here's one:
  1. If it's broken, FIX IT. No excuses.