tisdag, juni 17, 2008

Applications and libraries

In a recent discussion around one of Steve Yegge's blog post, an incidental remark was that it's OK that a language makes it harder for a library creator than for an application developer. This point was made by David Pollak and Martin Odersky in relation to some of the complications that you need to handle when creating a Scala library that you can intuitively use without a full understanding of the Scala type system. Make no mistake, I have lots of respect for both Martin and David, it's just that in this case I think it's actually a quite damaging assumption to make. And they are not the only ones who reason like that either. Joshua Bloch's book Effective Java includes this assumption too, in many places.

So what's wrong with it then? Isn't there a difference between developing an application and a library. Yes, there is a difference, but it's definitely not as large as people make it out to be. And even more importantly: it _shouldn't_ be that much of a difference. The argument from David was that when creating a library in Scala, he needs to focus and work with quite complicated parts of the type system so that the consumer gets a nice API to use the library through. This process is much harder than just using the library would be.

Effective Java contains much good advice, but most of them are from the perspective of someone who creates libraries for a living, and there are a few places where Josh explicitly says that his advice isn't necessarily applicable when writing an application, since he doesn't have that point of view.

Let's take a look at a fundamental question then. What is actually a library, and what is an application? In my opinion, a library is a module providing functionality of some kind, restricted to a specific domain. This can be a horizontal or vertical domain, that doesn't matter, but it's usually something that is usable in more than one circumstance. It's not uncommon that libraries use other libraries to implements its functionality. An application is usually a collection of libraries that provide functionality to an end user. That end user can be either a person, a program or another computer - that doesn't matter. But wait, isn't libraries usually also created to provide functionality to other pieces of code? And even though libraries have a tendency to contain more specific code, and less usage of other libraries, the line is extremely fuzzy.

The way most applications seems to be built now, most of the work is done to collect libraries, provide the missing functionality and glue them together in some way. But that doesn't mean that the code you write in the application won't be used as a library by another consumer. In fact, it's more and more common to try to reuse as much as possible, and especially when you extend an existing application, it's extremely important that you can consume the existing functionality in a sane way.

So why make the distinction? Doing that seems to me to be an excuse for writing bad code if it's in an application. Why won't we as programmers admit that we don't know if someone else will need to consume the code later, and write the best code we can, including creating usable ad well thought out public APIs? Yes, the cost and time will be higher, but that's true for writing tests too. I don't see any value in arguing that libraries should be designed with more care than application code. In fact, I think that attitude is actively detrimental to the industry. And adding a language feature to a language that is complicated, and then arguing that only "library developers" will need to understand it is definitely not the right way to go. A responsible developer using a language needs to understand how that language works. Otherwise that developer will sooner or later cause a great mess. It's just a matter of time.

7 kommentarer:

helium sa...

From my experience as a former C++ programmer I can say that writing librarys is very different from writing applications. When I write a library in C++ I use a lot of templates and some realy advanced template-meta-programming stuff. When I write an application I have very few templates and no need for template-meta-programming.

And I think the same is true for any langauge. You can write something like Raganwald's "andand" in a Ruby library. It opens class Object! You can do something like this in a library. But would you ever open class Object in a Ruby program? I don't think so.

Mike Harris sa...

Agreed. When one of the biggest complaints about most languages is "it doesn't have any libraries," it seems silly to make it more difficult to create libraries.

Ola Bini sa...

helium: actually, it's funny that you mention opening up Object in Ruby. Because one of the differences in Ruby is that you should _never_ open up Object in a library. That's extremely bad style and causes no end of troubles. But you are totally fine to open up Object in your own applications, because you can trust that no libraries do it, and so you have full control over it.

But really, what you're saying is that you use more advanced stuff in libraries than in your applications. Why? Or is it just that you extract everything complicated into a library once it reaches a threshold? Or do you always start out with the intention of designing a library or an application? Things aren't that clear cut for me - which means I feel a responsibility to write my good as good as possible, using all available means, in both libraries and applications.

Chris Stevenson sa...

I think the problem with Effective Java (and library writers in general) is trust. If you don't trust the users of your library, then you need to write the library to protect them from themselves, and hence you need all the careful tricks that Effective Java teaches you.

If you do trust your users, then you allow them to use the same tricks that you allow yourself. Ruby trusts its users to open Object. I like that.

It sounds like the problems that the Scala guys are trying to solve is that they are trying to hide the complexities of the type system. I say fix the type system! Easier said than done though.

David Linsin sa...

I'm developing an OSGi application at the moment. So what I'm trying to do is divide my application in small little libraries hidden behind a well defined API.

You are right Chris, I don't trust any user of my API, that's why I'm careful and suspicious, e.g. when it comes to "user" input. But I don't think it's a bad thing per se, it's just a little more work.

Unknown sa...

That's an interesting perspective. I have a couple of comments, tho:

Firstly, one could define a library to be any piece of code that has a *published interface* a 1a Fowler. This implies the existence of client codebases owned by third parties. For instance, I remember reading somewhere the Google collection guys commenting on the difficulty of exposing previously internal code to the world in that they no longer could rely on the ability of doing automatic wholesale refactorings throughout the Google repository.

But all that is kind of beside the point. I agree it is dangerous to consider certain language features as "too complicate" for application development but good enough for library devs. But, OTOH, there are features that just fit better in infrastructure kind of code rather than in "business logic". Java Generics is a case in point. When writing collection or command[GoF]-like things they feel natural (not obvious, but natural). In business logic there aren't many concepts that are "generic", so the issues with parametrized types rarely come up. I think this is related to the distinction you made in the past between stable and dynamic layers; in a way we have a subsets of a language that are more adequate to one or the other domain.

Nick sa...

I also tend to think of most of my work on applications as writing a library to the business functionality, of which I myself (or my co-workers) are clients. I tend to find this makes me think more about what I'm trying to do, and helps effectively separate concerns. So, I'd agree that the line between libraries and application are indeed blury, as the application can consist of application-specific libraries to the business logic.

This being said, most of that business logic doesn't require a deep understanding of the type system (although it occasionally helps). As Chris said, you can also trust your co-workers to a much greater extent, so you can make greater assumptions about what it is reasonable for your business library to cover. Similarly, the further removed a library is from the 'metal', the less chances there are that it gets used elsewhere than originally envisioned by the library author, so less precautions need to be taken to define how it can be used. So to an extent I do understand library writers having a different mindset than application writers. Perhaps the extent to which that's the case depends on the language in use?