代码精进之路
范学雷
Oracle首席软件工程师,Java SE安全组成员,OpenJDK评审成员
立即订阅
6316 人已学习
课程目录
已完结 47 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 你写的每一行代码,都是你的名片
免费
第一模块:代码“规范”篇 (16讲)
01 | 从条件运算符说起,反思什么是好代码
02 | 把错误关在笼子里的五道关卡
03 | 优秀程序员的六个关键特质
04 | 代码规范的价值:复盘苹果公司的GoToFail漏洞
05 | 经验总结:如何给你的代码起好名字?
06 | 代码整理的关键逻辑和最佳案例
07 | 写好注释,真的是小菜一碟吗?
08 | 写好声明的“八项纪律”
09 | 怎么用好Java注解?
10 | 异常处理都有哪些陷阱?
11 | 组织好代码段,让人对它“一见钟情”
12丨组织好代码文件,要有“用户思维”
13 | 接口规范,是协作的合约
14 | 怎么写好用户指南?
15 | 编写规范代码的检查清单
16丨代码“规范”篇用户答疑
第二模块:代码“经济”篇 (14讲)
17 | 为什么需要经济的代码?
18丨思考框架:什么样的代码才是高效的代码?
19 | 怎么避免过度设计?
20 | 简单和直观,是永恒的解决方案
21 | 怎么设计一个简单又直观的接口?
22丨高效率,从超越线程同步开始!
23 | 怎么减少内存使用,减轻内存管理负担?
24 | 黑白灰,理解延迟分配的两面性
25 | 使用有序的代码,调动异步的事件
26 | 有哪些招惹麻烦的性能陷阱?
27 | 怎么编写可持续发展的代码?
28 | 怎么尽量“不写”代码?
29 | 编写经济代码的检查清单
30丨“代码经济篇”答疑汇总
第三模块:代码“安全”篇 (14讲)
31 | 为什么安全的代码这么重要?
32 | 如何评估代码的安全缺陷?
33 | 整数的运算有哪些安全威胁?
34 | 数组和集合,可变量的安全陷阱
35 | 怎么处理敏感信息?
36 | 继承有什么安全缺陷?
37 | 边界,信任的分水岭
38 | 对象序列化的危害有多大?
39 | 怎么控制好代码的权力?
40 | 规范,代码长治久安的基础
41 | 预案,代码的主动风险管理
42 | 纵深,代码安全的深度防御
43 | 编写安全代码的最佳实践清单
44 | “代码安全篇”答疑汇总
加餐 (1讲)
Q&A加餐丨关于代码质量,你关心的那些事儿
结束语 (1讲)
结束语|如何成为一个编程好手?
代码精进之路
登录|注册

21 | 怎么设计一个简单又直观的接口?

范学雷 2019-02-20
我们前面聊过接口规范,开放的接口规范是使用者和实现者之间的合约。既然是合约,就要成文、清楚、稳定。合约是好东西,它可以让代码之间的组合有规可依。但同时它也是坏东西,让接口的变更变得困难重重。
接口设计的困境,大多数来自于接口的稳定性要求。摆脱困境的有效办法不是太多,其中最有效的一个方法就是要保持接口的简单直观。那么该怎么设计一个简单直观的接口呢?

从问题开始

软件接口的设计,要从真实的问题开始。
一个解决方案,是从需要解决的现实问题开始的。要解决的问题,可以是用户需求,也可以是现实用例。面对要解决的问题,我们要把大问题分解成小问题,把小问题分解成更小的问题,直到呈现在我们眼前的是公认的事实或者是可以轻易验证的问题。
比如说,是否可以授权一个用户使用某一个在线服务呢?这个问题就可以分解为两个小问题:
该用户是否为已注册的用户?
该用户是否持有正确的密码?
我们可以使用思维导图来描述这个分解。
分解问题时,我们要注意分解的问题一定要“相互独立,完全穷尽”(Mutually Exclusive and Collectively Exhaustive)。这就是 MECE 原则。使用 MECE 原则,可以帮助我们用最高的条理化和最大的完善度理清思路。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《代码精进之路》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(7)

  • hua168
    1.说到接口,现在网站接口风格还是 RESTful API,GraphQL用得少吧?
    2.我看了之前的文章想起了一个实现的问题:
       像我们中小公司人员流失比较大,从0开发一个电商网站的话,很多开发为了赶时间都不愿意写详细的开发文档,代码只是简单的做一下注解,交接文档也写得随便,这种情况如果原始团队的开发换完了,
    那不是没有人敢动代码了?或者只剩下一两原始开发没走,不是可以要挟老板升工资了?怎么避免~~
       我们是想达到:无论开发怎么换,招一个新的开发进来就能上手,像工厂流水线那样,工人怎么走都不会影响工厂的运行,招一个新工人简单做一下培训就能上岗了,不能让“没人TA就不行”这种情况发生,需要怎做?
        除了你前面的强制要求代码规范(类、方法、属性、注解、代码块、缩进、空行等)、开发文档、还有哪些工作需要做?

    作者回复: #1. 我知道的,RESTful API用的多些。我对这方面的不熟,希望留言区有人可以帮着回答。
    #2. 其实,短期内我们很难做到“铁打的营盘,流水的兵”。软件开发还算是一项复杂的活动,很多时候,也会体现出是“流水的营盘,铁打的将”的现象。优秀的程序员,还是要想办法留住的。有研究表明,替换一个工程师,需要花费平均6到9个月的薪水,甚至是1.5到2年的薪水。如果我们把替换成本变成现有工程师的薪水涨幅,也许事情就简单了很多。

    代码没人敢动,一个很重要的原因,就是没有回归测试或者回归测试不完备,我们搞不清修改代码带来的后果。JDK运行在几十亿台设备上,每天都做很多修改。之所以能够做这么大量的修改,除了规范、文档、评审之外,还有大量的回归测试案例。代码修改提交之前,要把相关的回归测试跑一遍。一旦修改带来了兼容性问题,回归测试就会检测出来,工程师就会知道修改带来的影响,会重新考量修改方案。

    另外,要用好现代的工具,不能停留在手种刀割的时代。很多工具都是开源软件,搭建起来,形成习惯就可好了。比如,bug管理工具(bug systems), 版本控制工具(git,mercurial),这些工具都会留有历史信息,用好了可以更好地理解代码和变更。不使用这些工具,好多有价值的东西,极小一部分留在工程师的脑子里,人走了,价值也就随着走了;大部分都会被岁月冲散。JDK的开发过程中,我经常需要找找十多年前历史信息,看看当初为什么那样设计,要解决的到底是什么问题,变更起来影响可以有多坏。

    2019-02-20
    5
  • 克里斯
    作者应该是看了《金字塔原理》这本书。作者基本上到目前的章节,基本都在表述程序员版的《金字塔原理》😁

    作者回复: 搜了一下,是《金字塔原理:麦肯锡40年经典培训教材》吗?你的阅读面很广啊! 嗯,有机会我也要买来看看。作为一名老旧式的五道口技校经管的学生, 推荐大家多读读经济管理的书籍,对产品设计很有帮助的,大部分的设计思想都逃脱不了经济管理的原理范畴。

    2019-05-03
    3
  • 克里斯
    这种强依赖问题属于归纳思维中的时间顺序范涛。

    但是时间顺序的过程在代码里表现为 结构顺序,丢失了时间顺序的信息。

    为了解决这个问题:
    一种方案是假设用户调用顺序错乱,但在方法内保证按时间顺序走,具体就是在代码里确保每个方法调用前,他依赖的逻辑一定会被调用;

    一种方案是假设用户能正确按时间顺序调用,这需要我们尽可能让用户知道我们方法的顺序意图,具体就是让方法名称和注释上尽量表达出时间顺序的意图,让使用者能明确获取信息。

    另外,也有两种混合搭配使用的。

    个人小小的观点,望指教。

    作者回复: 这两种都是很好的方法。 第一个方案的一个小缺点是如果用户传入参数,内部整理在个别的情况下没有办法自动处理,不过大部分情况下都没有问题。第二种理论上没什么问题,就是对规范和用户的要求都有一点点高,需要规范标注;仔细阅读规范;并且遵守时间顺序。😣,编码的难处就在于要反复地妥协和平衡。

    2019-05-03
    2
  • Sisyphus235
    Signature 继承 SignatureSpi,实现签名算法。
    setParameter 方法通过传入参数启动 Signature engine,initVerify 初始化 verification 对象,initSign 初始化 signing 对象。
    update 更新 signed 或者 verified data,sign 返回二进制签名,verify 验证传入的签名。

    排版不利于阅读,整理上面逻辑花了好长时间/::-|,方便后续读者。

    Signature 类容易出错,要按规定动作执行才能完成工作,先启动 engine,再分别初始化 verification 和 signing 对象。可以写成一个内部方法按照顺序完成规定动作,而不是分开交给用户调用处理。
    其他信息不多,验证签名和加密签名都是基本功能,更新数据不知道具体逻辑,或许有问题

    作者回复: 嗯,估计你使用小屏幕阅读的。代码的显示在小屏幕上,的确是个问题。

    这个Signature类设计的最大问题,就来源于update()这个方法。 因为签名数据可能很大很大,这种情况下,需要分批传入数据,使用update()方法。 当然,还有更好的解决办法。

    2019-05-23
    1
  • LeasonZ
    问题: 如何划分一件事?
    就像吃饭,简单说吃饭就是拿东西吃,更细一点变成了拿食物->张嘴->咬->咀嚼->吞咽,再细点就变成肌肉运动,电信号之类的.所以划分维度在代码设计时该怎么去把控,这是长久困扰我的一个疑问,希望老师能解答下

    作者回复: MESE的原则是划分到事实为止。用到代码上,划分到有现成方法可以用为止。如果有吞咽这个方法,划到吞咽就够了。

    2019-03-20
    1
  • 唐名之
    我们习惯这样写,:
    private final void initVerify(PublicKey publicKey)
                throws InvalidKeyException {
            // snipped
        }

        private final void initSign(PrivateKey privateKey)
                throws InvalidKeyException {
            // snipped
        }

        private final void update(byte[] data) throws SignatureException {
            // snipped
        }

        public final byte[] sign(PrivateKey privateKey, byte[] data) throws InvalidKeyException, SignatureException {
    initSign(privateKey);
    return update(byte);
        }

      public final boolean verify(PublicKey publicKey, byte[] signature) throws InvalidKeyException,SignatureException {
            initVerify(publicKey);
    // snipped
        }

    作者回复: 这样适合处理小数据,如果签名数据很大,比如文件,图像,sign方法需要占用的内存太多,占用时间太长(data参数)。verify方法怎么传要签名的数据呢?

    2019-02-20
    1
  • Tom
    签名数据太大,比如文件图片,占用内存大,使用流处理可以减少内存占用吗?
    2019-03-02
收起评论
7
返回
顶部