Sunday, November 23, 2008

Prestige Class: Java Developer

Golden days when you were a skilled <insert you favourite language> developer and it was enough to be competitive on the market are unfortunately over.
Today you need to be proficient not only with the language and standard libraries (like STL or java.util), but also more specific frameworks that let you do the work in acceptable time frame.

Following statements may describe level of advancement in some technology or technique:
  1. It's black magic!
  2. Hey, I've learnt a few cool rituals!
  3. I know everything now, I can do anything in no-time.
  4. Hmm, there are a few caveats I didn't know about...
  5. I know what I am (not)doing and why.
As a customer, beware of #3's. They are capable of dealing the most damage to the project, with good intentions.
And more importantly, know when you are level 3.

Hint: get alert when you hear (or say) the following too often:
  • It worked on my computer/database/app server instance/yesterday.
  • This framework is stupid, why would they do it this way?
  • I don't get why this needs to be so complicated, lets just take a shortcut.
  • I just googled some solution, pasting...
  • I know XXX which does similar things, how different can this one be?
  • I know I said "just 2 hours" 3 days ago, but I just have to finish this last unexpected XXX.

Greetings to all that know what the title is about :-)

Friday, November 14, 2008

Useful MVC Trick

Breaking my grand tradition of writing only about cars and about Things That Suck (TM), this post will be about something Java-related (oh, the horror!) as well as cool (you haven't seen this one coming, have you?).
So we have been implementing some MVC-based piece of code lately. The model contains a collection of JIRA issues, the view is a JTree and its builder, the controller is a bunch of Swing buttons and some such. Nothing special. The model's interface looks more-less like this (housekeeping and other misc. code omitted for brevity):
public interface JIRAIssueListModel {
Collection<JIRAIssue> getIssues();
void notifyListeners();
void addModelListener(JIRAIssueListModelListener listener);
void removeModelListener(JIRAIssueListModelListener listener);
}

The view registers as model's listener and whenever the model calls it, it in return calls getIssues() and populates the JTree. Nothing to write home about.
Now, the requirement for this code was to sort the issues in the tree in priority order. The problem is, the model cannot keep the issues sorted in this order, and due to a bunch of factors (the most important being my laziness), I found it problematic to sort the issues within the JTree-based view. So what have I done instead? I have invented a contraption, which is a class, that from one end (the "upper" end) looks like the model - implements the same interface as the one above) and from the other end (the "lower" end) looks like the view - implements the model listener interface. Like so:
public abstract class SortingJIRAIssueListModel
implements JIRAIssueListModel, JIRAIssueListModelListener {
public SortingJIRAIssueListModel(JIRAIssueListModel parent) {
this.parent = parent;
listeners = new ArrayList<JIRAIssueListModelListener>();
parent.addModelListener(this);
}

...etc...
}

Note the fact that the constructor of the object registers itself as the listener in the "parent" model.

The crucial piece of code in this class consists of two methods:
public Collection<JIRAIssue> getIssues() {
Collection<JIRAIssue> col = parent.getIssues();
List<JIRAIssue> list = new ArrayList<JIRAIssue>();
for (JIRAIssue i : col) {
list.add(i);
}
Collections.sort(list, getComparator());
return list;
}

public void modelChanged(JIRAIssueListModel model) {
notifyListeners();
}

When called by the parent model, this sorting model will notify listeners that have registered as its views. These views will then call this model's getIssues(), which sorts the list of JIRA issues retrieved from the parent. The getComparator() method is abstract, so that you can easily switch sorting order by subclassing (this could also be organized by injecting the comparator object in the setter, but setters are evil and inelegant, and I don't want to use them whenever I can find the alternative).
The finishing touch is registering the JTree-based view in the sorting model, instead of the previous one.

But wait! There is more! What if I want to have an incremental search facility, a'la iTunes search box? It turns out that if you use the "model stack" approach described above, this is super-easy.

What you do is:
  • provide a JTextField and add a document listener to it (look it up in the Swing Javadoc if you don't know how :))
  • create yet another "model-view" class, whose parent is the previous "sorting: model, with the following crucial pieces of code:

public void setSearchTerm(@NotNull String searchTerm) {
if (this.searchTerm.equals(searchTerm)) {
return;
}
this.searchTerm = searchTerm.toLowerCase();
notifyListeners();
}

public Collection<JIRAIssue> getIssues() {
Collection<JIRAIssue> col = parent.getIssues();
if (searchTerm.length() == 0) {
return col;
}
List<JIRAIssue> list = new ArrayList<JIRAIssue>();
for (JIRAIssue i : col) {
if (i.getKey()
.toLowerCase()
.indexOf(searchTerm) > -1
||
i.getSummary()
.toLowerCase()
.indexOf(searchTerm) > -1) {

list.add(i);
}
}
return list;
}

Now, if I:
  • register my view in the searching model instead of the sorting model
  • invoke this model's setSearchTerm() method whenever the JTextField text changes
I get an instant incremental search in less than 30 lines of sparsely formatted code :).

Now, all of the above probably has a fancy name (probably "decorator pattern" or whatever) and has been known to computer science experts for decades :). But nevertheless, I find this sort of thing quite cool.

If anybody is interested, the whole code can be found here (you need to register in JIRA Studio to get access, but the registration is free and everybody is welcome to have a look).

Tuesday, November 4, 2008

Flying to San Francisco: German organization vs American chaos

Yesterday I was flying from Gdansk to San Francisco via Frankfurt.

I had 4 hours for the transfer in Frankfurt, so I was pretty confident that this time I won't miss the flight as I did when I was flying via London.
Problems started when I took a taxi to the airport. There was foggy. Very foggy. Extremely fogy. I would say visibility was below 100 meters. We could not see our aircraft from the waiting room.
I thought the fog would disappear in an hour or so and optimistically went to the airport.

The checking proceeded without any sight of delays, but at the gate it turned out that no aircraft was going to depart or land until the fog goes away. Having ca. 3 hours of safety margin, I was calm. After 1 hour, the weather did not improve. They cancelled Munich flight first. Later also flight to Warsaw was cancelled. After the next hour, flight to Copenhagen. The crowd was getting angry :) I was getting anxious.

After 3 hours of waiting at the gate, I almost lost my faith that I would catch the flight in Frankfurt. Then they suddenly announced the boarding, although the fog did not go away whatsoever. It turned out that they really want to use the slot they got and from the start of boarding to the actual takeoff it took only a quarter or so. And on the runway it wasn't really better with the fog. I could hardly see runway edges while taking off. Taxiways were covered with clouds of fog.

We happily took off and after almost two hours (a few holding patterns near our destination) we successfully landed in Frankfurt. We touched down exactly at the moment the boarding to San Francisco was to start. I had bad feelings about me catching this flight. Luckily, I know Frankfurt airport quite well - I visited it hundreds times (really!) and often worked at it when I was developing software for Lufthansa for almost 6 hears. I did not know the exact departure gate before the bus took us to the arrival gate, so I thought there will be at least one additional security check (you know that going to US should not be easy...) and a passport control. When the bus arrived at the arrival gate, I had 30 minutes to departure. And I was at the different hall. And my flight was departing from almost the very end of terminal A. Then I used my eyes and brain and instead of going through passport control (which was the obvious choice as all the signs were directing passengers there), I descended into dungeons :) (better sings would be welcome) and run via underground passage directly to terminal A. It took me 5 minutes to reach it and after taking a lift upstairs, I emerged 200 meters from my gate. No passport control, no security check whatsoever. Great! I arrived at the gate while still 1/3 of passengers were queuing at the gate waiting for the boarding.

Done. Awesome Frankfurt. A huge airport and you need only minutes to actually transfer anywhere (last time I changed from an arrival gate at terminal D to some distant departure gate at terminal B in less than 15 minutes). And you know what: may luggage was also transferred. I actually heard that they are loading last pieces of luggage (my?) after they initially closed the cargo doors.
Behold Germany organization and a great design of Frankfurt airport.

After 12 hours or so (again with a few holding patterns near our destination and changing headwind/tailwind from -40 kts to+40 kts - quite bumpy moments) I landed in San Francisco International airport.
There I wanted to rebook my ticket to Vancouver. Just to postpone it by a day or two. First of all, it was hardly impossible to find ticketing counter just relying on signs. I had two ask a few people at the information desks and check-ins and their instructions on where I can rebook my flights were contradictory. Finally one guy correctly (?) directed me to domestic departure hall where I could find United ticketing counter and queued up there.

It turned out that two people in front of me spent 30 minutes each to buy their tickets. I was shocked. Still the worse was yet to come. A lady just in front of me and I myself spent almost 2 hours (two hours) waiting for United officers to handle bloody simple stuff. I was told that calculating the taxes for my newly rebooked flight took a long time (read: more than 1.5 hour). I could almost walk to Vancouver in that time... ;)
I almost wanted to give up (I thought they actually wanted to make me give up), but after almost 3 hours from arriving to the airport, I had my new tickets. Awesome? Rather frightening.
Se beware of United clerks. Really friendly, but quite helpless people.
Next time I'll fly with Lufthansa.

Monday, November 3, 2008

Transylvania JUG


Two weeks ago Janusz and I flew to Cluj-Napoca in Romania - the center of Transylvania.
We were invited to speak there at Java User Group. This event was co-sponsored by Atlassian, which generously paid for our trip (thank you Jon!).

Gabriel Pop was the organizer of JUG and our host there. A young and very enthusiastic guy and very passionate about Java, agile and growing JUG in the area. Thank you Gabi!

We did not want to do any pseudo-marketing bullshit there. Thus our presentations were strictly technical. Just the meat for software engineers.

On Wednesday the first day of JUG started and Janusz was talking about agile development processes using Atlassian tools (but the people and process, not tools, were the focal point). This topic attracted more than 60 people - it was the biggest Transylvania JUG ever! All of them stayed till the very end - almost 9 PM, despite of the most important event of this week - the match in European Champions League (real ;) football) between local team CRF Cluj Napoca and French Bordeaux.

People were mostly interested in how we at Atlassian cope with various problems related to agile software development. They have asked numerous questions and Q&A part took more than half an hour. Janusz received a great applause at the end of the session.

During the session we were asking several questions and gathering rough (hands-up) statistics :
  • out of ca. 62 participants only 5 were students (JUG was held at a university)
  • there were 16 women present! Wow, impossible in Poland :(
  • about 30% uses agile development methods
  • about 50% uses Eclipse as their IDE of choice, 20% Netbeans, 10% IDEA
  • only 10% follows TDD principles
On Thursday I was giving more technical presentation split in two parts: Java technologies used by Atlassian and IoC in action (with Spring and PicoContainer in our products as examples).
I was trying to explain why some of technologies (and Open Source in general) are preferred by Atlassian. Then I moved to code samples showing various “dos” and “dont's” basing on our IntelliJ Connector (PicoContainer) and Crucible (Spring). Yeah, after 2 hours of talk I was quite exhausted.
I ended up the session with a short presentation of our Atlassian IntelliJ Connector. People were quite excited.

Romania did not disappoint me. It is somewhat different country than any other places I saw in Europe, but quickly catches up with the rest of European countries which ca. 20 years ago moved from communism epoch to democracy and capitalism.
Comparing it to Poland I would say they are just a few years behind (also they joined EU 3 years later than Poland), but they really determined and develop quickly. Only in Cluj itself, several western companies invested last year and created branch offices. One of such companies is Betfair who was hosting us.