Archive for May, 2009

Fighting Against Unnecessary Complexity

Friday, May 22nd, 2009

java-logo-thumb.png

I've been working all day on a single feature for this application at the Shop. It's got potential, but the way in which it's put together just screams 'Unnecessary Complexity', and I, for one, want to put an end to this kind of thing once and for all.

What is it about Java developers that makes them design such systems? What kind? you ask, I'll be glad to explain.

Java, as a langauge, is not evil. It's a tool. No more, no less. It's got a lot of nice features, and just as many limitations. It's not slow, per se, it's just not fast at everything. It's capable, descriptive, and works just fine - as long as you don't ask it to do something it's not meant to do. But that's not the real problem.

The problem, I think, is the way in which Java is evangelized by it's proponents.

Substituting design and planning for scores of small interfaces and "wiring it together" with something like Spring or even the equivalent of the Swing GUI tools, is not the right thing to do. IDEs like Eclipse and the rest allow these developers to put together projects that even they don't understand. This is a real problem.

Case in point. I was working with the author of this package today and asked him where a class was located. I'm a Vim/makefile guy for production software. It's universally available, easily transported, easily used on low-speed lines, and for all these reasons and many more, this is the most efficient toolset I've seen for the complete project lifecycle. So I asked him where the class was so I could load it up in Vim.

He didn't know.

He couldn't remember.

He had to have his Eclipse workarea opened up in order to find this class - that he was clearly very familiar with. After all, he mentioned it to me, and I just asked where it could be found.

This is but one danger - Package Explosion. Dozens of packages that have no reason to exist. He would be far far better served by simply thinking about the project and then laying out a few, well thought out packages and placing his code in these. Having this overly complex package layout is unnecessary, and while it's easy to use in Eclipse, it's a pain even to the developer that created it.

If I could pass these ideas on to this developer, I would. Sadly, he's likely too old to change his ways as he's a strong proponent of this type of development. However, in the hopes that someone someday might read this, here are a few pointers for coding that I've found exceptionally helpful over the years.

  • If you can't remember where you put it, the structure is too complicated.
  • If you require an IDE, then the project is poorly laid out and too complicated.
  • Simplify, simplify... the best designs are the simplest.

I don't think this is exhaustive, but if you can stick to these few rules, you'll be far better off than what I've been dealing with all day. Holy Cow.

Google Chrome 2.0.172.28 is Released

Friday, May 22nd, 2009

GoogleChrome.jpg

Well... they have helped me once again, those Googlers. They have released as stable Chrome 2 (actually 2.0.172.28), and with significant changes in the V8 JavaScript engine they are reporting a 30% increase in speed in JavaScript-heavy pages. Also, with the latest WebKit, page rendering is even faster.

I have to say this comes at a great time. I'm struggling with the size and memory footprint of my web app at work, and I have high hopes that this version of Chrome is going to be more stable, faster, and more memory efficient. Given that the problems are all in Google's hands (Chrome, Google Visualization API), I hope they have made real progress.

Interesting PHP Solution to WebDAV for Cloud Files

Friday, May 22nd, 2009

NetworkedWorld.jpg

I was reading the news feeds this morning and ran across this post about using WebDAV to bridge to Cloud Files - specifically for Skitch. I've always wanted HostMonster to support WebDAV so that I could point Skitch to my server there and not have to worry about Skitch going under. But they have repeatedly said that WebDAV poses security risks that they aren't yet willing to deal with. Gotta appreciate that, no doubt, and while I have WebDAV hosted at home, it's not the same because I'm never sure if Comcast is going to drop the ball at any moment and that link would be inaccessible.

While Cloud Files aren't exactly what I'm looking for, it does offer me an option if I wanted to go that way. After checking out at least one place, it's an interesting idea - Amazon S3, or Mosso... interesting.

I have to say that when I get a chance, I may look into this. It's something I've thought about for a long time - a place to store everything in the house off site. If I decide to go that way, then this is a really attractive alternative for hosting Skitch images.

Nice Ant Targets for Updating/Bouncing Tomcat

Thursday, May 21st, 2009

WebDevel.jpg

I've been working with 29West over the last few days and while I can see it's value, it's a little different than server-based messaging systems, and I can see why it's got advantages, and disadvantages. No need to critique it here... it's just what I have to use. But there's a consequence of using 29West's Java API on Tomcat and that's the fact that 29West's Java API uses JNI to get to the real C libraries under the covers.

With JNI, the shared libraries are loaded once in the Tomcat server, but if you want to change the code and remove and install the app again, you're in trouble because the shared library is not unloaded when the class loader is dropped. There's a lot of unhappy people about it, but in the end, there's nothing you can do. You have to remove the web app, shut down the Tomcat instance to drop the shared library, then start up Tomcat again, and then install the web app again.

I wanted it to be easier.

I got an interesting set of targets to do that. First, I need to have the start and stop targets, and they are simply exec targets to the locations of the startup and shutdown scripts:

  <target name="start" description="Start Tomcat application">
    <exec executable="${catalina.home}/bin/startup.sh"/>
  </target>

and:

  <target name="stop" description="Stop Tomcat application">
    <exec executable="${catalina.home}/bin/shutdown.sh">
      <arg value="-force"/>
    </exec>
  </target>

The value of the argument to shutdown.sh is that if I define:

  CATALINA_PID="/usr/local/tomcat/bin/.catalina.pid"

then catalina.sh will save the pid in the file and then on shutdown.sh it'll do a nice kill -9 on that pid and make sure it dies. This is really important because I need to kill the Tomcat instance and I need it to die right now.

Given that we have the standard remove and install targets from the default Tomcat Ant build.xml file, then all I need to do is glue these together:

  <target name="update" description="Update the application and bounce the server">
    <antcall target="remove"/>
    <antcall target="stop"/>
    <antcall target="start"/>
    <waitfor maxwait="3" maxwaitunit="minute" checkevery="500">
      <http url="http://localhost:8080/index.html"/>
    </waitfor>
    <antcall target="install"/>
  </target>

What's happening here is that we're removing the web app from the Tomcat instance, and then shutting him down forcefully. Then we're starting him back up, but since the startup.sh is asynchronous I need to wait until I can get a page back. When I can, then I'll install the web app again.

All in all, it's pretty sweet. It's not as nice a knowing that it's smart enough to unload the shared library, but there's nothing I can do about it. Actually... now that I think about it, I think it'd be better if the loader was smart enough to see that it's the same bloody file and link into it without an issue. But I'm clearly not as clever as these guys.

What I've got is workable, and given the limitations I have (29West and Tomcat), it's as good as I can expect to do for now.

Starting to Work with 29West – Interesting

Wednesday, May 20th, 2009

servers.jpg

Today I've spent a lot of time adding a new way of getting data into my web app. The Shop has standardized on 29West, and I've seen it in a lot of the smaller shops, but there's got to be something more to it... cost... performance... something because Tibco is the 800lb Gorilla, but not used in a lot of the shops around town. I'm guessing it's cost. 29West may be a lot more reasonable. In any case, it's different from the majority of messaging systems I've used in the past in that there's no central messaging server. You don't connect to a server and then get a topic. Instead, you simply connect into the system and then find your topic.

It's interesting.

It's using some multicast/broadcast system to talk to the other 29West clients on the network. You connect in a machine-to-machine scheme - publisher to subscriber. It's going to be more efficient with network switches as there's no single point that all messages have to go through. Makes sense. Looks a little like magic to simply "find" the publisher, but that's good coding for you.

If there's a downside, it's in the way you have to set up the communications. It's pretty nasty. You have to create a context attributes and then populate that with configuration values, and then from there you make a context, and then a context thread to handle the socket maintenance so you don't have to do it yourself, and then you find your topic for this context, and then either a source (publisher) or receiver (subscriber) for this topic and context.

It's all needed for maximum flexibility, but really... if you're going to make it look like magic, then why not just do the context, have it take a simple map of attributes - or nothing if the defaults will do, and have it fire up a thread. Then it's find the topic and you're off to the races.

You shouldn't need to make a source or receiver... those should be done in the context, or topic. Send and receive... can't get a lot simpler than that.

I was talking to one of the 29West guys here in the Shop, and it became much clearer to me as to why it was this way: 29West is C libraries and every one of their APIs are just shells onto these C libraries. In that case, it makes sense to have a not-very-object-oriented view of things. Reasonable, and you only need to code it up one.

I haven't had a lot of experience with the performance of it, but I'm guessing I will in the coming months. For now, I'm glad I have test sources and test receivers to make sure I can move messages around - box to box, window to linux, all that. Tomorrow I'm going to have to deal with a few nagging things about the impact on Tomcat, and see if I can't get data from the guy sending it to me to me.

Interesting Programming Font: Inconsolata

Tuesday, May 19th, 2009

GeneralDev.jpg

This morning I was reading this article about favorite prgramming fonts, and I have to agree with the list. It's really amazing that the author and I have seemingly traveled the same font path from Monaco to Panic Sans to Consolas. But he had one I hadn't seen - a variant of Consolas (it appears) called Inconsolata. He likes it over Consolas because it's free, but I have to say, in addition to that little 'plus', the biggest difference I like about it is the native spacing. It always seemed to me that Consolas had a little too much line spacing. Inconsolata solves that problem.

So have a read and see what you think. You can download Inconsolata and try it. Worth the time.

Today’s Lesson: Always Specify Widths in HTML Tables

Monday, May 18th, 2009

WebDevel.jpg

I've been working on a few pesky HTML/CSS layout issues today and finally got them worked out. If you don't specify the widths of td elements in the page, then the browser is going to attempt a rough layout on the screen and then after it's all up there (placed), it goes back and does the fine-tuning on the location to move it to it's final location. Most times it's not a big deal, but when it's little movements, it's sort of annoying. I had a few of these today.

The lesson: specify everything. Don't make the browser figure anything out. Do it all beforehand and then you won't get this secondary movement.

What I had was a table with several things in it, and since the page was largely static once it was loaded (AJAX refreshed the data) it wasn't a huge deal, but it was annoying and I wanted to make this app as smooth as possible.

I started with defining the widths of the td elements. Not bad, but still not all there. Then I did a few more. And a few more. In the end, they were all specified, but still I was having movement on one page.

Then it hit me - maybe it was the table's cellspacing and cellpadding. So I used 1 for the padding and 0 for the spacing and then took into account the padding on all horizontal calculations. Bingo!

The HTML docs say the default is 0 for both these, but that's not what Firefox and Chrome were using. With these values and carefully counting all the pixels, I get exactly what I want.

It pays to be precise with layout.

Now it's perfectly set up initially and there's no secondary move. Just what I was hoping to have.

Adium 1.3.4 is Out

Monday, May 18th, 2009

Adium.jpg

I noticed this morning that Adium 1.3.4 is out with fixes for Facebook, Jabber, and a new libpurple. At the same time, I was surprised to see that Adium was using Mercurial for source control. It's one of the significant distributed source control systems, but I hadn't heard of it being used for Adium. Interesting.

Anyway, it's a nice update, and since I use it all day long, every day, it's something I need to keep up to date.

Fun with Simple JavaScript Queues

Friday, May 15th, 2009

SquirrelFish.jpg

I was adding a few things to my web app today and needed to implement a simple FIFO queue in JavaScript, but didn't need a fancy class. Thankfully, the JavaScript Array has everything I need. There's already a push() and pop() which make a LIFO queue, and if you use shift() you get the first element in the array which makes it a FIFO queue. Pretty sweet.

But the really cool part was making a queue of complex data structures. Sure, you can make JavaScript objects, and push() and shift() them, but you can make a queue that has multiple queues in it and then in your own push() method, you push the different parts onto the different queues.

Say I needed to have a queue of names and sizes. I could have the code at the top of my page:

  var  myQueue = { name: new Array(), size: new Array() };

and then later have the method:

  function push(name, size) {
    myQueue.name.push(name);
    myQueue.size.push(size);
  }

So that if we need to process what's in the queue you might say:

  function processAll() {
    while (myQueue.name.length > 0) {
      doIt(myQueue.name.shift(), myQueue.size.shift());
    }
  }

This is a really slick little way to handle data structures. This isn't real rocket science, but it's fast, simple, and for my application, it's just what I needed. Make a queue, populate it with event data, and then process them en masse.

Not bad.

Struggling with Visual Studio 2008 and Scripts

Thursday, May 14th, 2009

Csharp.jpg

Today has been a day of struggling with Visual Studio 2008, C# and VBA scripts. It's not my favorite suite of tools, but I didn't get to pick them, and there was a bug that needed to be fixed, and this was the easiest way to fix it.

There's a Windows app with an exposed COM interface and the VBA script 'talked' to it and set it in a state ready to do some work. Then the C# app hit it and did the work, but the end result was that the numbers weren't right. So I had to find out what was wrong, and why.

To it's defense, Visual Studio 2008 is a decent windows development IDE. It's got all kinds of nice things to make it easier to develop and debug an app, but it's the fact that I've been away from Windows for so long that getting back into it is just painful. There's no gdb and make, and it's C# as opposed to Java or C or C++. So it's a struggle for every little thing.

In the end, I was able to set breakpoints and see that the values weren't what I expected. There was a bug in the VBA script and the value folks thought were defined, really weren't, and so were assumed to be zeros by VBA. This caused all kinds of problems, the upshot of which was the numbers were wrong.

By defining the enum values in the VBA script, all of a sudden everything worked. The C#, the underlying app... it all just worked. All for the lack of a few undefined variables. I had wondered where these were defined, but the answer I kept getting was "in the DLL". I had my doubts, which is why I was able to see this problem, but it's just another reason I'm not fond of Windows programming.

Life would be so much simpler if I could code on my Mac all day long. Or linux... that's not horrible, but it's not as sweet as the Mac.