2005/12/01

Web development:

It seems as if we're slowly adding more and more languages to the web development mix. We had HTTP and HTML, then we added JavaScript for scripting and CSS for styling, and we also have XSLT for transformations, XML for data transfer, and not including MathML and SVG, oh my! One client-server protocol, one markup language, one declarative expression language, one scripting language, what is the world coming too?

(I should add, for the benefit of any Microsoft coders out there: if you don't get support MathML and SVG in IE right soon you'll end up displaying GIFS and loading klunky Adobemedia plugins when the rest of the world is dragging and dropping formulas and vectors, not to mention serving all this stuff inline that not even a plugin will help you with, no siree. - see Paul's comment below
)

Should I get worried? Well, I know all this stuff, so no. Also, it is still easy to get started. You don't have to know HTTP to know HTML, which is the substrate upon which the rest is built.

Also, I would add that we've got these things for a reason: having played around with REST XML APIs + JavaScripting XSLT + CSS + XHTML, I have to say that this is a sweet combo that makes me emit an evil laugh everytime I do something ridiculously complex in ten lines of JavaScript.

Anyway, this leads me to the conclusion that a) dumping XML on the client for transformation is not intrinsically wrong, b) JSON-RPC is nice, c) passing HTML clips via XMLHttpRequest is not an ideal situation but works.

Also, despite me not working on Gradient for ages, I still believe that the web is missing a real-time control channel and the ability for clients to communicate more-or-less directly with each other, and that XMPP is the solution to that.

What's changed is that Firefox 1.5 supports SVG now... I'm thinking of digging up the old and obsolete JiM or fiddling with Mozchat and seeing if I can wire either of them directly into the DOM.

When creating DOM-related library / utility functions in JavaScript:

Using document to do stuff like createElement is a good idea 99% of the time, and the other 1% of the time, guess what - I've loaded an XMLDocument from XMLHttpRequest. Therefore, take your operand element and use element.ownerDocument to construct stuff.

This advert was paid for by the Council for Prevention of Headaches in Web Developers.

Attention Java webapp developers: No JSP in your JavaScript.

This has been both a confession and a public service announcement.

Trust me, it's a bad idea, except maybe to rewrite the odd URL...

Before somebody else says it:

I get the sinking feeling that half a dozen bugs that I've observed will turn out to be unreproducible, and therefore my fault, and therefore yet another case of hubris on my part. Oh well, such is life.

One more annoying IE6 bug:

Assuming this CSS:
div { border: solid black 1px; }
And this HTML:
<div id="foo" style="background-color:lightgrey; border:solid red 1px">...</div>
When I evaluate $("foo").style.border=""; I expect to see a div with a light grey background and a black border. And lo, Mozilla doth fulfill my expectations, whereas the venerable IE nuketh not only the element-level style declaration, but also the entire cascade of styles applied heretofore, despite MS and IE having INVENTED Cascading Style Sheets.

Much as I sympathize with frustration at the W3C's glacial process of standards-making (in 'net years), it does seem as if people who don't pay attention to standards bodies end up producing products markably inferior to develop for than those who do.

Grr.

The only cross-platform way to add dynamically parameterized events to DOM elements:

To explain what I mean. This is static:
<div onclick="foo()">...</div>
This is dynamic, unparameterized:
div.setAttribute("onclick", "foo()"); //not in IE6

//or:

div.onclick = foo; // works everywhere
This is dynamic, parameterized (and works on Mozilla):
div.setAttribute("inclick", "foo(this, 1, 2, 3, 'bar')")
This allows you do do stuff like construct your function as you would a string. But you can't do div.onclick = foo; and pass arguments as well. So you have to do this:
div.onclick = function() { foo(this, 1, 2, 3, "bar"); };
Which basically creates an anonymous function each time it's evaluated. If you want to construct your function call as a string, do that and then use eval(). (I would also add that if you have to do that here, you have bigger problems than dynamically parameterized events.) But hey, it works.

You might wonder why I'm passing this when I could use the event target instead. First, getting the event target is non-cross platform, and second, I might want to do foo( $("id") ...), which again is more cross-platform than fireEvent or whatever.

2005/11/24

The earth goes round the sun, the moon goes round the earth, JSP sucks.

blogsMoaningAboutJSP.add(
Blogger.getInstance("http://ianso.blogspot.com")
.createBlankAnnoyedProgrammerEntry()
);


So anyway, although I do realise that JSP came a long before MVC was applied to webapp development, but WTF is a templating solution doing setting the MIME type on my response?

This is not even taking into account the stupid, stupid, requirement to compile JSPs into Java files and then Java classes, meaning that there are twice as many places for compilation errors, and twice as many places for logical errors, and a PIA to write a decent IDE for, Hell! JSP is never a good idea. But it's standard.

Ingredients for a seamless iframe with no border in IE6:

In most webapp development, you don't want to draw attention to your techniques - iframes are a good example, you don't want a "look ma, a page within a page!" feeling, you just want it to display and look & feel like the rest of your app.

In FF this is easy: the CSS is "iframe {border:0;}". Naturally, this also applies to stuff you add to the DOM via scripting.

In IE, it's a complete pain in the ass, as usual. Not only do you have to set the old-style "like it's 1999!" attributes as follows:

iFrame.setAttribute("border", "0");
iFrame.setAttribute("frameborder", "0");

you also have to set the style on the body of the iframe you loaded, as follows:

body {border:0;}

As if there was any other circumstance in which the border style of your body affects the container. Grr.

2005/11/18

More IE quirks: "This page contains secure and non-secure items. Do you want to display the non-secure items?" when using iframes in https web-pages

This one is more google-able than the ones I've noted down below, but anyway: the gist of the issue is that iframes loaded into a secure page with an src attribute of "" (an empty string) or missing, or "about:blank", are treated as insecure.

This is done when the iframe is going to be filled dynamically via javascript or equivalent.

Since network sniffing doesn't show any non-ssl HTTP requests, this one might be a bit of a pain to debug, were it not for the users of a a wysiwyg/textarea replacement project who reported the problem on their forums.

Anyway, the solution is to use src="javascript:;" as an initial value, which is apparently secure enough for IE not to throw an error message in the user's face.

1/12/2005: This also appears to happen with <object>s, with a codebase that is not https, and that sucks.

2005/10/28

The world is beautiful place to be born into...

Read this.

Best heard read in "unforscene - the world is", and is (like life itself) both uplifting and depressing. Yay.

RoooooaR!

Crushing all in it's path

So it's become increasingly evident to me that the the hour at which Ruby on Rails proceeds to stomp all over 80-90% of all Java webapp development is coming closer and closer, if it hasn't got here already.

As a developer, who's been online for ages and a computerphile for even longer, seeing whole fields of technology and millions of man-hours of work obsoleted in a period of months is something I've seen over and over again, so I knew it would inevitably happen to my own sub-sub-field.

And so, as a Java webapp developer, this necessarily requires a response, such as (for example) moving to RoR myself. I can do that if I have to, no problem, in fact I'd kinda look forward to it.

However, I'd like to make one thing clear: to anyone who claims that RoR can do things Java can't, I would politely request that they renew their acquaintance with the concept of the 'Universal Turing Machine', and then come back an re-examine those claims in the light of their newfound knowledge.

</snide>. Myself, I've also seen plenty of reaction from the world of Java, starting with things like Trails and Sails, and continuing with the various solutions that have been welded ontop of existing frameworks.

However, this is not enough to prevent Java's obsolescence in this field. All these solutions so far have been reactionary, and while it's good that the world of Java can readily admit influence from outside sources, all these solutions, by virtue of being copies or tributes to the original, cannot help but serve as a mere reflection of the power of the original.

(It's also worth noting that Python, Perl, Lisp etc. all had their Rails knock-offs months before Java did.)

Firstly, there are interesting ideas that don't exist in RoR. Of all of these, the most interesting by far is continuations.

Put simply, Spring Web Flow and Apache Beehive both encapsulate page-navigation workflow through the construction of state machines, similar in principle to directed state graphs, and influenced to a certain extent by JSF. [Web Flow does actually support continuations, I've just discovered.]

This is one way of expressing logic. However, logic is far better expressed in (guess what) a full-featured programming language, which will always be richer than any configuration file. This is what continuations should be used for. Construction of wizards, guides and sub-sequences could hardly be more natural.

Secondly, the (at least) two areas in which RoR is indisputably king is in inferring webapp structure from database structure, and in the all-important zero-turnaround time. Neither of these are impossible to do in Java, but I'll take them in turn.

Firstly, ActiveRecord. What is it that RoR does? Simply put, it makes the database the 'center of authority' (CoA) for the structure of the web-app. It infers what it can, which is usually 90% of what is needed, and lets the developer add the finishing touches.

Trails is similar in that it uses the business object model (BOM) as the CoA, and uses that to generate both the persistence (database) and the frontend webapp. This is in keeping with the Java view of keeping the semantic discussion at the object level instead of the DB level.

However, Trails also requires you do use annotations, which assumes that you have control over the source of your BOM, which in many cases isn't true (SOA-based methodologies can mean that you're simply the client of a different division, and that your BOM is generated from WSDL/XSD). This isn't a problem, Trails could just as easily use reflection to infer all the stuff that the tags point out to the framework.

Secondly, zero-turnaround time. Template-wise, Java already has this because JSP is recompiled when the source file changes. Personally however, I think JSP (1.x) sucks, and the whole idea of compiling markup templates into .class files is braindead, so I won't rely on this example too heavily, but nevertheless it proves my point.

WRT. zero-turnaround Java, in the traditional webapp this is of course not possible, but (a) this assumes that Java is your workaday language, whereas in fact it's entirely possible (and often desirable) for other languages such as Groovy, Rhino etc. to provide the meat of the application, for this very reason among others, and (b) you're not using something like Janino, which effectively provides the eval() function, and then some, to your normal JVM. (At a cost of course, but that's what facades are for.)

Yet another framework?

Which brings me to my point. If Java webapp development is not just to survive but also to thrive, reacting to RoR is not enough. It must also leapfrog RoR in the metrics by which RoR judges itself.

You can stop laughing now.

It's OK, I'll wait.

This in itself is fairly simple. So far people have been expressing web-development in lots of different languages, some (such as Ruby) more sympa than others (Java), but all of them, even JavaScript, when it comes down to it are not webapp-native languages.

For webapps, when it comes down to it, the language is very simple. There are four verbs: Create, Read, Update, Delete (CRUD). Your set of base nouns is defined by your database, or your object model, where-ever you put your authority. You derive nouns by operations on your base nouns. Each noun can have the four verbs applied to it.

This is all you need for webapps. The rest is reporting - list views, summary pages, query interfaces, etc. In an SOA environment these are simply other services, so that's easy for me, but I imagine other solutions would have to be found for this.

Thus the whole issue is resolved to three domain-specific problems: how to derive nouns, how to customise templating, and how to customise verbs.

(The typical Java response would be to have three different XML config files. Grr. Me, all my config files are generated via xDoclet and other fiddles, so *.xml is simply not part of my development world.)

Deriving nouns: can be done either way, by reducing/eliminating BOM fields or by expansion, i.e. creating new objects mapped from the old ones. Both should be possible, so I'm thinking of something like XPath or JxPath, or CSS-style selectors.

Customizing templating: obviously, model changes shouldn't re-generate and overwrite changes you made to previously generated templates, so a merge algorithm should be used by the framework in updating templates (this may be the sledgehammer approach.)

Customizing verbs: obviously done in the same language as the verbs themselves. Again, either with merges or an AOP-style thing (not my preferred choice).

Once this is all done, continuations take the verb-noun operations and turn them into complete sentences.

The one thing I haven't mentioned so far is validation, and that's because this is a simple choice: it should be done in JavaScript. This is so that exactly the same logic is used server- and client-side, It also avoids extra code-generation, is DRY and can be changed in-flight, just like the above thee things.

Or not.


So, that is my idea. Not that complicated, intended to be incredibly powerful and very flexible. Why shouldn't I do it?

Firstly, there are already far too many frameworks out there. I should find a way of augmenting an existing structure, saving myself lots of time and contributing to something bigger than this in the process.

Secondly, creating a framework is a bad idea. I should know, I've already done it once or twice.

Thirdly, Java webapp developers such as I are not paid to work on frameworks, but on solutions. Therefore this should be done in my spare time, which introduces all kinds of issues when using it at work, for example.

In conclusion, the world would be a much better place if only everyone did what I said. the world of Java is not without hope in the latest mindshare battle. That said, any cool idea used in a Java framework would probably still end up easier to use and simpler in Ruby, by virtue of it being a nicer language.

Aargh.

2005/10/23

Another stupid IE bug: selectedIndex on IE6

Presupposing these functions:

function addNewOption(select, value, label) {
var option = document.createElement("option");
option.setAttribute("value", value);
option.appendChild(document.createTextNode(label));
select.appendChild(option);
}

function getOptionIdx(select, value) {
if(!select.options) return -1;
for(var oNum = 0; oNum != select.options.length; oNum++) {
if(select.options[oNum].value == value) return oNum;
}
return -1;
}
Now watch carefully:
var optVal = "1";
var select = $("exampleSelect"); //prototype shortcut

addNewOption(select, optVal, "one");

This code retrieves a select by ID and adds an option to it. (The select is a single-value select.) The following code selects that option:

select.selectedIndex = getOptionIdx(select, optVal);


Or it would do, if it worked in IE. Apparently selectedIndex is readonly in IE4, which I don't care about. However, selectedIndex is also readonly in IE6, under certain circumstances, but it just fails silently. The workaround for the IE4 bug was as follows:

select.options[getOptionIdx(select, optVal)].selected = true;

This fails in IE6 with the stunningly unhelpful message "Could not set the selected property. Unspecified error."

HOWEVER, this code does work:

var optIdx = getOptionIdx(select, optVal);

alert("optIdx="+optIdx);

select.options[optIdx].selected = true; // [1]


Removing the alert (or logging statement or whatever) gets you straight back to square one. Wierder still, surrounding [1] with a try-catch block will throw an "undefined" error, and set the select to the value, which I guess is the workaround I need.

Needless to say, I don't have this problem on FireFox. My completely uneducated guess is that DOM tree operations are slightly asynchronous, and that the time it took for the JS interpreter to move onto the next instruction was longer than the time it took for the DOM update thread to finish making changes, when computers were slower than they are now. I have no idea.

2005/10/16

In which I serve as a warning to others

  1. When assigning a value to the innerHTML property of any element that allows it on IE, if the string contains a <form> element, Microsoft IE6 throws an alert with "unknown runtime error".
  2. On Firefox, if you use a popup that makes callback to the window.opener and instantiates an XMLHttpRequest from within that callback, subsequent invocations of XMLHttpRequest fail with an internal exception. This has been a known issue since July 2004. The workaround for this is to have your callback function do setTimeout(0, "actualCallbackCode(/*args...*/)"), which (as I understand it) executes the callback within the original scriptContext instead of that of the popup's.
  3. Similarly, calls to window.open after having callback code executed in FF can fail with the same error message when the url is relative instead of absolute. The workaround for this is to compute an absolute URL from document.location.
  4. The IE team (much as I appreciate the hard work they do, etc.</diplomacy>) should scrap their scripting engine completely and use seamonkey's. The IE engine is old, crufty, nasty to debug in, and even when you have the (ancient) debugger installed(which also installs a different version of the scripting engine than that used by non-debugger-using users version of IE, making some bugs stupidly, braindeadeningly hard to pin down) tells you the line number of the error but not the file it occured in,and even gives you the relative line number of the error in the case of inline script, which is stupid.

Lessons learnt:
  • I spent more time hunting for the FF bug (which was documented) than for the IE bug (which isn't). Yet because FF is OS, and IE is closed, IE is more annoying.
  • innerHTML is like the easy path that leads to ruin, whereas true AJAX (i.e. with the response actually being XML and not JS or HTML fragments) is probably nicer and easier to work with yet harder to write in the first place.
  • prototype.js is a wonderful library but only deals with responseText, never responseXML. This is something I would like to fix.

2005/08/14

Random links

Jason van Steenwyck on army logistics via armor plate. This is a place where some smart people put effort into saving lives. I wonder what business can learn from army logistics, and vice versa. It's all about the agility.

And again on the strategic importance of Haditha. This is exactly the type of 100% 24 Carat analysis that doesn't make it to TV.

Discussion on PC for the xBox's 'exception? what exception?' bug. Link ettiquete? This is new. (And regarding the timing of the leak, and it's effect on the share price: Steve, you're just too cool...)

Article from /. story above, which rests on the commoditization of the PC hardware business as providing apple a target against which to define itself.

2005/08/13

How I see RoR changing the way we use, read & write software:

  1. Organic qualities of autonomy. Create a body then spend time on the brain. The body should evolved as the code grows. The brain is where firing a single neuron can tell the body to catch a ball, or make a face smile.

    Each line of code in your brain that is not as important as this should be evolved into the body.

  2. Minimizing the amount of code between the thought and the code that expresses the action resulting from that thought.