Friday, June 22, 2012

CanJS (or: How I Learned to Stop Worrying and Love the DOM)

Javascript?!? Ewww....

Let's face it: Javascript has gotten a bad rap over the years, and with good reason (mostly). Anyone with a less than favorable view of the language has likely formed that opinion after an encounter with some ugly messy spaghetti code, perhaps in a legacy enterprise web app, sprinkled throughout the HTML to add some basic form validation, or toggle visibility of a page section, or provide a rudimentary tabs control. When code grows organically, without an over-arching framework to guide its evolution, it tends to grow like a weed: out of control and in all the wrong places.

So we recognize that we need a framework, if we've got any shot of building a significant maintainable application. The problem then becomes, which one? There are a multitude of frameworks to choose from. The sheer volume of projects can make it quite intimidating to start on a greenfield javascript application.

This article will not be delving into the specifics of why to choose one framework over another; I don't have enough experience in all of them to make that an educated statement. It will, however, detail my experiences with CanJS, (and its sibling projects, StealJS, JQuery++, and FuncUnit, all of which now exist under the umbrella project DoneJS) and go into some depth on how I was able to utilize it successfully in a recent project. (also, I'm realizing that this will most likely end up a series of articles, as I'm finding that I've got a surprising amount to say on the topic)


CanJS: tl;dr

So what is CanJS, exactly? The website has a great explanation and description which I won't parrot here, but essentially it gives you some useful tools for building an application in Javascript conceptually as an aggregation of models, views, and controls (MVC, anyone?). There are a number of whiz-bang features they sprinkle in as well, like the concept of an 'observable' object, live binding with views, and URL hash 'routes'. It sits on top of a number of the "big" foundation javascript framework / libraries (e.g. mootools, dojo), but JQuery is the one I chose to base my app on (since, like, everyone is using it and stuff). You then use StealJS to "import" all of the dependency scripts for your app's components, with the added benefit of being able to compile complete, minified production js (and css) artifacts in a build process.

A big aspect of the DoneJS project is that it emphasizes and facilitates the creation of functional and unit tests for your code. Management-types will be giddy over the FuncUnit feature which can show you a line- and branch-coverage report for your test suite.

Why I think Can/DoneJS is cool

I like the way I'm able to logically structure my application into reusable components. I really like the EJS template library, which allows me to write my HTML in reusable fragments, "hookup" javascript objects and events to those fragments, and even "live-bind" to observable objects (where the view actually changes when you update an attribute on an observable). Can.Construct (and can.construct.super) give me class inheritance in Javascript with a nice syntax. Can.proxy allows me to write event handling and asynchronous code without devolving into nested nested callback functions. The Control concept is simple yet powerful.

Why I think Can/DoneJS is hard

My background is predominantly Java, with a heavy emphasis on server-side "enterprise" applications. It's possible that the doc sites are more grokkable by those native Javascripters, but I find them hard to decipher at times, and also often out of date or incomplete. That requires you to get familiar with the internals of the framework in order to troubleshoot when things don't work as advertised. That said, the guys at Bitovi do a good job of patrolling the forums and respond quickly to pull requests on github.

More to Come...

Now that I've (perhaps) whetted your appetite a bit, I will next go into deeper dives on some cool / interesting things I've done with CanJS, as well as illustrate some gotchas that I encountered which will hopefully help you in your coding. 


Tuesday, May 17, 2011

Hey 2011: Where is my easy pagination and sort?

Update (6/22/12): Even better; I've found a great new ORM library called ebean. Article forthcoming!


Update (5/23/11): I found some exciting stuff around JPA and pagination in the new Spring Data project: http://www.springsource.org/spring-data/jpa

No matter which framework I use, it always seems like I need to re-invent the wheel when it comes to supporting pagination and sort in my web applications. Now, I'll admit that my experience is still mostly limited to Java and Spring (and JPA/Hibernate, for that matter), but c'mon, at least give me something basic, like what I've written below. When you want to display a pagable, sortable table in a UI, you are going to want to do common things like determine total rows, total filtered rows, current count, as well as sort on one or more fields.



This snippet did require me to come up with a cool bit of code to statically determine the type of a nested property specified using bean notation:



*note that this uses org.springframework.beans.BeanUtils, and not org.apache.commons.beanutils.BeanUtils; this is mainly because Spring's version allows for static type resolution already.

Wednesday, August 25, 2010

System.currentTimeMillis();

I ran across an interesting issue today involving JVM internals, and how they behave differently based on the host OS.

The issue was with the following code snippet:

MyEntity a = new MyEntity();
a.setUid("foo" + System.currentTimeMillis());
a.setName("my entity");
entityService.save(a);

This was part of some object creation code I was using in a unit test, which ran successfully every time on my macbook but was failing on other's windows machines. When I found out the reason behind this, I was definitely surprised.

Believe it or not, it is more or less a known issue that the resolution of currentTimeMillis() on windows machines hovers around 10-15ms (linux and mac have a resolution of around 1ms). This was causing duplicate foreign key violations to occur.

So, as a general rule of thumb, it is a bad idea to rely on currentTimeMillis() to have a millisecond-resolution on windows, especially if you are using it to generate unique things like file names or db IDs. Looks like System.nanoTime() might tick faster.

Here are some links I found on StackOverflow about this:

On Windows, you'll more or less be limited to 10 ms resolution at best. Here's a bit from the Inside Windows NT High Resolution Timers article from TechNet:

Windows NT bases all of its timer support off of one system clock interrupt, which by default runs at a 10 millisecond granularity. This is therefore the resolution of standard Windows timers.

In my experience, using System.currentTimeMillis method gives about 15-16 ms resolution on Windows. Getting better time than the operating system timer will probably require more exotic methods.

Here's the StackOverflow question which helped me solve this issue:
http://stackoverflow.com/questions/351565/system-currenttimemillis-vs-system-nanotime

At the end of the day, I decided it was simpler for my test to use a static synchronized counter variable rather than depending upon currentTimeMillis() for generating my UIDs. Another possible solution could be to use UUID.randomUUID().toString().

Wednesday, August 11, 2010

Fixing ClassNotFoundExceptions when working with Eclipse WTP, Maven, Tomcat

Lately, I've been struggling off and on with ClassNotFoundExceptions when starting tomcat from within Eclipse (Springsource Tool Suite, to be exact). My projects are all dependency-managed by the Maven m2eclipse plugin (side note: its really important to install the m2eclipse WTP add-on, found here: http://m2eclipse.sonatype.org/sites/m2e-extras so that the web dependencies are all configured correctly).

Anyways, I would tend to encounter this error after restarting Eclipse. When I would investigate, by looking into the [tomcat_home]/wtpwebapps/[app]/WEB-INF/lib folder, it would of course be empty (hence, class not found). I would always flail about aimlessly for hours until it would magically start working again.

I have in the past week discovered a new trick, which has worked *both* times I've tried it: when I got the class not found error, I stopped tomcat, right clicked on my project in the Package Explorer, and clicked Maven -> Update Dependencies. For whatever reason, this caused WTP to publish the dependent jars into WEB-INF/lib, and everything worked again. :-)

Hope that helps save some debugging hours for some!

Thursday, June 3, 2010

DOM Events for HTML Radio Buttons

An interesting bug came up today, and it had to do with the way IE 8 processes DOM events differently than the other browsers.

Here's the scenario:

We were attaching to a radio button's onchange event to do some processing. When you click on an option, we show you a particular div relevant to your selected option. This worked just fine on Firefox and Chrome, but was wacky on IE8. It turns out that IE8 doesn't seem to fire the onchange DOM event until after the element *loses focus*, meaning that our divs didn't show up until we clicked somewhere else on the screen.

We fixed the issue by switching to the onclick event, which fires nicely, on the click, as you would expect, on all three browsers.

In summary: when you want to trigger something when a user selects one of your radio buttons, attach to the onclick event, and not the onchange event, which has variable behavior across browsers.

Friday, February 19, 2010

Unsigned Java Primitives

This one's just a quick note about unsigned primitives and how to work with them in Java, which technically has no notion of 'unsigned'.

If you need to find the unsigned value of a primitive (e.g. you are porting code in another language, or dealing with byte-level networking), you basically need to promote it to the next higher data type, and mask out the bits you don't need (anything above the size of your unsigned data type).

Examples...

To find the unsigned value of a byte (8 bits):


byte b = ...;
short unsignedB = (0x00FF & ((short)b));


And for a short (16 bits):


short s = ...;
int unsignedShort = (0x0000FFFF & ((int)s));


And so on.

You can read more on this and other exciting topics such as *-endian byte ordering, and why Java doesn't have unsigned in the first place here: http://www.darksleep.com/player/JavaAndUnsignedTypes.html

(hint: Gosling didn't think Java developers could understand them!)

Monday, November 16, 2009

ISO Language Codes

Every so often, I need to obtain a full list of ISO language codes for use in an application. I thought I'd write a reference post for future reference, and whomever else might find this kind of thing useful.

Languages are given a two-character code in ISO-639-2, which the Library of Congress is nice enough to host for us here.

I wrote a simple bit of code to generate a 'Language' table for MySQL, and posted it here:
http://www.fiestacabin.com/files/iso-lang-codes.sql.txt

Feel free to use this snippet; the table I created looks like:

CREATE TABLE IF NOT EXISTS Language (
id unsigned int not null auto_increment,
code char(2) not null,
description varchar(64),
primary key (id),
unique index iLanguage_code (code)
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;


Just for fun, I am including my Java snippet which generated the SQL; critique at will!

package sandbox;

import java.io.File;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrTokenizer;

public class ISOLangCodes {
public static void main(String[] args) throws Exception {
List<String> lines = (List<String>) FileUtils.readLines(new File("c:/temp/iso-lang-codes.txt"), "UTF-8");

for( String line : lines ){
StrTokenizer s = StrTokenizer.getCSVInstance(line).setDelimiterChar('|');
String langCode = s.getTokenArray()[2];
String langDesc = s.getTokenArray()[3];

if( StringUtils.isNotBlank(langCode) )
System.out.println(
"INSERT INTO Languages (code, description) VALUES ('" + langCode +
"', '" + StringEscapeUtils.escapeSql(langDesc) + "');");
}
}
}