9/11/2009

What if HTML wasn't Top Dog?

What if HTML wasn't the top node in our web pages? Sounds strange right? But, what if it was just another node inside a larger structure? HTML is great for defining textual documents where you want page flow layout as your choice. However, it really is painful to use a general purpose UI layout language. Which I would argue is the more common practice these days. Even the simplest blogs, forums, or search pages have some form of application layout involved. Why is it so hard with HTML? Lots of that derives from page flow layout and legacy support of this concept. But, if we embed HTML in a larger structure we could do whatever we wanted.

What sucks most about HTML? I would argue it's all the time I waste trying to get the layout I wanted. All the time I spent learning CSS and HTML 4 was probably 6 months or more before I felt comfortable with it. I could come close to the layout I had in my mind. However, as soon as I switched browsers my beautiful layout went to crap, and I had to dig into arcane browser hacks to make it work. Who enjoys that?

How much of that is the complexity of CSS rules and HTML? Ever tried or thought about creating a browser? It's NOT easy. I find understanding the interaction between CSS and HTML arcane as a web designer. If I find it hard then it's really hard for the browser developer to get it right. And that's precisely what we've seen. Lots of inconsistency in how they interpret the meaning of things. Leading to browser inconsistencies. If it's simple to understand then it's simple to implement. If it's simple to implement it's easier for two people to come to a common expectation.

Let's get specific. Say I wanted my node to be position relative to it's parent. I want to set the top left corner of an element to be 50 pixels from the left and 50 pixels from the top. In HTML I can set the left and right of my component, but I also have to set the layout to absolute on the child, and set the parent to relative. This is a common practice in other UI toolkits, but it's complex in HTML. What if all I did was this:


<application>
<box top="50" left="50" width="200" height="200"></box>
</application>


Pretty simple right? Although this isn't that far from HTML/CSS, there are other things that aren't so easy. What if I wanted to horizontally align that box relative to the parent's center.


<application>
<box width="800" height="600" horizontalCenter="0"></box>
</application>


Simple. HTML/CSS you would use margin: auto? WTF!? Doesn't horizontalCenter make more sense? Of course it does. Try vertical centering on for size:


<application>
<box width="800" height="600" verticalCenter="0"></box>
</application>


Try that with HTML and you'll come up short or at best bizarre.

What about defining boxes that grow when the window is changed? That can easy too:


<application>
<box id="banner" left="0" right="0" top="0" height="50"></box>
<box id="leftmenubar" left="0" width="250" top="50" bottom="0"></box>
<box id="content" left="250" right="0" top="50" bottom="0"></box>
</application>


Simple. The content area sets his left and right relative to the parent's edges. When the parent grows so does the child. The banner and leftmenubar are fixed in position. However, the banner grows its width as the parent's width grows.

Even supporting legacy HTML documents could be simple.


<application>
<box width="800" height="600" horizontalCenter="0" verticalCenter="0">
<HTML width="100%" height="100%">
</HTML>
</box>
</application>


HTML just becomes another possible node within the super document. It would create yet another box that can display text documents using what you want for text documents which is page flow layout. HTML nodes could occur as many times as we need in our over all application.

Furthermore, legacy HTML documents (e.g. those starting with HTML) could be converted into our application tag just by surrounding the application tag around the legacy HTML only document. Hence making all HTML documents forward compatible with application documents.

It's a simple idea to fix the constant layout problems with the web.

9/03/2009

On the Importance of being Synchronous: Asynchronous + Actionscript

Dealing with Asynchronous Events Part-2

Damn Blogspot sucks. What the hell? Why haven't they added the 1st new feature in like 5 years? Trackbacks hello???? WTF? I'm not up for cobbling a solution together with greasemonkey, yada, yada, yada. I need a new blog platform. Enough about that let's get to code.

Anyway I wanted to add my fuel to the fire on asynchronous programming. This is a topic I'm very interested in because Actionscript isn't the only language suffering from this. It's very much rooted in classic Computer Science so it's a deep topic. That blog post is old, but it's still something that doesn't have a satisfactory answer yet. Computer scientists have been discussing this topic since the 1970s in one form or another.

I'm very satisfied with my solution to the single request problem. By that I mean making a single round trip to the server and back. Here is roughly how I do asynchronous calls in actionscript.


var tag : String = "Archive";
var loader : URLLoader = defaultLoader();
loader.addEventListener( Event.COMPLETE, function( event : Event ) : void {
var json : Object = JSON.decode(loader.data);
var mail : Array = json.map( funcion( json : Object, index : int, arr : Array ) : Email {
return new Email( json )
} );
var event : DynamicEvent = new DynamicEvent('mail.loaded');
event.mail = mail;
dispatch( event );
} );
loader.load( session.httpGet( '/home/email/', { tag: tag } ) );


Really tight code, and it doesn't feel like the infrastructure for doing the calls are in the way of understanding what's going on. Now I'm using several factory methods to encapsulate common error handling, host name, authentication tokens, etc. Of course all of this can be overridden, but having defaults keeps that code out of the flow of how you work.

The difficult part comes when you need synchronous flow control over asynchronous calls. This only starts to show up with more than one trip to the server. Say for example, server call 1 must complete before server call 2. You can chain them like so:


var loader : URLLoader = defaultLoader();
loader.addEventListener( Event.COMPLETE, function( event : Event ) : void {
var json1 : Object = JSON.decode(loader.data);

// do something with json1

var nextLoader : URLLoader = defaultLoader();
loader.addEventListener( Event.COMPLETE, function( event : Event ) : void {
var json2 : Object = JSON.decode( nextLoader.data );

// do something else with json2, and maybe json1

});
loader.load( session.httpPost( '/home/update', { arg1: json1.arg1 } ) );
} );
loader.load( session.httpGet( '/home/synchronize/', { hashkey: hashkey } ) );


It's doable, but it's getting messy. And quite frankly a little hard to understand. Is that all we need? If so, then we can stop here and be ok. Sadly, no the rabbit hole can get worse and twisted. Say we want to do server call 1, server call 2, or both based on some conditions! And we want to maintain the order call 1 precedes call 2 if call 1 is done. Kinda of like:


var result : Object = null;
if( someExpression ) {
result = executeServerCall1();
}

var result2 : Object = null;
if( someOtherExpression ) {
result2 = executeServerCall2( result.arg1 );
}


Now I want to stop right here and say. Look how easy that was to specify in synchronous code. Jr. programmers can understand that code. All things like conditional logic, control flow, data flow, and more importantly re-usability are all effortless. Just doing simple control flow between asynchronous code is a real challenge.

One thing that I really have trouble with is refactoring logic into a re-usable method that I can call from multiple locations. In synchronous land I can wrap behavior around it doing logic before and after that method. I can easily pass data between in and out. All of these properties lead to reuse and powerful constructs for hiding details. The basis of easy to follow and maintain algorithms.

Adding logic before and after is very hard when the method uses asynchronous calls. I've decided that adding callback objects into the calls it the best route. For example,


public function updateUser( user : User, callback : Function ) : void {
var loader : URLLoader = defaultLoader();
loader.addEventListener( Event.COMPLETE, function( event : Event ) : void {
var json : Object = JSON.decode(loader.data);
var user : User = new User( json );
callback( user );
});
loader.load( session.httpPost( '/user/update/', { id: user.id, email: user.email } ) );
}


I prefer callbacks to using event listener. The main reason for that is event listeners are more long living, i.e. longer than a single method call. If you use event listeners you have to register and unregister between calls, i.e. more mess. If this method is apart of a longer living instance, as I typically do, you could get more than one callback happening. Callbacks are isolated between method calls so they can independent from one another. (There's a lot to discuss here too, but I'll save that for later).

I'm working on my next evolution of this idea to try and build up an architecture to help aid in making multiple round trips to the server in order without adding fuss, and hopefully allowing an outside person to read my code without needing a lobotomy to put my brain in their head. We will have to step away from our friend closure for this to work. But, I want to leave you with this thought.

All of the tools we use today are aided by synchronous control flow. When we remove synchronous flow our tools fall apart. We have very little tools at our disposal to help specify complex flow using asynchronous semantics. Closures are about it, but they aren't enough and fall apart quickly. We need new constructs that aid in asynchronous control flow. Possibly a way to restore synchronous flow, but asynchronous underneath. If we had these constructs we could do this type of work independent from things we typically think of like threads, processes, message passing, etc. Those constructs could be underneath it, but we as programmers would be less involved with their presence.