What the ugliest API for a relatively well known library that you have seen, and why and how could it be improved? [closed]
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this questionI have been looking at the differences between Lucene 2.9 particular the redone tokenstream API and it just occurs to me its particularly ugly compared to the old just return a new or repopulate the given with values if your reusing said Token.
I have not done any profiling but it seems using a MAP to store attributes is not that efficient and it would be easier to just create a new value type holding values开发者_如何学运维 etc. The TokenStream and Attribute stuff looks like object pooling which is pretty much never necessary these days for simple value types like a Token of text.
creat()
When Ken Thompson and Dennis Ritchie received the 1983 Turing Award, after their respective acceptance speeches, someone in the audience asked Ken what he would do differently with Unix if he were to do it all over again. He said, "I'd spell 'creat' with an 'e'."
Livelink (OpenText) API
- Everything comes back as some bizarre form of a jagged array
- The documentation provides absolutely no examples
- [your favorite search engine] typically returns no results for a given API method
- The support forums feel near abandoned
- The only reliable way of understanding the resultant data is to run the data in the Livelink debugger
- And finally... the system costs tens (hundreds) of thousands of dollars
The wall next to my desk has an imprint of my head...
A very simple example of getting a value out of an API method:
var workflow = new LAPI_Workflow(CurrentSession);
// every Livelink method uses an out variable
LLValue outValue;
// every method returns an integer that says if the call was
// a success or not, where 0 = success and any other integer
// is a failure... oh yeah, there is no reference to what any
// of the failure values mean, you have to create your own
// error dictionary.
int result = workflow.ListWorkTasks(workId, subWorkId, taskId, outValue);
if (result = 0)
{
// and now let's traverse through at least 3 different arrays!
string taskName = outValue.toValue(0).toValue("TASKS").toValue(0).toString("TaskName");
}
Aaack!!! :D
I've never been a fan of the java.sql package...
- You have to catch the checked exception for everything, and there's only one exception, so it doesn't really give any indication of what went wrong without examining the SQL code String.
- Add to that the fact that you have to use java.sql.Date instead of java.util.Data, so you always have to specify the full package for one or the other. Not to mention the conversion that has to take place between the two.
- And then there's the parameter index, which is 1-base-indexed instead of the rest of Java, which is 0-base-indexed.
All in all, a pretty annoying library. Thankfully, the Spring library does make it quite a bit easier to work with.
COM. Its biggest improvements ended up being .NET.
Certain java.io.File
methods, critical to systems programming, return a boolean to indicate success or failure. If such a method (like, say, mkdir
or delete
) fails, you have no way at all to find out why.
This always leaves my jaw a-hangin' open.
Java's date/time API is pretty horrible to work with. java.util.Date has several constructors to create an instance for a specific date, but all of them are deprecated. java.util.GregorianCalendar should be used instead, but that has an extremely annoying way of setting fields (think calendar.setField(GregorianCalendar.MONTH, 7) instead of calendar.setMonth(7) which would be far better). The finishing touch is that most other classes and libraries still expect a Date instead of a Calendar, so you have to constantly convert back and forth.
Not not a winner, but deserves a honourably mention; Android. Uses the Java 5 programming language, but barely any of the Java 5 language features. Instead of enums you get integer constants with prefix or suffix.
It can not quite decide if it should be object oriented, or procedural. Showing dialogs being a prime example. Several callbacks with self defined integer ids to display call upon the dialog, that smells of an old C API. And then you get an inner builder class class with chained methods, that smells of over architectured OOP of the worst kind.
The MotionEvent class have X and Y coordinates as absolute and relative values from the same accessory method. But no way to check what kind of coordinates it currently holds.
Android sure is a mixed bag.
I'm going to turn this question on its head and name a beautiful API for a library whose standard API is mostly ugly: the Haskell bindings for OpenGL.
These are the reasons:
Instead of lumping everything into a small number of headers, the library is organized logically into discrete modules, whose contents parallel the structure of the OpenGL specification. This makes browsing the documentation a pleasant experience.
Pairs of "begin/end" functions are replaced by higher-order procedures. For example, instead of
pushMatrix(); doSomeStuff(); doSomeMoreStuff(); popMatrix();
you'd say
preservingMatrix $ do doSomeStuff doSomeMoreStuff
The syntax of the bindings enforces the conventions of the library, instead of making you do it by hand. This works for the drawing primitives of quads, triangles, lines, etc. as well. All of this is exception-safe, of course.
Getters and setters are replaced by idiomatic "StateVars", making reading and writing a more symmetric operation.
Multiple versions of functions replaced by polymorphism and extra datatypes. Instead of calling, say,
glVertex2f
with two float values, you callvertex
with a value of typeVertex2 GLFloat
.
References:
- API Reference
- The HaskellWiki page on OpenGL
- Beautiful Code, Compelling Evidence (pdf)
- Praise from Scott Dillard, quoted in Beautiful Code, Compelling Evidence
Direct3D!
No doubt the old pre-Direct3D 5 interface was pretty darn fugly:
// GL code
glBegin (GL_TRIANGLES);
glVertex (0,0,0);
glVertex (1,1,0);
glVertex (2,0,0);
glEnd ();
// D3D code, tonnes of crap removed
v = &buffer.vertexes[0];
v->x = 0; v->y = 0; v->z = 0;
v++;
v->x = 1; v->y = 1; v->z = 0;
v++;
v->x = 2; v->y = 0; v->z = 0;
c = &buffer.commands;
c->operation = DRAW_TRIANGLE;
c->vertexes[0] = 0;
c->vertexes[1] = 1;
c->vertexes[2] = 2;
IssueExecuteBuffer (buffer);
Its not too bad, nowadays - it only took Microsoft 10 versions to get it right...
I would say MFC, ATL and WTL. All 3 of these libraries use excessive hungarian notation, redefine data types for no apparent reason (CString redefined over and over) and are notoriously changed with each version of visual studio.
I like COM. It provides a component oriented architecture long before .NET was even developed. However, the expansion of COM into DCOM, its many wrappers like ATL and its general lack of comprehensive documentation make it the ugliest API i have to deal with at work.
Most certainly not the ugliest. There are probably so many, but Flex has a special place in hell. Specifically UIComponent which compared to the Sprite, feels like using a chainsaw to peel an apple. I believe Flex would have been much improved by using more lightweight objects and mixin-style features similar to how Dojo works on the Javascript side.
The ECMAScript/Actionscript Date class is all but backwards and useless. It's been a constant pain any time I've needed to do something more complex than add timestamps to logs. They need more parsing options (e.g., the ability to specify the input format), and better time management, like intelligent increments, convenience functions, etc...
C++ STL libraries (and templates in general), while obviously useful, have always felt plain ugly. No suggestions for improvements though. They work.
Oracle's ProC, ProAda, Pro*this-that-the-other things. They were a preprocessor front end for C, Ada, and Fortran, I think, maybe some others, that let you jam SQL into your source code.
They did also have a library which worked much better, and was much more flexible.
(That was more than 10 years ago, I have no idea what they do now, though I wouldn't be surprised if it was still the same, just so as not to break people's code.)
well, it was a well-known library about 20 years ago, but i think the original btrieve data engine has the worst api ever written. almost everything goes through a single call, with each of its many parameters containing a different value depending on which call you're really doing (one parameter was a flag telling the system if you wanted to open a file, close a file, search, insert, etc). i liked btrieve way back then, but i spent a long time making a good abstraction layer.
it could have been easily improved by not forcing everything into one call. not only was the one call hideous, but the programmer was responsible for allocating, passing in, and freeing the position block ... some memory used by btrieve to track the open file handle, position, etc. another improvement would be to allow ascii text to be used when defining the indexing. indices had to be specified by a convoluted binary representation.
best regards, don
A lot of the CRT library functions are poorly or vaguely named possibly due to legacy coding restrictions back in the day and thus require frequent use of the F1 key for people to find the right function and supply the right arguments.
I've been using CRT functions for a while and I still find myself hitting F1 a fair amount.
精彩评论