http://www.wklken.me/posts/2013/11/24/the-clean-coder.html
相比问题本身,解决问题的方式、步骤以及反思深度都体现出一个人的职业素养
职业素养: 它体现了能力和素质,又强调了持续的积累和养成
"专业主义"就意味着担当责任
1.3 首先,不行损害之事
1.3.1 不要破坏软件的功能
要做得专业,就不能留下bug
要对自己的不完美负责
所谓专业人士,就是能对自己犯下的错误负责的人,哪怕那些错误实际上是在所难免的
你有责任让失误率无限接近0
所有软件项目的根本指导原则是,软件要易于修改
如果你希望自己的软件灵活可变,那就应该时常修改它: 要证明易于修改,唯一办法就是做些实际的修改
"无情重构",每次读、修改代码,就要比原来更简洁
不要害怕修改代码,(有一套完整测试,你就根本不会害怕)
1.4.1 了解你的领域
1.设计模式
2.设计原则。必须了解SOLID原则,而且要深刻理解组件设计原则
3.方法。必须了解XP/Scrum/精益/看板/瀑布/结构化分析/结构化设计
4.实践。TDD、OOP、结构化编程、持续集成和结对编程
5.工件、UML/DFD/结构图/Petri网络图/状态迁移图表、流程图和决策表
1.4.7 与雇主/客户保持一致
必需弄明白雇主的真正问题, 站在其角度思考.
1.4.8 谦逊
要学会说"不"
第三章 说“是”
3.1 承诺用语
口头上说自己将会去做
心里认真对待做出的承诺
真正付诸行动
当我们承诺某事时,必须认证对待承诺
第四章 编码
具备"出错感知力", 说明你已经能够非常迅速地获得反馈, 能够更为快速地从错误中学习.
要精熟掌握每项技艺, 关键都是要具备"信心"和"出错感知"能力
1.代码必须能够正常工作
2.代码必须能够帮你解决客户提出的问题
3.代码必须能和现有系统结合得天衣无缝
4.其他程序员必须能读懂你的代码
管理延迟的秘诀, 便是早期检测和保持透明.
三个考虑到多种因素的期限:乐观预估,标称预估,悲观预估
4.6.1 期望
调整和确认期望
4.6.4 交付失误
最糟糕:明知道没有完成任务却宣称已经完成
第九章 时间管理
9.1 会议
关于会议,有两条真理
1.会议是必须的
2.会议浪费了大量的时间
专业开发人员同样清楚会议额的高昂成本。所以,如果会议没有现实且显著的成效,他们会主动拒绝
9.1.1 拒绝
邀请你参加会议的人并不负责管理你的时间,为时间负责的人只有你
理智地使用时间,谨慎选择,应当参加哪些会议,礼貌拒绝哪些会议
领导的最重要责任之一, 就是帮你从某些会议脱身. 好的领导一定会主动维护你拒绝出席的决定, 因为她和你一样关心你的时间
站立会议
1.我昨天做了什么
2.今天打算做什么
3.我遇到了什么问题
每个人发言不超过1分钟
9.4 要避免的行为
优先级错乱:提高某个任务优先级来借口推迟真正急迫的任务
专业开发人员会评估每个人物的优先级,排除个人喜好和需求,按照真实的紧急程度来执行任务
9.5 死胡同
慎重的态度和积累的经验可以帮你避免某些死胡同,但无法避免所有
在走入死胡同时,要迅速意识到,并有足够的勇气走回头路
坑法则,The Rule of Holes:如果你掉进坑里,别挖
第十二章 协作
大多数软件都是有团队开发出来的
单打独斗与有利于团队之外都是不专业的表现.
12.1 程序员与人
12.1.1 程序员与雇主
专业程序员的首要职责是满足雇主的需求
专业程序员会花时间去理解业务
12.1.2 程序员与程序员
1.代码个体所有
不正常团队的糟糕症状
2.协作性的代码共有权
共有, 每个人都可以做出合适的修改
3.结对
12.2 小脑
专业人士会共同工作
有些时候,单独工作是正确的。但是一般来说,和他人紧密协作,在大部分时间段中结对工作,是最好的做法
http://boxingp.github.io/blog/2015/02/02/the-clean-coder-reading-notes/
http://game-lab.org/posts/zoc-cleancode-1/
http://game-lab.org/posts/zoc-cleancode-2/
http://game-lab.org/posts/zoc-cleancode-3/
5. 原则:每个函数位于同一抽象层级
要确保函数只做一件事,函数中的语句都要在同一个抽象层级上
自顶下下读代码
6. 原则:无副作用
相比问题本身,解决问题的方式、步骤以及反思深度都体现出一个人的职业素养
职业素养: 它体现了能力和素质,又强调了持续的积累和养成
"专业主义"就意味着担当责任
1.3 首先,不行损害之事
1.3.1 不要破坏软件的功能
要做得专业,就不能留下bug
要对自己的不完美负责
所谓专业人士,就是能对自己犯下的错误负责的人,哪怕那些错误实际上是在所难免的
你有责任让失误率无限接近0
所有软件项目的根本指导原则是,软件要易于修改
如果你希望自己的软件灵活可变,那就应该时常修改它: 要证明易于修改,唯一办法就是做些实际的修改
"无情重构",每次读、修改代码,就要比原来更简洁
不要害怕修改代码,(有一套完整测试,你就根本不会害怕)
1.4.1 了解你的领域
1.设计模式
2.设计原则。必须了解SOLID原则,而且要深刻理解组件设计原则
3.方法。必须了解XP/Scrum/精益/看板/瀑布/结构化分析/结构化设计
4.实践。TDD、OOP、结构化编程、持续集成和结对编程
5.工件、UML/DFD/结构图/Petri网络图/状态迁移图表、流程图和决策表
1.4.7 与雇主/客户保持一致
必需弄明白雇主的真正问题, 站在其角度思考.
1.4.8 谦逊
要学会说"不"
第三章 说“是”
3.1 承诺用语
口头上说自己将会去做
心里认真对待做出的承诺
真正付诸行动
当我们承诺某事时,必须认证对待承诺
第四章 编码
具备"出错感知力", 说明你已经能够非常迅速地获得反馈, 能够更为快速地从错误中学习.
要精熟掌握每项技艺, 关键都是要具备"信心"和"出错感知"能力
1.代码必须能够正常工作
2.代码必须能够帮你解决客户提出的问题
3.代码必须能和现有系统结合得天衣无缝
4.其他程序员必须能读懂你的代码
管理延迟的秘诀, 便是早期检测和保持透明.
三个考虑到多种因素的期限:乐观预估,标称预估,悲观预估
4.6.1 期望
调整和确认期望
4.6.4 交付失误
最糟糕:明知道没有完成任务却宣称已经完成
第九章 时间管理
9.1 会议
关于会议,有两条真理
1.会议是必须的
2.会议浪费了大量的时间
专业开发人员同样清楚会议额的高昂成本。所以,如果会议没有现实且显著的成效,他们会主动拒绝
9.1.1 拒绝
邀请你参加会议的人并不负责管理你的时间,为时间负责的人只有你
理智地使用时间,谨慎选择,应当参加哪些会议,礼貌拒绝哪些会议
领导的最重要责任之一, 就是帮你从某些会议脱身. 好的领导一定会主动维护你拒绝出席的决定, 因为她和你一样关心你的时间
站立会议
1.我昨天做了什么
2.今天打算做什么
3.我遇到了什么问题
每个人发言不超过1分钟
9.4 要避免的行为
优先级错乱:提高某个任务优先级来借口推迟真正急迫的任务
专业开发人员会评估每个人物的优先级,排除个人喜好和需求,按照真实的紧急程度来执行任务
9.5 死胡同
慎重的态度和积累的经验可以帮你避免某些死胡同,但无法避免所有
在走入死胡同时,要迅速意识到,并有足够的勇气走回头路
坑法则,The Rule of Holes:如果你掉进坑里,别挖
第十二章 协作
大多数软件都是有团队开发出来的
单打独斗与有利于团队之外都是不专业的表现.
12.1 程序员与人
12.1.1 程序员与雇主
专业程序员的首要职责是满足雇主的需求
专业程序员会花时间去理解业务
12.1.2 程序员与程序员
1.代码个体所有
不正常团队的糟糕症状
2.协作性的代码共有权
共有, 每个人都可以做出合适的修改
3.结对
12.2 小脑
专业人士会共同工作
有些时候,单独工作是正确的。但是一般来说,和他人紧密协作,在大部分时间段中结对工作,是最好的做法
http://boxingp.github.io/blog/2015/02/02/the-clean-coder-reading-notes/
http://game-lab.org/posts/zoc-cleancode-1/
http://game-lab.org/posts/zoc-cleancode-2/
1. 原则:名副其实
- 选名字是件严肃的事情,选个好名字很重要。
- 如果名字需要注释来补充,那就不是个好名字。
- 最重要的是要名副其实,名字能表达出概念和意图。
BAD:
int t = currentTime.elapse(e); // 消逝的时间,以毫秒计
...
if (t > timeout_value)
{
Zebra::logger->debug("---一次循环用时 %u 毫秒-----", t);
}
GOOD:
int elapsed_ms = currentTime.elapse(e);
...
if (elapsed_ms > timeout_value)
{
Zebra::logger->debug("-----一次循环用时 %u 毫秒---", elapsed_ms);
}
2. 原则:避免误导
- 必须避免留下掩藏代码本意的错误线索
- 避免使用与本意相悖的词
- 提防使用不同之处较小的名称
- 拼写前后不一致就是误导
BAD:
std::vector<int> account_list; // _list就是一个误导, accounts会更好
bool sendToZoneServer(); // 和下面的函数差别很小
bool sendToZoneServers(); // sendToAllZoneServers会好点
3. 原则:做有意义的区分
- 代码是写给人看的,仅仅是满足编译器的要求,就会引起混乱
- 以数字系列命名(a1,a2,…),纯属误导
- 无意义的废话: a, an, the, Info, Data
BAD:
void copy(char a1[], char a2[]) {
for (size_t i = 0; a1[i] != '\0'; i++)
a2[i] = a1[i];
}
GOOD:
void copy(char source[], char dest[]) {
for (size_t i = 0; source[i] != '\0'; i++)
dest[i] = source[i];
}
4. 原则:使用可读的名字
- 避免过度使用缩写
- 可读的名字交流方便
5. 原则:使用可搜索的名字
- 避免使用Magic Number
- 避免使用单字母,或出现频率极高的短字母组合(注意度的把握)
BAD:
if (obj->base->id == 4661) // 4661是啥玩意?
{
usetype = Cmd::XXXXXXX;
}
int e; // 怎么查找?
XXXX:iterator it; // 变量作用的范围比较大的时候,也不见得是个好名字
6. 原则:避免使用编码”
- 匈牙利标记法:
- Windows API时代留下的玩意
- 形如:
wdXX, dwXXX, strXXX
- 类型变换导致名不副实,就有可能出现明明是个
DWORD
,变量名却是qwNum
。
PS.匈牙利命名对于我们这些在Linux下摸爬滚打的好多年的来说,看着真心别扭。
- 成员前缀:
- 形如:
m_name, m_xxx
- 基本上都无视,为何要多次一举
PS.说到这一点,可能有些同学有不同意见了,“我这样写是为了区分成员变量和临时变量啊!”,好像这样写也没什么大不了,遵循代码规范即可。如Google的C++代码规范,私有变量形如:xxx_
,加后缀_
,其目的除了让你知道这货是个私有变量,还有一点就是防止有些人图省事把带私有变量直接public掉,因为谁也不喜欢在代码里面看到大量这些带把的玩意。
- 接口和实现:
- 接口名形如:IXXX, I-接口修饰前缀
- 类名形如:CXXX, C-类修饰前缀
- 这些修饰多数时候都是废话
7. 原则:名字尽量来自解决方案领域或问题领域
- 使用解决方案领域名称:
写代码的同学多数都是都出自CS,术语、算法名、模式名、数学术语尽管用。如AccountVisitor:Visitor模式实现的Account类。
- 使用问题领域的名称
我们代码里面多数都是这些名称,不明白找策划问问,基本上都是功能相关的名称。
8. 原则:适当使用有意义的语境
- 良好命名的类、函数、名称空间来放置名称,给读者提供语境
- 只有两三个变量,给名称前加前缀
- 事不过三,变量超过三个考虑封装成概念,添加struct或class
BAD:
// 看着整齐?使用方便?
DWORD love_ensure_type_; //当前的爱情保险类型
DWORD love_ensure_ret_; //购买爱情保险回应标示
DWORD love_ensure_total_; //现在已经盖章数目
DWORD love_ensure_..._; //...
DWORD love_ensure_..._; //...
- 写下任何一行代码的时候,心里都要想着自己的代码是给别人看的。
- 为函数、变量、类取个好名字,遵循规范和原则。
- 见到不符合规范和原则的名字,确毫不留情的干掉它,特别是功能性的代码。
这些超大号函数是怎么来得呢?
- 直接从别处COPY一段代码,随便改改即可,造成大量重复代码。
- 缺少封装,甚至说就没有封装,完全就是随意乱加一气,造成各个抽象层次的代码混合在一起,混乱不堪。
- 成篇的异常处理和特殊处理,核心逻辑或许就是函数体开头、中间或结束那么几行而已。
原则:取个描述性的名字
- 取个一眼就看出函数意图的名字很重要
- 长而具有描述性的名称,要比短而让人费解的好(长度适中,也不能过分长)
2. 原则:保持参数列表的简洁
- 无参数最好,其次一元,再次二元,三元尽量避免
- 尽量避免标识参数
- 使用参数对象
- 参数列表
- 避免输出和输入混用,无法避免则输出在左,输入在右
bool isBossNpc();
void summonNpc(int id);
void summonNpc(int id, int type);
void summonNpc(int id, int state, int type); // 还能记得参数顺序吗?
void showCurrentEffect(int state, bool show); // Bad!!!
void showCurrentEffect(int state); // Good!!
void hideCurrentEffect(int state); // 新加个函数也没多难吧?
bool needWeapon(DWORD skillid, BYTE& failtype); // Bad!!!
3. 原则:保持函数短小
4. 原则:只做一件事5. 原则:每个函数位于同一抽象层级
要确保函数只做一件事,函数中的语句都要在同一个抽象层级上
自顶下下读代码
6. 原则:无副作用
8. 原则:使用异常来代替返回错误码
- 抽离try-cacth
- 错误处理也是一件事情,也应该封装为函数
9. 原则:减少重复代码”
重复是一些邪恶的根源!!!
10. 原则:避免丑陋不堪的switch-case
- 天生要做N件事情的货色
- 多次出现就要考虑用多态进行重构
当在添加新函数的时候:
- 刚下手时违反规范和原则没关系
- 开发过程中逐步打磨
- 保证提交后的代码是整洁的即可
重构现有的函数,有下面情况的,见一个消灭一个:
- 冗长而复杂
- 有太多缩进和嵌套循环
- 参数列表过长
- 名字随意取
- 重复了三次以上
在C++语言中,既可以使用使用过程式的struct来做数据抽象,同时也可以使用面向对象的class来做抽象。在语言层面上,struct和class除了默认访问权限不一样,其它都是一样,但本文中区别对待之,一般使用struct时代表的是数据,Plain Of Data,即就是所谓的POD类型,可以直接存档和在网络上传输。而class代表的是对象的类,支持面向对象中的各种用法。