软件框架设计的艺术
2021-09-23 11:59:27 15 举报
AI智能生成
软件框架设计的艺术
作者其他创作
大纲/内容
“API一旦发布,便于我们永恒共存”
想要将知识传授给其他人的时候,就会因为他们没有类似于我们的经验,也就很难说服他们接受我们的知识
序言
组内如何一致?
共同的愿景
P2 一年后,我证明了当时的这一猜测。因为Netbeans是一个开源项目,有一个API吸引了一个外部的开发人员。开始的时候,这位外部代码贡献者主要是做一些修复Bug的工作。随后,他开始单独负责一个子项目,并设计相关的API。原先负责设计这个API的人说他发现这个子项目的API变得越来越差,但他找不出原因,希望我帮一手。他说:非常不喜欢这些新的API,更不想把它们集成到他负责的项目中。但他也同样说不清楚这些新的API到底有什么问题。最后,他说这些新的API看起来和他原来的设想不一致。我曾经也对他说过类似的话。以我的标准来评价的话,他所编写的API与NetBeans的API的设想不一致!
公共术语
方法论
合作无间
API的重要独特性:一致性
”艺术“还是”工程“
理性主义
经验主义
对某种事物的了解程度只限于掌握使用方法即可
浅层理解
掌握某种事物背后的原则、规律
深层理解
大多数时候”浅层理解“已经足够
某些内如需要深入了解
针对性无绪(selective cluelessness)
无绪
尽量让最终负责集成的相关人员不需要深入了解系统也可以把集成工作做好
对象:人
应用程序开发的无绪原则
我们希望能够将大块的构建模块”无绪“的集合成应用程序
Why?
方法、类、字段签名
文件(unix管道)
环境变量和命令行选型
文本信息(toString)
协议
判断兼容性最重要的方式是”正常运行“,但这一点却是由内部具体实现决定的
null返回值
行为
国际化
……
what?
设计人员和开发人员之间交流的途径
范例的重要性
可理解性
降低学习曲线
保持兼容
一致性
基于实际或预期的目标与任务
提供”入口“,以便找到需要的解决方案
用户不关心具体的类
可见性
普通的使用者
扩展的使用者
简单的任务应该有简单的方案
多为用户考虑
保护投资
Quality
评价API好坏的标准
源代码兼容
二进制兼容
容易被遗漏
态度,“好老板”不会抱怨客户
功能兼容
向后兼容
我应该怎么做
用例
你应该先做这件事,然后再做那件事就可以了
场景
面向用例的重要性
设计API时,要基于一些具体的场景和对API的认识进行抽象分析,最终给出设计
用例驱动的API设计
API往往是由多位设计者来完成的,但整个团队中必须能够保持“最佳实践”的一些基本原则。一个接口设计得再好,只要它违反整个团队的一致性,就宁愿退而求其次
API设计的一致性
简单而常见的任务应该更容易处理。如果基于用例驱动的方式进行设计,就可以很容易的通过那些可以简单实现的场景来验证这些API是否可以完成那些重要的用例
简单明了的API
一个API对外提供的功能应该只包括用例中说明的功能。这样可以避免出现需要的功能与实际提供的功能两者之间出现差异。
少即是多
必须能够持续的维护该类库。即使出现新的需求,或者原作者离开,都不会放弃这个类库
支持改进
API设计评审(优秀API规则)
不断变化的目标
理论与理由
添加容易,移除困难
发布第一个版本时,移除不必要的内容
除了static和final声明的基本类型、string常量、枚举和不变对象外,其他字段都不应该被公开
方法优于字段
工厂方法返回值不一定是声明类型的实例,可以是子类的实例
每次返回的对象也不一定是新建的对象,可以将其缓存
同步控制,对创建对象前后的代码进行统一处理
工厂方法优于函数
如不希望拥有子类,就应该让其不可被继承
让所有内容不可更改
如无必要,绝不要在正式的API中声明setter方法
可能上下文敏感
isEnable判断,使setEnable失去意义
setEnable
避免滥用setter方法
java默认的package访问方式,内部类
尽可能通过友元方法来公开功能
访问权限
赋予对象创建者更多权利
代码复用
功能复用
“继承”不是用来改变具体的行为,而是用来添加一些额外的动作
如果去继承一个类,只是为了切换某些方法的执行路径,那么这种做法应予以避免
建议:避免深层次继承,定义程序接口,并让用户来实现这些接口
避免暴漏深层次继承
只公开你要公开的内容
抽象定义(接口)与实现分离
向API用户讲清楚:使用APi时,应该遵循正确的原则。如果需要使用一个API就要遵守API的原则,不要破坏
清楚的说明API的需求,定义相应的用例,帮助API设计者实现这样的API
合作
protected方法不可移除,导致子类修改
在接口中增加抽象方法,会强迫其非抽象子类实现该方法
面向接口而非实现进行编程
面向对象并不能避免意大利面条式的编程
模块化的目的:实现各组成部分的松耦合
在规范所在的模块中,至少会有一个小的“入口”
模块化架构将规范与实现分离
Spring
Netbean lookup
扩展
依赖注入
其实还有几个词:架构、模式
P111 2001年,我们给JavaOne大会提交了一份名为“组件定位与协作”的议题,该议题中的内容与本章多少有些关系,我们认为该议题涉及的内容对于所有的模块化程序都很重要。然而,当时的JavaOne会议的组委会可能仅仅因为觉得这个议题的名称不够酷,或者可能因为他们觉得组件这个词用得太滥了,要知道“组件”这个词几乎包含了所有可以想象的内容,所以没有接受该议题。直到2006年,我和同事Tim Boudreau又提交了一份类似的议题,名为“模块化架构中那些发现注入和依赖注入的模式”。果然,如我们所料,议题被组委会接受了。这说明一定要找到能够贴近目标人群的术语才能打动他们。一旦听到“依赖注入”这个词,他们的心就被打动了。就像API这个词一样,恰当的名称有益交流。对于用户来说,他们越容易理解API这个词,就越容易接受API的相关内容。
模块化架构
可以添加但不能移除
供他人调用来完成某些功能
final类
内聚,自包含
API
Service Provider Interface
可以移除但不可增加
供其他人扩展API功能
接口
SPI
避免两者混用
核心API
支持API
核心SPI
支持SPI
NetBeans的分类
根据用户群体的不同需求来组织你的API结构
合理分解API
设计API时要区分其目标用户群\t
为API提供Mock对象
Mock对象
测试代码是规范的一部分
向导
让客户尽快的上手
NetBeans中每一项重要的技术都有一个相应的向导来建立初始的基础框架
项目的第一目标快速推向市场
面向SPI用户和API实现者
兼容性测试套件
好工具让API设计更简单
牢记可测试性
包装模式
谨慎使用第三方API
暴露的越多,演进的余地就越小
只暴露抽象内容
强化API一致性
代理和组合
所有的层次之间都需要保持一致性。
避免API的误用
与其他API协作
”臭名远扬“—与其抱怨用户,不如改变自己的态度
”保卫者“——自动化测试
正确且恰当的描述其线程模型
继承影响synchronized
对于公开的API,不能将对外方法申明为同步
Java Monitors中的陷阱
处处陷阱的Java同步与死锁
同步与死锁
API具体运行时的一些内容
基本思路:不是让API用户一步步告诉程序如何做,而只需要告诉程序他们的结果,然后交给API去完成
NetBeans Lookup实现,只需要简单XML描述,不需要用户注册、注销
自描述性
声明式编程
设计实战
现实生活充满了变化因素,理论的东西不可能一成不变的用在生活中。不仅要知道哪些事情可行,哪些事情不可行,还要知道如何运作才能可行
是漂亮的
如果为了正确性而牺牲了易用性,那么可能会引发更多的问题
Mercurial和SVN
是正确的
尽量简单
是高性能的
绝对兼容
是对称的
API必须
极端意见有害无益
Wiki定义:“同时相信两种互相矛盾的观点,而没有意识到两者是矛盾的”
自相矛盾
飞机安检
开发人员抱怨的事项总是不断,如评审、编程规范,等等。但API监护人需要时刻保持警醒的状态,否则就可能因为一个小小的疏忽而引发问题。另一方面,不是出个小问题,至少说明了你所做的工作确实很有用。
少数派报告
安全部门
API设计中的矛盾
改进API
在提交代码前进行代码评审
在写代码之前
概述
FAQ
倒推法
说服开发人员为他们的API提供文档
工具监控所有需要关注的变更情况
没有工具,需要一个”全知全能“的人
尽职尽责的监控者
只接受正确的建议
制定要求
要求不能太复杂
接收API的补丁
团队协作
利用竞赛游戏来改进API设计技巧
日常生活
软件框架设计的艺术
0 条评论
回复 删除
下一页