1e41f4b71Sopenharmony_ci# OpenHarmony API 设计规范
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci* 修订记录
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci| 版本           | 作者                | 时间       | 更新内容   |
6e41f4b71Sopenharmony_ci| -------------- | ------------------- | ---------- | ---------- |
7e41f4b71Sopenharmony_ci| v0.1,试运行版 | OpenHarmony API SIG | 2022年11月 | 初版发布 |
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci## 目的
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ciAPI是软件实现者提供给使用者在编程界面上的定义,API在很大程度上体现了软件实体的能力范围。
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ci同时,API定义的好坏极大影响了使用者的体验。
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci为了保障OpenHarmony生态健康发展,保证开发者使用体验,现制定OpenHarmony API设计规范。
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci## 范围
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ciOpenHarmony API主要包含了对应用开放的外部API,以及系统实现部分的内部API。
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci本设计规范主要用以约束以下API(不区分编程语言):
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci* OpenHarmony Public API
24e41f4b71Sopenharmony_ci* OpenHarmony System API
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci关于OpenHarmony API的分类,请参见[《OpenHarmony API治理章程》](https://gitee.com/openharmony/docs/blob/master/zh-cn/design/OpenHarmony-API-governance.md)。
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci## 接口设计目标
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci好的接口设计应该满足以下四点:
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ci* **可使用** (Operational):这一点是毋庸置疑的,接口必须要能完成它提供的能力。可使用是最基本的要求。
33e41f4b71Sopenharmony_ci* **富于表现力** (Expressive):与可使用同样重要的是,借助接口,使用者能够清晰表达他们想要做的事情。
34e41f4b71Sopenharmony_ci* **简单** (Simple):接口的设计要保证学习和使用简单,避免难于理解或者使用出错的情况发生。
35e41f4b71Sopenharmony_ci* **可预测** (Predictable):API应当始终一致的按照接口的定义完成使命。如果接口定义中不包含出错和异常的情况,那么这个API被调用任意多遍,都不应该发生任何异常。当然,如果实际情况是有可能出错或者失败的,那就要在接口定义中说明清楚什么情况下会出什么错,并准确的在相应的时机下返回对应的错误。
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci除此之外,API的设计还应该注意以下几点:
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ci* **API的稳定性和一致性是最重要的,API并非越多越好。**
40e41f4b71Sopenharmony_ci* **API命名应当容易理解,API命名并非越短越好。**
41e41f4b71Sopenharmony_ci* **API应当做好封装和抽象,并非暴露的信息或者能力越多越好。**
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ci从开发者使用API的阶段上来看,API应当做到:
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ci* **在学习阶段**
46e41f4b71Sopenharmony_ci  * 容易理解
47e41f4b71Sopenharmony_ci  * 容易上手
48e41f4b71Sopenharmony_ci* **在开发阶段**
49e41f4b71Sopenharmony_ci  * 富于表现力
50e41f4b71Sopenharmony_ci  * 简单
51e41f4b71Sopenharmony_ci  * 可预测
52e41f4b71Sopenharmony_ci* **在维护阶段**
53e41f4b71Sopenharmony_ci  * 行为稳定
54e41f4b71Sopenharmony_ci  * 容易维护
55e41f4b71Sopenharmony_ci
56e41f4b71Sopenharmony_ci## API设计概述
57e41f4b71Sopenharmony_ci
58e41f4b71Sopenharmony_ci为了使得规则尽可能通用,本规范不会涉及具体编程语言的差异,也不会涉及编码规约。这部分内容只要遵守相应的本地要求即可。
59e41f4b71Sopenharmony_ci
60e41f4b71Sopenharmony_ci从整体上来看,本规范将API规范分成**发布前评审规范**和**发布后评价**两个部分。
61e41f4b71Sopenharmony_ci
62e41f4b71Sopenharmony_ci* **发布前评审规范** :是对于API的最基本要求,所有API必须满足这些要求才能通过评审。
63e41f4b71Sopenharmony_ci* **发布后评价** :尽管在发布前已经做了很多的规则要求。但是仍然不能保证API是完美的。因此,API发布后仍然要保持对API的关注。发布后的审视将影响对API提供者的评价。
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ci以下是所有的API设计规则的罗列,以供快速索引,详细的说明在后文中展开。
66e41f4b71Sopenharmony_ci
67e41f4b71Sopenharmony_ci每一个OpenHarmony API提供者都应该熟悉以下规则。
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci### 发布前评审规范
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_ci* 易用性
72e41f4b71Sopenharmony_ci  * 规则1:符合编码规则
73e41f4b71Sopenharmony_ci  * 规则2:准确使用英语语法
74e41f4b71Sopenharmony_ci  * 规则3:合理使用缩写
75e41f4b71Sopenharmony_ci  * 规则4:准确使用对仗词
76e41f4b71Sopenharmony_ci  * 规则5:准确使用设计/架构模式
77e41f4b71Sopenharmony_ci  * 规则6:避免有争议的命名
78e41f4b71Sopenharmony_ci  * 规则7:参数类型合理
79e41f4b71Sopenharmony_ci  * 规则8:参数数量合理
80e41f4b71Sopenharmony_ci  * 规则9:参数顺序合理
81e41f4b71Sopenharmony_ci  * 规则10:返回值定义完备
82e41f4b71Sopenharmony_ci  * 规则11:异常定义合理
83e41f4b71Sopenharmony_ci  * 规则12:从正面表达
84e41f4b71Sopenharmony_ci  * 规则13:降低出错的可能性
85e41f4b71Sopenharmony_ci  * 规则14:避免顺序耦合
86e41f4b71Sopenharmony_ci  * 规则15:准确表达所有逻辑
87e41f4b71Sopenharmony_ci  * 规则16:注意封装
88e41f4b71Sopenharmony_ci  * 规则17:单一职责
89e41f4b71Sopenharmony_ci* 可用性
90e41f4b71Sopenharmony_ci  * 规则18:保证可靠性
91e41f4b71Sopenharmony_ci  * 规则19:功能完备
92e41f4b71Sopenharmony_ci  * 规则20:考虑权限与隐私保护
93e41f4b71Sopenharmony_ci  * 规则21:考虑并发环境
94e41f4b71Sopenharmony_ci  * 规则22:注意资源管理闭合
95e41f4b71Sopenharmony_ci  * 规则23:考虑重试逻辑
96e41f4b71Sopenharmony_ci  * 规则24:满足幂等要求
97e41f4b71Sopenharmony_ci  * 规则25:考虑设备通用性
98e41f4b71Sopenharmony_ci* 一致性
99e41f4b71Sopenharmony_ci  * 规则26:保证术语、概念一致性
100e41f4b71Sopenharmony_ci  * 规则27:保证设备间行为一致性
101e41f4b71Sopenharmony_ci  * 规则28:注意版本演进一致性
102e41f4b71Sopenharmony_ci  * 规则29:命名风格保持一致
103e41f4b71Sopenharmony_ci  * 规则30:参数顺序保持一致
104e41f4b71Sopenharmony_ci  * 规则31:同步/异步风格一致
105e41f4b71Sopenharmony_ci* 兼容性
106e41f4b71Sopenharmony_ci  * 规则32:注意新旧系统版本的兼容性
107e41f4b71Sopenharmony_ci  * 规则33:二进制向后兼容性
108e41f4b71Sopenharmony_ci* API资料
109e41f4b71Sopenharmony_ci  * 规则34:模块、命名空间、类需要包含基础说明
110e41f4b71Sopenharmony_ci  * 规则35:使用场景说明清晰
111e41f4b71Sopenharmony_ci  * 规则36:接口说明准确
112e41f4b71Sopenharmony_ci  * 规则37:参数说明准确
113e41f4b71Sopenharmony_ci  * 规则38:返回值/异常描述准确
114e41f4b71Sopenharmony_ci  * 规则39:元信息完备
115e41f4b71Sopenharmony_ci  * 规则40:风格一致
116e41f4b71Sopenharmony_ci* 组织方式
117e41f4b71Sopenharmony_ci  * 规则41:分层合理
118e41f4b71Sopenharmony_ci  * 规则42:模块划分合理
119e41f4b71Sopenharmony_ci  * 规则43:应用描述文件也是接口的一部分
120e41f4b71Sopenharmony_ci* 质量属性
121e41f4b71Sopenharmony_ci  * 规则44:性能满足要求
122e41f4b71Sopenharmony_ci  * 规则45:功耗设计合理
123e41f4b71Sopenharmony_ci  * 规则46:需要保证可测试性
124e41f4b71Sopenharmony_ci  * 规则47:考虑环境适应性
125e41f4b71Sopenharmony_ci
126e41f4b71Sopenharmony_ci### 发布后评价
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_ci* 稳定性
129e41f4b71Sopenharmony_ci  * 规则48:接口废弃率/变更率越低越好
130e41f4b71Sopenharmony_ci* 安全性
131e41f4b71Sopenharmony_ci  * 规则49:避免接口被滥用
132e41f4b71Sopenharmony_ci  * 规则50:避免接口被利用
133e41f4b71Sopenharmony_ci* 可维护性
134e41f4b71Sopenharmony_ci  * 规则51:能承载业务演进
135e41f4b71Sopenharmony_ci  * 规则52:功能扩展后不影响原先行为
136e41f4b71Sopenharmony_ci  * 规则53:文档和资料配套更新
137e41f4b71Sopenharmony_ci* 不可替代性
138e41f4b71Sopenharmony_ci  * 规则54:保证API之间正交
139e41f4b71Sopenharmony_ci* 开发者反馈
140e41f4b71Sopenharmony_ci  * 规则55:关注开发者反馈
141e41f4b71Sopenharmony_ci
142e41f4b71Sopenharmony_ci## 发布前评审规范说明
143e41f4b71Sopenharmony_ci
144e41f4b71Sopenharmony_ci### 易用性
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ci任何设计都应该考虑易用性。对于OpenHarmony API来说,易用性需要考虑以下几个方面:
147e41f4b71Sopenharmony_ci
148e41f4b71Sopenharmony_ci#### 命名
149e41f4b71Sopenharmony_ci
150e41f4b71Sopenharmony_ci* **规则1:符合编码规约**
151e41f4b71Sopenharmony_ci
152e41f4b71Sopenharmony_ciAPI的定义首先应当满足所属项目的编码规约,例如:大小写的定义、下划线、连字符规则、前缀规则等。
153e41f4b71Sopenharmony_ci
154e41f4b71Sopenharmony_ci对于OpenHarmony生态而言,可参考如下编码规约:
155e41f4b71Sopenharmony_ci
156e41f4b71Sopenharmony_ci* [《OpenHarmony JavaScript语言通用编程规范》](https://gitee.com/openharmony/docs/blob/master/zh-cn/contribute/OpenHarmony-JavaScript-coding-style-guide.md)
157e41f4b71Sopenharmony_ci* [《OpenHarmony C语言编程规范》](https://gitee.com/openharmony/docs/blob/master/zh-cn/contribute/OpenHarmony-c-coding-style-guide.md)
158e41f4b71Sopenharmony_ci* [《OpenHarmony C++语言编程规范》](https://gitee.com/openharmony/docs/blob/master/zh-cn/contribute/OpenHarmony-cpp-coding-style-guide.md)
159e41f4b71Sopenharmony_ci* [《OpenHarmony C&C++ 安全编程指南》](https://gitee.com/openharmony/docs/blob/master/zh-cn/contribute/OpenHarmony-c-cpp-secure-coding-guide.md)
160e41f4b71Sopenharmony_ci* [《OpenHarmony HDF驱动编程规范》](https://gitee.com/openharmony/docs/blob/master/zh-cn/contribute/OpenHarmony-hdf-coding-guide.md)
161e41f4b71Sopenharmony_ci* **规则2:准确使用英语语法**
162e41f4b71Sopenharmony_ci
163e41f4b71Sopenharmony_ciAPI命名只允许使用英语。通常,类的名称是名词,例如:`XXXManager`,`XXXService`,`XXXAnimation`等。函数通常是动词或动宾结构,例如:`start()`,`createUser()`,`startBoot()`等。
164e41f4b71Sopenharmony_ci
165e41f4b71Sopenharmony_ci对于一个名称叫做`Start`的类,或者一个叫做`ball()`的函数,通常是错误的做法。
166e41f4b71Sopenharmony_ci
167e41f4b71Sopenharmony_ci另外,还请注意及物动词和不及物动词,避免语法错误。对于动词,根据场景需要注意时态。例如:如果时机上就存在“开始传输”和“渲染完成”这些事件,就应该用上`transferStarted()`以及`renderDone()`这类的表达。
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ci* **规则3:合理使用缩写**
170e41f4b71Sopenharmony_ci
171e41f4b71Sopenharmony_ci应当尽可能避免使用缩写。缩写不仅仅是难于理解,还有一个问题是:一个缩写可能会有多个解释,在上下文信息不全的情况下,使用者会很难分辨。
172e41f4b71Sopenharmony_ci
173e41f4b71Sopenharmony_ci如果是大家都熟知的缩写是允许的,除此之外,应该尽量避免。尤其是,只有自己能明白的缩写,这是禁止的。
174e41f4b71Sopenharmony_ci
175e41f4b71Sopenharmony_ci* **规则4:准确使用对仗词**
176e41f4b71Sopenharmony_ci
177e41f4b71Sopenharmony_ci在语言表达中,同一个含义可能有很多个类似的词可以表达,例如:
178e41f4b71Sopenharmony_ci
179e41f4b71Sopenharmony_ci| 词语  | 近义词                                             |
180e41f4b71Sopenharmony_ci| ----- | -------------------------------------------------- |
181e41f4b71Sopenharmony_ci| send  | deliver, dispatch, announce, distribute, route     |
182e41f4b71Sopenharmony_ci| find  | search, extract, locate, recover                   |
183e41f4b71Sopenharmony_ci| start | launch, create, begin, open                        |
184e41f4b71Sopenharmony_ci| make  | create, set up, build, generate, compose, add, new |
185e41f4b71Sopenharmony_ci
186e41f4b71Sopenharmony_ci但在API命名中,应当注意对仗词的使用。
187e41f4b71Sopenharmony_ci
188e41f4b71Sopenharmony_ci例如,如果你使用了`add`就应该使用`remove`,而不是`destroy`。使用了`increase`就应该使用`decrease`,而不是`reduce`。
189e41f4b71Sopenharmony_ci
190e41f4b71Sopenharmony_ci下面是一些常见的对仗词:
191e41f4b71Sopenharmony_ci
192e41f4b71Sopenharmony_ci| 词语     | 对仗     |
193e41f4b71Sopenharmony_ci| -------- | -------- |
194e41f4b71Sopenharmony_ci| add      | remove   |
195e41f4b71Sopenharmony_ci| increase | decrease |
196e41f4b71Sopenharmony_ci| open     | close    |
197e41f4b71Sopenharmony_ci| begin    | end      |
198e41f4b71Sopenharmony_ci| insert   | delete   |
199e41f4b71Sopenharmony_ci| show     | hide     |
200e41f4b71Sopenharmony_ci| create   | destroy  |
201e41f4b71Sopenharmony_ci| lock     | unlock   |
202e41f4b71Sopenharmony_ci| source   | target   |
203e41f4b71Sopenharmony_ci| first    | last     |
204e41f4b71Sopenharmony_ci| min      | max      |
205e41f4b71Sopenharmony_ci| start    | stop     |
206e41f4b71Sopenharmony_ci| get      | set      |
207e41f4b71Sopenharmony_ci| next     | previous |
208e41f4b71Sopenharmony_ci| up       | down     |
209e41f4b71Sopenharmony_ci| new      | old      |
210e41f4b71Sopenharmony_ci
211e41f4b71Sopenharmony_ci* **规则5:准确使用模式**
212e41f4b71Sopenharmony_ci
213e41f4b71Sopenharmony_ci设计模式或者架构模式其实是软件行业的“行话”。既然是行话,就要正确的使用,否则别人就可能误解你的意思。
214e41f4b71Sopenharmony_ci
215e41f4b71Sopenharmony_ci因此,当你的接口中包含了`Strategy`,`Builder`,`Factory`,`Singleton`这类的词语时,请确保你准确理解了这些设计模式,并且正确使用了它们。
216e41f4b71Sopenharmony_ci
217e41f4b71Sopenharmony_ci另外,如果你确定的是在使用某个模式,那就准确的在名称上使用标准术语,不要随便修改词性或者打乱名称的词语顺序,这样使用者会更容易理解。
218e41f4b71Sopenharmony_ci
219e41f4b71Sopenharmony_ci* **规则6:避免有争议命名**
220e41f4b71Sopenharmony_ci
221e41f4b71Sopenharmony_ci命名要遵守的底线,是应该避免有争议的名称。这其中,包括但不限于任何违反法律、产生宗教争议、或导致种族歧视的词语。
222e41f4b71Sopenharmony_ci
223e41f4b71Sopenharmony_ci当然,使用脏话也是绝对禁止的。考虑到OpenHarmony会使能千行百业,对于避免有争议命名,需要思考得更多。
224e41f4b71Sopenharmony_ci
225e41f4b71Sopenharmony_ci#### 参数
226e41f4b71Sopenharmony_ci
227e41f4b71Sopenharmony_ci* **规则7:参数类型合理**
228e41f4b71Sopenharmony_ci
229e41f4b71Sopenharmony_ci通常,使用类类型参数比使用简单类型要更好。
230e41f4b71Sopenharmony_ci
231e41f4b71Sopenharmony_ci例如:对于下面的一组接口看似没什么问题:
232e41f4b71Sopenharmony_ci
233e41f4b71Sopenharmony_ci* `addPerson(string id, string name, int age)`
234e41f4b71Sopenharmony_ci* `removePerson(string id, string name, int age)`
235e41f4b71Sopenharmony_ci* `modifyPerson(string id, string name, int age)`
236e41f4b71Sopenharmony_ci
237e41f4b71Sopenharmony_ci但是这个定义不便于扩展,因为后期可能要新增参数。但是如果一开始就通过一个类类型`Person`来定义参数,则添加一个字段就很容易,并且,对于接口本身不用做任何改变。
238e41f4b71Sopenharmony_ci
239e41f4b71Sopenharmony_ci使用类类型而不是简单类型,还有一个好处是:参数数量会少,更容易记忆。
240e41f4b71Sopenharmony_ci
241e41f4b71Sopenharmony_ci* **规则8:参数数量合理**
242e41f4b71Sopenharmony_ci
243e41f4b71Sopenharmony_ci参数数量应当控制在7个以内。在更多的情况下,参数控制在3~5会更容易使用。
244e41f4b71Sopenharmony_ci
245e41f4b71Sopenharmony_ci在任何情况,参数的数量都不应当超过10个,这种接口通常很难记忆和使用。如果遇到这种情况,通常是对类型没有做很好的封装,或者是接口的实现逻辑包含太多的内容。请考虑拆解。
246e41f4b71Sopenharmony_ci
247e41f4b71Sopenharmony_ci* **规则9:参数顺序合理**
248e41f4b71Sopenharmony_ci
249e41f4b71Sopenharmony_ci在一些编程语言中,常常会以先输入参数、后输出参数的顺序来组织参数列表。
250e41f4b71Sopenharmony_ci
251e41f4b71Sopenharmony_ci但其实,如果能再根据参数的大小逻辑关系、参数的重要性来进行排序,那对于使用者来说,会更容易记忆和使用。
252e41f4b71Sopenharmony_ci
253e41f4b71Sopenharmony_ci比如,可选参数应该放到必选参数的后面,回调函数作为参数应该放到最后等。以`fs.readFile` 方法为例,路径参数是必填的,`encoding` 和 `flag` 是有默认值的。
254e41f4b71Sopenharmony_ci
255e41f4b71Sopenharmony_ci```js
256e41f4b71Sopenharmony_cifs.readFile(path[, options], callback)
257e41f4b71Sopenharmony_ci```
258e41f4b71Sopenharmony_ci
259e41f4b71Sopenharmony_ci```js
260e41f4b71Sopenharmony_cifs.readFile('/etc/passwd', (err, data) => {
261e41f4b71Sopenharmony_ci  if (err) throw err;
262e41f4b71Sopenharmony_ci  console.log(data);
263e41f4b71Sopenharmony_ci});
264e41f4b71Sopenharmony_ci
265e41f4b71Sopenharmony_cifs.readFile('/etc/passwd', {
266e41f4b71Sopenharmony_ci    encoding: 'utf-8',
267e41f4b71Sopenharmony_ci    flag: 'r+'
268e41f4b71Sopenharmony_ci}, (err, data) => {
269e41f4b71Sopenharmony_ci  if (err) throw err;
270e41f4b71Sopenharmony_ci  console.log(data);
271e41f4b71Sopenharmony_ci});
272e41f4b71Sopenharmony_ci```
273e41f4b71Sopenharmony_ci
274e41f4b71Sopenharmony_ci#### 返回值
275e41f4b71Sopenharmony_ci
276e41f4b71Sopenharmony_ci* **规则10:返回值定义完备**
277e41f4b71Sopenharmony_ci
278e41f4b71Sopenharmony_ci返回值定义完备需要做到:不能只考虑正常情况,对于接口的定义,也要考虑异常和无效的情况。要让开发者能合理处理。
279e41f4b71Sopenharmony_ci
280e41f4b71Sopenharmony_ci例如:
281e41f4b71Sopenharmony_ci
282e41f4b71Sopenharmony_ci* 对于数字类型的返回值,要定义清楚返回的范围,什么情况下会出现极值。
283e41f4b71Sopenharmony_ci* 对于布尔类型的返回值,要定义清楚什么时候返回`true`,什么时候返回`false`。
284e41f4b71Sopenharmony_ci* 对于数组或者集合类型的返回值,要定义清楚什么时候返回`null`,什么时候返回包含空元素的集合。
285e41f4b71Sopenharmony_ci* 对于枚举类型的返回值,要确保每种情况都准确定义了。
286e41f4b71Sopenharmony_ci* **规则11:异常定义合理**
287e41f4b71Sopenharmony_ci
288e41f4b71Sopenharmony_ci异常是特殊情况的返回,这通常意味着输入参数无效或者函数根本无法正常处理。
289e41f4b71Sopenharmony_ci
290e41f4b71Sopenharmony_ci对于同一个模块,或者同样的业务,在何种情况下返回错误值,在何种情况下直接返回异常,应该有统一的定义。
291e41f4b71Sopenharmony_ci
292e41f4b71Sopenharmony_ci另外,针对同样的异常情况下,应当返回同样的异常类型。
293e41f4b71Sopenharmony_ci
294e41f4b71Sopenharmony_ci保持一致可以很大程度上降低开发者的使用难度,并且避免使用出错。
295e41f4b71Sopenharmony_ci
296e41f4b71Sopenharmony_ci#### 其他
297e41f4b71Sopenharmony_ci
298e41f4b71Sopenharmony_ci对于易用性而言,除了上面提到的内容,还有一些推荐的做法,可以降低开发者的使用难度。
299e41f4b71Sopenharmony_ci
300e41f4b71Sopenharmony_ci* **规则12:从正面表达**
301e41f4b71Sopenharmony_ci
302e41f4b71Sopenharmony_ci从正面表达可以降低开发者的思考成本。
303e41f4b71Sopenharmony_ci
304e41f4b71Sopenharmony_ci通俗来说就是:接口的命名尽量使用肯定的词语,而不是否定方式的表达。因为否定表达很难理解。
305e41f4b71Sopenharmony_ci
306e41f4b71Sopenharmony_ci下面是一个反例:
307e41f4b71Sopenharmony_ci
308e41f4b71Sopenharmony_ci```js
309e41f4b71Sopenharmony_ciif (!isNotAccessible() || !isNotWritable() || !isNotPrintable())
310e41f4b71Sopenharmony_ci```
311e41f4b71Sopenharmony_ci
312e41f4b71Sopenharmony_ci如何接口都是正面表达,就更容易理解了,下面是推荐的做法:
313e41f4b71Sopenharmony_ci
314e41f4b71Sopenharmony_ci```js
315e41f4b71Sopenharmony_ciif (isAccessible() && isWritable() && isPrintable())
316e41f4b71Sopenharmony_ci```
317e41f4b71Sopenharmony_ci
318e41f4b71Sopenharmony_ci* **规则13:降低出错的可能性**
319e41f4b71Sopenharmony_ci
320e41f4b71Sopenharmony_ci调用者使用错误很大程度在于参数传递上。
321e41f4b71Sopenharmony_ci
322e41f4b71Sopenharmony_ci例如下面这个函数。第二个和第三个参数都是布尔值,这样使用者很容易记错顺序,或者搞不清楚该传入`true`还是`false`。
323e41f4b71Sopenharmony_ci
324e41f4b71Sopenharmony_ci```js
325e41f4b71Sopenharmony_cideclare function findString(text: string, isForward: boolean, isCaseSensitive: boolean): string;
326e41f4b71Sopenharmony_ci```
327e41f4b71Sopenharmony_ci
328e41f4b71Sopenharmony_ci通过枚举在定义上就避免这种错误存在的可能:
329e41f4b71Sopenharmony_ci
330e41f4b71Sopenharmony_ci```js
331e41f4b71Sopenharmony_cienum SearchDirection {
332e41f4b71Sopenharmony_ci    FORWARD,
333e41f4b71Sopenharmony_ci    BACKWARD
334e41f4b71Sopenharmony_ci}; 
335e41f4b71Sopenharmony_ci
336e41f4b71Sopenharmony_cienum CaseSensitivity {
337e41f4b71Sopenharmony_ci    SENSITIVE,
338e41f4b71Sopenharmony_ci    INSENSITIVE
339e41f4b71Sopenharmony_ci}; 
340e41f4b71Sopenharmony_ci
341e41f4b71Sopenharmony_cideclare function findString(text: string, direction: SearchDirection, sensitivity: CaseSensitivity): string;
342e41f4b71Sopenharmony_ci```
343e41f4b71Sopenharmony_ci
344e41f4b71Sopenharmony_ci很多时候,通过枚举代替布尔值以及整数表达的类型,可以减少使用者出错的可能性。
345e41f4b71Sopenharmony_ci
346e41f4b71Sopenharmony_ci再者,通过将多个参数组成一个类型的形式,也可以降低参数传递出错的可能性。
347e41f4b71Sopenharmony_ci
348e41f4b71Sopenharmony_ci* **规则14:避免顺序耦合**
349e41f4b71Sopenharmony_ci
350e41f4b71Sopenharmony_ci软件设计要尽可能保证高内聚,低耦合。这一点对于大型项目尤其重要。
351e41f4b71Sopenharmony_ci
352e41f4b71Sopenharmony_ci耦合表达了软件模块之间的依赖程度,耦合过深常常意味着架构设计没有做好。
353e41f4b71Sopenharmony_ci
354e41f4b71Sopenharmony_ci从一个软件静态结构或者分层架构图上可以看得出:如果模块之间的依赖关系比较少,上下层之间有明显的调用方向,则是比较好的设计。相反的,如果模块之间依赖关系非常复杂,或者上下层之间存在相反方向的调用链,则不是一个好的结构。
355e41f4b71Sopenharmony_ci
356e41f4b71Sopenharmony_ci耦合有很多种,对于接口来说,顺序耦合就是要注意的。顺序耦合是指:类中方法需要按照某个特定的顺序调用才能工作。
357e41f4b71Sopenharmony_ci
358e41f4b71Sopenharmony_ci类似下面这组命名的接口,很可能就是顺序耦合:
359e41f4b71Sopenharmony_ci
360e41f4b71Sopenharmony_ci```js
361e41f4b71Sopenharmony_cidoSomethingFirst()
362e41f4b71Sopenharmony_cidoSomethingSecond()
363e41f4b71Sopenharmony_cidoSomethingThird()
364e41f4b71Sopenharmony_ci```
365e41f4b71Sopenharmony_ci
366e41f4b71Sopenharmony_ci这种设计的问题在于:对于使用者的要求太高了,很容易用错。
367e41f4b71Sopenharmony_ci
368e41f4b71Sopenharmony_ci对于这类问题,通常可以使用`模板方法`设计模式来解决。
369e41f4b71Sopenharmony_ci
370e41f4b71Sopenharmony_ci* **规则15:准确表达所有逻辑**
371e41f4b71Sopenharmony_ci
372e41f4b71Sopenharmony_ci有些接口是用来查询信息的,例如`getUserAccount()`。有些是进行操作的,会修改数据,例如`createUserAccount()`。
373e41f4b71Sopenharmony_ci
374e41f4b71Sopenharmony_ci**永远不要在一个看起来是查询操作的接口里面去做修改数据的动作** ,因为这样使用者会非常的迷惑。
375e41f4b71Sopenharmony_ci
376e41f4b71Sopenharmony_ci更通用的来讲, **接口的名称应当表达它所做的所有事情** ,不要有所隐瞒。只有这样,在阅读代码的时候,才能更容易理解代码到底做了什么。
377e41f4b71Sopenharmony_ci
378e41f4b71Sopenharmony_ci如果接口包含了内容太多,很难通过几个单词描述清楚所做的所有事情该怎么办?对于这种情况,通常意味着需要将这个接口拆分成多个,因为这个接口不够“内聚”。
379e41f4b71Sopenharmony_ci
380e41f4b71Sopenharmony_ci还有一些情况下,大家在做某件事的时候,会本能的以为别人也有同样的背景认识。但事实往往并不是这样。在编程时也是一样。
381e41f4b71Sopenharmony_ci
382e41f4b71Sopenharmony_ci例如,对于一个描述编程语言的字段,可能会将其命名为`language`。这是因为大家默认认为已经在讨论编程语言了,但是`language`到底是编程语言还是国际化语言?是不是叫做`programmingLanguage`更好一些呢?
383e41f4b71Sopenharmony_ci
384e41f4b71Sopenharmony_ci当然,对于这一条还是要举一个反例,不要走到另外一个极端:如果类名或者namespace名称中已经明确带了一个前缀,在函数中就没必要再重复一遍了。毫无信息量的冗余是没有必要的。
385e41f4b71Sopenharmony_ci
386e41f4b71Sopenharmony_ci* **规则16:注意封装:不暴露实现细节**
387e41f4b71Sopenharmony_ci
388e41f4b71Sopenharmony_ci对于面向对象编程来说,大家都知道“封装”的重要性。
389e41f4b71Sopenharmony_ci
390e41f4b71Sopenharmony_ci这意味着,系统能力应当尽可能封装好实现细节,提供简洁的接口供调用者使用。
391e41f4b71Sopenharmony_ci
392e41f4b71Sopenharmony_ci这就好像冰山,埋在水里的部分不管多庞大,露在水面上的部分要足够的小,足够的简洁。这才是友好的界面(Interface)。
393e41f4b71Sopenharmony_ci
394e41f4b71Sopenharmony_ci封装的重要性,不仅仅是让开发者容易使用。其实也是使得开发者不容易出错。举一个生活中的例子:电子工程师将房间的电路线接好之后,只留一个开关按钮给到用户,这就是一个很好的封装。既避免了让用户理解复杂的电路结构(方便使用),也不会产生触电(出错)的风险。
395e41f4b71Sopenharmony_ci
396e41f4b71Sopenharmony_ci* **规则17:单一职责**
397e41f4b71Sopenharmony_ci
398e41f4b71Sopenharmony_ci一个 API 应当尽量只做一件事情,尽可能保持单一核心的职责。例如:
399e41f4b71Sopenharmony_ci
400e41f4b71Sopenharmony_ci```js
401e41f4b71Sopenharmony_ci// 不推荐
402e41f4b71Sopenharmony_ciview.fetchDataAndRender(url, templete);
403e41f4b71Sopenharmony_ci
404e41f4b71Sopenharmony_ci// 推荐
405e41f4b71Sopenharmony_cilet data = view.dataManager.fetchData(url);
406e41f4b71Sopenharmony_ciview.render(data, templete);
407e41f4b71Sopenharmony_ci```
408e41f4b71Sopenharmony_ci
409e41f4b71Sopenharmony_ci这么做的目的是因为:开发者可以根据需要,按最小单位来使用接口。也可以根据多个单一职责的组合,来进一步封装自己需要的业务逻辑。
410e41f4b71Sopenharmony_ci
411e41f4b71Sopenharmony_ci单一职责与注重封装性在一些情况下可能是矛盾的:如果提供了多个单一能力的接口,势必需要使用者关心多次的调用细节。
412e41f4b71Sopenharmony_ci
413e41f4b71Sopenharmony_ci在这种情况下,需要从封装的“层次”来考虑决定,接口提供给开发者的,到底是哪个层级的能力?面向高层次使用者的一件事,对于低一个层次来说,可能就是多件事情。
414e41f4b71Sopenharmony_ci
415e41f4b71Sopenharmony_ci### 可用性
416e41f4b71Sopenharmony_ci
417e41f4b71Sopenharmony_ci* **规则18:保证可靠性**
418e41f4b71Sopenharmony_ci
419e41f4b71Sopenharmony_ci操作系统所提供的接口,必须是完全可靠的。
420e41f4b71Sopenharmony_ci
421e41f4b71Sopenharmony_ci当然,可靠性不意味每次调用都是成功的。例如:在资源已经耗尽的情况下,应当给调用者合理的返回值或者异常。
422e41f4b71Sopenharmony_ci
423e41f4b71Sopenharmony_ci每个接口必须针对所有的情况进行准确的定义,并在相应的情况下按照定义的行为完成工作。
424e41f4b71Sopenharmony_ci
425e41f4b71Sopenharmony_ci没有按照预定行为返回结果,或者无故导致应用程序异常都属于不可靠行为。
426e41f4b71Sopenharmony_ci
427e41f4b71Sopenharmony_ci* **规则19:功能完备**
428e41f4b71Sopenharmony_ci
429e41f4b71Sopenharmony_ci每个特性或者能力在规划时,需考虑到功能的完备性。不应当出现:在支持的范围内,某个流程中断,或者某个选项缺失的情况发生。API设计者应当做好足够的验证和推演。
430e41f4b71Sopenharmony_ci
431e41f4b71Sopenharmony_ci即便操作系统的特性常常会伴随系统版本几年内才能完全迭代完备。但是,对于每一个特定版本,在其包含的范围内应当是闭合的,自洽的。这要求模块的设计者划分好版本迭代的边界。
432e41f4b71Sopenharmony_ci
433e41f4b71Sopenharmony_ci* **规则20:注意权限和隐私保护**
434e41f4b71Sopenharmony_ci
435e41f4b71Sopenharmony_ci任何涉及到用户数据、用户隐私的接口都必须做好权限限制和数据保护。
436e41f4b71Sopenharmony_ci
437e41f4b71Sopenharmony_ci对于权限控制,应当遵循以下几个原则:
438e41f4b71Sopenharmony_ci
439e41f4b71Sopenharmony_ci1. 完备性原则:一切穿透应用沙箱的行为都需考虑使用权限来管控。
440e41f4b71Sopenharmony_ci2. 最优粒度原则:一个权限只保护一类对象;一个接口只需申请最小粒度的权限。
441e41f4b71Sopenharmony_ci3. 清晰完整原则:权限定义中必须清晰说明保护对象、开放范围、敏感级别。
442e41f4b71Sopenharmony_ci4. 最小开放原则:一个权限仅对确有正当业务需求的应用开放,开放控制可通过权限来实现。
443e41f4b71Sopenharmony_ci
444e41f4b71Sopenharmony_ci对于隐私包含,应当遵守以下几个原则:
445e41f4b71Sopenharmony_ci
446e41f4b71Sopenharmony_ci1. API调用的返回仅包含必要的内容, 避免携带额外信息。
447e41f4b71Sopenharmony_ci2. API调用不允许获取、收集用户个人数据, 除非通过用户权限管控、由用户授权同意。
448e41f4b71Sopenharmony_ci3. API涉及跨应用调用时,如涉及个人数据向被调用者的披露,由调用方在隐私声明中说明披露的数据类型、数据接收者和数据使用目的。
449e41f4b71Sopenharmony_ci4. API涉及到用户敏感数据(如电话、通讯录、媒体等)访问时,需要使用system picker的机制,禁止API通过申请敏感权限方式访问。
450e41f4b71Sopenharmony_ci5. API开放禁止捆绑与所开放能力不相关的功能。
451e41f4b71Sopenharmony_ci
452e41f4b71Sopenharmony_ci* **规则21:考虑并发环境**
453e41f4b71Sopenharmony_ci
454e41f4b71Sopenharmony_ci保证所有的接口线程安全需要付出很大的代价(程序复杂度、性能影响),因此OpenHarmony API不必要求所有接口线程安全。只需根据需要选择即可。
455e41f4b71Sopenharmony_ci
456e41f4b71Sopenharmony_ci但是,对于设计上就是为了并发环境使用的接口,必须做好相应的设计和说明。
457e41f4b71Sopenharmony_ci
458e41f4b71Sopenharmony_ci当然,对于接口的内部实现中,应当尽可能避免出现线程不安全的问题发生。
459e41f4b71Sopenharmony_ci
460e41f4b71Sopenharmony_ci* **规则22:注意资源管理闭合**
461e41f4b71Sopenharmony_ci
462e41f4b71Sopenharmony_ci在一些情况下,有些接口包含了动态资源的申请。此种情况下,这些接口也需要考虑到资源的释放。
463e41f4b71Sopenharmony_ci
464e41f4b71Sopenharmony_ci如果申请的资源是直接返回开发者的,则需要提供相应的接口来释放资源。
465e41f4b71Sopenharmony_ci
466e41f4b71Sopenharmony_ci如果资源没有直接返回给开发者,则接口自身要考虑到资源的生命周期,以及释放的时机。
467e41f4b71Sopenharmony_ci
468e41f4b71Sopenharmony_ci对于有资源使用上限的情况,应当给开发者说明清楚。并且提供接口查询是否已经到达上限。
469e41f4b71Sopenharmony_ci
470e41f4b71Sopenharmony_ci对于独占资源更加应当注意资源的释放时机。
471e41f4b71Sopenharmony_ci
472e41f4b71Sopenharmony_ci* **规则23:考虑重试逻辑**
473e41f4b71Sopenharmony_ci
474e41f4b71Sopenharmony_ci对于可能失败的接口,应当考虑好给开发者相应的机制来重试。例如:对于相机这类独占的资源,一旦有某个进程使用了,其他进程就无法获取到。这种情况下,应当提供接口给开发者查询是否可用的接口。
475e41f4b71Sopenharmony_ci
476e41f4b71Sopenharmony_ci在一些情况下,为了避免开发者反复尝试,还需要提供给开发者状态监听的机制。
477e41f4b71Sopenharmony_ci
478e41f4b71Sopenharmony_ci并且,API要明确客户端调用失败后,能够发起重试的最大次数。
479e41f4b71Sopenharmony_ci
480e41f4b71Sopenharmony_ci* **规则24:满足幂等要求**
481e41f4b71Sopenharmony_ci
482e41f4b71Sopenharmony_ci在数学中,幂等用函数表达式就是:`f(x) = f(f(x))`。例如求绝对值的函数,就是幂等的,``abs(x) = abs(abs(x))``。
483e41f4b71Sopenharmony_ci
484e41f4b71Sopenharmony_ci计算机科学中,幂等表示一次和多次请求某一个资源应该具有同样的效果,或者说,多次请求所产生的影响与一次请求执行的影响效果相同。
485e41f4b71Sopenharmony_ci
486e41f4b71Sopenharmony_ci具体到实际场景:文件打开,或者的硬件资源使用,打开一次和打开多次其效果应当是一样的,不应该有其他副作用。当然,关闭,也是类似。
487e41f4b71Sopenharmony_ci
488e41f4b71Sopenharmony_ci* **规则25:考虑设备通用性**
489e41f4b71Sopenharmony_ci
490e41f4b71Sopenharmony_ciOpenHarmony是为多种不同类型设备设计的统一操作系统。
491e41f4b71Sopenharmony_ci
492e41f4b71Sopenharmony_ci考虑到设备的复杂性,接口的设计应当要能面对多种设备的适用性。例如:
493e41f4b71Sopenharmony_ci
494e41f4b71Sopenharmony_ci* 对于用户界面的控件,要考虑到不同屏幕尺寸的大小。
495e41f4b71Sopenharmony_ci* 对于数据的存储,要考虑到不同大小的存储空间。
496e41f4b71Sopenharmony_ci* 对于用户输入事件,要考虑不同的用户交互方式:触摸、语音、按键等。
497e41f4b71Sopenharmony_ci
498e41f4b71Sopenharmony_ci当然,有一些API只在某些特定设备上才有,例如:
499e41f4b71Sopenharmony_ci
500e41f4b71Sopenharmony_ci* 健康类传感器只在穿戴设备上有
501e41f4b71Sopenharmony_ci* 车控类接口只在车机设备上有
502e41f4b71Sopenharmony_ci
503e41f4b71Sopenharmony_ci这种情况,请参考[《SysCap使用指南》](../application-dev/reference/syscap.md),来标定API的适用范围。
504e41f4b71Sopenharmony_ci
505e41f4b71Sopenharmony_ci### 一致性
506e41f4b71Sopenharmony_ci
507e41f4b71Sopenharmony_ci* **规则26:保证术语、概念的一致性**
508e41f4b71Sopenharmony_ci
509e41f4b71Sopenharmony_ci为了容易理解,接口在命名和说明上应当注意术语和概念的一致性,不应该出现“方言”。基于场景的业务模型抽象,形成OpenHarmony的连贯、一致、自恰的业务概念。
510e41f4b71Sopenharmony_ci
511e41f4b71Sopenharmony_ci
512e41f4b71Sopenharmony_ci
513e41f4b71Sopenharmony_ci在这方面,应当遵循以下原则:
514e41f4b71Sopenharmony_ci
515e41f4b71Sopenharmony_ci1. 每个概念只应该有 **唯一** 的一个术语,同一个对象不应该有两个名称。
516e41f4b71Sopenharmony_ci2. 术语命名应该是 **贴切的** , **可解释** , **易理解** 。
517e41f4b71Sopenharmony_ci4. 术语的定义应当 **精准、无二义**。
518e41f4b71Sopenharmony_ci5. 对于业界通用术语, **不应该重新定义** ,应当遵循业内做法。
519e41f4b71Sopenharmony_ci
520e41f4b71Sopenharmony_ci总体来说,要避免随意添加术语概念,尽可能以[《OpenHarmony 技术术语集》](https://gitee.com/openharmony/docs/blob/master/zh-cn/glossary.md)为准。如果需要,可以在术语集中新增词条。
521e41f4b71Sopenharmony_ci
522e41f4b71Sopenharmony_ci* **规则27:保证设备间行为一致性**
523e41f4b71Sopenharmony_ci
524e41f4b71Sopenharmony_ci在默认情况下,同一个接口在不同的设备上应当保证行为是一致的。
525e41f4b71Sopenharmony_ci
526e41f4b71Sopenharmony_ci对于因为设备形态而导致的行为不一致,应当给予开发者充分的说明,并且提供相应的检查机制。
527e41f4b71Sopenharmony_ci
528e41f4b71Sopenharmony_ci* **规则28:注意版本演进一致性**
529e41f4b71Sopenharmony_ci
530e41f4b71Sopenharmony_ci在默认情况下,所有接口应当保证在系统版本演进的情况下,其行为是一致的。如果在新版本上出现了行为不兼容的变更,最低要求是需要对应用的目标版本做区分处理。
531e41f4b71Sopenharmony_ci
532e41f4b71Sopenharmony_ci简单而言:接口的行为变更不能影响已经开发完的应用。
533e41f4b71Sopenharmony_ci
534e41f4b71Sopenharmony_ci* **规则29:命名风格保持一致**
535e41f4b71Sopenharmony_ci
536e41f4b71Sopenharmony_ci在一些 API 设计的场景中,即使命名已经做到准确,但在有些情况下仍然可能碰到不一致的场景。比如,API 中经常会看到 picture 和 image、path 和 url 混用的情况,这两组词的意思非常接近,容易出现混乱。在指代同一内容时,应该使用相同的命名。
537e41f4b71Sopenharmony_ci
538e41f4b71Sopenharmony_ci例如,下面这些接口都是为了获取媒体资源,但是命名风格不一致。
539e41f4b71Sopenharmony_ci
540e41f4b71Sopenharmony_ci```js
541e41f4b71Sopenharmony_cideclare function getMediaAsserts(): Array<MediaAssert>;
542e41f4b71Sopenharmony_cideclare function getAudios(): Array<AudioAssert>;
543e41f4b71Sopenharmony_cideclare function getVideos(): Array<VideoAssert>;
544e41f4b71Sopenharmony_cideclare function getImages(): Array<ImageAssert>;
545e41f4b71Sopenharmony_ci```
546e41f4b71Sopenharmony_ci
547e41f4b71Sopenharmony_ci应该修改为:
548e41f4b71Sopenharmony_ci
549e41f4b71Sopenharmony_ci```js
550e41f4b71Sopenharmony_cifunction getMediaAsserts(): Array<MediaAssert>;
551e41f4b71Sopenharmony_cifunction getAudioAsserts(): Array<AudioAssert>;
552e41f4b71Sopenharmony_cifunction getVideoAsserts(): Array<VideoAssert>;
553e41f4b71Sopenharmony_cifunction getImageAsserts(): Array<ImageAssert>;
554e41f4b71Sopenharmony_ci```
555e41f4b71Sopenharmony_ci
556e41f4b71Sopenharmony_ci* **规则30:参数顺序保持一致**
557e41f4b71Sopenharmony_ci
558e41f4b71Sopenharmony_ci为了开发者便于理解,对于同一个命名空间或者是同一个模块来说,其成套的接口的参数顺序应当是一致的。
559e41f4b71Sopenharmony_ci
560e41f4b71Sopenharmony_ci例如:`deviceId`和`missionId`在单个接口中的顺序没有强制要求,但是在同一模块接口中必须保持顺序一致。
561e41f4b71Sopenharmony_ci
562e41f4b71Sopenharmony_ci```js
563e41f4b71Sopenharmony_cifunction getMissionInfo(deviceId: string, missionId: number): Promise<MissionInfo>;
564e41f4b71Sopenharmony_cifunction getMissionSnapShot(deviceId: string, missionId: number): Promise<MissionSnapshot>;
565e41f4b71Sopenharmony_ci
566e41f4b71Sopenharmony_ci// 正确
567e41f4b71Sopenharmony_cifunction getLowResolutionMissionSnapShot(deviceId: string, missionId: number): Promise<MissionSnapshot>;
568e41f4b71Sopenharmony_ci
569e41f4b71Sopenharmony_ci// 错误
570e41f4b71Sopenharmony_cifunction getLowResolutionMissionSnapShot(missionId: number, deviceId: string): Promise<MissionSnapshot>;
571e41f4b71Sopenharmony_ci```
572e41f4b71Sopenharmony_ci
573e41f4b71Sopenharmony_ci* **规则31:同步/异步风格一致**
574e41f4b71Sopenharmony_ci
575e41f4b71Sopenharmony_ci异步接口应该可以通过入参和返回值判断出来,风格上要保持统一。例如:
576e41f4b71Sopenharmony_ci
577e41f4b71Sopenharmony_ci```javascript
578e41f4b71Sopenharmony_ci// Callback形式
579e41f4b71Sopenharmony_cifunction getDefaultDisplay(callback: AsyncCallback<Display>): void;
580e41f4b71Sopenharmony_ci// Promise形式
581e41f4b71Sopenharmony_cifunction getDefaultDisplay(): Promise<Display>;
582e41f4b71Sopenharmony_ci```
583e41f4b71Sopenharmony_ci
584e41f4b71Sopenharmony_ci如果同时提供了同步和异步接口,可以在同步函数名后加上后缀`Sync`加以区别,例如:
585e41f4b71Sopenharmony_ci
586e41f4b71Sopenharmony_ci```js
587e41f4b71Sopenharmony_cifunction getDefaultDisplaySync(): Display;
588e41f4b71Sopenharmony_ci```
589e41f4b71Sopenharmony_ci
590e41f4b71Sopenharmony_ci如果只提供了同步接口,且返回值不是`void`,可以不用加后缀,例如:
591e41f4b71Sopenharmony_ci
592e41f4b71Sopenharmony_ci```js
593e41f4b71Sopenharmony_cifunction registerMissionListener(listener: MissionListener): number;
594e41f4b71Sopenharmony_ci```
595e41f4b71Sopenharmony_ci
596e41f4b71Sopenharmony_ci### 兼容性
597e41f4b71Sopenharmony_ci
598e41f4b71Sopenharmony_ci* **规则32:注意新旧系统版本的兼容性**
599e41f4b71Sopenharmony_ci
600e41f4b71Sopenharmony_ciAPI 变更的成本非常高,在设计之初就应该做尽可能完备的考虑。但是API变更始终是系统发展过程中不可避免的。
601e41f4b71Sopenharmony_ci
602e41f4b71Sopenharmony_ciAPI 变更要保证向后兼容原则,API 变更后,废弃的 API 要在源码和文档中显著标识 `deprecated`,并引导开发者使用变更后 API 。
603e41f4b71Sopenharmony_ci
604e41f4b71Sopenharmony_ci废弃的 API 要保证其功能仍然可用,至少保留5个版本。5个版本后,在充分告知开发者,并给与充分的时间供开发者修改后,可予以删除。
605e41f4b71Sopenharmony_ci
606e41f4b71Sopenharmony_ci* **规则33:二进制向后兼容性**
607e41f4b71Sopenharmony_ci
608e41f4b71Sopenharmony_ci二进制兼容,指版本演进后,开发者已有程序不用重新编译可正常链接、运行。这也意味着,二进制兼容是保证在版本升级的情况下,对象实例的内存布局不会发生变化。
609e41f4b71Sopenharmony_ci
610e41f4b71Sopenharmony_ci以C++接口为例,常见破坏二进制兼容的API变更包括:
611e41f4b71Sopenharmony_ci
612e41f4b71Sopenharmony_ci1. 任何API元素删除
613e41f4b71Sopenharmony_ci2. 添加新的虚函数
614e41f4b71Sopenharmony_ci3. 改变类的继承
615e41f4b71Sopenharmony_ci4. 改变虚函数声明时的顺序
616e41f4b71Sopenharmony_ci5. 添加新的非静态成员变量
617e41f4b71Sopenharmony_ci6. 改变非静态成员变量的声明顺序
618e41f4b71Sopenharmony_ci
619e41f4b71Sopenharmony_ci由于C接口相比C++接口在二进制兼容性上有天然的优势,所以OpenHarmony的Native API推荐使用C接口定义。
620e41f4b71Sopenharmony_ci
621e41f4b71Sopenharmony_ci### API资料
622e41f4b71Sopenharmony_ci
623e41f4b71Sopenharmony_ciAPI的很多信息需要通过文档和资料进行说明,因此,配套的这些内容也应当做好质量管理。
624e41f4b71Sopenharmony_ci
625e41f4b71Sopenharmony_ci* **规则34:模块、命名空间、类、函数需要包含基础说明**
626e41f4b71Sopenharmony_ci
627e41f4b71Sopenharmony_ci每个模块、命名空间、类和函数都需要包含基本的说明。
628e41f4b71Sopenharmony_ci
629e41f4b71Sopenharmony_ci对于关键模块、复杂模块需要有详细的说明。
630e41f4b71Sopenharmony_ci
631e41f4b71Sopenharmony_ci说明采用英文的形式。
632e41f4b71Sopenharmony_ci
633e41f4b71Sopenharmony_ci* **规则35:使用场景说明清晰**
634e41f4b71Sopenharmony_ci
635e41f4b71Sopenharmony_ci所有接口应当提供示例代码,覆盖常见使用场景。
636e41f4b71Sopenharmony_ci
637e41f4b71Sopenharmony_ci复杂接口需要详细说明使用场景。可以在接口的说明上增加详细教程的链接。
638e41f4b71Sopenharmony_ci
639e41f4b71Sopenharmony_ci* **规则36:接口说明准确**
640e41f4b71Sopenharmony_ci
641e41f4b71Sopenharmony_ci接口说明的文字不应该出现拼写错误或者错别字。
642e41f4b71Sopenharmony_ci
643e41f4b71Sopenharmony_ci所有代码示例应当保证能够正常运行。如果接口在不同版本上存在行为不一致,则需要针对每种情况做详细说明。
644e41f4b71Sopenharmony_ci
645e41f4b71Sopenharmony_ci对于废弃接口,需做明确标记,并做好替代接口说明。
646e41f4b71Sopenharmony_ci
647e41f4b71Sopenharmony_ci* **规则37:参数说明准确**
648e41f4b71Sopenharmony_ci
649e41f4b71Sopenharmony_ci对于API的每一个参数,都应该说明清楚。例如:
650e41f4b71Sopenharmony_ci
651e41f4b71Sopenharmony_ci* 如果是非简单类型,则需说明清楚是否允许参数为空
652e41f4b71Sopenharmony_ci* 如果是枚举类型,则需针对每个枚举值说明清楚使用场景
653e41f4b71Sopenharmony_ci* 如果是可选参数,则需说明清楚什么时候该传参,什么时候可省略
654e41f4b71Sopenharmony_ci
655e41f4b71Sopenharmony_ci**规则38:返回值/异常定义准确**
656e41f4b71Sopenharmony_ci
657e41f4b71Sopenharmony_ci如果接口有返回值/异常,需要在接口说明中描述完整。例如:
658e41f4b71Sopenharmony_ci
659e41f4b71Sopenharmony_ci```js
660e41f4b71Sopenharmony_ci/**
661e41f4b71Sopenharmony_ci * Sync function of rename.
662e41f4b71Sopenharmony_ci * @param {string} path - path.
663e41f4b71Sopenharmony_ci * @returns {void} rmdir success.
664e41f4b71Sopenharmony_ci * @throws {BusinessError} 401 - if type of path is not string.
665e41f4b71Sopenharmony_ci * @throws {BusinessError} 201 - if permission denied.
666e41f4b71Sopenharmony_ci * @syscap SystemCapability.FileManagement.File.FileIO
667e41f4b71Sopenharmony_ci * @since 7
668e41f4b71Sopenharmony_ci */
669e41f4b71Sopenharmony_cideclare function rmdirSync(path: string): void;
670e41f4b71Sopenharmony_ci```
671e41f4b71Sopenharmony_ci
672e41f4b71Sopenharmony_ci* **规则39:元信息完备**
673e41f4b71Sopenharmony_ci
674e41f4b71Sopenharmony_ci接口的方法说明上应当包含基本的元信息,例如:`@syscap`、`@since`等。
675e41f4b71Sopenharmony_ci
676e41f4b71Sopenharmony_ci元信息描述了API自身的基本信息。工具和SDK会利用这个信息进行相应的处理,例如:针对已经废弃的接口会给出警告提示。
677e41f4b71Sopenharmony_ci
678e41f4b71Sopenharmony_ci* **规则40:风格一致**
679e41f4b71Sopenharmony_ci
680e41f4b71Sopenharmony_ciAPI的说明资料,在风格和样式上应当保持一致。例如,文字的加粗,资料图片的配色等。
681e41f4b71Sopenharmony_ci
682e41f4b71Sopenharmony_ci### 组织方式
683e41f4b71Sopenharmony_ci
684e41f4b71Sopenharmony_ci* **规则41:分层合理**
685e41f4b71Sopenharmony_ci
686e41f4b71Sopenharmony_ci操作系统通常是以分层的模型来进行架构的。这意味着每一层要解决不同层次上的问题。
687e41f4b71Sopenharmony_ci
688e41f4b71Sopenharmony_ci因此,接口的设计也要注意相应的层次。
689e41f4b71Sopenharmony_ci
690e41f4b71Sopenharmony_ci可以使用建筑行业来进行类比:所有的建筑都会包含墙体和房间的门。墙体是有砖块构成的,门是有木料构成的。在这种情况下,抽象可能会分为下面几层:
691e41f4b71Sopenharmony_ci
692e41f4b71Sopenharmony_ci* 第一层是基本都原材料,包括水泥、沙子、木材等
693e41f4b71Sopenharmony_ci* 第二层是用原材料构建出来的建筑元素,例如:门、窗户、墙体等
694e41f4b71Sopenharmony_ci* 第三层是房间的种类,例如:卧室、卫生间、客厅等
695e41f4b71Sopenharmony_ci* 最后,最上面一层是各种不同用途的建筑。例如:酒店、公寓等
696e41f4b71Sopenharmony_ci
697e41f4b71Sopenharmony_ci这里每一层所要考虑的概念和要处理的问题都是不一样的,请仔细思考你提供的API是在哪一个层次上。
698e41f4b71Sopenharmony_ci
699e41f4b71Sopenharmony_ci* **规则42:模块划分合理**
700e41f4b71Sopenharmony_ci
701e41f4b71Sopenharmony_ci大家不仅要关注水平层面的分层,也应该关注垂直层面的划分。因此,模块的组织也同样重要。OpenHarmony的接口是以命名空间的形式组织的。一个命名空间通常对应了一个模块。
702e41f4b71Sopenharmony_ci
703e41f4b71Sopenharmony_ci从子系统的角度,一个较小的子系统应该尽可能将接口放在同一个命名空间中。较大的子系统,可以提供多个命名空间。
704e41f4b71Sopenharmony_ci
705e41f4b71Sopenharmony_ci* **规则43:应用描述文件也是接口的一部分**
706e41f4b71Sopenharmony_ci
707e41f4b71Sopenharmony_ci接口的英文是Interface,这个词还有界面的意思。操作系统提供给开发者的接口并不仅仅是编程接口。任何公开给开发者的机制,都是API的一部分。
708e41f4b71Sopenharmony_ci
709e41f4b71Sopenharmony_ci这其中,最明显的就是应用描述文件,这些文件也需要按照接口规范一样的规则来管理。
710e41f4b71Sopenharmony_ci
711e41f4b71Sopenharmony_ci### 质量属性
712e41f4b71Sopenharmony_ci
713e41f4b71Sopenharmony_ci* **规则44:性能满足要求**
714e41f4b71Sopenharmony_ci
715e41f4b71Sopenharmony_ci操作系统所提供的接口所有上层应用都可能会使用到,因此,其实现的性能应当是能够满足实际要求的。
716e41f4b71Sopenharmony_ci
717e41f4b71Sopenharmony_ci下面是一些举例:
718e41f4b71Sopenharmony_ci
719e41f4b71Sopenharmony_ci1. 应及时响应,避免调用者等待;如果API调用执行时间过长应设计为异步方式。
720e41f4b71Sopenharmony_ci2. 接口存在大量数据传输时,应考虑使用共享内存、消息队列等。
721e41f4b71Sopenharmony_ci3. 尽可能减少新增进程实体。
722e41f4b71Sopenharmony_ci4. 对使用资源的API调用需要能及时释放资源,异常场景具备容错机制,保障资源及时释放。
723e41f4b71Sopenharmony_ci
724e41f4b71Sopenharmony_ci* **规则45:功耗设计合理**
725e41f4b71Sopenharmony_ci
726e41f4b71Sopenharmony_ciOpenHarmony 操作系统在设计之初就需要面向多种不同类型的设备,这些设备中绝大多数是无源设备。因此,功耗的考虑是毋庸置疑的。
727e41f4b71Sopenharmony_ci
728e41f4b71Sopenharmony_ci每个功能/机制在实现上应当把功耗的合理性作为最基本的要求。除此之外,对于高功耗的接口应当在说明中给开发者充足的解释,并且对于使用方式给与足够的指导。
729e41f4b71Sopenharmony_ci
730e41f4b71Sopenharmony_ci同时,在使用上要避免开发者错误的使用。例如,在设备锁屏之后,或者应用切换到后台之后,就应当停止高功耗的行为。
731e41f4b71Sopenharmony_ci
732e41f4b71Sopenharmony_ci另外,还应当注意在版本演进过程中,功耗不出现劣化。
733e41f4b71Sopenharmony_ci
734e41f4b71Sopenharmony_ci* **规则46:需要保证可测试性**
735e41f4b71Sopenharmony_ci
736e41f4b71Sopenharmony_ci完备的自动化测试用例,可以带来很多好处:
737e41f4b71Sopenharmony_ci
738e41f4b71Sopenharmony_ci1. 开发过程中,提前快速发现问题,提高接口质量。
739e41f4b71Sopenharmony_ci2. 版本迭代时,保证代码修改不影响功能,提高代码修改的信心。
740e41f4b71Sopenharmony_ci3. 确保接口向后兼容性。
741e41f4b71Sopenharmony_ci
742e41f4b71Sopenharmony_ci所以,对于一个OpenHarmony API,都要求做到以下几点:
743e41f4b71Sopenharmony_ci
744e41f4b71Sopenharmony_ci1. 新增API必须同步交付API自动化测试用例,用例100%覆盖API接口。
745e41f4b71Sopenharmony_ci2. 用例场景单一,单条用例覆盖接口单个功能场景,简化单条用例代码逻辑。
746e41f4b71Sopenharmony_ci3. 用例执行高效,每条用例执行时间控制在毫秒级。
747e41f4b71Sopenharmony_ci4. 用例执行全自动化:接口用例需要达成100%自动化。
748e41f4b71Sopenharmony_ci5. 用例有效性:用户要求必须存在断言,且不能仅是检查是否抛出异常,需要有功能逻辑的断言。
749e41f4b71Sopenharmony_ci
750e41f4b71Sopenharmony_ci
751e41f4b71Sopenharmony_ci
752e41f4b71Sopenharmony_ci* **规则47:考虑环境适应性**
753e41f4b71Sopenharmony_ci
754e41f4b71Sopenharmony_ci考虑到用户的个性化,操作系统通常会提供一些环境自定义的能力,例如:语言国际化、浅色/深色主题、字体大小等。
755e41f4b71Sopenharmony_ci
756e41f4b71Sopenharmony_ci对于这方面相关的接口,在开发者没有传递指定参数的情况下,应当能够根据当前所属的环境,自适应的返回相应环境下的结果。
757e41f4b71Sopenharmony_ci
758e41f4b71Sopenharmony_ci## 发布后评价说明
759e41f4b71Sopenharmony_ci
760e41f4b71Sopenharmony_ci尽管在API发布前已经做了多方面规则约束,但总可能还有一些问题在开发者使用之后才能发现。
761e41f4b71Sopenharmony_ci
762e41f4b71Sopenharmony_ci即便是这样,但并不意味着在设计API之初不需要考虑这些问题。
763e41f4b71Sopenharmony_ci
764e41f4b71Sopenharmony_ci相反的,大家应当时刻避免发布后问题的发生。
765e41f4b71Sopenharmony_ci
766e41f4b71Sopenharmony_ci如果在接口发布后,发现了下面几条规则问题的发生,则该模块的接口质量是比较差的。
767e41f4b71Sopenharmony_ci
768e41f4b71Sopenharmony_ci### 稳定性
769e41f4b71Sopenharmony_ci
770e41f4b71Sopenharmony_ci* **规则48:接口废弃率/变更率越低越好**
771e41f4b71Sopenharmony_ci
772e41f4b71Sopenharmony_ci对于接口来说,稳定是其最重要的属性。
773e41f4b71Sopenharmony_ci
774e41f4b71Sopenharmony_ci这是因为接口的废弃和行为变更将极大的影响开发者的维护效率。考虑上多种设备类型、多个系统版本,这个问题会变得更加复杂。
775e41f4b71Sopenharmony_ci
776e41f4b71Sopenharmony_ci设计出能保证长期稳定,持续兼容的接口是每个API设计者应当追求的目标。
777e41f4b71Sopenharmony_ci
778e41f4b71Sopenharmony_ci接口的废弃率/变更率与接口的质量在一定程度上成反比。
779e41f4b71Sopenharmony_ci
780e41f4b71Sopenharmony_ci### 安全性
781e41f4b71Sopenharmony_ci
782e41f4b71Sopenharmony_ci* **规则49:避免接口被滥用**
783e41f4b71Sopenharmony_ci
784e41f4b71Sopenharmony_ci所有接口在设计上,应当考虑到不能被过度滥用。滥用既可能是数量上的滥用,也可能是范围上的滥用。
785e41f4b71Sopenharmony_ci
786e41f4b71Sopenharmony_ci例如:对于用户公共数据(相册、联系人等)的访问,对于长时间后台运行的能力,都可能被滥用。
787e41f4b71Sopenharmony_ci
788e41f4b71Sopenharmony_ci对于数量滥用的防止,可以考虑“仅一次授权”这样的机制。
789e41f4b71Sopenharmony_ci
790e41f4b71Sopenharmony_ci在实现上,可以根据调用者的身份进行相应的限制。
791e41f4b71Sopenharmony_ci
792e41f4b71Sopenharmony_ci当然,无论是哪种限制,都应该在接口说明中说明清楚。并且在检测到过度滥用的情况下,有相应的返回值告知调用者。
793e41f4b71Sopenharmony_ci
794e41f4b71Sopenharmony_ci* **规则50:避免接口被利用**
795e41f4b71Sopenharmony_ci
796e41f4b71Sopenharmony_ci被滥用是指接口的使用超出了原先预期的限制。而被利用是指:接口可以被用来造成负面影响,例如攻击系统。
797e41f4b71Sopenharmony_ci
798e41f4b71Sopenharmony_ci无论开发者以何种方式使用OpenHarmony提供的接口,如果某个接口,或某些接口组合调用导致系统出现了问题,那么就一定接口本身存在问题。
799e41f4b71Sopenharmony_ci
800e41f4b71Sopenharmony_ci特别的,如果某些接口(无论在何种情况下)一旦调用就可以使用系统崩溃,或者进入不能工作的场景,或者能够窃取用户数据,这是绝对不允许的。这就要求API的设计者从API被调用的所有可能都场景上进行考虑,避免一些极端情况的发生。
801e41f4b71Sopenharmony_ci
802e41f4b71Sopenharmony_ci### 可维护性
803e41f4b71Sopenharmony_ci
804e41f4b71Sopenharmony_ci* **规则51:能承载业务能力演进**
805e41f4b71Sopenharmony_ci
806e41f4b71Sopenharmony_ci考虑到操作系统的一些较大特性,需要经过数年才能打磨完成。因此接口在设计上应当考虑今后的可扩展性。
807e41f4b71Sopenharmony_ci
808e41f4b71Sopenharmony_ci随着能力的演进,如果出现了在新版本上新起了一组新的接口,而废弃了原先旧的接口,那么就是接口的设计上存在问题。这是应当避免的。
809e41f4b71Sopenharmony_ci
810e41f4b71Sopenharmony_ci* **规则52:功能扩展后不影响原先行为**
811e41f4b71Sopenharmony_ci
812e41f4b71Sopenharmony_ci随着OpenHarmony 操作系统版本的演进,一些接口新增了参数,或者一些参数新增了新的选项是很常见的一种行为。
813e41f4b71Sopenharmony_ci
814e41f4b71Sopenharmony_ci但是,在这种情况下,一定要考虑清楚对于过往已存在行为的一致性。不应当因为新的场景的引入,而破坏了原先存在的行为。
815e41f4b71Sopenharmony_ci
816e41f4b71Sopenharmony_ci这里需要遵循的原则是:如果在新版本上行为要发生变化,只允许针对目标版本是新版本的应用生效。对于目标版本是旧版本的应用应当继续保持原先的行为。
817e41f4b71Sopenharmony_ci
818e41f4b71Sopenharmony_ci* **规则53:文档和资料应当配套更新**
819e41f4b71Sopenharmony_ci
820e41f4b71Sopenharmony_ci当大家在更新接口实现的时候,一定要记得更新接口的说明。从兼容性的角度来看,不能修改原先存在的行为。通常应当提供新的接口来完成新的功能。
821e41f4b71Sopenharmony_ci
822e41f4b71Sopenharmony_ci但在下面的情况下,可以考虑修改既有接口的行为:
823e41f4b71Sopenharmony_ci
824e41f4b71Sopenharmony_ci1. 缺陷的修复。
825e41f4b71Sopenharmony_ci2. 性能/功耗的改进。
826e41f4b71Sopenharmony_ci3. 为接口拓展新的特性或场景,但不影响原有特性或场景逻辑。
827e41f4b71Sopenharmony_ci
828e41f4b71Sopenharmony_ci第1、2种情况,通常在Release Note里面说明;第3种情况就需要在接口说明上表述清楚。
829e41f4b71Sopenharmony_ci
830e41f4b71Sopenharmony_ci### 不可替代性
831e41f4b71Sopenharmony_ci
832e41f4b71Sopenharmony_ci* **规则54:保证API之间正交**
833e41f4b71Sopenharmony_ci
834e41f4b71Sopenharmony_ci正交(Orthogonality),意味着多个接口之间不应该出现重合的功能。
835e41f4b71Sopenharmony_ci
836e41f4b71Sopenharmony_ci例如:一个接口提供了创建用户账号的能力。另外一个接口包含了创建用户并登录的功能。如果是这样,就应该把第二个接口拆开,只保留单独登录的功能。
837e41f4b71Sopenharmony_ci
838e41f4b71Sopenharmony_ci如果将接口的能力画成一个个图形,那么这些图形之间不应该出现重叠交错的想象。对于同一个层级的接口,不应该出现某个接口提供了1、2、3功能,另外一个接口又提供了2、3、4功能这种情况发生。
839e41f4b71Sopenharmony_ci
840e41f4b71Sopenharmony_ci当然,为了便于调用,允许将一些接口组合成一个更高阶的接口。这通常是抽象层次的不一样,并非是同一个层次的重叠。
841e41f4b71Sopenharmony_ci
842e41f4b71Sopenharmony_ci### 开发者反馈
843e41f4b71Sopenharmony_ci
844e41f4b71Sopenharmony_ci* **规则55:关注开发者反馈**
845e41f4b71Sopenharmony_ci
846e41f4b71Sopenharmony_ci尽管API在正式发布之前,会经过试用阶段,但考虑到试用时间和试用范围是有限的,实际上无法保证能避免所有问题。
847e41f4b71Sopenharmony_ci
848e41f4b71Sopenharmony_ci因此,在接口正式发布之后,也应该继续关注开发者的反馈。
849e41f4b71Sopenharmony_ci
850e41f4b71Sopenharmony_ci开发者反馈可能分为以下几种情况:
851e41f4b71Sopenharmony_ci
852e41f4b71Sopenharmony_ci* 希望提供更多API来满足目前不能实现的功能,这种情况可以将需求导入到下个版本的规划中。
853e41f4b71Sopenharmony_ci* 反馈API的行为与文档描述不一致,这通常是缺陷,应当尽快修复。如果是文档的问题,也应当尽快修改。
854e41f4b71Sopenharmony_ci* 反馈接口设计不合理,可能是命名或者参数设置存在问题,这种情况就需要考虑API废弃同时用新API代替。
855e41f4b71Sopenharmony_ci
856e41f4b71Sopenharmony_ci在一些情况下,可能要变更已经发布的API行为。这种情况下,应当要注意:行为变化只能发生在新开发的应用上,对于已经发布的应用,不能产生行为变化。API提供者可以根据应用的目标API版本来进行判断。
857e41f4b71Sopenharmony_ci
858e41f4b71Sopenharmony_ci在最坏的情况下,需要将既存API废弃,提供新的API代替。
859