Quiz: Whats one of the most heard flaws of Java compared to other languages?
Bad Performance? That%u2019s a long overhauled myth. Slow startup? OK, this can be improved%u2026 It%u2019s verbosity, right? Right but wrong. Yes, it is one of the most mentioned flaws but is it really inherit to the language Java? Do you really think Closures, annotations or any other new introduced language feature will significantly reduce the clutter? Don%u2019t get me wrong here: closures are a mighty construct and I like them a lot. But the source of the problem lies elsewhere: the APIs. What?! You will tell me Java has some great libraries. These are the ones that let Java stand out! I don%u2019t talk about the functionality of the libraries here I mean the design of the API. Let me elaborate on this.
Example 1: HTML parsing/manipulation
Say you want to parse a HTML page and remove all infoboxes and add your link to a blog box:
01 | DOMFragmentParser parser = new DOMFragmentParser(); |
07 | HTMLDocument document = new HTMLDocumentImpl(); |
08 | DocumentFragment fragment = document.createDocumentFragment(); |
09 | parser.parse( new InputSource( new StringReader(html)), fragment); |
10 | XPathFactory factory = XPathFactory.newInstance(); |
11 | XPath xpath = factory.newXPath(); |
12 | Node infobox = xpath.evaluate( "//*/div[@class='infobox']" , fragment, XPathConstants.NODE); |
13 | infobox.getParentNode().removeChild(infobox); |
14 | Node blog = xpath.evaluate( "//*[@id='blog']" , fragment, XPathConstants.NODE); |
15 | NodeList children = blog.getChildNodes(); |
16 | for ( int i = 0 ; i < children.getLength(); i ) { |
17 | node.remove(children.item(i)); |
19 | blog.appendChild(/*create Elementtree*/); |
What you really want to say is:
1 | HTMLDocument document = new HTMLDocument(url); |
2 | document.at( "//*/div[@class='infobox']" ).remove(); |
3 | document.at( "//*[@id='blog']" ).setInnerHtml( "Blog" ); |
Much more concise, easy to read and it communicates its purpose clearly. The functionality is the same but what you need to do is vastly different.
The library behind the API should do the heavy lifting not the API's user.
Example 2: HTTP requests
Take this example of sending a post request to an URL:
01 | HttpClient client = new HttpClient(); |
02 | PostMethod post = new PostMethod(url); |
03 | for (Entry param : params.entrySet()) { |
04 | post.setParameter(param.key, param.value); |
07 | return client.executeMethod(post); |
09 | post.releaseConnection(); |
and compare it with:
1 | HttpClient client = new HttpClient(); |
2 | client.post(url, params); |
Yes, there are cases where you want to specify additional attributes or options but mostly you just want to send some params to an URL. This is the default functionality you want to use, so why not:
Make the easy and most used cases easy, the difficult ones not impossible to achieve.
Example 3: Swing%u2019s JTable
So what happens when you designed for one purpose but people usually use it for another one?
The following code displays a JTable filled with attachments showing their name and additional actions:
(Disclaimer: this one makes heavy use of our internal frameworks)
01 | JTable attachmentTable = new JTable(); |
02 | TableColumnBinder<FileAttachment> tableBinding = new TableColumnBinder<FileAttachment>(); |
03 | tableBinding.addColumnBinding( new StringColumnBinding<FileAttachment>( "Attachments" ) { |
05 | public String getValueFor(FileAttachment element, int row) { |
06 | return element.getName(); |
09 | tableBinding.addColumnBinding( new ActionColumnBinding<FileAttachment>( "Actions" ) { |
11 | public IAction<?, ?>[] getValueFor(FileAttachment element, int row) { |
12 | return getActionsFor(element); |
15 | tableBinding.bindTo(attachmentTable, this .attachments); |
Now think about you had to implement this using bare Swing. You need to create a TableModel which is unfortunately based on row and column indexes instead of elements, you need to write your own renderers and editors, not talking about the different listeners which need to map the passed indexes to the corresponding element.
JTable was designed as a spreadsheet like grid but most of the time people use it as a list of items. This change in use case needs a change in the API. Now indexes are not a good reference method for a cell, you want a list of elements and a column property. When the usage pattern changes you can write a new library or component or you can:
Evolve your API.
Designed to be used
So why is one API design better than another? The better ones are designed to be used. They have a clearly defined purpose: to get the task done in a simple way. Just that. They don%u2019t want to satisfy a standard or a specification. They don%u2019t need to open up a huge new world of configuration options or preference tweaks.
Call to action
So I argue that to make Java (or your language of choice) a better language and environment we have to design better APIs. Better designed APIs help an environment more than just another new language feature. Don%u2019t jump on the next super duper language band wagon because it has X or Y or any other cool language feature. Improve your (API) design skills! It will help you in every language/environment you use and will use. Learning new languages is good to give you new viewpoints but don%u2019t just flee to them.
No comments:
Post a Comment