从GIT系统设计认识编程领域中的‘抽象和分层’思想
一、前言
“抽象与分层,是计算与程序世界里最根本的思想。逻辑之始。”
宇宙的终极图景人类无法认知,愚蠢是人类理智的最后一道防线 ——《论克苏鲁世界观中的认知哲学》
毋庸置疑,现实世界是无比复杂的,以人类有限的脑力来认识和解构世界,无疑是需要一定的方法论的。
在编程领域中,系统可以是无比复杂的。而人类为了开发和持续维护复杂系统,必然要做好优秀的架构设计,才能有效降低开发者的心智负担
因此,抽象和分层是人类应对方法。
抽象是对普遍性的表达,分层则是在恰当的语义层上放置抽象
二、概念
抽象
抽象主要有通用域抽象和领域抽象。通用域抽象是所有软件都会复用的概念、实体与交互;领域抽象则特定于某个具体的行业领域。抽象通常使用术语来表达
主要有六类抽象:
- 流程型抽象: 表达应用流程,将单一功能构造成实用的服务
- 任务型抽象: 使用有限可控的任务执行者集稳定高效地完成源源不断来临的任务
- 数据处理抽象: 任务的实际内容
- 结构型抽象: 存储和容纳执行任务所需要的资源、数据集
- 数据模型抽象: 具有语义关联的数据项聚合体
- 原子数据抽象: 组成数据的基本数据单位
分层
- 高层语义表达意图,底层语义呈现细节
- 相同层次一般不相互直接调用
- 不建议跨层调用
什么是整洁代码
摘录自《代码整洁之道》298页:
1,代码逻辑直接了当,让缺陷难以隐藏
2,尽量减少依赖关系,使之便于维护
3,依据某种分层策略完善错误处理代码
4,性能调至最优,省得引诱别人做没规矩的优化
5,整洁的代码只做一件事
6,简单直接,具有可读性
7,有单元测试和验收测试
8,有意义的命名
9,代码应在字面上表达其含义
10,尽量少的实体:类、方法、函数
11,没有重复代码
三、GIT系统设计
概念
从GIT系统分析可知,应该有如下的抽象(对象)
commit:一次确切的提交记录
branch:分支对象
tag: 标签
stash:暂存对象
stashList: 暂存栈
repo:GIT仓库对象
diff:提交、暂存所对应的文件改变内容对象
而我们自顶而下的设计该系统,应有如下分层:repo(仓库源) →branch(分支) -> commit(提交) → diff(文件改变内容对象)
对于一些特殊的抽象,可由其他抽象派生而得,比如tag派生自commit抽象
伪代码
如下是一些说明上述抽象的伪代码
// 每个Diff对象包含每个变更文件的具体变更信息:增加内容(行数),删除内容(行数)
class Diff {
constructor() {
this.changeFileList = []
this.changeContent = {}
}
}
class Commit {
constructor() {
this.type = 'commit'
this.diffContent = new Diff()
this.committer = '' // 提交者
this.email = 'example@git.com'
this.timestamp = Date.now() // 提交时间
this.msgTitle = '' // commit message
this.msgContent = '' // commit message content
this.hash = '' // 38位hash字符串
this.parentNode = null // 父节点,该属性可以将所有的commit列表转化为一颗commit树。
}
}
class Branch {
constructor() {
this.name = ''
this.startNode = new Commit()
// endNode属性的作用是:当在某个分支的某个commit节点上分叉出一个新的分支,endNode用于确定当前分支的commit列表的结束位置。因此,会出现某个commit节点技术某个分支的endNode,也是另一个分支的startNode
this.endNode = null
}
}
// Tag对象抽象与Commit不同的是:有tag属性和explain属性,且tag节点不能在向下生长commit节点
class Tag extends Commit {
constructor() {
super()
this.type = 'tag'
this.tag = ''
this.explain = '' // 该tag的解释内容
}
}
// Stash抽象对象不能推送到远程,stash并没有在commit树中,而是在StashList栈中list
class Stash extends Commit {
constructor() {
super()
this.type = 'stash'
}
}
class StashList {
constructor() {
this.list = []
}
pop() {}
apply() {}
}
class Repo {
constructor() {
this.currentBranch = '' // HEAD指向
this.commitList = []
this.branchList = []
this.tagList = []
}
}
// 工作区
class WordSpace {
}
四、其他
抽象和分层是开发者在编程领域中的不二法宝,我们在阅读优秀的库/框架源码时,如果以“抽象和分层”的角度切入,进行源码的梳理解读,应该不失为一种高效的阅读源码的方法。