This is the fourth post about my experiments with a fluent I/O API. This post covers conclusions and limitations of the implementation. You can find downloads and source repository details further down the page.
Conclusions
In my first post, I outlined some of the goals of the API. Here's a run down of how the API measures up.
Goal: reduce the amount of code required for I/O operations
In terms of the number of characters you're required to type, the API does do its job. It won't necessarily result in fewer lines of code, but the fluent style combined with IDE code completion should make them easier to write.
Where the API might fall down is in using many external stream
types. If you have to write a bunch of Doctor
implementations just to decorate a stream, this may result in more code
than just using the core API.
Goal: be extensible
The Doctor
mechanism is quite powerful. It is
possible to chain a bunch of these operations together to produce a
single Doctor
type that transforms an input type through a
series of intermediate types to an output type.
The main weakness of the current Doctor
implementation is in its generics support. The type support is weak,
despite the fact that the types are known at compile time. Writing a
method in a parameterized type to transform a parameterized
type of a parameterized type (T<A<B>>
) to
another parameterized type of a parameterized type is tricky to
get working in a single compiler. Getting it working in multiple
compilers has so far proved beyond my abilities. As a result, some of
the methods just take wild cards and trust the programmer to do the
right thing.
This is why many of the Doctor
implementations are static instead of being returned via strongly typed
methods (as in the Collections.emptySet
-style methods).
There is no advantage in doing this until stronger typing can be
enforced in other parts of the API.
Goal: interoperate with the existing java.io API and any 3rd party frameworks that build on it
Support can be added for these stream types via the Doctor
type. It would be necessary to write a support library for each I/O
library.
Goal: reduce the opportunities for resource leaks and poor error handling
To use the API, you have to use a Closer
instance.
Whether this will drum into people that they have to use the try/finally
pattern or not is another matter. But if all the examples do, perhaps we
can hope people will copy them.
Goal: encourage good character data transcoding
The API doesn't let the user create an InputStreamReader
/InputStreamReader
without specifying a Charset
instance. This should reduce
the number of character transcoding bugs. The API also makes it easy
(and preferable) to use UTF-8, which should reduce character-related
data-loss bugs.
Goal: add some support for runtime exception handling
Switching entirely to runtime exceptions from IOException
requires a lot of stream type decorators. The API adds limited support
for some operations, but I'm sure there is more that could be done.
Goal: be small, clean and easily understood
This one is a bit subjective. The type and method naming definitely needs work.
The API in its current form has 28 types. This is too many. Some of these should be removed and there is scope for better division via packages.
Other issues and limitations
To me, the glaring omission is NIO support. I'm sure something can be done here, but I'm still mulling over exactly what.
Source code
You can download a binary here: fluentio-0.0.1-SNAPSHOT-dist.zip
All the sources are available in a public Subversion repository.
Repository:
http://illegalargumentexception.googlecode.com/svn/trunk/code/java/
License: MIT
Project: fluentio
Related posts
- Part 1: introduction
- Part 2: extending the API
- Part 3: error handling
- Part 4: conclusions and downloads
Comments & criticism are welcome.
Hello, well that was an interesting articles, I don't manipulate IO that often to have a worthy feedback, but I like the approach. In these time there might be a good opportunity to create a good fluent API. You might want to propose your ideas to the Google Guava project.
ReplyDeleteMaybe you might can offer to the API an IO builder style, instead of returning specific objects such InputDie or ReaderDie.
As for testing you should defintely try mockito. Maybe there's some idea to take from this library too. The OO design of the mockito is somehow inspiring compared to other "old school" libraries.
As for the Doctors, there should be precoded utilities like the Preconditions or Functions.