您见过的相对知名的库中最丑陋的 API 是什么?为什么以及如何改进它?

发布于 2024-08-07 18:26:28 字数 1431 浏览 5 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

怪我鬧 2024-08-14 18:26:28

创建()

当肯·汤普森 (Ken Thompson) 和丹尼斯·里奇 (Dennis Ritchie) 获得 1983 年图灵奖时,在各自发表获奖感言后,观众中有人问肯,如果重来一次,他会对 Unix 采取什么不同的做法。他说,“我会把‘creat’拼写成‘e’。”

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'."

尤怨 2024-08-14 18:26:28

Livelink (OpenText) API

  • 一切都以锯齿状数组的某种奇怪形式返回
  • 文档绝对没有提供任何示例
  • [您最喜欢的搜索引擎]通常不会为给定的 API 方法返回任何结果
  • 支持论坛感觉接近被遗弃
  • 理解结果数据的唯一可靠方法是在 Livelink 调试器中运行数据
  • 最后...系统花费数万(数十)万美元

我办公桌旁边的墙上有我头的印记

...从 API 方法中获取值的非常简单的示例:

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

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

↙厌世 2024-08-14 18:26:28

我从来都不喜欢 java.sql 包...

  1. 你必须捕获所有内容的已检查异常,并且只有一个异常,因此在不检查 SQL 代码的情况下它并不能真正给出任何错误指示细绳。
  2. 除此之外,您必须使用 java.sql.Date 而不是 java.util.Data,因此您始终必须指定其中之一的完整包。更不用说两者之间必须进行的转换了。
  3. 然后是参数索引,它是 1 基索引的,而不是 Java 的其余部分,它是 0 基索引的。

总而言之,这是一个非常烦人的库。值得庆幸的是,Spring 库确实使它更容易使用。

I've never been a fan of the java.sql package...

  1. 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.
  2. 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.
  3. 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.

梦屿孤独相伴 2024-08-14 18:26:28

COM。它最大的改进最终是.NET。

COM. Its biggest improvements ended up being .NET.

绝不放开 2024-08-14 18:26:28

某些对于系统编程至关重要的 java.io.File 方法会返回一个布尔值来指示成功或失败。如果这样的方法(例如,mkdirdelete)失败,您将根本无法找出原因。

这总是让我张大了嘴巴。

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.

桃扇骨 2024-08-14 18:26:28

Java 的日期/时间 API 很难使用。 java.util.Date 有几个构造函数来创建特定日期的实例,但它们都已弃用。应该使用 java.util.GregorianCalendar,但是它有一种非常烦人的设置字段的方式(认为 calendar.setField(GregorianCalendar.MONTH, 7) 而不是 calendar.setMonth(7) 会好得多)。最后一点是,大多数其他类和库仍然期望日期而不是日历,因此您必须不断地来回转换。

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.

时光瘦了 2024-08-14 18:26:28

并非不是胜利者,但值得荣誉提及;安卓。使用 Java 5 编程语言,但几乎没有任何 Java 5 语言功能。您得到的是带有前缀或后缀的整数常量,而不是枚举。

它不能完全决定它应该是面向对象的还是过程的。显示对话框就是一个很好的例子。几个带有自定义整数 ID 的回调,用于在对话框上显示调用,这有点旧 C API 的味道。然后你会得到一个带有链式方法的内部构建器类,它带有最糟糕的过度架构 OOP 的味道。

MotionEvent 类将 X 和 Y 坐标作为来自同一附件方法的绝对值和相对值。但无法检查它当前拥有什么样的坐标。

Android 确实是鱼龙混杂。

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.

追风人 2024-08-14 18:26:28

我将彻底扭转这个问题,并为一个其标准 API 大多丑陋的库命名一个漂亮的 API:OpenGL 的 Haskell 绑定。

原因如下:

  • 该库不是将所有内容都集中到少量标头中,而是在逻辑上组织成离散模块,其内容与 OpenGL 规范的结构平行。这使得浏览文档成为一种愉快的体验。

  • 成对的“开始/结束”函数被高阶过程取代。例如,代替

    pushMatrix();
      doSomeStuff();
      doSomeMoreStuff();
    弹出矩阵();
    

    你会说

    preservingMatrix $ 做
        做一些事情
        多做一些事
    

    绑定的语法强制执行库的约定,而不是让您手动执行。这也适用于四边形、三角形、直线等的绘制基元。当然,所有这些都是异常安全的。

  • getter 和 setter 被惯用的“StateVars”取代,使得读写操作更加对称。

  • 多个版本的函数被多态性和额外的数据类型取代。例如,您不用使用两个浮点值调用 glVertex2f,而是使用 Vertex2 GLFloat 类型的值调用 vertex

参考资料:

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 call vertex with a value of type Vertex2 GLFloat.

References:

乙白 2024-08-14 18:26:28

Direct3D!

毫无疑问,Direct3D 5 之前的旧界面非常丑陋:

// 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); 

现在还不错 - 只需 Microsoft 10 版本就可以正确使用...

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...

烏雲後面有陽光 2024-08-14 18:26:28

我会说MFC、ATL 和WTL。所有这 3 个库都使用过多的匈牙利表示法,无缘无故地重新定义数据类型(一遍又一遍地重新定义 CString),并且随着 Visual Studio 的每个版本的不同而发生变化。

我喜欢COM。早在 .NET 开发之前,它就提供了面向组件的体系结构。然而,COM 扩展为 DCOM、它的许多包装器(如 ATL)以及普遍缺乏全面的文档使其成为我在工作中必须处理的最丑陋的 API。

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.

溇涏 2024-08-14 18:26:28

肯定不是最丑的。可能有很多,但 Flex 在地狱中占有特殊的地位。具体来说,UIComponent 与 Sprite 相比,感觉就像用电锯削苹果一样。我相信通过使用更轻量级的对象和 mixin 风格的功能(类似于 Dojo 在 Javascript 端的工作方式),Flex 将会得到很大的改进。

ECMAScript/Actionscript Date 类几乎是倒退且无用的。每当我需要做一些比向日志添加时间戳更复杂的事情时,这都是一个持续的痛苦。他们需要更多的解析选项(例如,指定输入格式的能力),以及更好的时间管理,如智能增量、便利函数等……

C++ STL 库(以及一般的模板)虽然明显有用,但一直感觉简直丑陋。但没有改进建议。他们工作。

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.

天荒地未老 2024-08-14 18:26:28

Oracle 的 ProC、ProAda、Pro*this-that-the-other 等。它们是 C、Ada 和 Fortran 的预处理器前端,我想,也许还有其他一些,可以让你将 SQL 塞进源代码中。

他们确实还有一个工作得更好、更灵活的库。

(那是十多年前的事了,我不知道他们现在在做什么,不过如果还是一样我也不会感到惊讶,只是为了不破坏人们的代码。)

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.)

白首有我共你 2024-08-14 18:26:28

嗯,大约 20 年前它是一个著名的库,但我认为最初的 btrieve 数据引擎拥有有史以来编写的最糟糕的 api。几乎所有事情都经过一次调用,其中每个参数都包含不同的值,具体取决于您实际执行的调用(一个参数是一个标志,告诉系统您是否要打开文件、关闭文件、搜索、插入等)。那时我很喜欢 btrieve,但我花了很长时间制作一个好的抽象层。

如果不强迫所有事情都集中在一次调用中,它可以很容易地得到改进。不仅这个调用很丑陋,而且程序员还负责分配、传入和释放位置块…… btrieve 使用一些内存来跟踪打开的文件句柄、位置等。另一项改进是允许 ascii定义索引时要使用的文本。索引必须通过复杂的二进制表示来指定。

此致,
大学教师

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

全部不再 2024-08-14 18:26:28

许多 CRT 库函数的命名很糟糕或模糊,可能是由于当时遗留的编码限制,因此需要频繁使用 F1 键才能找到正确的函数并提供正确的参数。

我已经使用 CRT 功能一段时间了,但我仍然发现自己经常按 F1。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文