优良的设计能够有效避免焦油坑
设计价值观
简洁性: 当两种程序设计能够完成相同的功能的时候,选择更简洁的那一个.简洁不等于直观. 关键在于抽取出很多事情中的共性.好比牛顿把世间万物力学规律归结为仅仅三条定律.
可靠性: 程序设计时候要定下契约,各个方法要符合这个契约. 在能够解决问题的情况下,契约越细越好.例如接口只传递frm或json数据, 且不能为空;所有的步骤类都有do函数.细致的契约能够有效避免各种潜在问题.
可拓展性:好的模块像乐高积木,可以组合成各种有意义的形态解决新的问题.
道可道非常道: 希望大家多思考,多学习,不断提升自己的品味.可以以前看起来不错的设计,未来境界提升之后就看出问题来了.
设计准备工作
- 要解决什么问题?
列举出用户故事,越全越好,这些就是我们要解决的问题.为了找到问题可以写一些简单的脚本来验证. - 别人有什么解决方案?
他山之石: 可否有别人的设计方案可以参考?例如github上,BTAJ美团/万得东方财富等公司的设计,例如程序员论坛上的设计.通过我们的价值观来评估他们设计的优缺点是什么. - 我们最佳解决方案是什么?
反复质疑: 要反复质疑自己的设计.有没有无法实现的情况?哪些地方可能会报错?哪些地方风险最高?可以写伪代码来推演.
权衡: 尽量选择更可靠更简洁可拓展更好的方案.有时候要同时写多个方案.然后比较后定下planA与planB. - 写探索性脚本. 如果用到了自己不熟悉的技术栈,或者对程序逻辑还不是很有把握的时候,可以尝试性写脚本.跑通一些简单的case.在这个基础之上再做设计.
所有的模块开发之前都要有设计
- 要写用户故事
- 所有的类与外部接口都要设计,写清楚每个类与外部接口是要做什么。
- 所有的外部方法都要写测试用例。关键的外部接口要写至少两个测试用例。
- 每次设计2-8个类。随着能力的提高可以扩大。
- 当可行性问题解决之后,要描述程序设计可扩展性,设计的简洁性,设计的契约.
提交
- 使用codedesign工具做完设计之后,用钉钉把设计发给我。
- 如果商议完还是有不同意见的设计,就先不放到设计定稿里面.可以先在脚本里做这些功能.等到大家都更清楚这个事情了,再做决定.
用户故事
-要写代码设计是用来解决哪些问题.
例如"从上交所按照日期,公司名抓取所有的公告".
-对所有的usercase,要写伪代码来说明我们的设计如何解决这个问题.
方法
-所有的方法都要有参数
-要设计参数的默认值,类型. 所有的参数都要有注释说明
状态码,错误码
-要写所有的状态码与错误码的对应与解释.例如:
error_code_dict = {
10053: '文件名有非法字符',
10054: '找不到改文件'
}
类的命名
观察者模式可以中的被观察者可以命名为XXXInformer(公告), 观察者可以命名为XXXDealer.
一个专门分类的类可以命名为ClassfyXXX.
状态模式中的多态的类可以命名为XXXState
测试用例的写法
.方法1
@参数1 @参数2=> 结果
参考案例:
.read: 打开指定的本地路径上的文件,如果不存在报错。
- path: 路径
- mode: 文件打开模式
@D:/test/code.frm @'r' => pd.DataFrame(data=[[1,4],[4,5]], columns=['line','num'])
类与类之间的关系
- 步骤类与步骤类之间一般只有数据依赖.为了防止僵化,在module中一般不要把多个步骤类封装成一个总的步骤类.
- 同一个模块中的类,最多只有两层继承关系.
- 最小依赖原则: 尽可能找到找到最小依赖的那种设计方案.
类与类之间的依赖性排序: 构造依赖>参数依赖 > 数据依赖
要尽量采取依赖性小的方式.例如下面展示了如何构造依赖改造为参数依赖进而转变为数据依赖.
def __init__(self):
self.some_bhv = Behavior() # 构造依赖
def __init__(self, some_behv = None): # 参数依赖
if some_behv is None:
some_bhv = Behavior()
assert isinsatnce(some_behv, BaseBehavior)
self.some_bhv = some_bhv
def __init__(self):
pass
def do(self, behv_res): # 数据依赖
# do_something
构造依赖一般只对标准库, numpy, pandas这样的第三方库使用.当使用ylib中的类的时候,不允许出现构造依赖.对于能够改造为数据依赖的情况,要改造为数据依赖.
网友评论