Monday, October 31, 2005

I'm bitwise, are you?

When I finally decided to get a Java Programmer Certification and had to review all that bit shifting, bitwise operating, etc. I just kept thinking...."My domain is basic business apps. I don't use this crap."

I have been proven wrong.

private static final int ACCOUNTDISABLE = 2;
if (ACCOUNTDISABLE == (accountStatusValue & ACCOUNTDISABLE))
System.out.println("The account's disabled. Whoo-hoo!");

Granted, this isn't the actual code, but it's pretty darn close. One dinky line to determine if someone's AD account is disabled or not. Doh! Maybe there is something to this whole computer "science" thing. :) (I'm kidding, people.)

That certification is way expired, by the way, but what's the point if you're not job hunting.....

Saturday, October 29, 2005

Rocky Mountain High

Just returned from a week in lovely Keystone, Colorado at the Colorado Software Summit. (Clearly, I am not a photographer. Trust me, it's breathtaking.)

This time, I wasn't wandering around in flu-fever-nyquil haze all week, so I actually had some fun and made some friends. And got just enough inspiration to re-energize my approach to least for a couple of weeks. :) A yearly dose of such inspiration is definitely required.

Next year: ice skating BOF before Sunday's reception. Be there.

Friday, July 01, 2005

MIT too

Take the MIT Weblog Survey

Thanks for the cool link, Road to Amherst. I love being a statistic. You should too.

Tuesday, June 21, 2005

Hibernate is evil

Hi, I'm Kim (Hi, Kim) and I don't like Hibernate. (gasps from the crowd)

Yes, it's true. I will come forward and admit it. I don't like Hibernate.

I was just chalking up my distaste to learning curve, etc., but every time I try to do something not totally simple with Hibernate it takes forever to figure out, then I'm not happy with what it ends up actually doing. I finally realized that I just don't like it. Based one what "everybody else is doing", it seemed like I _had_ to like it. But I rarely go with the crowd, so why start now?

Hibernate is for people who are afraid of SQL. Legend has it that my predecessor at my current job didn't know how to write a simple SQL join and apparently loved Hibernate. There are times when you should let the database do what it does best. Hibernate greatly complicates that goal. Recently, I was trying to do some optimization to an inherited system. My SQL-fearing predecessor had implemented a "search" feature by first selecting all records from multiple tables, then used java code to loop the objects multiple times looking for matches on String values. I wanted to fix this so the database only returned the rows that actually mattered.

What would've taken me about an hour with plain-old JDBC and object mapping by hand
took who knows how long with Hibernate. I worked on it for about a day and a half, then had to stop because our funding was temporarily cut on that project. We have funding back and I have a meeting this afternoon to discuss scheduling. How in the world do I estimate this monster? I may just re-implement that piece without Hibernate and save myself the headaches.

What have I found that makes the world right again? IBatis. (Thanks, Gary!)IBatis is great because it lets the database do what it does best, then does the results to object mapping for you. You put some plain-old SQL in XML config files, then add some mapping info so it knows what objects to use for getting and setting data. It even has a very cool dynamic SQL builder that's helpful for things like search screens.

What does it not have that Hibernate does? Oh, I don't know. Maybe just that it doesn't "know" what has been updated locally, but not persisted. I can handle that if it makes my life this much easier. Overall, it just makes a hell of a lot more sense than Hibernate and it feels like there's less "magic". I feel better feeling like I understand what's actually going on. Plus, I've always liked SQL.

Tuesday, April 26, 2005

JavaDoc library

Found this today while perusing the available eclipse plug-ins: Google finds things every time, but this looks pretty convenient. Strangely enough :) there is an eclipse plug-in that will link to and search the site by clicking on a java element in your workspace.

Monday, April 25, 2005

m2 for Maven users

I have been working through trying to get m2 to work with my latest projects because I do want to use Maven and I think it might be simpler for others to pick up than Maven1. But there has been plenty of frustration and confusion along the way.

There is still no DTD or XSD for any of the config files, which drives me batty. But, at least this time, you'll get a somewhat helpful error message when you screw up. Something along the lines of 'we wanted to find a tag here, but we found this text instead'. In general, that's the only improvement I've seen in error messages. You still have to hunt and peck if it's anything else that's gone wrong.

There's this concept of 'scope' for dependencies. I'll admit it's a really good idea. I don't need junit files or my mock objects jar in my deployed war. But either I don't quite get it, or they don't work as they should. First of all, out of the four scopes, one of them is called 'build' and one is called 'compile'. I've yet to figure out what the difference is there. I guess it doesn't matter because I soon found out that if I set my dependency scope to 'build', none of my dependencies were included in the compile classpath. I had to set them all to compile for it to, well, compile. And even that was a trick. For every dependency it sees, it not only tries to fetch the artifact, but an associated .pom file. That's great if you've got a common thing that resides in the central repository. It's not so great for things like the JavaMail jar (which cannot be legally hosted on ibiblio). For that and a few others, I had to put together my own pom and put it in the appropriate repository directory. Yeesh!

They've changed the repository layout as well. I understand what they're trying to do, but I don't like it. I just end up having to navigate through a lot more directories. Instead of groupId/jars, the pattern is groupId/artifactId/version/. Like I said, I get it, but I don't like it yet.

They have made it easier for newbies to understand, "what do I type to create a jar", etc. Rather than needing to remember a plugin and/or goal name, you just need to know which "phase" of the project you want to execute. I believe there are five phases, and if you execute one, you execute all of it's predecessors. To name a few from memory, there's compile, test, and package. Just type 'm2 package' and your jar, war, whatever will be compiled, tested, and packaged into your desired archive format. You can also still access plugins and goals directly, but they have to be configured in your pom.xml. I haven't gone there yet, so I can't speak to how much pain that will be.

Other low impact, but noticeable changes:
- project.xml has been replaced with pom.xml
- I'm pretty sure it's impossible to set your 'home' to anything other than "user.home/.m2"
- no more,, etc. Instead, there is a settings.xml file that resides in user.home/.m2 directory. So far, mine looks something like this:


That's all I have for now. I am using it for two very simple projects that only produce .jar files. For this type of project, the only real pain involved is getting all the files available in the repository.

I have a couple of web projects that are still using Ant. I'm sure the process there will not fit into the m2 "box". However, I noticed that they released tech preview 2 today, which can hook into Ant tasks. Maybe I'll have to see what that's about next.

Wednesday, April 06, 2005

mystery NullPointerException from Hibernate

So, I spent the entire weekend on what was expected to be a fairly simple application bug. See, there is this page that displays a list of summary information about Thingies. Each Thingie has several other associated objects such as Thing-a-ma-bobs, etc. If you went to the page and hit refresh in your browser several times, you would eventually get a NullPointerException (that went unhandled, by the way). Hit refresh again, the listing of Thingies would display. Hit refresh a few more times and you'd probably get the Exception again.

The thought was that Hibernate (or this application's implementation of Hibernate) had a leak somewhere or was just doing too much dang work to display this screen. The application owners wanted to reduce the amount of work for this page, likely by not loading all the associated objects (what the geeks like to call 'lazy-loading').

Well, I tried that. And the Exception still happened. With the need to understand what the real problem was so I could actually fix it, I spent plenty of time getting the code setup in my workspace. I mean a _L_O_T_ of time. Cyclic dependencies and duplicate classes abound. Ick. Multiple properties files with some correct database information and some INcorrect database information. Which was correct? Oh yeah, and did I mention I was grabbing the code from the WRONG directory for the first few hours? Oy! Just because you see the name of the app in a directory name does not mean that's the correct directory. Several hours later, it was ready. And then: I couldn't reproduce the problem. Double check-checked jar versions and all was identical. Okay, what's different? Well, the entire operating system for one. JVM versions were the same (though from different vendors). There was the fact that Eclipse debugging is a dog on my desktop, so it could just be a timing issue. My slow machine could be slowing it down just enough to appear like everything was okay.

So, with the code on my machine and the problem observable on the (ahem) Windows server with only FTP access, I set about adding logs here and there and manually uploading changed class files as needed. The fact that the FTP server dropped my connection after about 7 seconds of inactivity was an added "bonus". The added logs told me nothing I didn't already know. Tried running Tomcat in profiling mode on the server. The problem went away! That made me think it's gotta be a race condition buried somewhere. Profiling slowed things down enough that it no longer stepped on itself. Then I thought, "Well, let's prove or disprove that the code being called from this page is actually the problem". I created a load test to repeatedly call the module 50 times each on 5 different threads. Worked great on my machine. Worked great on the server. Why didn't I think of this earlier?!?

It can't be just that code, then. It's got to be a combination of things. I double-checked the application flow and there wasn't much else going on outside of the load-tested method.....just some basic Struts stuff. Now, this particular server is painfully out-of-date as far as Tomcat is concerned. Hmmmm....could be. I downloaded a close-to-latest version and "installed" it on the server. I began configuration, then realized that the port would be blocked and I wouldn't be able to run it. (Even if I had the rights, I'm no network admin.) What I didn't think of (and am kicking myself) was to shut down the other Tomcat instance and use it's port for the test. Anyway, I left 'upgrade Tomcat' as my last words in the effort to fix the problem. Know what? pssst....(that was it)

I guess the lesson here is that if you're using the "next big thing" persistence framework, everyone assumes you're using the nearly latest servlet engine. Otherwise, Google would've helped me out a long time ago. To all you other poor saps out there, I hope the magical 'G' will find this post and it will help you.