JavaAPI最佳实践指尖上的代码go

身为软件开发工程师,我们每天都编写代码。然而不可思议的是,这些代码会一直“存在于真空中”,与所有其他开发的软件隔离开来。在软件工程领域,“站在巨人的肩膀上”这个比喻从来没有像今天这样合适。GitHub、StackOverflow、MavenCentral以及所有其他代码仓库、支持库和软件库都唾手可得。

软件是由应用程序编程接口(API)构建的——我们每天都在使用Maven或Gradle等工具引入的JDKAPI和数量众多的依赖API。如果你走到一个待满了软件工程师房间里,问他们是不是API开发者,他们的回答通常是:“不,我们不是”。这是不正确的!任何曾经亲手设计过publicclass或定义过publicmethod的人都应该认为自己是API开发者。这里故意使用了“手工设计(craft)”这个词。软件工程往往会被工程的形式所掩盖,但某种程度上API设计更像是一门艺术,而非一门精确的科学,需要依赖打磨多年的创造力和直觉。

2.API的特点

2.1容易理解

从Maven下载了函数库,接下来该从哪个class下手?如果不能凭直觉找到入口,可能就算不上一个成功函数库。

API开发者应该充分考虑API的入口。完整的文档对于帮助使用API使用者了解全局非常有用,但理想情况下我们希望确保开发者使用API时遇到的阻碍降到最低。因此,应该在文档的开始部分为开发人员提供最少的步骤。好的API会从入口公开其最重要的功能,帮助开发者掌握API的主要功能。然后,开发人员可以根据需要通过外部文档了解更高级的功能。

2.2文档完备

既然是提供给他人使用,那么完备的文档很重要。接下来会介绍如何编写高质量、详尽的JavaDoc文档。

2.3一致性

一个好的API不应该让用户在使用过程中感到意外,比如前后概念不一致。在讨论一致性时,我们的意思是确保在API中重复相同的概念,而不是引入不同的临时概念。比如下面的例子:

重点是建立一套团队中公用的词汇表和“备忘清单”,并在整个SDK中通过这种方式保证一致性。

2.4适用性

在开发API的过程中,必须确保API为目标用户提供合适的抽象级别。可以从两方面考虑:

JDK中的CollectionAPI就是最佳范例。使用者不用关心存储空间的阈值、扩容策略、hash冲突策略、装载系数、缓存策略等。只要调用、存储就可以了。开发人员不必理解内部工作机制就可以使用集合框架实现自己想要的功能。

2.5约束

开发新API的过程可能非常快。但我们应该在心里提醒自己,每个新的API都有可能承诺终身支持。

我们对API决策的实际成本在很大程度上取决于我们的项目和社区——一些项目乐于不断地进行突破性的改进,而其他项目(如JDK本身)则希望尽可能少地出现突破性改进。而大多数项目则处于中间地带,采用一种语义版本控制方法,在主版本删除API之前小心地弃用它们。

有些项目甚至提供了各种标记区分experimental、beta和preview功能,以便在最终锁定API之前寻求反馈。一种通常的做法是,对新引入的实验性API加上@Deprecated,当它们已经就绪的时候再把注解拿掉。

2.6可扩展性

每次API的决定,都让自己的余地变得更小。所以尽可能从SDK的长远发展来考虑。

3.API即约定

API更像是一种约定,为其他开发者承诺了某种功能。我们需要不断改进API实现,每次改进都深思熟虑。每次冒险增加新功,都可能给下游API的使用者带来bug风险。

4.必要性

最容易维护的API就是不使用API,因此证明API中每个方法和类存在的必要性是一件十分重要的事情。在设计API的过程中,我们要时刻问这样的问题:“它真的是必须的吗?”只有不断地提问和证明,才能确保留下的函数都是必须的,而且是值得长久保留的。

5.吃自己的狗粮

作为API开发者,如何保证自己设计的API能够满足现实需求?我们需要用API使用的视角而非自己的角度来看待这个问题。要做到这点,最好的方法就是“吃自己的狗粮”,在整个开发过程中不但自己要使用自己开发的API,更重要的是还要确保有“真实世界”中可信赖的用户使用你的API。

引入真实用户的价值,在于能够避免自己失去限制,仅凭自己对API的理解加入高级功能。“真实世界”的用户可以平衡这点,让我们能够确保只修复那些真正的问题。

6.API文档

JavaDoc是API的说明书。开发API的工程师需要确保JavaDoc的完整性,包括类功能说明、函数功能说明、期望的输入格式、输出结果、异常等等。虽然起到了说明书的作用,但是很重要的一点,它既不是详细的开发指南也不讨论实现细节。

JavaDoc的价值不仅为其他开发人员提供价值,还能为我们提供帮助。JavaDoc对API进行了过滤,只展示标记了public的方法。如果我们定期生成JavaDoc,就能审查API中JavaDoc缺失、遗漏实现类、缺少外部依赖及其他没有想到的问题。

Java项目大多基于Maven或Gradle构建,生成JavaDoc非常方便,可以分别运行mvnjavadoc:javadoc或者gradlejavadoc。养成定期生成JavaDoc的好习惯(可以设置在错误或报警时生成失败),能够确保及早发现API中的问题,提醒自己在哪些地方还需要更详细的JavaDoc。

6.1JavaDoc中的行为约定

JavaDoc一个未被充分利用的方面是通过它来定义行为约定。关于行为约定的一个例子是Arrays.sort()方法,该方法保证是“稳定的”(即不对相等的元素重新排序)。想要通过API本身信息没有办法很容易地做到这一点(除非使API变得难以使用,比如Arrays.stableSort()),但JavaDoc提供了最理想的实现场所。

然而,如果我们添加行为约定作为API的一部分,那么它就会成为API的一部分,就像API本身一样。我们不能在API层次改变行为约定,这么做可能会给API下游的使用者带来问题。

6.2JavaDoc标签

JavaDoc附带了许多标签,例如@link、@param和@return。它们为JavaDoc工具提供了更多的上下文,并在生成HTML时提供更丰富的体验。在编写JavaDoc时,将这些内容牢记在心是非常有用的,可以确保它们在需要的时候用到。要了解何时使用这些标记,请参阅“J2SE参考文档”中的“标记注释”部分。

7.一致性

现在很少有软件由一个人开发。即便是,人类也会反复无常,今天认为伟大的东西第二天可能会被认为是大错特错。幸运的是,在设计API的时候,我们清楚地记录了以publicAPI的形式所做的决策,并且很容易发现什么东西背离了这种约定。

API具备一致性,短期的好处是可以减小让用户感到沮丧的风险。长期来看,可以让用户在使用API功能的时候凭直觉就知道该如何使用。

关于一致性需要考虑:

7.1返回值

理想情况下,所有返回集合的API都应该保持一致,只使用几个集合类而不是所有可能的类。返回集合的一个很好的子集可以是List、Set和Iterator(这种情况下,绝对不要用Collection、Iterable和Stream。但是请注意,这些都是有效的返回类型——仅在本例中,它们不在考虑的子集范围中)。对应的,如果(针对某种类型)API在大多数情况下都不返回null,那么最好不要为该返回类型返回null。

7.2方法命名模式

7.3参数顺序

重载API以接受不同数量或类型的参数时,应该始终确保参数顺序的一致性和逻辑性。在某些情况下,我们会按照某种逻辑分组的形式将参数传递给方法。这时,引入封装这些参数的中间类型可能是有意义的。这样能够减少API后续版本中需要重载方法以接受更多参数的风险。这也有助于我们达成API可扩展这个目标。

8.最小化API

开发更强大的API是API开发者的本能——提供更多而不是更少的便利。但是这会导致两个问题:

所有API开发者都应该从了解他们负责的API所需的关键用例开始,设计API并支持这些用例。应该抵制增加更多便利的冲动(自认为通过增加新API使开发人员少写几行代码)。

话虽如此,需要澄清一点,便捷的API在任何好的API中都扮演着至关重要的角色,尤其是让API变得易于理解方面非常有用。挑战在于,决定什么应该被作为有价值的东西被接纳,什么东西不能“证明自己的价值”应该拒绝。JDKAPI中一个很好的例子是List.add(Object),可以避免开发人员必须总是调用List.add(int,Object)。

在与OracleJDK团队的工程师StuartMarks讨论这个主题时,他发表了以下见解:

另一方面,我也见过一些API因为“便捷性”而陷入困境。这里有一个假设的例子。假设有一个提供了bar()和foo()操作的API。它们可以单独使用,但经常会放在一起使用。这时,可能有一个bf()操作,它能同时做这两件事。目前为止没有问题。

现在,假设你增加了一个mumble()操作,需要分别调用bf()和mumble()因此需要更方便的API,比如bfm()。好吧,如果你不需要foo()怎么办?再提供一个bm()怎么样?另外,还可以再增加一个fm()。现在你有了7个方法,其中一半以上是三个基本操作的组合。也许这是好事,也许不是;当然,这么干可能会使API膨胀。在某种程度上,有足够多的便捷API,它们往往会比基本操作更方便。现在,主要是风格问题。可以只执行基本操作,交给用户来组合,这是JDK的风格。或者你可以提供所有的组合,这样一旦用户了解他们的系统,所需的任何组合都已经有了。后者的例子可以参考EclipseCollections。9.防止泄露

防止“泄露”很重要。要确保实现类、属于外部依赖项的类不在publicAPI中以返回类型或参数类型的形式暴露出来。应该采取适当的措施来确保这些类被隐藏。

隐藏实现类主要有两种方法:

10.理解protected

Java中的protected关键字经常被误解,甚至被滥用。简而言之,protected成员用于与子类通信,而public成员用于与调用者通信。

在某些情况下,protected在API开发人员工具箱中可能是非常有用的工具,但是除非从一开始就将它设计成一个类,否则它经常被错误地使用。导致看起来类是可扩展的,但实际上并不是。实际上,有时候protected关键字看做感染class的一种病毒,用户越来越多地要求API中private方法变成protected(或public)时,为class加上protected满足他们的需求。

此外,API开发者需要理解,protected方法和publicAPI一样,也是其中的一部分。这一点常常被API开发的新手误解,最终造成伤害。

11.有意的继承

作为一名API开发者,我们必须保持一种平衡,既能为开发人员提供功能和灵活性以完成他们的工作,又让自己的API具有长期可扩展性。确保我们能够保持一定程度的控制,一种方法是使用final关键字。通过将我们的类或方法设置为final,我们向开发人员发出的信号是,此时他们不能扩展或覆盖这些特定的类和方法。

final对API开发者的价值是基于这样的事实,我们的API不是完美的。相比联系API开发者修复问题,更多的开发人员会绕过我们的问题来改进自己的代码,这样他们就可以继续解决下一个问题。通过这种方法,他们只会给自己提出新问题,最终会给我们这些API开发者提新需求。理想情况下,当API使用者遇到一个final类或方法时,会联系我们讨论他们的需求,这将引出一个更好的API。明智的做法,不要在发布版本后再标记final,毕竟final关键字总是可以在以后的版本中删除。

12.向后兼容

另一种是由开发人员不知道所做更改带来的影响造成的API意外中断。这种情况比理想种的情况更常见,而且往往很难注意到。有一些工具可以监视API变化,并通知已经引入的向后不兼容情况。Revapi就是这样一个工具,我在微软参与的几个项目中它都起到了很好的效果。

为什么要关心向后的兼容性呢?就是因为破坏兼容性对我们的用户来说真的很痛苦。有一些项目由于过于快速和随意地应对向后兼容性而遭受了相当严重的后果。

13.不要返回null

TonyHoare称null引用的发明(他创造的东西)是他的“十亿美元错误”。在Java中,我们已经非常习惯于通过返回null来处理一些错误条件。所以,对所有内容进行null检查成为了第二天性。但在许多情况下,有比直接返回null更好的方法。一些常见的用法可参阅下表:

通过保证向API调用者返回非null值,用户在他们的代码中不必到处写检查null的代码。然而重要的是,如果采用这种方式,必须确保在整个API中保持一致。如果API不能始终如一地应用模式,就很容易损害使用者对它的信任(如果不这样做,会导致用户遇到意外的空指针异常)。

译注:TonyHoare爵士,计算机领域专家,图灵奖得主,发明了快速排序算法。

14.理解何时使用Optional

Java8引入Optional是为了减少可能出现的空指针异常,因为当一个方法返回Optional时,能保证返回值非null。然后由API的调用者决定返回的Optional包含元素还是为空。换句话说,Optional可以看作最多包含一个元素的容器。

Optional返回类型最适用于以下情况:

假设有publicOptionalgetFastest(Listcars)方法,Optional在这种情况下提供了许多便捷的方法,下面展示了其中一些方法:

上面展示了正确调用API返回Optional的示例。如果大多数API使用者像下面这样处理Optional返回值,则有可能认为这是一个检查空引用的面向对象版本,并且可能不如返回null更好(或者更直观)。

API返回Optional有两条终极规则:

15.总结

无论为自己使用编写API,还是为组织中的其他人编写API,或者更广泛地将其作为开源项目或商业开发库的一部分,思考本文中列举的内容将有助于指导读者产出更高质量和更专业的结果。这不应该被简单地看作是“更多的工作”,更应该看成是对自己的一种挑战,即专注于为我们的用户提供一个愉快的、功能丰富的、高效的API。

THE END
1.自己动手制作狗粮的方法宠物用品圣宠宠物官网自己动手制作狗粮的方法,下面圣宠小编来给大家介绍下如何自己动手DIY制作狗粮? 材料: 胡萝卜、土豆、玉米面、鸡蛋。 做法: 1、先把胡萝卜,土豆刨成丝。 2、把玉米面用清水调稠,打入鸡蛋。再搅拌均匀。 3、然后把锅里放入清水烧开,放入胡萝卜,土豆丝,(因为这个比较难熟一点)等胡萝卜、土豆好了之后,再放入玉米...http://www.petjm.com/chongwuyongpin/3790.html
2.自己做狗粮的简单方法自己做狗粮的简单方法简单是幸福 精选回答 1、可以按照蔬菜和肉一比一的比例调配狗粮,首选先把蔬菜和肉剁碎煮熟,然后把它们小颗粒,或者小圆球,需要注意的是狗粮里面不要加入任何调味品,只要保证制作狗粮足够干净就可以了,然后把狗粮放入烤箱中烘烤,一般烘烤半个小时左右,温度180摄氏度,狗粮就制作好了。 2、可以...https://edu.iask.sina.com.cn/jy/iMkMwCTX9v.html
3.用对待情人的方法和孩子在一起十、用心动手做礼物 情人,总会用心选礼物,甚至动手做礼物,最近看到有朋友把微信书精心挑选打印出来,撒了我满满一肚子狗粮,也看到亲自做巧克力的,做定制胸针耳环戒指的(这个可以找小丸子妈妈)。 孩子,很多人都喜欢到玩具店买礼物,或者在某宝上挑选同款,也有些送书送券送红包,找机会亲手为孩子做一些礼物吧,做一段视...https://www.jianshu.com/p/e5c60191f164
4.对付男人的最好办法就是“以爆制爆”综艺免费在线观看单身族要时刻激励自己 单身最大的困扰是孤独 一个人吃自助VS一个人做手术 《单身情歌》唱出了单身的理由 要想告别单身 选择偶像很重要 现代人的生活到底有多快 拖延症都是古代人遗传下来的 坏人都是没有选择困难症的 教你如何一秒治好强迫症患者 社交恐惧症最喜欢的季节是夏天 如何以最有效的方法杜绝校园贷 熟...http://www.qiyi.com/v_19rr9n2j40.html
5.狗粮泡喂方法狗粮泡喂方法 1、泡狗粮的水温大概在40度到60度之间; 2、泡狗粮的水量最好刚没过狗粮,尽量保持1:1的比例; 3、泡狗粮的时间不要太长,一般用手捏狗粮没有硬的芯即可。 4、注意事项:热水时要注意安全,不要烫伤自己,泡狗粮的水温也不要太高,避免烫到狗狗。http://www.wnl7.com/shenghuo_3032429/
1.从狗粮到吃饭,如何让宠物狗降饮食(以狗狗为主)狗粮的保质期和存放方法都是非常重要的。需要将狗粮放在干燥、通风的地方保存,并注意狗粮的保质期,及时更换新的狗粮。八、自己动手做狗饭如果有时间和精力,也可以尝试自己为宠物制作饭菜。需要根据宠物的需求和健康状态选择食材,同时注意烹调方式和食材搭配。https://m.mcbbbk.com/newsview570635.html
2.家庭教育经验分享其实这个一个极端错误的做法,孩子的学习不仅在书面上,孩子在生活中,我们要给孩子提供自己动手的机会,孩子自己做出来的东西是孩子最为自豪礼物。我们父母要做的是给孩子指明方向,告诉孩子解决问题的方法。对待孩子,我们要平起平做,不要以自己的喜好来批评孩子,父母要多鼓励孩子,给孩子讲解道理。https://www.jy135.com/edu/67.html
3.大班数学区区域活动方案(精选10篇)2、迁移经验,引导幼儿在生活中继续运用统计的方法。 大班数学区区域活动方案 4 教材分析: 让幼儿利用各种风车、花朵等图片,亲自动手设计规律,摆一摆,贴一贴,做一幅图案。一方面巩固所学的知识,另一方面可以自己创造规律,体会数学学习的乐趣。幼儿完成自己的创作后,将作品贴出来欣赏,感觉数学美、形式美,同时感受创新的...https://www.ruiwen.com/fangan/5374696.html
4.一刻钟带你读完最近最棒的创业思维书:《从0到1》创业事实上,同一产业内,企业间的利润差异并不比产业间的利润差异小。其次,波特的价值链分析虽然提 供了寻找竞争优势的有效方法,但并没有指出如何根据重要性来确定企业的核心竞争优势。 垄断者谎言 VS 非垄断者谎言 垄断者为了规避政府审核打击等,往往会通过各种方法隐瞒自己的垄断实质,以便让自己能够在一边做一个“安静...https://www.open-open.com/news/view/1893651
5.《ZerotoOne》读书笔记其实当一个企业做大做强之后,有意无意的,也会制造出竞争出来,这除了有本人前一篇文章《成功企业垄断,失败企业竞争》描述的“垄断着谎言”这个原因: 垄断者为了规避政府审核打击等,往往会通过各种方法隐瞒自己的垄断实质,以便让自己能够在一边做一个”安静的美男子“大把大把的数钞票。所以Google就把自己称作是一个...https://blog.csdn.net/huluedeai/article/details/51474063
6.步骤图自制狗粮的做法自制狗粮的做法步骤自制宠物食品自制狗粮 家有两只法斗,为了吃的更好更健康,改良了老妈的方法,省去了玉米面,加上了鸡胸肉,做出来更香,也更好看。肉菜比例1:1,可以根据狗子自身情况加肉或菜。肉和菜的种类都可以根据自家小崽子喜欢吃的改变。没有加玉米面,最后上蒸笼的时候散了两个,又用玉米面再加工了下。https://m.xiachufang.com/recipe/104526427
7.◆六年级了,作文写不好,还有办法吗?小学教育小学教育我为她随手删改了部分,同时写一个② ,要求她自己补充、修改。) 走过一条小径,来到一个门柱(“门柱”说法不对,我随手为她改成“大门”)前,上面刻着许多字,老师问我们,这个叫什么,我们纷纷摇头,老师笑了,说:“这个叫牌坊,孔庙里都有的,有木头做的,有的是石头做的。”(句式不统一,我随手为她删掉后面一句的...https://www.19lou.com/forum-263-thread-6641382983502624-1-1.html
8.家庭教育经验交流心得体会范文(通用14篇)比如写作业时,要在规定的时间内完成老师布置的作业,不能边做边玩;自己的作业自己检查,自己对自己负责,家长不得当老师;家长必须注重错题原因分析,不得只盯着分数。这样,让孩子觉得学习是自己的事情,好的学习习惯,可事半功倍。 二、讲究和孩子交流的方式方法...https://www.fwsir.com/xinde/html/xinde_20200708080253_441113.html