Skip to main content

API Blogs

Posted by timboudreau on August 5, 2008 at 11:38 AM PDT

One thing which I think about often is the design of code,
software libraries
and APIs. I've been working on
deriving some principles from the things I do intuitively based on
experience. Whether those are useful to anyone else is an open question.
Peer review is the best tool for figuring
out if these really make sense or not, so I'd appreciate
feedback on my next few blogs - hopefully one day they can
make up some articles or a book or similar.

Whether the results are of value is not for me
to judge. If, at worst, what comes out of this
is a healthy debate and identifying some things that
are not good ideas, that has value too.

Why is a subject like API-usability interesting? Well, the history
of software is a history of libraries. Libraries have APIs.
An operating system is a
set of libraries. The Apache web server is a set of libraries.
The Java platform is a set of libraries.
The set of things people simply take for granted when they
write code are things provided by libraries.
The fact that there are things called
files that contain data and folders that contain files was not
always
(and in some domains still isn't, nor should be) a truism.
-->
If you're writing code, you're usually creating an API whether you
know it or not. Better API design skills on average means
more software that people can use and rely on faster.

There are plenty of prescriptive books on coding -
Effective Java
is one of the best, and I recently reread it. I do hope some
prescriptions can come out of this writing; what I miss in
prescriptive books is the sort of “Here's how to think about
such and such a problem in order to arrive at a good solution”
advice that helps one to know when one has encountered the
illness the prescription cures.

A good little computer scientist is very tempted to avoid
anything that isn't more-or-less mathematically provable, or at
least demonstrable from statistical evidence.

But objects are a convenience for human beings! There is
a psychology of how you carve a problem up into objects, how you
name things, and so forth. Some
ways will be easier to use for the majority of people than others.
Yet, at the same time, design is a matter of balancing sometimes
fuzzy principles of code ease-of-use with the requirement that
the result ask only a sane amount of work from the computer, and
sometimes you still have to let the computer win.

Take, for example, the argument against mixing concerns in
a single class. There are excellent arguments from the perspective
of architectural purism, and from the perspective of code reuse,
for why mixing concerns is a bad idea. What I seldom see
articulated is the simple notion that if you mix concerns,
people will have a harder time understanding how to use what
you create.
You can't write a proof for that - and there will
be cases where mixing concerns actually is the optimal
solution. Those are the dark waters I would like to venture into.

 

There is much fascinating research to be done in the area of
api-usability. To be done properly, that should involve
not only programmers and usability experts, but cognitive
psychologists. It would be wonderful to have such research, and
would also take years to do, and I suspect cognitive psychologists
have their hands full with problems more interesting to them than
how to design an API.

In the absence of such research, perhaps some thoughts from one
humble programmer will stir up some wisdom.

 

The problem with writing this sort of thing is that often you
cannot write about single patterns or principles in isolation -
the point is how a number of patterns interact. This inevitably
makes the subject complex. For example, this first of these,
which I will post shortly, touches on

  • Statefulness and Model Driven Architecture
  • The Don't Call Us, We'll Call You principle
  • The listener pattern being more harmful than good, and
  • Threading models.

Discussing each of these in isolation might be interesting, but
it wouldn't provide the “here's a useful way to think about
this class of problems” aspect — and that's the thing I really feel
is missing from most design prescriptions - prescriptions are the
“what”. The “when”,
“how” and “why” are
at least as interesting as the prescription itself.

Hopefully your feedback, flames and/or howls of protest will
help sort the relevant from the irrelevant. Don't be sparing - if I don't
post at least one thing that is approaches dead-wrong,
I'm not thinking hard enough.

library1.png


Stern warning in the
University of the Philippines Computer Science Building
Related Topics >>

Comments

> Thank you for pointing out it has been published, I was waiting for it. Just ordered. Sure thing, it's a unique read, more philosophical and personal than most design books and with some controversial remarks (simplicity and elegance might not not be a goal by itself, but to me it sure is a quality attribute worth keeping in mind). Interestingly, it appears he invites us readers to participate in a dialog: http://wiki.apidesign.org/wiki/Blogs /Casper

Perhaps I don’t really understand what your post is about but I thought you wonted to start a discussion about some global software architecture question. I have to check my budget to know how many more Java books I can afford this year (I already have a bunch of Netbeans and RCP books here). But before that: several days before, I’ve posted a question on the dev@openide.netbeans.org and got no answer. What I basically wanted to know is what role the lookup and the module API are playing in a RCP transition scenario where the old app used other patterns. So I have an app which is relatively strict build with the MVC – Observer Patterns in mind. We have a DataModel (xml half binding) we have a LogicModel and we have a lot of Views passing information to the Model over the specific Controllers. Well so far we have the one way the over way is done over the observer pattern. So the views observe the LogicModel. If some part of the model is changed the Observers listening to this part of the model are informed and update themselves. So 2-3 Sentences on the role of the lookup API in this scenario would be great. What do you think?

"And now, about to open up the package from Amazon containing Practical API Design by Jaroslav Tulach." Thank you for pointing out it has been published, I was waiting for it. Just ordered.

I don't think it will. Let me set expectations here: I'm attempting to express some useful ideas I know, in the hope that we can thrash some out. I do not intend be the Voice Of Sun here :-)

I realize there's an item in Bloch's latest "Effective Java" that can be bend to apply to this scenario as well. "Item 37: Use Marker interfaces to define types." In this case both the marker annotation and the getCapability pattern helps us out by simulating an is-a relationship with a has-an. All I am saying is that I don't think doing this scales very well at the micro-level within a class hierachy. Between components and modules is quite another matter and it has obviously proven useful in NetBeans. Looking forward to your next post, particularly if it will address this silly marketing whitepaper. http://java.sun.com/docs/white/delegates.html

Layer files aren't pretty or terribly manageable; at least the META-INF/services injection method is somewhat better. But whenever you're doing loose coupling via some sort of dependency injection, there is going to be some place outside Java code where that injection happens, and outside Java code is outside of the world of type-safety. Ideally you enforce this at compile time, and you can definitely fail at runtime before a caller is handed an object of an unexpected type. Any layer of indirection comes at a price - but without layers of indirection, we'd all still be building direct video and disk read/write into our software. As far as locking down event handling, this has more to do with the myriad anti-patterns in the listener pattern - there are simply better ways to do that sort of thing. My next post will discuss that.

> I don't quite see how either is counter to the type system, since both are type-safe. I should rephrase, it's still all statically typed of course, but interrelationships and dependencies are no longer readability available. So you really start having to rely on tools to handle this, as NetBeans does so well with the use of layer files. It's the same level of indirection added by the observer pattern, it becomes more complicated to reason about what's going on, which I guess is why NetBeans feels obliged to lock down all the event handling and prevent the programmer from touching. That's definitely one usability aspect of NetBeans I don't agree with, that you have to go behind NetBeans back to refactor a name of an event handler callback or remove one.

mmorris: The capability pattern is a simplification of Lookup (i.e. no collections and no listening for changes). I don't quite see how either is counter to the type system, since both are type-safe. Agree completely about there being far to many DateUtils and StringUtils types of things out there.

Re the observer pattern, you really want to read my friend Jarda Tulach's book at http://apidesign.org - he specifically uses it as an example of applying some of the ideas he presents there. Re the module system wars, I prefer to stay mostly on the sidelines - they are all addressing the same problem, in mostly similar ways. If you want to use the NB module system that way, in NetBeans just create a module "suite" and exclude just about everything but the module system API and its dependencies.

Seems to me there are some great topics to discuss. I am especially interested in an observer pattern discussion. For an architect there are always several suitable solutions for a problem. Since a decision of an architect can affect years of development this decisions are really hard to make. So any standards or rules of behavior are big time savers even if there are not effective in each situation. The versioning strategy for a big software and API landscape that develops over time and has many different versions of the same API’s and the same products would be a great topic too. And to say something on the OSGI <-> SUN Topic. Basically what SUN People told to me on the last CeBit: • IBM, eclipse, Equinox no good. (Well nothing new. And the IBM people are talking the same language) • JSR277 will rule OSGi and make it a dead end. • OSGI will not work well in the EE world. Addressing module system is not enough. I think that we need a standard. OSGi is really successful in the moment. You hear allot about NetBeans RCP too, but no one speaks about the module system of Netbeans. The ‘easy to use’ and the ‘swing’ arguments bringing a lot of folks to Netbeans RCP in the moment but NetBeans RCP with OSGI would be a killer Technology. Well just some thoughts… -Pavel-

I assume the capability pattern is similar to the description of the lookup API in your RCP book? I now use that a lot along with an SPI approach, thanks for broadining my horizon! But strictly speaking, isn't that counter-productive to the type system, in that it gets hard to really say anything concrete about interactions and behavior within the system. Taken to the extreme, we would end up using Martin Fowler's dynamic properties pattern (where everything is effectively a Map). It solves some problems in larger long-lived frameworks (same level as OSGi/JSR-277 operates on) but I don't really see it compete with that of finer grained constructs readily at hand to the floor level programmer, who do not necessarily know the GoF book by heart. Perhaps my notion of API usability is just different. I do find the example of extension methods and/or mixins catering to usability, probably caused by having seen too many projects with each their own version of a DateUtils, StringUtils with no leverage between them all.

I have some (slim) hopes that the JDK 7 module system JSR will address versionability - OSGi and the NetBeans Module System already do, and it's actually difficult to write these things and have to leave out the fact that you can, say, separate API and SPI into separate JARs so client APIs can be entirely final classes as an API client can be completely isolated from even potentially touching the SPI. Re type safety, the capability pattern provides a nice way to add extensibility to a final class without requiring casts or violating API/SPI separation. In its essence it is simply T getCapability (Class type); Re general verbosity, I think there is great room for improvement without significant changes to the language. That's not to say Ruby is not less verbose. But, I think many common Java APIs are designed in such a way that they require much more verbosity than is strictly necessary. In other words, while there is some case for arguing that Java is verbose, we Java programmers share a good bit of the blame. -Tim

Software architecture is the single most fascinating and difficult aspect (apart perhaps from dealing with users) within our industry. We have gotten far with sound principles, rules of thumb, conventions, patterns and anti-patterns... but to truly assist in usability and productivity I think we need some stronger abstractions at our disposal, directly in the language, to mitigate the layers of indirection we're so dependent on in Java. I'm thinking of constructs which would address the issue of versionability, resource management and type safety. I'm still hoping we will see such things as properties, extension methods and akin to C#'s using statement (Bloch's ARM proposal) but it does not seem to be very popular. Not sure I understand why this is though, seems to me the Java 5 Enum addition have done wonders in improving API usability and type safety, even if it took 10 years to get it. Perhaps with a little more leeway, we would not see so much become hidden inside string tokens of annotations which makes us say bye-bye to type safety. And now, about to open up the package from Amazon containing Practical API Design by Jaroslav Tulach.