Archive for the ‘Software Development’ Category

Bad, Better, Best

Bad…what is the data type of the customer ID?

public Customer getCustomer(Object customerId) { ... }

Better…but a null customer ID makes no sense:

public Customer getCustomer(Integer customerId) { ... }

Best:

public Customer getCustomer(int customerId) { ... }

Seeking Atom Debugging Help

I’m producing an Atom 1.0 feed in a servlet. To debug, I’m pointing Firefox at the feed URL. But Firefox shows a “friendly” page that formats the page as HTML and prompts me to subscribe.

When I view the page source in Firefox, I see HTML and RSS from the “user friendly” subscription page. I really want to see the raw Atom XML source.

I get similar results in IE and Safari. UPDATE: It seems that I can view source in IE, and I see the original Atom feed.

Is there a way to view the raw feed XML source in Firefox???

UPDATE 2: I am at home now, trying this in Firefox on my blog’s feed. I can view page source just fine and I see the Atom feed content. Now I’m completely confused by what I saw at work. When at work, hitting a servlet that generated Atom, the page source was always the “friendly” page. But at home, hitting a different Atom feed, I’m seeing the raw feed source. I don’t get it. Maybe I’m just nuts.

Logger Level Confession

I confess…I never know what log level to use. Some levels make sense to me:

  • SEVERE - the program is about to exit
  • WARNING - bad, but I’ll keep on running

Those two levels should always appear in the log, because they indicate bad things that must be fixed.

But the remaining levels are a mystery to me: INFO, CONFIG, FINE, FINER, FINEST. In my opinion, there are too many choices. I believe the overall power of an API diminishes as you add more choices, particularly if these choices are ambiguous and subjective. I believe that no two programmers will interpret the choices in exactly the same way.

I figure I’ll stick with INFO, WARNING, and SEVERE.

Number of Methods in the String Class

Python, Java, Ruby.

String Methods

I just counted methods on these pages:

Bonus challenge: write a program in each language that counts the number of methods in the String class.

I Disagree

This comment from ApplesAndOranges misses the point:

What your companies app wants: full tax details as required by the government so we tax you the correct amount.

If your app wanted something as simple as google (a none specific set of words) you’d only have one input box and a button too.

To which I reply…that’s not really what this comic is about. A comic is not a literal statement of fact. Did you really think I was claiming — or even remotely implying — that a data-entry application can be written with a single field and button?

Using the specific example of tax forms, there are many competing tax software packages. Although all must collect the same data, their usability and efficiency varies widely. There is much more to this puzzle than a 1-to-1 mapping from data entry fields to database fields.

And using Apple as another example, contrast their MP3 player user interfaces with competing products. Again, all of these devices perform the same tasks and have the same data behind the scenes. Yet the Apple product is simpler and more efficient. We can apply many of the same design principles to tax software.

If you need to collect ten pieces of data, that is an essential complexity. But most GUIs are littered with accidental complexity. That is what the comic is about.

By and large, companies do NOT create good user interfaces. These apps do not need:

  • Cluttered, sloppy GUIs.
  • Poor keyboard navigation.
  • Modal dialog after modal dialog. Modality is a cheap and lazy programming fix and is frequently abused. This locks users out when they need to browse to some other screen for research while in the middle of a data entry task.
  • Bad scrolling, forcing users to reach for the mouse to see essential data.
  • Weird data entry fields that interfere with “normal” typing. Avoid weird custom components that attempt to do auto-completion for things like dates and decimals unless they are PERFECT. Anything less interrupts the flow.
  • Sluggish performance, such as making long server calls on the EDT.
  • COBOL-like presentation that converts EVERYTHING TO ALL CAPS. (ick…ok, that’s just a pet peeve)
  • 12 “extra” fields to capture unrelated data that some committee decided was important. (The truth is, there probably isn’t a committee. Instead, features creep in one-by-one from various interests throughout the company)

It is easy to tack on features. It takes focus and discipline to create exactly what you need, and no more. Sure, if your tax form needs N pieces of data, you’ll need N fields. But few corporate apps are that efficient.

And another comment from Steve Bennett:

(by the way, thank you for using your real name — I use mine)

Your company’s app is probably industry specific and will be used by a smallish number of people for hundreds or thousands of hours to do their job. Power, flexibility and efficiency become far more important than intuitiveness, beauty and user-friendliness.

I don’t think most custom apps are flexible, efficient, or powerful. :-) How many times have you ordered something at a fast food restaurant and watched as the poor cashier struggled with a horrible GUI? I fail to understand how it requires 37 keystrokes to order a taco without lettuce.

Ease of use is a competitive advantage! If thousands of stock brokers spend thousands of hours using some proprietary tool, a quality GUI is damn important. I’ll even argue that fade-ins, animations, drag-and-drop, and overlays are also important, effective ways to convey additional information without cluttering the GUI.

But that’s pie-in-the-sky stuff. For the most part, I think typical apps don’t even get the basics right.

ZDNet: The Computer Experts

Someone just walked up and asked me to check out this web page:

Photos: OLPC, Classmate and Eee

He wanted to know if I could figure out how to view the remainder of the article. The summary page ends with this tease:

In the following pages we take a comparative pictorial look at the OLPC XO, Intel Classmate and ASUS Eee.

I can’t figure it out. The first comment on the article is great:

Am I retarded…or is there no way to get to the next page of the article? All I see is “In the following pages we take a comparative pictorial look at the OLPC XO, Intel Classmate and ASUS Eee” and then… nothing.

He then follows up with:

Nevermind. I see how it works.

Worst. Navigation system. Ever.

I must agree, although I still can’t figure it out.

Java 6 Broken Web Services

I would expect that the 1.6.0_03 to 1.6.0_04 JDK update would contain very minor bug fixes. Instead, it contains a major JAX-WS upgrade from JAX-WS 2.0 to JAX-WS 2.1. Ouch.

*** UPDATE ***

Someone pointed me to Java 6.4 is a whole new Java Release! Also, Rama disagrees in the comments on his blog. I stand by my original opinion that this change warranted more than an upgrade from _03 to _04.

Wouldn’t you know it…all of our web services (well, for one app, at least) broke. Why didn’t they call this 1.6.1?

Sample Code

Here is some sample code someone I work with sent me. This worked on JDK 1.6.0_03:

private void addHttpHeaders(final SOAPMessageContext context,
                            final String userName,
                            final String companyId,
                            final String enterpriseId) {
  //JDK1.6.0 - JDK1.6.0_03
  final MimeHeaders hd = context.getMessage().getMimeHeaders();
  hd.addHeader(USERNAME_HEADER, userName);
  hd.addHeader(COMPANY_HEADER, companyId);
  hd.addHeader(ENTERPRISE_HEADER, enterpriseId);
...

The point is to add custom HTTP headers. On the server, a Servlet filter intercepts these custom headers for some security-related functions.

With JDK 1.6.0_4, he had to change the code to this:

  //JDK1.6.0_04 - switch to JAXWS-2.1
  Map<String, List<String>> requestHeaders = (Map)
       context.get(MessageContext.HTTP_REQUEST_HEADERS);

  if(requestHeaders == null) {
    requestHeaders = new HashMap<String, List<String>>();
    context.put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);
  }

  requestHeaders.put(USERNAME_HEADER,
      Collections.singletonList(userName));
  requestHeaders.put(COMPANY_HEADER,
      Collections.singletonList(companyId));
  requestHeaders.put(ENTERPRISE_HEADER,
      Collections.singletonList(enterpriseId));
}

New Way…Old Way…

To make this code portable across BOTH 1.6.0_03 and 1.6.0_4, he ended up leaving BOTH techniques in the code.

My Advice

This is just typical WS-* crap, in my opinion. It’s always very cryptic and complex, not to mention fragile if you try switching from one implementation to another. The promises never live up to the reality.

Thus, I use REST whenever possible.

Key People Matter

Weiqi says:

The point? Java has survived in the face of all these public high profile separations. It will live on past this one.

I don’t think “Java” will die because one key engineer left Sun. Weiqi gives a list of important people who left Sun, and of course Java is still around.

Something May Suffer

While Java won’t die, individual initiatives may suffer. For example, now that Peter Ahé no longer works for Sun, who is championing the idea to erase erasure in Java 7? As far as we know, nobody. This makes part of me die inside.

I find myself wondering if maybe Sun would have continued advocating and promoting Jini if Bill Joy, the “father of Jini”, hadn’t left Sun. Who knows.

For a non-Sun example, take a look at Jython. Jython was a revolutionary step towards bringing scripting languages to the JVM — YEARS before today’s efforts with other languages like JRuby. UPDATE: See Alan Kennedy’s comment below. Yet when the Jython creator accepted a job at Microsoft, look how long it took for others to step up and revitalize Jython. It’s damn hard to pick up the pieces when the tech lead leaves.

For yet another example, take a look at the hit HSQLDB took when Thomas Mueller left the project. Again, it took years for another team to pick up the pieces and fully get back on track.

What will Die?

I don’t know. Perhaps nothing. Certainly not Java. But news like this does make me nervous, that’s all I’m saying. Here is why…

  • Back in the old days, Sun heavily promoted Java on the desktop. JavaBeans were HUGE in the old days.
  • Then came EJB. For many years, Sun lost interest in the desktop. Flash kicked our asses and today dominates.
  • Only recently, Sun regained interest in client Java. Probably because key people in Sun strongly advocated this initiative.
  • Now one of these key people just left Sun.

Best of all, Chet’s own words:

One of the things that attracted me to Flex, and to Adobe, was a client platform that enables very rich user experiences; transitions, animations, filters, and just darned good-looking UIs are all pretty exciting to this graphics geek.

So…Java didn’t offer enough of those things?

Disclaimer

I don’t know anything. I’m just blogging. You know, writing down my thoughts and ideas. In my opinion, everybody is replaceable.

It is also my opinion that when important people move on, the organization’s focus shifts to reflect the priorities of the replacement people.

And finally, I think it made for a good comic. That’s all.

O p t i m i z i n g

I spent the last few days profiling and optimizing one of our app’s primary GUI screens. Here are some observations:

  1. Our app includes a built-in diagnostic tool that logs every server call. We can bring up a dialog and watch the calls as they occur. For our first optimization, we moved one of these calls off the EDT to a SwingWorker. Although the call itself only took 10-30ms, it was called often enough to introduce noticeable sluggishness. Having built-in diagnostic tools is priceless, because you can monitor what is happening behind the scenes.
  2. NetBeans includes a decent profiler, and the price is right: $0. Despite using IDEA for most coding, I always turn to NetBeans for profiling. IDEA could really use an integrated profiler.
  3. Having a super fast PC is helpful, because profiling is extremely taxing on your system. I don’t have a super fast PC, which makes the profiling experience painful and tedious.
  4. Despite the pain of a slow PC, profiling is very rewarding when you find a problem and fix it.
  5. We found several hot spots — NetBeans does a great job making these obvious. Each time we’d fix one issue, we’d run our scenarios again and find the next most critical issue.
  6. When optimizing, start with the worst hot spot and work your way down the list. A “hot spot” might mean a method is called once and consumes 13 seconds, or perhaps a method only takes 3 milliseconds but is called 800,000 times.
  7. Profiling is always surprising. One bottleneck was caused by an obvious programming error, and that error has been in our code since 2005. Ouch.
  8. You will hit dead ends. For example, one hot spot involves a small helper class that is executed tens of thousands of times. Unfortunately, the code is mutable with a wide open public API, making optimization quite hard. If this class was immutable and had fewer methods, I’m sure I could optimize it further.
  9. I try to fire up the profiler and spend time looking for problems before customers complain about bugs. I tend to focus on either runtime performance or else memory leaks, but generally not both in the same session. I may spend a few days each month focusing on one or the other.
  10. Optimizing always involves risk. Fixing one thing may introduce a new bug, so proceed with caution. Mitigate this risk by focusing on the most critical bottlenecks first. Optimize enough to make these bottlenecks go away, but don’t go so far that your code becomes unmaintainable.
  11. I found that after optimizing, the code is often cleaner than before. This might seem counter intuitive, but spending time meticulously analyzing a particular method line-by-line often gives you insight into better implementations. It think it is wrong to blindly assume that all time spent on optimization and efficiency necessarily leads to cryptic code.

TODO: Fix the TODOs

One of the apps I work on contained 29 TODO comments. This is a problem because with so many loose ends lingering on in the code, newly introduced TODOs simply get lost in the noise and never get fixed. In fact, some of those 29 TODOs dated back to 2005.

So this afternoon, two of us decided to take a look at each of those 29 issues. We found a room with a projector, fired up IDEA, and analyzed every TODO. In about an hour, we eliminated almost every issue. We generated change requests for each of the remaining 5 or so TODOs, and will fix those tomorrow.

I am simply amazed we never got around to doing this sooner. We’ve been looking at this noise for years now, and it ended up taking an hour to eliminate most of the problems. It might take another few hours tomorrow for the “hard cases”, but that’s time well spent.

Next up? I think we have some nagging errors in the application server log files. These bogus errors, warnings, and overly chatty log statements must all die.

Advice

  1. Don’t let your TODOs, broken tests, and cluttered log files fester. Resolve the problems as soon as possible. (for the record, our tests always pass 100% on this project)
  2. Once you get to a clean slate, keep it clean. TODOs are fine for quick fixes and temporary workarounds, but make a concerted effort to resolve the TODOs as soon as possible. A lot of small, minor improvements are easier to deal with than one massive cleanup effort down the road.
  3. Noise masks true problems. If your IDE and log files flood you with false warnings, you will fail to notice really important issues.