Personal Workflow Blog

To content | To menu | To search

Sunday, August 3 2008

Daisy Chain Setters and Handle Optional Parameters Effectively

A side effect of RAII in Java is that all the parameters have to be set at construction time, since construction time is the time to acquire the resources. A quite common problem is the handling of optional parameters.

The Pure RAII way

You use many different constructor signatures. It's quite suboptimal if you have many parameters that have nothing in common except their type : you have to use the infamous null, or have a special value that conveys a not specified meaning.

Code usage is something like this :

MyFile fileRead = new MyFile("in.txt", Flags.Read);
MyFile fileTemp = new MyFile("tmp.txt", 
    Flags.Write, Boolean.TRUE, Boolean.FALSE);
MyFile fileWrite = new MyFile("out.txt", 
    Flags.Write, null, Flags.Boolean.FALSE); 

The JavaBean way

The JavaBean standard militates for a simple constructor : the default one. The client uses then setters to initialize the object. This isn't RAII anymore, but is a very common idiom in Java. But in my opinion the code produced (like the one below) is quite cluttered.

It produces code like this :

MyFile file = new MyFile();
file.setFileName(fileName);
file.setOpenFlags(openFlags);
file.setShouldLock(shouldLock);
file.setIsSync(isSync);
file.setMaxFileSize(maxFileSize);
file.setReadAheadSize(readAheadSize); 

The StringBuffer way

With the same trick as the StringBuffer.append(), it is possible to chain all the setters just like this :

MyFile file = new MyFile()
    .setFileName(fileName)
    .setOpenFlags(openFlags)
    .setShouldLock(shouldLock)
    .setIsSync(isSync)
    .setMaxFileSize(maxFileSize)
    .setReadAheadSize(readAheadSize)
  ; 

In my opinion this is more typo-proof, since you don't need to repeat the variable name each time. It may also been seen as easier to read since the whole initializing part is done in one block.

The main design point with this construct is that the setters must honor exactly the same contract than the constructor does :

  • They cannot return null (otherwise chaining them will throw an uninformative NPE). Only exceptions are allowed to signal a failure while setting the value.
  • In case they throw an exception, they have to cleanup any non-memory resource, since the caller has no reference on the object anymore.

These rules are quite natural if you think of the setters as a extension to the constructor. The object is still responsible for the resources it manages, although the resources itself can change when calling setters (by setting a different filename for example).

The Immutable way

Since every setter returns a MyFile, you can use an immutable design. It has many benefits, specifically when multi threading. The concept is quite easy, and inspired from the String object. Each constructor creates a brand new object that copies every properties from the parent except the one that is changing. The downside is it might create many unnecessary objects but it is a good concept for factories that are seldom created, but used many times.

Factories, can then create object that have already all their properties set with the factory default. It can then reuse pooled objets that have the same properties.

An example for a factory can be :

private final static MyFileFactory fileFactory = 
    new MyFileFactory().setIsSync(true);
...
    MyFile file =fileFactory.create("filename.txt");

The MyFileFactory.create() must honor the same contract than the MyFile constructor for the same reasons than the setters do.

Sunday, July 27 2008

RAII in Java to clean your code

RAII is a very common idiom in C++ and some other languages that don't have an integrated garbage collection management.

Java has GC, therefore this idiom is not as popular. But the main problem of Java is that although the GC system has become quite efficient, it only handles the memory management. For other resources (database connections, sockets or file descriptors for exemple), this system is not really adequate. The release of these resources has always to be explicit, and handling this via the finalize() method is not satisfactory.

In short the finalize execute itself when the object is about to be garbaged. The main problem is that this garbaging does only take into account the memory limits, not the resources limits (max number of open file descriptors for example). So you can run out of open file descriptors way before running out of free memory.

So, the usual construction is like this :

MyResource res = null;
try {
  res = new MyResource();
  res.setSomething(someValue);
  /* Use the resource */
  res.close();
} catch (Exception e) {
  // release the resource if needed
  if (res != null) { res.close(); }
}

But hey, that's many code lines, and in case of a Throwable, you don't release the resource. The concept of releasing the resources with a try { } finally { } construct is much better (actually, it's one of the most common usage of finally).

The construction becomes :

MyResource res = null;
try {
  res = new MyResource();
  res.setSomething(someValue);
  /* Use the resource */
} finally {
  if (res != null) { res.close(); }
}

But here we can see that Java is not quite different from C++ for that matter, so we can just adapt the C++-ism that is RAII, and write a much cleaner version that aquire the ressource in the constructor, so most failure conditions can be checked immediatly.

The construction becomes finally :

MyResource res = new MyResource(someValue);
try {
  /* Use the resource */
} finally {
  res.close();
}

Since a constructor never returns a null value, there is no need to test. And if the constructor throws an exceptions, the general contract is that the object does not exists. Therefore no resource has been allocated since it would be impossible for the caller to release it (remember, no object was created). So there is no need to release it.

The setter is also integrated in the constructor, since the whole RAII concept is that the constructor returns a completely initialized object. It also enables to write cleaner code since when calling the close() there is no need to do some if() to know the object initialisation-state.

Monday, May 26 2008

Why Negative comments are better than positive ones

Why Negative comments are better than positive onesIf you are reading this blog and thinking Hey ! What a He's just talking nonsense... please don't walk away in horror. It would be very much appreciated if you drop me a comment about what is wrong in my post instead. I actually prefer to have negative comments than positive ones... at least when they are well argumented.

As a matter of fact, we mostly learn by our mistakes. If you do something and it works, you are really happy but you don't know why it works. The next time you have to do something quite similar you are tempted to change the least possible in order not to be disappointed. This leads to the infamous Cargo Cult Programming effect. Whereas if it doesn't work you spend some times, but just learned something that you can subsequently reuse.

It's actually by been challenged that you make the most interesting progress. I nevertheless agree that when in isolation your raw productivity is much bigger than when being part of a team. The reason if quite obvious : since you don't have to argue with others, you can spend all your time doing useful stuff. The main problem with this approach is that the real goal (where you really should go), isn't necessarily where you think it is. So you just might go very fast, but aiming the wrong goal. Sometimes the very fact explaining something to someone (that didn't even disagree) can show you the internal problems of your way of thinking.

It's actually the convincing-battle that you have to fight with your audience/co-workers/etc that leads to the most interesting solutions. We are all humans, and each had different experiences, hence different point of views. So the real cleverness is to be able to take the ladder of your opinions, climb with them on the shoulder of giants and give the feed back your fellow giants what your new point of view gives you to see. I really insist on the feed-back stage, knowledge is something you can even increase by giving it, since it usually makes you think ways that you would not have explored normally.

So I do write in this blog with my own convictions. It is certainly not the universal truth, but it's my very own vision of it. If you feel that I'm wrong, feel free to tell me : I don't say I'll agree with you, but it may be a very interesting battle that might even elevate both of us.

Friday, March 28 2008

Speedup OpenOffice with LeapHeap

Using a new heap manager like Leap Heap under windows takes OpenOffice to blazing speeds. Tried the same with FireFox with the same conclusions.

Would it be possible to learn from this little add-in ?

Saturday, January 5 2008

A Little History of PWKF

It all began with a scratching need as I just felt that workflows (mostly BPM engines to be more precise) were the way to do many things in IT of the future. There are even many workflows out here already. My main feeling was that they put too much emphasis on how much of the standard they support, mostly in order to be "Entreprise Grade".

That felt just plain wrong to me : WF where at first designed (at least that's was the usual original marketing scheme) to put back the design of the business rules in the hands of our beloved users, in order to mostly bypass the IT departement, and be able to change and adapt the process very rapidly as described on ACM. With the current implementations of WF, i just have to feeling that it involves a lot more of XML and/or BPEL files to be written than a non-IT worker can manage.

I think that WFs are a very good concept, but the emphasis should be on the modeling, on the reporting, and on the operational part (in that order). The number of constructs that the implementation recognise isn't that important : it could support a much smaller instruction set, but doing it in a user-friendly way.

  • The modeling is the most important part of the equation.

It's always über-fustrating that we have to attend to meetings, capturing the informations on how to model the business rules, tranlate it into something that the systems understand, and to try to explain it to the users. The most important part of the modeling is that the model is accurate enough. Modeling is usually the difficult part of the job. I don't advocate that the business users should be able to model it themselves : it's usually a recipe for a disaster since they mostly don't have the mind for this. But the opposite is also true : the user has to understand easily what is modeled. Modeling a workflow is like writing a book : it takes a different skillset to write it and to read it to be able to spot inaccuracies. Since users aren't very good at decyphering computer languages, having a good bijection between the modelling and a random-human-readable form is very important. That enables the fact that you users don't have to model their business through you, but with you.

  • Reporting is the second most important part

The debugging part is also very important. Since everyone makes mistakes, it's very important to be able to spot them. So we have to see what happened to a particular order. Usually that's the most difficult part of the system, but with workflow, it's quite easy to log everything that happened, and be able to show it later, even to show a snapshot of the current state and history of a particular workcase. If you also manage to show it with a graphical form that is the same than the modeling one, you'll have bug reports that would be much more accurate. The users will be able to tell you : This workcase has gone through here and there, but since it's the special case A, it should have gone here instead. and then bugfixing would be usually like a piece of cake.

  • Operating the workflow is also important.

You don't use the workflow for a living. you design them. But that's not a reason to make the life of operators miserable :-). And then they should have a nice list of tasks to be done. Tasks forms should be standardized, and it should be possible to have a wizard-like approach so they don't need to fill submit, reopen the case on another task, fill and resubmit anbd so one. The current workcase could be left opened, with the forms "advancing" without need to reselect them again. And as Alan Kay said : "Simple things should be simple, complex things should be possible. ", once all those 3 priorities are done, it's very easy to divide task that's isn't defined in the core workflow to an external "plugin", such as "signaling an other application to do something, via a webservice for example".

So, that laid the initial approach to PWKF, which was at first named "Perl Workflow" since I was planning to do it in Perl & wxWidgets. I migrated to Java since i wasn't that fluent in Perl anymore since I mostly use Java now at work and therefore rename PWKF in "Personal Workflow", in the way PHP is for 'Personal Home Page'.

- page 1 of 3