mercredi 24 décembre 2008

Checked exception : why the debat is not over for everyone

I've just read Clean Code by Bob Martin.

In this book uncle Bob says :
"The debate is over [...] At the time, we thought that checked exceptions were a great idea; and yes, they can yield some benefit. However, it is clear now that they aren’t necessary for the production of robust software"

I do agree, but as I was reading these lines I was wondering why, for plenty of people, checked exception is still the way to go when writing a java app.

Here is my humble hypothesis.

First, I need two acronyms :

  • SLJA : "Significantly Large JAVA Application". let's say a 500+ java classes application with at least two layers.

  • BTDT : "Been There, Done That"


So, in the checked vs unchecked exception debate I think that we may find at least 5 categories of contestant :


  • Category 1 : programmers who have never worked on any SLJA and just didn't experience what the real difficulties are with checked exceptions, so these programmers think that checked exceptions must be systematically used. BTDT (remember my second acronym ?)

  • Category 2 : programmers who have already worked on one or two SLJA and who also think that checked exceptions must be systematically used. Still they wonder why they need to use so many try/catch blocks and so many throws directives when the number of classes increases and the layers stack. The bigger the SLJA the more painful it becomes. BTDT.

  • Category 3a : programmers who have aleady worked on some SLJA and who know that exception hierarchy in an application must be thoroughly designed in order to keep the verbosity of the try/catch/throws at a manageable level and to keep a coherence in the abstraction levels.They are sure that checked exception must be used, granted that a MyApplicationException is used as the top most exception in the exception hierarchy of their application. They use "throws MyApplicationException" in every methods, to please the compiler and allow most of their exceptions to bubble up. Most of their try/catch/finally became try/finally as they don't need to rethrow most exceptions anymore, thanks to the "throws MyApplicationException" directive in almost all methods signature. BTDT.

  • Category 3b : programmers who have aleady worked on some SLJA and who are fed up with the MyApplication exception trick. They understand that's only a symptom of the fact that in any SLJA most exceptions must bubble up and unchecked exceptions must be used instead of the "throws MyApplicationException" everywhere. Still, they think that checked exceptions could be useful sometimes for the recoverable errors. BTDT.

  • Category 3c : programmers who have aleady worked on some SLJA. They never use checked exceptions anymore. they have a few unchecked exceptions at the top most level of their exception hierarchy. They declare as many unchecked exceptions as necessary in the packages of the classes that might need to throw specific exceptions. As soon as they have to work with an API that throws checked exceptions, they wrap them with unchecked exceptions.


So, actually, the debate is only over for category 3c (I consider that I'm in 3c now).

It's interesting to understand how you move from 3b to 3c (You're in 3b because you think that checked exception might sometimes be used for recoverable errors).

Let's say you're in 3b and one day you have to design a factory method that parses a string for a credit card number and transform it into a CreditCardNumber object.

The first client of this factory method is the GUI layer, so you think : "hey, the user may have made a mistake when entering the credit card number, it is a recoverable error because the GUI must warn him and retry, so I'm going to use a checked exception". So your factory method throws a BadCreditCardNumberException checked exception that inherit from a more general BadFormatException checked exception.

Two weeks later you have to store the credit card number as a string into a database, and when you reread the record, you must transform the string back into a CreditCardNumber object. So you obviously reuse the factory method that was created. But now you have to catch the BadCreditCardNumber exception in your DAO, and you don't want to do that, because it is really not a recoverable error in this layer. It is a fatal error (data corruption ?) and you just want the application to bubble up and hit the fault barrier of your application as a BadFormatException.

That's the exact moment you move from 3b to 3c because you see that an error that's recoverable in a layer may not be recoverable in an other layer and you really don't want to be forced to artificially chain a checked exception that is not recoverable. You prefer to choose to catch an unchecked exception when you think that it is recoverable for you in your layer.

When you choose to use checked exception for errors that you think are recoverable, you try to decide for the client of you API, whereas only he may know what's recoverable and what isn't in his own context.

Update : Everething was already there

mardi 23 décembre 2008

How to negate a regexp with a negative lookahead

When I need it, I tend to forget how to create a regular expression that matches a large set of strings but does not match some specific strings. It's tricky because it involves the negative lookahead syntax.

For exemple the regexp

.+\.java

matches any java filename.


But the following regexp

(?!Foo\.java).+\.java

matches any java filename except Foo.java because the negative lookahead of Foo\.java will prevent .+\.java from matching.

The negative lookahead syntax is
(?!X) where X is the string that must not be matched.

dimanche 9 novembre 2008

Sepia GFA Basic code

Internet is such a strange place. I've found by chance some lines of GFA Basic code I wrote something like 20 years ago.

Actually in the late 80s the French magazine ST Mag used to publish short GFA Basic programs written by the readers. These were called GFA Punch. They had to have at most 20 lines of code, and had to do something funny or useful. Some GFA Punch I had written were published. Someone kept a floppy disk of a bunch of GFA Punch that were published and made it available.

Now, among all these programs I've found some of my old GFA Punch. For me its like finding an old sepia picture in a box. It's weird. I've decided to post two of these programs just for archeological reason. There isn't any technological interest as the quality of the code is poor.

This one draw colored frames :


This one draw a big ugly and slow scroll text :

jeudi 6 novembre 2008

TDD and tomatoes

Tomatoes are like tests, it is easier to make a tomato go from green to red, than from red to green.

mardi 14 octobre 2008

Sanitize dates in podcast title with groovy + jid3lib

When I sort the podcasts I download by their ID3 titles, I want to see an older episode sorted after a newer episode.

Here is a groovy script that modifies the MP3 title of an MP3 file passed as first parameter of the script, and replaces any dd.mm.20yy date by a 20yy.mm.dd date. It also moves the date at the beginning of the title.

You need the Java ID3 Tag Library (jid3lib) and an embeddable Groovy (groovy-all.jar)

Now in order to run the script after each download, your podcast receiver must be able to run a custom command after each download. You can use Juice.

So here is a quick and dirty script sanitize_dates.groovy :



In the preferences of Juice you can use Run this command after each download with for exemple :

samedi 11 octobre 2008

MTP Mp3 players and Asus eee

Works like a charm :

Open a console : CTRL+ALT+T then
sudo apt-get install libmtp libnjb gnomad2
./gnomad2

Does not work with Amarok though, as the MTP support does not seem to be compiled in the version provided with the eee.

jeudi 9 octobre 2008

MTP devices, udev and permissions in Ubuntu Dapper

I had to install Gnomad2 in Ubuntu Dapper in order to upload files to my MTP Mp3 player.

I followed this great How To

However Gnomad2 could not open the device unless I was root (same thing for mtp-detect)

It looked like a permission problem in /dev/bus/usb

This worked for me :

In /etc/udev/rules.d/40-permissions.rules I changed

# USB devices (usbfs replacement)
SUBSYSTEM=="usb_device", MODE="0664"
to

# USB devices (usbfs replacement)
SUBSYSTEM=="usb_device", MODE="0664", GROUP="plugdev"

Then

sudo /etc/init.d/udev restart

vendredi 5 septembre 2008

samedi 30 août 2008

TDD : Can Shared Fixture test unexpected statefulness ?

When praticing TDD, the impact of the different types of fixture that can be used to setup the tests must be known in order to avoid to create Obscure Tests

The usual default fixture type is the Fresh Fixture

When the fresh fixture takes too much time a Shared Fixture can be used. Now, that being said, the shared fixture should usually be avoided (there's a risk of Erratic Test)

A few days ago, during a discussion about test fixture, some colleagues of mine and I were wondering if shared fixture could be used in order to test the statelessness of the objects used in the fixture as a side effect of the sharing.

Here is the initial reasoning : when an object is supposed to be stateless, but is buggy and not actually stateless , the use of this object will lead to some failing test, since the state left by some tests will make some subsequent tests fail. The statelessness is tested "for free" with a lot of different combination. Actually, if the object happens to be stateful it is a case of Interacting Tests and the reason why some tests fail could be quite hard to find.

I must admit that it may help to find some obscure statefulness interaction, but I do not really like this idea :
Actually, the statefulness should be tested in its own test. Of course it means that only a few method call combination will be tested but it should be enough to prove the statelessness (or else it means that the code of the class under test must be refactored in order to make the stalessness explicit in the code structure)

To try to use the side effect of the shared fixture to test statelessness may seem to be worthwhile at first, but it creates Technical Debt. And in this case I think that the financial interest of the debt is pretty high.

dimanche 13 avril 2008

Albert Einstein quote

“Insanity: doing the same thing over and over again and expecting different results.”Albert Einstein

Closely related to the quotation in the header of this blog

mercredi 5 mars 2008

90s geek flashback

Wooow...Internet still surprising me.

(Just skip this post if terms Atari ST + Demo do no ring a bell)

I never imagined I would have the opportunity to listen to this track again : the Union Demo main menu.

samedi 23 février 2008

"Unit Integrated Tests" for integrator objects

Whether I use interaction based testing or state based testing I usually write "real" unit tests in the sense that only one real object is involved (the SUT, System Under Test) and only stubs and mocks are used for the fixture. It usually is the only way to easily get a good code coverage (or at least to easily specifically cover some parts of the code )

However, Lately, when testing Facade or Adapter objects he seemed to me that the unit tests for these objects were :
- too complicated
- too...useless

For most Facade or Adapter objects :
- They're stateless, so let's forget state based testing, we must use mocks
- They're highly coupled to the contract of the adapted objects (by definition of a Facade or of an Adapter)

This kind of class does nothing clever, they basically chain one or multiples calls. They may have bug though if they do not respect the contracts of the adapted classes.

So a unit test for this kind of class depends more on the contract of the mocked objects, than on the behavior of the class under test. A very clear test smell.

Even worse, the fixtures for the mocks are going to closely mimick the code of the SUT (if a method of a Facade calls an object A and then an object B, the fixture for the test on mocks and stubs will tell the exact same thing).

In this specific case the unit test does not provide an orthogonal view of the behavior implemented by the code (the usual value of a unit test) ; it is the exact same view. If I make a wrong assumption on the contract of the adapted objects, I'm going to make the same exact mistake both in the test and then in the code (TDDly speaking)

The problem basically is that the job of this kind of objects is to integrate other objects in the system. So he seemed to me that it is very hard to try to test an integration behavior in isolation.

That's why, now, when I must deal with objects that heavily depend on the contract of the collaborating objects but do not do anything complicated, "integrator objects", I use integrated tests.

However when I encounter an object that heavily depend on the contract of the collaborating objects and does many complicated things, it just means that it is too hard to test, I refactor.

dimanche 3 février 2008

TDD : How I was overusing mocks

The path to TDD is hard. When you think that you begin to understand how to apply it, you read this great Jay Fields post, and you understand that you missed the point about stubs...

As explained in his post, I was overusing mocks. I knew that I had to improve a lot in my way of using mocks, but what I really had to do was to use fewer mocks and more stubs. Basically I was missing the point that stubs are still of great use and are not superseded by mocks.

It's been a long time since I learned such an important thing in a post about TDD. Now I'm really going to try to stick to "one assert per test" (including "one mock assert per test")

And trying to do that, I'm also going to try "one test class per test setup". See this presentation about BDD by Dave Astels

Asus eee and FullerScreen for Firefox

The Asus eee PC is a terrific machine. Now, the screen resolution being what it is you must find ways to use as much as possible the available area in Firefox.

Enters FullerScreen an extension for Firefox. After the install, F11 gives you a real fullscreen (even for a tab)

In full screen mode, you may need the following shorcuts of Firefox :

  • Ctr + T : open tab

  • Ctrl + W : close tab

  • Ctrl + Tab : next tab (yeah, I know)

  • Ctrl + L : go to location dialog

  • Ctrl + K : go to search page