Friday, September 07, 2007

Java & Ruby HTTP Clients: Part 2

Several months ago I wrote an article about how to create an HTTP client in Java or Ruby. I included examples in both languages for getting by BASIC and FORM based authentication. I also showed you how to resubmit the value of an HTTP cookie that many websites use to store state.

What I didn't mention is that quite often web applications store state not in a cookie but within the HTML itself. In order for you to programmatically interact with the website, you'll need to get that data out of the HTML and put it in your next request.

Java

So the basic recipe is to to use HttpClient (the way I demonstrated last time) to get the raw HTML. Then feed that text into NekoHTML, an HTML parser. It can correct the various problems you see in old-school HTML, namely unbalanced tags, missing parent tags, and mismatched elements.

Neko returns a standard Document object, but personally, I don't care much for the standard XML API. Instead I prefer to use the simpler API of DOM4J. So the next step is to take the XML that NekoHTML provides and feed it into DOM4J so that I can use XPath expressions to find what I need.

Now the question becomes what data do you need to post. Well my answer is to simply look through the FORM you're trying to submit, and resubmit everything. Look for 'hidden' tags, input tags of type 'text', 'password', and 'select', gather the names and values of all those tags. Override the ones where you need to provide the information (like id and password for example) and then do the POST.

Ruby

The Ruby approach is exactly the same: get the raw HTML, parse it, use XPath to get the name-value pairs of the FORM elements, override some of the values, and resubmit. The only additional rubygem from my last article is hpricot. It provides the same functionality of NekoHTML and DOM4J in Java. The typical script might look like this:


require 'net/http'
require 'rubygems'
require 'hpricot'

res = Net::HTTP.new('myserver', 80)
# res.set_debug_output $stderr #uncomment this to get console debug info
res.start do |http|
#go to the first page
get = Net::HTTP::Get.new('/home.aspx')
response = http.request(get)

#collect the cookie information
cookies = ''
response.response['set-cookie'].split(';').each{|c|
cookies += c.split(/path=.*?,/).last.strip + ';'
}

#collect the existing form data
doc = Hpricot(response.body)
form_data = {}
['text', 'password', 'hidden'].each{|t|
elements = doc.search("//form[@name='loginForm']//input[@type='#{t}']")
elements.each{ |e|
form_data[e['name']] = e['value'].to_s
}
}

#override some of the values
form_data['username'] = 'my_username'
form_data['password'] = 'my_secret'

#login
post = Net::HTTP::Post.new('/login.aspx')
post.set_form_data(form_data)
post['Cookie'] = cookies
puts http.request(post)
end

In this case all I did was print out the resulting HTML. At the very least you'd probably do the hpricot thing one more time to retrieve the data in which you're interested.

Other

Finally one last gotcha... At least half the websites I've tried to scrape do something "interesting" with Javascript to set various form elements. Since we don't have a Javascript engine executing you should expect that you'll have to parse the HTML and Javascript yourself to figure out what's going on, and set the fields manually in your script. I highly recommend Firefox and the "Web Developer" and Firebug plugins for inspecting the HTML, JS files and the HTTP Requests that the browser submits.

P.S.: I was a bit lazy this time and didn't provide any Java code. If you're really having trouble and can't get it working, leave me a message and I'll put together an example. Secondly, there are other Java HTML parsers out there that may work just as well or maybe even better than Neko, but since I don't have any personal experience with them I didn't mention them. If you like something else, leave a message.

Thursday, May 03, 2007

Aptana RADRails & JRuby

I thought I'd go and take a look at what's been happening on the RADRails project lately. As it turns out, quite a bit! Aptana has taken over the project and are making quite a bit a progress integrating it with their Eclipse based IDE. The most impressive thing I saw was refactoring support! Fantastic! It's great to see RADRails getting some attention again. Go download the beta.

Then I went over to the JRuby project to see what they've been up to. JRuby 0.9.9 is out and looks very good. The Java integration is quite good. But I've been mostly interested in seeing support for deploying a Rails app in a JEE Web Container. Well nestled in beside the JRuby TAR file is a file called sample-rails-warfile.tar.gz. I downloaded it and pretty quickly had a rails application running in Tomcat. The app doesn't do much of anything but it's still pretty impressive to see it. My hope is that this kind of integration will help to get Ruby & Rails adopted into some of Java-only environment I tend to work in. The next thing I did was build my own Rails app and deploy it in Tomcat. I also tried deploying it in WebLogic but didn't have as much luck. Obviously there's still some work to do. Check out the JRuby WIKI for details.

Friday, April 13, 2007

Ruby OLE

The other day someone came over to my desk and asked me how they could programatically invoke the "Find Computer" function of the Windows shell. Normally you just press CTRL-WINDOWS-F and up pops an Explorer window ready for searching. I didn't have a quick answer for him... so I immediately took up the challenge to figure it out.

After a couple dead ends I started looking at Windows Script Host (WSH). It allows you to write VB or JavaScript to access the ActiveX API of a Windows application. After a bit of googling I found the "Shell.Application" documentation on MSDN. After futzing around with Javascript for a few minutes I started thinking that I should be able to do the same things with Ruby. So with a little more searching I discovered that by adding "require 'win32ole'" at the top of my ruby script I could instantiate an instance of "Shell.Application".

The only problem left was finding the right API call. A three line Ruby script like this gave me a list of methods:

require 'win32ole'
wsh = WIN32OLE.new('Shell.Application')

wsh.ole_methods.collect{|m| m.to_s}.sort.each{|m| puts m}


A quick change and my final script looked like:

require 'win32ole'
wsh = WIN32OLE.new('Shell.Application')

wsh.FindComputer()


or in JavaScript:

wsh = WScript.CreateObject("Shell.Application");
wsh.FindComputer();


If you want to take this scripting stuff to the next level I suggest you go check out David Mullet's "Ruby on Windows" blog. He describes some of the same things I just demonstrated above and goes into a lot greater depth about how to use Ruby to script think like Word and Excel.

And in case you're wondering why I had to use Ruby to get a list of methods instead of just looking it up in MSDN, well just try looking at the MSDN page I referenced above with Firefox instead of IE.... That's right... the site navigation only works correctly in Internet Explorer.

Tuesday, April 10, 2007

It's spelled S-Q-L

Why do so many Java developers suck at SQL? Are they just born that way? Are they brainwashed? Do they think that Hibernate will just do it all for them? What's the problem?

The reason I ask is that I'm working on a Java system where the developers obviously thought nothing of letting Hibernate lazily instantiate every relationship as they iterated through collections and navigated down relationships. Not once did they stop to consider the SQL that was being thrown across the network to the database or the performance penalty that it would incur. Just a couple weeks ago I turned on Hibernate's SQL logging just to see 631 queries go flying by in order to prepare the data for a single JSP. WTF?! 631 Queries!!?

Then today I saw another atrocious example of bad code that instantiated several collections of some very large classes from the database to just throw them all away after navigating through them to get a count. Whatever happened to count(*)? In the end I replaced hundreds of lines of convoluted Java code with about twenty lines of SQL. Yes SQL, not HQL (which rocks BTW), but just wasn't appropriate for this task.

Perhaps it's unfair of me to pick on Java developers but for one reason or another a lot of the Java developers I run into have this resistance to leveraging the relational query engine at their disposal. They don't strike a good balance between the object oriented and relational worlds that their systems stride. Use the right language for the right task. And if you can't determine when to turn to SQL, turn on SQL logging and watch what the heck is going on. When you see SQL tearing by, just pause for a moment and ask yourself if there's a better way to do what you want. And remember you have decades of querying technology just waiting to be used. Don't be afraid of writing an elegant query.

Tuesday, April 03, 2007

Prototype, Sitemesh and Struts

The Java environment for my current project is stuck at Java 1.4, but that doesn't mean I have to build my webapps like it's 2002 (that's when 1.4 was released). As a matter of fact I decided to take some lessons from Ruby on Rails.

First of all I decided to ditch Tiles in favor of Sitemesh. Tiles gets the job done but at the expense of a little too much abstraction for my taste. Sitemesh uses the decorator pattern and just simply feels a whole lot cleaner. While not as simple as dropping an RHTML file into a "layouts" directory, it's certainly a whole lot easier than the XML config needed for Tiles.

Secondly, I use DispatchAction to get multiple "action" methods in one Struts Action subclass. It's nothing I haven't done before but keeping the number of classes down is a good thing.

Finally I decided I liked the way RoR uses Prototype and Scriptaculous to provide a little more responsiveness to my webapps. So I decided to jump into Javascript and use Prototype in my Struts webapps. I had to configure Sitemesh to leave my AJAX responses alone and I needed to read a bit of the Prototype docs but it was pretty straightforward. I used the Rails partial convention to let my Java app generate HTML fragments through a Struts action and a JSP and then let my Javascript function replace a piece of the DOM with the result of the AJAX call.

When given lemons, make lemonade. When given ancient Java technology, spice it up with the techniques you learn by looking at alternative implementations.

Objective-C 2.0

Being a bit of a Mac-head and programmer to boot I've taken various looks at writing native Mac OS X apps withe XCode (the IDE), Cocoa (the frameworks), and Objective-C (the language). In general I've come away relatively happy with the toolset. But I must admit, I've filed my own share of enhancement requests with Apple. The top of my list was refactoring support in the IDE. I know it probably sounds lame to the hard core coders but after developing with Java for so long I just expect it and perhaps more embarassingly I feel I need it. Global regex search and replace just doesn't cut it. Secondly, I dislike all the boiler-plate "noise" that appears in your code to declare properties (instance var & accessor/mutator methods) and all the manual memory management.

Well Apple's been looking around at the competition and listening to feedback and judging by their website (here and here) and a few message boards (like this one), Apple has a lot in store for developers. Objective-C 2.0 sports Garbage Collection for the first time, some syntactical sugar for iterating over collections, and a nice simple way of declaring properties. XCode provides refactoring (YAY!) and more enhancements to keep your eyeballs on the code while editing and debugging. And even Interface Builder got cleaned up a bit and exposes nice simple ways of using core animation in Leopard. I'm looking forward to seeing it all in action.

BTW: I read on the RubyCocoa mailing list a few months ago that it might be bundled with Leopard too. Writing Mac OS X apps with Ruby... very cool... Have to wait and see if that one happens.

The New C#

About a year and a half ago I blogged about LINQ (Language INtegrated Query). Anders Hejlesberg starred in a video demoing object/xml/database query functionality and some new language features that Microsoft was playing with.

It's been in the oven for quite a while so it should be just about done, and as a matter of fact it looks like C# 3.0 is scheduled to be released this year. I suggest checking out this MSDN site to read the details for yourself or watch some of the videos. Things like implicitly typed local variables, extension methods, lamda expressions, and anonymous types all seem to be inspired by the features of the so-called scripting languages like Ruby, although Microsoft goes out of their way to make sure you don't confuse the similarity in syntax with the underlying implementation (and with good reason).

In short I'm still quite impressed. I've seriously looked at C# in the past and mostly dismissed it as a Java clone. But with these new features I think it's finally coming out from under it's Java shadow and beginning to shine on its own.

Thursday, March 22, 2007

My MacBook

Over the past few weeks, the developers at work have been taking turns bringing in their laptops... It wasn't something we planned but just started happening spontaneously. One guy brought his Centrino laptop running Linux, another guy brought a 17" screen Dell that he uses for CAD, one guy brought his shiny new Vista laptop and a couple days ago it was my turn to take in my MacBook.

In general my little black MacBook received a fairly warm welcome. People were surprised at how thin it was and the usability of a relatively small 13.3" screen. They liked the built in webcam and although the single button touchpad attracted a bit of grief they quieted down when I showed them that a two finger tap brought up contextual menus. I gave them the flashy demo with Exposé, the magnifying dock and Dashboard and gave them the super abbreviated tour of the iLife and iWork applications.

But in the end the one thing that seemed to get the most attention was the MagSafe Power Adapter. From the magnetic connector to the little brick with "wings" for winding the cord and a removable AC adapter, people definitely liked the design. But having just checked the Apple Store comments on this little item I'm hoping that my little white brick lasts a little longer than everyone else's. Yikes!

But other than the black finish which picks up fingerprints like nothing else I've ever owned, I'm very happy with my laptop. And now my co-workers don't think I'm so crazy for owning a Mac.

Saturday, January 06, 2007

Java & Ruby HTTP Clients

In a mythical IT universe designed around a service oriented architecture (SOA) you could assemble several loosely coupled, autonomous services into a business solution. Each service would communicate in a platform and technology agnostic manner and XML would be the lingua franca. For example, if you needed to integrate data from several business partners you could call various SOAP or RESTful services, get structured XML, and then transform the results into something you could use.

But unfortunately that's not what happens in the real world. Instead of nice composable services you usually get web sites targeted at people not machines. That means you need to automate what would typically be browser conversations with various websites to get the data you need. And then you need to deal with the format of the resulting data. If you're lucky, the data may be structured in a comma separated value (CSV) text file. But undoubtedly you'll have to parse unstructured text representations of a report or get the data out of an excel spreadsheet or even a PDF. It's not pretty.

But lets forget that unpleasantness for the moment and deal with the first problem you'll encounter in trying to automate a browser conversation, getting by the various authentication mechanisms. Let's look at BASIC authentication first. It's pretty common and well supported in the Java-based Jakarta Commons HttpClient library and the Ruby Net::HTTP Standard Library.

BASIC Authentication

To start things off I created a simple Java-based "Dynamic Web Project" using the Eclipse Web Tools Project (WTP) plugins. To keep things simple I created a servlet that returns a string. Then I configured the application to protect the url for that servlet with basic authentication in web.xml. Then in Tomcat's server.xml I modified the context element for my web app to include a reference to the default Tomcat in-memory user database:
<Context docBase="MyWebApp" path="/MyWebApp" [...]
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
debug="0" resourceName="UserDatabase"/>
</Context>
With that in place, and the server running we're able to write a couple of methods to access the servlet. In Java:
public static void basicAuthDemo()
throws HttpException, IOException{
HttpClient client = new HttpClient();
List<String> authPrefs = new ArrayList<String>();
authPrefs.add(AuthPolicy.BASIC);
client.getParams().setParameter(
AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);

client.getState().setCredentials(
new AuthScope("localhost", 8080, "localhost:8080"),
new UsernamePasswordCredentials("tomcat", "tomcat")
);

GetMethod get = new GetMethod(
"http://localhost:8080/MyWebApp/myservlet");
get.setDoAuthentication(true);
client.executeMethod(get);
System.out.println(get.getResponseBodyAsString());
get.releaseConnection();
}
In this example I limited HttpClient's default authentication mechanism to BASIC. I know what my target system uses so why complicate matters with DIGEST or NTLM? Then it was a simple matter of defining the credentials and telling HttpClient to automatically use them and then executing the Http GET method. It looks surprisingly similar in Ruby:
def basic_auth_demo
url = URI.parse('http://localhost:8080/MyWebApp/myservlet')
get = Net::HTTP::Get.new(url.path)
get.basic_auth('tomcat','tomcat')
response = Net::HTTP.new(url.host, url.port).start do |http|
http.request(get)
end
puts response.body
end
The difference between the two implementations is that the Java HttpClient is doing some housekeeping for you. You define a scope for your authentication and as long as you GetMethod is configured to do authentication it will automatically pick up any necessary credentials from the HttpClient instance. In Ruby you need to set the credentials on the GetMethod explicitly.

FORM based authentication

The next most common method is form-based authentication. When you make a request for a web resource, the response contains a cookie that identifies your session on the server. If that session indicates that you haven't been authenticated yet, then you're redirected to a form to enter your id and password. You fill in the values and then submit the form. Now assuming you entered the right credentials your session on the server will indicate that you're authenticated and every subsequent request (which includes the cookie to identify your now authenticated session) will execute normally. There are variations on this theme that may add more than one cookie so just be sure to capture the cookies and continue to submit them on every request in your conversation.

In order to test this I modified the web.xml file for my Java web app:
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/login-error.jsp</form-error-page>
</form-login-config>
</login-config>
and added the requisite JSP pages. The login.jsp contains a form that looks like this:
<form method="POST" action="j_security_check">
Username:<input type="text" name="j_username"><br/>
Password:<input type="password" name="j_password"><br/>
<input type=submit value="Login">
</form>
So the Java code to access the servlet using form based authentication looks like this:
public static void formAuthDemo()
throws IOException, HttpException {
HttpClient client = new HttpClient();

// make the initial get to get the JSESSION cookie
GetMethod get = new GetMethod(
"http://localhost:8080/MyWebApp/myservlet");
client.executeMethod(get);
get.releaseConnection();

// authorize
PostMethod post = new PostMethod(
"http://localhost:8080/MyWebApp/j_security_check");
NameValuePair[] data = {
new NameValuePair("j_username", "tomcat"),
new NameValuePair("j_password", "tomcat")
};
post.setRequestBody(data);
client.executeMethod(post);
post.releaseConnection();

//resubmit the original request
client.executeMethod(get);
String response = get.getResponseBodyAsString();
get.releaseConnection();
System.out.println(response);
}
The Ruby code looks like this:
def form_auth_demo
res = Net::HTTP.new('localhost', 8080).start do |http|
#make the initial get to get the JSESSION cookie
get = Net::HTTP::Get.new('/MyWebApp/myservlet')
response = http.request(get)
cookie = response.response['set-cookie'].split(';')[0]

#authorize
post = Net::HTTP::Post.new('/MyWebApp/j_security_check')
post.set_form_data({'j_username'=>'tomcat', 'j_password'=>'tomcat'})
post['Cookie'] = cookie
http.request(post)

#resubmit the original request
get['Cookie'] = cookie
response = http.request(get)
puts response.body
end
end
Again, the two implementations are remarkably similar. The biggest difference is that the Java HttpClient library is again doing the housekeeping, by tracking and automatically resubmitting the cookies for you. In the Ruby code you have to fetch the cookie yourself from the response header and set the HTTP header for all future requests.

So there you go, you're past the website authentication and are ready to make whatever requests you need to get the data you require.

Digg!

Tuesday, December 19, 2006

Mac OS X & Windows in Parallel

The first most natural reaction for a Mac guy like me is "Ick! Windows on my Mac?!". And yeah, it is a bit disgusting. After all we all know that Mac OS X is obviously the superior operating system, right?

Well even if you don't necessarily agree with that assertion, you have to agree that if you're any kind of web developer you can't ignore Internet Explorer. Despite all its warts and laughable standards adherence, it is the browser that most people use. So if you care about giving those users the best experience when visiting your site you need to view it in IE.

My solution was to use Windows 2000 (with SP4 and IE6 installed) within Parallels and I've been pretty happy. W2K runs very well and being able to seamlessly run my webapps in IE while continuing to work in Mac OS X gives me exactly what I need. So here's the recipe:
  1. Install Parallels (get a demo from Parallels to try it out). You might also want to give the beta 3036 version a try (I did). It has some great features like the "coherence" view that lets you mix the W2K windows in with your Mac OS X windows.
  2. Create a Windows virtual machine and install Windows (take a deep breath its a little surreal)
  3. Once you have the VM open go to the Parallels Action menu and choose "Install Parallels Tools...". This improves performance, mouse support, the graphics capabilities and lets you drag files to the Windows desktop (and probably a bunch of other stuff too).
  4. Set Windows' screen resolution, colour depth, font antialiasing, and be sure to set "Show window contents while dragging". The last option is important if you use Parallels' coherence view.
  5. Start up your web server in Mac OS X, and be sure to open the necessary ports in your built-in Mac OS X firewall to let Windows see your server (e.g., Tomcat is 8080 by default and WEBrick is 3000 by default).
  6. Type in your Mac's IP address in IE and enjoy! (Well hopefully enjoy, IE has a tendency of frustrating a lot of developers).

Wednesday, December 06, 2006

Passionate Development

A lot of people seem to have a real passion for developing software. So why is it that we have so much bad code? Well I have my own theories. So without further ado I present my most-wanted list of culprits, in no-particular order:

New coders

New developers are great. They're happy to have a job and are excited and keen and want to change the world. But they don't really know what they're doing. Hey sorry, but I've been there, I know. You can always do better the second time. And when you're new you write a lot of code. You do the first thing that pops into your head. That's not usually a good recipe for creating good code. I've said it before and I'll say it again, mentor these people and give them training. They don't mind learning and usually take constructive feedback well.

Gung ho Project Managers

Project deadlines are very rarely made with developer input and even if they are, deadlines are never adjusted to account for unanticipated problems or changing requirements. The usual solution is to throw more coders at the problem. To write code under the obligation to create software to help someone do their job is one thing. To do it under duress is completely another. Project Managers love to be "under budget" and "on-time". A lot of them don't care what it takes to get there. Tie some of their compensation to creating maintable systems and they'll help do the right thing.

Heroes

You know who I'm talking about. Every place has at least one of them. An environment that routinely has ridiculous productivity expectations seems to attract the evil genius who works his ass off to produce a solution. Like the new coder, this guy writes a lot of code and lives for the pat-on-the-back and the "attaboy". But he isn't really interested in producing an elegant bit of code. Rather he lives for the hack that will make things work at the last minute and "save the company". The problem with this guy is that he perpetuates the bad productivity expectations and increases the brittleness of the environment. Keep some kryptonite handy to slow him down.

The Architect

You know that fat dude from the Matrix who talks in riddles that nobody understands (says shit like "vis a vis" and "ergo"). Picture that guy and make him an IT architect and you'll get my drift. Architecture is a good thing and somebody needs to think about it, but a lot of these enterprise architects have no accountability to anyone and dream up all kinds of crazy impractical things to do. Take for instance all this SOA, Web Service stuff... Good Lord what a mess! But talk to an "architect" and he'll have tears in his eyes when he explains the world he sees through his rose colored glasses. If you're gonna have people called "architects" (regardless of how bad that analogy is for software development) then assign them to projects and make them responsible for something. (btw: I was a technical architect once so save your hate mail. I know what I'm talking about, vis a vis)

The Academic

These guys are aspiring architects. They love to look for the next great solution and somehow work it into their latest projects. There is such a thing as the progression of technology and you should upgrade the technology in your project so that it doesn't become a backwater for discarded frameworks. But you need to be careful. If you blindly adopt the latest and greatest all the time then you'll spend more of your time working the bugs out of these frameworks than you will actually developing your own software. The elusive silver bullet will often shoot you in the foot.

Support Developers

A lot of places I've been devote some developers to supporting the applications in production. They're motivated by the desire to fix bugs and enhance the application to meet ongoing user demand. So while that's a good thing, they usually have to support 20 applications simultaneously, don't really understand how any of them are put together, and only have to touch the code every so often. So what happens is that the application code (no matter how lovingly crafted during development) slowly decays over time. The solution? Make sure the people who developed the application are resonsible for maintaining them. There's nothing like knowing your own code may come back to haunt you, to keep you focussed on writing good code.

DBAs

These characters live in an alternate universe of sets, joins and intersections and they rule this kingdom. They institute all kinds of rules that don't always make sense from all perspectives. Understandably, they want to enforce certain conventions so that things are consistent and easier to maintain. But every once in a while these guys need to stop defending the battlements and adopt the prevailing wisdom of the land. For example, DBA purists will usually get pretty hostile if you talk about using surrogate primary keys to ease the object relational mapping burden. They'll get all academic about composite natural keys. And while their argument may make absolute sense from their perspective, they need to undertand that their unreasonable rules can result in less elegant code. Don't even get me started on the "law" about only updating tables through stored procedures.

Summary

Nobody sets out to create nasty tangles of code. Most people are at least somewhat passionate about what they do. They want to have pride in their work. Now it's easy to fall into the trap of negativity and start believing in the futility of trying to make things better. (Lord knows I've fallen in there once or twice). But in the end that's what you have to work with. Greenfield development seems to be a rare commodity. So recognize the poor behaviors, try to understand the motivations behind them, state your opinion, make good decisions (or at least try to influence the decision makers) and do what you can to make your coding world better. And for god sakes, stop writing crap code! ;-)


Digg!

Monday, December 04, 2006

Java Compiler Woes

To cut a long story short, I lost a couple days of effort to discover that you should always use the version of the Java compiler that matches your production environment. Take for example this little piece of Java code:

import java.math.BigDecimal;

public class BigDecimalTest {
public static void main(String[] args) {
BigDecimal big = new BigDecimal(100);
System.out.println(big);
}
}

Compile it and run it in Java 1.4 and it prints out "100". Compile it and run it in Java 5 and it prints out "100". But now take that Java 5 compiled class (e.g., javac -target 1.4 -source 1.4 BigDecimalTest.java) and run it in Java 1.4 and you get:

Exception in thread "main" java.lang.NoSuchMethodError:
java.math.BigDecimal.(I)V
at BigDecimalTest.main(BigDecimalTest.java:5)

The problem is that Java 5 introduced a new constructor for BigDecimal that takes an int. So once compiled in Java 5, the class expects to find a constructor to match that signature and when run in Java 1.4, it blows up spectacularly. Nasty little mess.

Sunday, December 03, 2006

Airmiles with that?

The latest edition to my family of computers is slowly making it's way around the world. It started its life in China, then Anchorage, then flew straight overhead to Memphis, and is now getting acquainted with Canadian customs in Mississauga. Unfortunately, more than half the shipping time has been spent there waiting for some customs official to give it the green light to move on. If only I could get air miles for the trip perhaps I'd have a little more patience for this delay. C'mon you guys, get a move on!

P.S., Ain't Google Maps cool?!

Wednesday, November 22, 2006

Enterprise Software? You gotta be kidding me!

If you create truly mediocre software for a vertical market in a mainstream technology like .NET, fill it with buzzwords like "web services", then the truly ignorant will shower you with bags of money. Apparently that's the recipe to becoming a success. Hard to believe isn't it? Well I wish it weren't true but it must be. Otherwise I have no explanation for the project that I'm working on.

Recommendation #1. Make it real ugly.
I commented earlier this year about the ugly UI, and since then things haven't gotten much better as I've started to dig around under the covers. The entire UI is driven via metadata. Nobody actually designs this interface to help the user solve his problem. Hell no! That's way too much work. Instead, tell it there's a new column and it just adds it the the grid. Wow. That's brilliant. Yeah it's ultimately flexible and configurable by every single client but then you end up with one ugly generic UI. Where's the dialogue between designer, developer, and user about what's critical?

Recommendation #2. Use .NET specific types in your Web Services
Because this is largely an integration project we tried to follow the vendor's recommendation to use their "platform-neutral, next-generation, SOA compliant", web services. Well that turned out to be a bust because their crappy implementation simply returns a serialized Microsoft .NET DataSet that no other toolset (including AXIS for Java) seems to be able to understand it. We ended up using a TCP/IP monitor to reverse engineer this abomination just so that we could figure out how to call it. And if you've ever looked at the XML of a serialized dataset you'd know immediately that this isn't something you should be exposing to your clients in the first place. It basically opens the kimono and says "here's my data model". So now there's zero abstraction from the database. If it changes then so does the web service. I can see that being nice and stable. Not!

Recommendation #3. Release often and change your external API.
Trying to write some code on top of something that changes all the time is like building a house on mud. Just yesterday, we discovered that their latest version of the app has a subtle change in the URLs for the web services. Suddenly none of our code worked. (BTW: I argued that we should test this thing before just dumping it on our servers but nobody listened).

Recommendation #4. Make ridiculous claims and milk your clients for consulting fees.
The vendor said it works with Oracle to make the sale but their consultant, who came onsite for a week to troubleshoot the performance problem, made the astounding pronouncement: "it works faster with SQL Server". What? What about the promises you made before and are you sure that'll fix anything? During our load testing we discovered that the CPU utilization on the database server is minimal regardless of database flavor. It's the application server that's pinned! How come they didn't mention that?

Conclusion Make crappy software for a niche market whose users are dumb enough to get dazzled by a flashy demo. Then sell a license for some exorbitant fee and just start milking them with expensive consulting served up by people who don't have a clue what they're talking about. Sure your users and their pathetic IT staff will grow to loathe you, but hey you already have their money and there's always another sucker knocking on your door just dying to buy your "enterprise software".

Or you could just Get Real...

Ruby on Rails demo

Yesterday I gave my co-workers a lunch time presentation about Ruby on Rails. Since these guys haven't even seen Ruby, never mind Rails, I kept it pretty basic and loosely based it on DHH's build-a-blog-in-15-minutes screencast at RubyOnRails.org. I coded live and in person and even the mistakes I made were good because they highlighted not only Rails' good error reporting but also the quick edit-and-refresh-the-browser style of coding. No Ant scripts, no compiling, no restarting the app server, no waiting for the VM, etc.

In the end I think I made the impact I wanted. I showed people some other ways of developing web applications that are fundamentally more productive than the endless configuration hell we Java developers tend to work in. Unfortunately, I also heard unfortunate statements like "that's cool but we're a Java shop and we'd never be able to deploy something like that". While that was disappointing, I kept my composure and plugged JRuby as a possible future solution (I can't wait to be able to a build a Rails app into a WAR and deploy it in WebLogic).

I planted the seed. Now all I have to do is continue to nurture the idea of Rails development, continue the education and hope for a brighter future.

Saturday, November 11, 2006

Tim Bray: PHP, Rails, & Java


Tim Bray, of Sun Microsystems, set off a little bombshell with one slide from a presentation he gave at the International PHP Conference. The slide in question compares PHP, Rails, & Java on four separate criteria: Scaling, Dev Speed, Dev Tools, & Maintainability. Rails won on Dev Speed and Maintainability and PHP won the scaling contest!

The presentation even goes on to talk about the WS-* specs being too complex (he even borrowed DHH's WS-Deathstar slide). Who would have thought things like this would be coming out of the mouths of people at Sun? Can't say that I disagree... Fewer lines of more readable code should mean greater productivity and better maintenance. That seems like a no-brainer.

Monday, November 06, 2006

Code Generation with Ruby

I just watched some parts of a Google Tech Talk Video about code generation. It was a videotaped presentation by Jack Harrington, the author of "Code Generation in Action" to some of the developers at Google. I didn't find most of the presentation to be that interesting, but there was one snippet of Ruby code that I liked. It looked something like this:

require 'erb'

File.open('./test.txt', 'w+') do |f|
name='Darcy'
erb = ERB.new(File.new('template').read)
f.write(erb.result(binding))
end

My template file was a single line that contained this: "Hello <%=name%>". I think you can probably figure out what the result would look like ;-)

The real example he used in his presentation was slightly more elaborate in that he had a source of data, an XML file, and he used REXML (a great XML library in Ruby) to read the source to generate a SQL file.

I'm not a big advocate of code generation but if you find yourself in the unenviable position of needing to do it then this is a great place to sprinkle in a little Ruby magic.

Wednesday, November 01, 2006

Sucking the Fun Out of Software Development

Last week I found myself being subjected to one of the worst fates known to the North American cubicle dweller... the dreaded team building meeting. Acckkkk!!!

But even worse was that the typical mind-numbing "personality profiling exercise" was replaced with the excruciating "enterprise architecture presentation".

Where do these guys come from anyway? Who uses words like "end user vision", "long range target architecture", "governance board" and garbage like that?

Quite frankly I don't have the patience for it. If you get a thrill trying to out-merriam-webster a bunch of other like minded architecture zombies then all the power to you, but don't come to my precious team-building meeting and make things worse by spouting that meaningless drivel at me.

I tried to pay attention in order to show some respect for my fellow man, but before I knew it I felt like Charlie Brown listening to his teacher, mwah-mwah-mwah...

So I first started sketching to try and relieve the tedium but soon found myself writing down a bunch of words to describe the corporate architecture team and this crap presentation. Here's what I wrote:
  • bureaucratic
  • roadblocks
  • undemocratic (appointed)
  • not a meritocracy
  • unrealistic
  • double talk
  • expensive
Does that list remind you of anything else? Well I dunno about you but my mind goes straight to several branches of the government. Uh oh...

Anyway, my point goes back to the stuff that DHH talks about all the time:
  1. Beauty leads to happiness
  2. Happiness leads to productivty
  3. (therefore) Beauty leads to productivity
Maybe, just maybe, if these IT departments would just stop sucking the fun out of software development, then maybe, just maybe, we could get back to actually delivering some real value to our clients. I'm not saying that we should completely ignore architecture or good design, but if you've somehow let your focus shift from delivering value to your customers to creating Powerpoint presentations full of words that nobody understands just in order to try and sound important then please find someone who cares and get out of my face so that I can get back to what really matters!


Digg!

Sunday, October 22, 2006

RadRails Refresher

So I started working a bit harder on a rails project this past weekend (several hours a day) and discovered a few things about Ruby/Rails and my IDE that I thought I'd share (in no particular order):
  1. RadRails has the ability to automatically run your unit tests whenever you modify certain files. The AutoTest functionality is great but only if you realize it's there. I had been staring at a big red 'X' in the toolbar occassionally wondering "I wonder what that's for" and then suddenly saw a nice big green checkmark after I fixed a bunch of tests. Duh!
  2. ctrl-space is your friend. In the absence of any true "intellisense"-like functionality, RadRails' templates will save you a bunch of typing. In fact if you're a TextMate refugee then try Corban Brook's textmate-like templates for RadRails.
  3. Rake is cool, but I always forget all the tasks I can run. Yes even the simple ones like "rake migrate VERSION=3" or "rake db:fixtures:load" seem to continually elude me. Well RadRails has a Rake view. Just make sure you're in a Rails project and then Bob's your uncle.
  4. I like watching the development log. And lo and behold RadRails allows me to right click on the .log file in the Rails Navigator and select "Tail". This allows me to watch the end of the file in a console window. I recommend creating a new console view, displaying the tailed log file, and then pinning it. Then drag it somewhere where you can always see it.
  5. The servers view allows me to set up a mongrel view and then start, stop, and restart it with the click of a button. It also has a handy little globe button for opening a browser within RadRails that goes to your default URL. The browser's functionality is a bit anemic, but it's still a nice touch.
  6. Autotest is awesome but if you want to run a single unit test, just open it in an editor, right click and select "Run As -> Test::Unit Test"
  7. When I use Eclipse to do Java editing I often like to click the button in the toolbar that only shows me the selected element in my editor. That way I can focus on a single method at a time. RadRails has this button too but it seems to be permanently disabled. But if you have the outline view kicking around, try clicking on a method and watch what happens.
  8. I like to keep the Data Navigator view around to see the table structures. Comes in handy when I can't remember some detail about my data model.
  9. My console view doesn't work. Something abut the readline library on Mac OS X I think... Regardless, if it works for you either use it or keep a terminal window open. The console rocks.
  10. Thanks to the "has_many :through" blog I discovered that I can add a block to associations in ActiveRecord classes and add methods to these associations. For example, I added a find method to one of my has_many relationships. The cool thing is that the find method is scoped by its outer has_many definition. Not sure if I really understand what's going on under the covers (still figuring this Ruby thing out) but it seems like an elegant way to express something like this: user.blog_entries.find_all_by_tag( tag ).
  11. Now if I could only remember what the RadRails shortcut keys were for navigating between models and tests and navigating between controllers and views I'd be happy...(UPDATE: CTRL-SHIFT-V to go between controller and view, CTRL-ALT-T to go between model/controller and test)

Digg!