序号
|
书中核心内容
|
收获和和总结
|
0
|
序言
-
没有最好的解决方案,无论是语言,工具还是操作系统,特定条件下才有所谓更合适的系统。
-
务实主义不应该拘泥于任何特定技术,应该有更加广泛的背景和经验基础,以便特定情况下找到所谓的合适解决方案
-
背景来自对计算机科学的基本原理的理解
-
经验来自广泛的实际项目
-
理论和实践会让你更加强大
-
本书为了快速获得经验,提高圣餐礼,更好理解这个开发过程,写出好的软件
-
务实开发者几种类型
-
早期采纳者/快速适配者:喜欢尝试和创新
-
好奇:会问很多问题,
-
批判性思考:没有接到证实很少接收既定的事实
-
现实主义:试图理解面临问题的本质,让你对事情有多困难,需要多少时间有个良好的认知
-
多面手:你努力学习各种环境和技术,并努力跟上新的进展。你喜欢迎接新的挑战
|
|
1
|
第一章:务实的哲学
-
务实程序员的特质
-
根据面临的问题找到宽泛全局的综合考虑,了解来龙去脉并结合实际,解决方案透露出态度,风格和理念
-
为所作的一切负责
-
人生是你的
-
是你在拥有、经营和创造
-
遇到瓶颈时为什么不考虑改变一下呢?
-
我都源码被猫吃了
-
团队信任:团队能信任你,你也能放心依赖团队
-
承担责任:你对手里事积极认同,并付出承诺
-
除了个人尽力,还要把超出自己控制范围之外的风险报告出来
-
犯错和延期时提供选择方案,别为自己找接口
-
当你意识自己不知道,但下一句一定是我会搞清楚的
-
软件的熵(熵增定律:随着时间变为更加混乱:封闭系统+无外力做功)
-
技术债:软件不要有混乱的开始,否则会越来越糟糕
-
绝望,或者不好的事务会传染
-
石头做的汤和煮熟的青蛙
-
筹备期的劳累:拿出石头(合理的请求)不断完善,然后展示给大家,说它还可以更好,只要我们再加点什么
-
牢记全景,关注大局,不要专注你个人做的事情上。
-
够好即可的软件
-
不要一开始就追求完美,先在有限的时间内达到用户要求,
-
让用户参与权衡,到底要做什么?好到什么程度
-
知道何时止步,不要过度修饰和精炼一个完美的程序,让代码该有位置驻留一段时间,它或许永远都不完美
-
知识组合
-
学习新事物的能力是你最重要的战略物资,如何获取学习方法,又如何学习什么?
-
我们将程序员所了解一切有关技术按过程的事实,工作,经验视为拥有的知识组合,构建知识组合
-
定期投资:你必须喜欢学习,即使数量有限,但要保证这一条
-
每年学习一门新语言
-
每月读一本技术书
-
读些非技术的书
-
上课:上些网上有趣课程,技术会议
-
加入本地的用户组或者交流群:主动参与,不只是当听众
-
尝试不同的环境:不止使用w10系统,
-
与时俱进:了解前沿的技术和欣慰,不同技术的特殊术语
-
多样化:知道东西越多,价值就越大,知道特定技术的来龙去脉
-
风险管理:鸡蛋不要放在一个篮子里
-
低买高卖:预测未来技术发展方向,提前做出准备
-
重新评估调整:把一些即将灭亡的技术放弃学习。
-
学习的机会
-
如饥似渴的阅读,所在领域的最新突破进展前沿
-
遇到问题时,把答案作为一项挑战,自己没有能力时,再去请教其他人
-
时间总是挤出来的,小小的10分钟可能让你有大收获
-
批判思维
-
判断自己得到的知识对不对?不要低估商业主义的力量
-
多问五个为什么?
-
谁从中获益?
-
有什么背景?
-
什么场景,解决什么问题
-
交流
-
写代码和沟通一样:写代码用自然语言写文章:尊重DRY原则,ETC,自动化
-
了解听众:知道怎样表达能让对方接受,主要目标对方获取你的知识
-
明白自己想说什么:
-
精炼到不能精炼为止,提取主旨
-
选择时机:知道事情的优先级
-
挑选风格,让它看起来不错:文档的封面和内容不要频频出错
-
让听众参与、做倾听者:听取别人的反馈,吸取他们的智慧
-
回应别人,哪怕简单一句稍后回复你
|
-
人生是自己的掌握主动权,和求知欲
-
不要看到“破窗”视而不见,好得习惯需要每个人的努力,一扇破窗可能是一个城市衰败的开始,要对自己编写代码负责
-
知识的输入是学习一切的前提
-
不做煮熟的青蛙,要掌握大局的动态
-
有效的沟通
-
代码注释
-
精简的语言表达你的意思
-
邮件的言简意赅,之后再高效沟通
-
本章重要的提炼名言
-
关注你的技艺,不断的提升自己,不断的学习
-
思考,思考你的工作:每天思考做什么,怎么做最好
-
你有权力选择:用自己的能力完成自己想做的事情
-
提供选择,别找借口:找到解决方式,或提供几个选择的解决方式代替做无用的狡辩
-
不要放任破窗:坏的事物会被传染
-
做推动变革的催化剂:做煮石头的人
-
牢记全景:不做温水里的青蛙
-
将质量要求视为需求问题:质量对项目至关重要
-
对知识组合做定期投资:每天投入时间学习。
-
批判性地分析你读到和听到的东西,你听到的不一定全是对的
-
英语就是另一门编程语言:开始学习
-
说什么和怎么说一样重要:沟通是传达高效率的信息,
-
把文档嵌进去,不要拴在表面:读源码,把注释好好维护下
|
2
|
第二章:务实的方法(怎样把代码写的更好更快更健壮,甚至还能看起来易懂)
-
优秀设计的精髓
-
能适应使用者的设计就是好的设计
-
ETC(Easier to Change更容易变更)是一种价值观念,不是一条规则:
-
解耦隔离关注点,让每一部分都容易变更
-
单一职责原则,需求变化仅体现某一个单一模块上
-
命名很重要,好的代码更容易阅读,读懂是变更的基础
-
ETC隐含的前提是,多条路线那一条更容易变更
-
想着代码的解耦和内聚
-
培养直觉的方式,把自己面临问题的想法和选择做记录,以后再遇到相似的分岔口会有所选择
-
DRY邪恶的重复
-
DRY是什么:在一个系统中,每一处知识必须单一,明确,权威的表达,不要重复自己
-
DRY针对你对知识和意图的复制
-
表征的重复
-
内部API的重复
-
外部API的重复
-
数据源引起的重复
-
开发人员间的重复:晨会解决
-
正交性
-
正交性是什么,俩条直线相交构成直角,他就是正交,XY轴,完全不影响南北朝向
-
构建出易于设计,构造,测试和扩展的系统
-
非正交的系统:飞机的操作秆,比较复杂,难以变更和控制
-
正交的好处:
-
消除不相关事物之间的影响
-
设计的组件自成一体,独立自主,由单一清晰定义的意图,称为内聚。
-
提高生产力及降低风险
-
工具包和程序库:是否将一些不该有的变化强加给代码
-
编码
-
保持代码解耦
-
避免全局数据
-
避免相似函数
-
测试:更易于自动测试
-
文档:修改更遍历
-
可逆性:面向弹性
-
灵活的架构:将代码分为多个组件
-
曳光弹:体会不到曳光代码怎么贯穿系统。
-
曳光弹是一种会显示轨迹的子弹,真实条件下根据移动目标进行及时反馈。
-
曳光代码不是一次性的,编写为了持续使用,总有东西需要改,总有新功能需要加
-
曳光弹并不总能击中目标:你需要不断的瞄准调整瞄准,直到击中目标。去想办法让它靠近目标
-
原型和便签
-
其它行业的原型和技术开发的原型:楼房或者汽车的模型图和流程图,原型图
-
原型用来研究有风险的东西,或者核心跟你息息相关
-
架构
-
已存在系统中新功能
-
数据结构或者外部数据内容
-
第三方工具和组件
-
性能问题
-
用户界面设计
-
制作原型时那些细节可以忽略
-
正确性:可以使用替代数据
-
完整性:满足有限的功能
-
健壮性:
-
格式:本身文档很少
-
制作架构原型:关注系统各个部分是怎么组成一个整体的,核心问题如下
-
主要组件的职责是否恰当,有没有定义清晰?
-
耦合度最小化了吗?
-
主要组件的协助是否定义清晰?
-
接口的定义和约束能否接受
-
执行过程中每个模块都有所需的数据路径?需要数据时能访问到吗?
-
不要把原型用于产品
-
原型是一次性代码
-
原型利用早期的开发识别出潜在的问题点,并给于修正
-
领域语言
-
计算机语言会影响你思考问题,怎样看待信息传播
-
每门语言都有特性列表,静态类型动态类型,早期绑定晚期绑定,函数式还是面向对象
-
C++的方式和Haskell思想大为不同
-
PSpec
-
Cucumber
-
领域语言的特征
-
Rspec和phonenix路由是宿主语言(Ruby和Elixir)编写,利用诸如元编程和宏迂回代码,像常规代码编译和运行。
-
嵌入运行的代码,它对你编程代码做了扩展。内部语言。
-
Cucumber和Ansible用他们自己专门语言编写,被转换成数据结构再编译
-
转换成代码可以使用莫种形式,外部语言
-
内部语言和外部语言的权衡
-
内部语言使用宿主语言特性,创造的领域语言更为强大
-
外部语言需要利用解析器(现成的外部语言:YAML,JSON,XML)
-
估算
-
多精确才够:面对不同估算采取不同单位
-
估算重合而来
-
理解在问什么
-
对系统建模
-
把模型分解成组件
-
确定每个参数的值
-
计算答案
-
记录自己的估算能力
-
估算项目进度
-
粉刷导弹:
-
计划评审技术:乐观,最有可能,最悲观的方法,做一个区间的值
-
吃掉大象
-
增量开发,做相关迭代
-
检查需求
-
分析风险
-
设计,实现,集成,
-
和用户一起验证,
-
吃掉大象也需要一次咬一口
-
被要求估算是说:我等下答复你,先做初步分析
|
怎样把代码写的更好更快更健壮,甚至还能看起来易懂
-
ETC(Easier to Change更容易变更)是一种价值观念,不是一条规则:
-
解耦隔离关注点,让每一部分都容易变更
-
单一职责原则,需求变化仅体现某一个单一模块上
-
命名很重要,好的代码更容易阅读,读懂是变更的基础
-
ETC隐含的前提是,多条路线那一条更容易变更
-
想着代码的解耦和内聚
-
DRY邪恶的重复
-
正交性:正交性是什么,俩条直线相交构成直角,他就是正交,XY轴,完全不影响南北朝向
-
可逆性:面向弹性
-
曳光弹:体会不到曳光代码怎么贯穿系统。
-
领域语言
-
估算
-
本章重要的提炼名言
-
优秀的设计比糟糕的设计更容易变更
-
DRY是什么:在一个系统中,每一处知识必须单一,明确,权威的表达,不要重复自己
-
让复用变得更容易:
-
消除不相关事物之间的影响:独立自主
-
不设定最终决定:项目的变化和迭代有很多不确定性
-
放弃追逐时尚,薛定谔的猫
-
使用曳光弹找到目标:找到目标,不断调整目中目标的几率。也可以多尝试几次
-
用原型学习:忽略细节,注重主旨
-
靠近问题域编程:明白自己的底层语言适不适用
-
通过估算避免意外:给出大体的范围,降低风险
-
根据代码不断迭代进度表:大的问题分解,不断的迭代完成
|
3
|
基础工具
工具需要学习和适应,需要扩充你的工具,
-
纯文本的威力
-
纯文本是由可打印字符组成,构成某种传递信息的形态,HTML,JSON,YAML都是纯文本,
-
协议也是纯文本:HTTP,SMTP,IMAP
-
文本的作用
-
为防备老化而加的保险
-
杠杆效应:版本控制系统到编辑器,再到命令行工具,计算机所有领域工具都可以对纯文本操作
-
最小公分母:各方使用的标准,能实现相互沟通,纯文本就是这个标准
-
shell游戏
-
shell是一个开发的工作台,操纵LInux系统的命令
-
你的专属的Shell
-
加强编辑能力
-
游刃有余意味什么
-
逐步游刃有余
-
培育你的编辑器
-
版本控制
-
版本控制系统VCS是大型的撤销按钮,
-
从源码开始
-
分支出去
-
把版本控制视为项目中枢
-
调试
-
调试心理学:调试只是在解决问题并为此攻克
-
调试心态:让自己放松,不要恐慌
-
从哪里开始
-
需要确认BUG的原因,或者找提出BUG的人确认
-
人为的充分测试,
-
调试策略:一旦发生问题就去查明
-
复制BUG:先复现问题,了解场景再去细分那的问题
-
身处陌生之地的程序员:确认出错信息,输入敏感值和边界值,
-
二分法不断缩小查找问题范围
-
输出日志和跟踪信息
-
找个橡皮鸭:向别人说出你的排查过程和确认问题的思路
-
排除法:你改变东西导致代码崩溃,不要想着是服务器的问题,理性的解决
-
让人吃惊的元素:不要假设,要证明
-
文本处理
-
学习一门文本处理语言:学习Python
-
工程日记
-
日记本的好处
-
他比记忆更可靠
-
他为你保存你当时的想法,专注于正在做的事情
-
为了避免当时大脑换挡
|
开发基础工具
-
尝试不用键盘写所有代码
-
Shell 功能需要我们不断大局
-
版本控制能力
-
调试的技术
-
心态
-
高效
-
目的是解决问题
-
文本处理
-
记录手头工作
-
文中重要提示
-
将知识用纯文本保留:用文本记录知识
-
发挥Shell命令的威力
-
游刃有余的使用编辑器:
-
永远使用版本控制:保存你电脑一切文件,当电脑出现问题时,会急速的恢复他们。
-
去解决问题,而不是责备:目的是解决问题
-
不要恐慌:心平气和的解决问题
-
修改代码先让代码测试中失败:找到问题复现
-
读下该死的出错信息
-
Select没问题:你写完代码有问题,大部分是你代码的问题
-
不要假设,要证明:找出BUG和可能涉及的点修改之后验证
-
学习一门文本处理语言:学习Python
|
4
|
务实的偏执
-
务实的程序员为自己的错误建立防御机制(就像全世界的司机)
-
客户和供应商必须就全力和责任达成共识
-
断言式编程为你写的代码主动校验代码
-
契约式设计(伯特兰迈耶《面向对象软件构造》发明)
-
契约就是为了人与人沟通:规定你的权利和责任同时也规定他人
-
使用相同的理念促进软件模块
-
DBC:简单但功能强大的技术,侧重于文档化软件模块的权利和责任,一种设计技术
-
前置条件:为什么调用这个例程,参数传输是否合法
-
后置条件:例程要做什么?得出什么样的结论,不允许无限循环
-
类的不变式:例程内部处理,可以不遵守不变式,但当退出给返回者,不变式必须为真
-
实现DBC:编写之前,简单的列出输入域范围,边界条件和实现的功能。
-
断言:断言是一种对逻辑条件的运行时检查
-
面向对象语言,断言并不能向下传播到继承的层次里
-
DBC与尽早崩溃:检查可能出现问题的点
-
语义不变公式:来表达不可变的需求,并公布让大家知道。
-
动态契约和代理:设计不可变项,例如合同的约束
-
死掉的程序不会说谎:通常问题早就被发现但一直没有解决
-
捕获再释放适合用在鱼身上:捕获要释放资源
-
崩溃,不要制造垃圾
-
代码故障的恢复机制,清理工作,以及重新启动
-
监管程序树构成的的设计,有助于解决语言高可用和容错性的系统用法
-
断言式编程
-
使用断言预防不可能的事情
-
保持断言常开:增加发现问题的途径,
-
如何保持资源平衡
-
有始有终:分配资源的函数和对象,对释放资源应该有责任
-
嵌套的分配
-
释放资源和分配资源的次序相反
-
在代码不用位置,分配同一组资源,以相同的顺序分配他们
-
对象和异常:构造函数会当你需要时初始化,操作作用域垃圾回收,异常机制可能对资源释放有干扰,
-
保持平衡和异常:不要尝试释放不存在的东西
-
当你无法保持资源平衡时
-
不要冲出前灯范围
-
小步前进,有始有终,使代码可替换,高内聚,解耦和DRY,实现好的总体设计
|
-
务实的程序员为自己的错误建立防御机制(就像全世界的司机)
-
契约式设计(伯特兰迈耶《面向对象软件构造》发明)
-
契约就是为了人与人沟通:规定你的权利和责任同时也规定他人
-
使用相同的理念促进软件模块
-
DBC:简单但功能强大的技术,侧重于文档化软件模块的权利和责任,一种设计技术
-
死掉的程序不会说谎:通常问题早就被发现但一直没有解决
-
断言式编程
-
如何保持资源平衡
-
不要冲出前灯范围
-
-
文中重要提示
-
你无法写出完美的软件:跟司机一样你需要建立防御机制
-
通过契约进行设计:有相关的思考和接口规范
-
尽早的奔溃:测试恢复数据,清理工作和和重新启动
-
使用断言预防不可能的事情:增加发现问题的途径
-
有始有终:分配资源的函数和对象,对释放资源应该有责任
-
在局部行动:在嵌套优雅完成资源分配
-
小步前进,有始有终,使代码可替换,高内聚,解耦和DRY,实现好的总体设计
-
避免占卜:明天会跟今天一样,但不要指望
|
5
|
宁弯不折:代码如何可逆,一切为了代码容易变更
-
解耦:代码之间的依赖关系,将不同的概念分开,以减少耦合
-
代码不需要刚性(不好变更)而更需要耦合性
-
耦合有传递性,如果A跟B,C耦合,B跟M,N耦合,C跟X,Y耦合
-
那么A跟BCMNXY都耦合
-
解耦的相关优化
-
铁道事故:一连串的方法调用
-
客户和订单问题:暴露客户的API
-
全局化:静态事物的风险
-
继承:为什么子类很危险
-
LoD得墨脦耳法则:定义在C类的函数只应该调用
-
C类的其它实例方法
-
它的参数
-
它所创建的对象的方法,包括它的栈上和堆上的对象
-
全局变量
-
邪恶的全局化
-
全局变量给代码带来耦合,分解和修改会影响全局代码
-
避免全局数据
-
如果全局唯一非常重要,将它包装到API中
-
集成也会郑家耦合
-
一切为了代码容易变更
-
耦合的代码无法变更
-
让代码害羞一点:让它只处理直接知道的事,有助于应用程序解耦
-
在现实世界中抛球杂耍
-
事件:表达出消息可用性
-
外部:用户触发了按钮
-
内部的:定时任务,完成搜索,像获取列表获取下一行数据
-
应用程序事一堆紧耦合的代码,帮助解决的四个策略
-
有限状态机FSM:实现只需要几行代码,但有助于解决很多潜在问题
-
务实的FSM的刨析:状态机是怎样处理事件的一份规范,由一组状态组成
-
由初始状态,读取消息,出错和完成几个主要状态组成
-
观察者模式:在用户界面特别流行,回调被用于通知应用程序,但引入耦合
-
事件源时被观察的对象,客户列表就是观察者
-
发布/订阅:推广了观察者模式,同时解决了耦合和性能问题
-
pubsub中有发布者和订阅者,通过信道连接,
-
通信在代码外处理,可以时异步的
-
缺点:很难查看重度使用的pubsub系统发生了什么:无法看发布同时订阅者设计特定消息
-
基本上时消息传递系统,创建响应事件的组合系统需要不仅仅是这些。
-
响应式编程与流:为事件处理添加维度
-
流让我们把事件当作数据集合来对待:可以操作、合并、过滤、以及其它我们对数据的处理1
-
变换式编程
-
所有程序都是对数据的一种变换,将输入变成输出
-
编程讲的是代码,而程序谈的是数据
-
寻找变换:确定输入和输出,继续变换
-
错误处理怎么做:首先选个表达式
-
继承税:很不幸继承就是耦合
-
子类耦合到父类,父类的父类,父类的父类
-
典型的例子是汽车是一种交通工具,后来变为资产,保险项目,贷款抵押等等所以实现了多重继承
-
三种更好的替代继承方案
-
接口和协议:尽量用接口表达多态:接口和协议给我们不使用继承的多态性
-
委托:用委托提供服务:有一个胜过是一个
-
mixin与特征:类别,协议扩展。利用mixin共享功能
-
希望能够为类和扩展新的功能,但不用继承
-
配置
-
如果代码依赖某些值,这些值再应用程序发布之后还有可能改变,那么先把这些值放在程序的外部
-
静态配置:YAML和JSON可定制配到服务当中
-
配置服务化:保持应用程序外部,不放在程序里,也不放在数据库,存储在服务的API里的好处。
-
身份认证和访问权限控制的哟个程序共享配置信息
-
配置的变更可以任何地方进行
-
配置数据可以通过专有的UI维护
-
配置数据变的动态
|
宁弯不折:代码如何可逆,一切为了代码容易变更
-
解耦:代码之间的依赖关系,将不同的概念分开,以减少耦合
-
编程讲的是代码,而程序谈的是数据
-
不要囤积状态,传递下去
-
不要付继承税:继承意味着耦合,使用其他技术代替
-
尽量用接口表达多态:接口和协议给我们不使用继承的多态性
-
用委托提供服务:有一个胜过是一个
-
mixin与特征:类别,协议扩展。利用mixin共享功能
-
使用外部配置参数化应用程序:配置服务化:保持应用程序外部,不放在程序里,也不放在数据库,存储在服务的API里的好处。
-
本章重要总结
-
解耦让代码改变更容易:灵活性
-
只管命令不要询问:不应该根据对象的内部状态做出决策,然后更新该对象
-
不要链式调用方法
-
避免全局数据
-
如果全局很重要,将它包装到API当中
-
编程讲的是代码,而程序谈的是数据
-
不要囤积状态,传递下去
-
不要付继承税:继承意味着耦合
-
尽量用接口表达多态:接口和协议给我们不使用继承的多态性
-
用委托提供服务:有一个胜过是一个
-
mixin与特征:类别,协议扩展。利用mixin共享功能
-
使用外部配置参数化应用程序:配置服务化:保持应用程序外部,不放在程序里,也不放在数据库,存储在服务的API里的好处。
|
6
|
并发和并行
-
获得并行性
-
并发性指的是俩个或者更多的代码段在执行过程表现的像同时运行,排队去去咖啡,一台咖啡机
-
特殊环境运行代码,不同部分之间切换执行过程。环境基于纤程,线程,进程。
-
并行性指的是他们确实同一时刻一起运行,俩个队俩台咖啡机
-
同时做俩件事的硬件,通常同一个CPU多核心,同一机器多个CPU,连接在一起的多台机器
-
一切都会并发
-
并发是程序的必要条件:用户交互,数据在获取中,外部服务调用中,都是同时进行的。
-
并发和并行的困难:
-
我们使用顺序系统学习编程,俩件事同时调用资源,罪魁祸首是共享状态(俩块以上代码对同一可变数据的引用)
-
解决方式:角色模型构建并发应用,他不允许独立进程之间共享任何数据,只通过预定好多简单语义进行通信
-
打破时域的耦合
-
时域耦合时实践,并发性(在同一时刻发生多件事)以及次序(事情在时间轴的相对位置)
-
搜寻并发性
-
通过分析流提高并发性(制作鸡尾酒的流程)
-
并发的机会:审视活动中可并发的时间(让CPU更加的忙碌)
-
并行的机会:多个处理器,处理器分配
-
共享状态是不正确的状态:并发的问题是共享状态
-
非原子更新:信号量和其它形式互斥
-
让资源具有事务性
-
多个资源的事务:
-
非事务性更新
-
其他类型的独占访问
-
角色和进程
-
角色:一个独立的虚拟处理单元,具有自己本地的虚拟状态,角色有信箱,消息出现在信箱中且角色处于空闲状态,就会被激活
-
处理该条消息,他将继续处理信箱其它消息,信箱为空返回休眠状态。
-
进程:代表一种更通用的虚拟处理机,操作系统实现,使并发更容易,进程约束以角色的形式运转
-
角色只会是并发的
-
没有一件事是可控的
-
系统中唯一的状态,保存在消息和每个角色的本地状态中。
-
所有消息都是单向的,没有回应的概念
-
角色会将每一条消息处理完,一次处理一条
-
没有显式的并发
-
黑板
-
放任并发的形式,侦探是独立的进程,代理人,角色等
-
侦探不知道其他人存在,通过观察通过黑板获取新的信息,并向黑板添加发现。
-
他们有着共同的目标,破掉黑板上的案子
-
不同的侦探加入又退出,可能轮班工作
-
黑板上内容没有限制,图片,句子,物证等
-
基于计算机的黑板系统,最初被用于人工智能的应用,所解决大型复杂的问题-语音识别,推理系统等
-
黑板擅长的事
-
工作流处理每一个可能出现的问题组合,不得不去修改代码,硬编码的地方也需修改
-
解决困难的优雅方案,发布一个事实,触发适当规则,反馈更容易处理,任何跪着都可发布在黑板上
-
消息系统可以像黑板一样工作(KAfka和NATS:数据发送,持久化数据,检索消息)
-
黑板的缺点
-
面向架构的角色,黑板和微服务解决方案,消除了潜在的并发类型问题。
-
代价是比较难推理出来,很多操作都是间接的
-
这类系统的部署和管理比较麻烦,需要更多的活动组件,在一定程度上系统的粒度更细
|
-
通过分析工作流提高并发性:
-
共享状态是不正确的状态:并发的问题是共享状态
-
随机故障通常是并发问题
-
用角色实现并发性时不必共享状态
-
使用黑板来协调工作流
|
7
|
-
当你在编码时
-
编码不是机械的工作
-
务实的程序猿会对所有代码进行批判性思考,包括自己的代码
-
命名是软件开发中最困难的事情之一,保持头脑清醒
-
听从蜥蜴脑
-
害怕空白页:你可能担心自己会犯错
-
听从你内心的蜥蜴:首先停止正在做的事,充分休息,试着描述代码
-
做原型,然后休息开始工作
-
不仅仅是你的代码
-
我们的大部分工作是处理现有的代码,这些代码通常由其它人编写,机械的读别人代码,这是一件苦差事
-
理解别人代码模式
-
巧合编程
-
我们应该避免通过巧合编程,靠运气和意外获来成功是行不通的,编程应该深思熟虑。
-
不要依赖巧合编程
-
你构建的代码只是为了模仿而缺乏内容吗,找到恰好能用的答案和找到正确答案不是一回事。
-
算法速度
-
务实的程序员每天在做:评估算法所需的时间,处理器,内存等资源
-
你知道程序跑1000记录的时长吗?跑1千万会怎样,那部分代码需要优化呢
-
通常解答需要常识的分析,引入大量的O符号描述近似值
-
评估算法到底是什么
-
编写任何包含循环和递归调用会下意识检查运行时间和内存需求
-
大多数非平凡算法处理一些可变输入,对N个字符串排序,对m*n矩阵取反,用一个n比特解密一条信息。
-
输入的大小会影响算法:输入数量越大,运行时间就越长,使用内存就越多,但大多数算法非线性
-
大O符号:对N个记录排写作O(n2的平方),最糟糕,时间随着N平方变化,记录翻倍,时间会四倍正增加,测量对象(时间,内存)的上限
-
函数所需时间不超过n2的平方
-
算法的运行时间,假设1S处理100条记录
-
O(1):常量(访问数组中元素,简单的代码段)1s
-
O(lg n:log n)对数(二分查找)3s
-
二分法:二分查找,遍历二叉树,找到机器最高位
-
O(n):线性(顺序查找)10s
-
简单循环:穷举查找,数组最大值,生成校验和
-
O(n lg n)(快速排序和堆排序)33s
-
分治法
-
O(n的平方)(选择排序和插入排序)100s
-
嵌套循环:冒泡排序,俩层循环
-
O(n的立方)(两个矩阵N*N的乘法)
-
O(C的n次方)(旅行推销员问题,集合划分)
-
实践中的算法速度
-
评估算法级别实践优化,
-
对估算做测试
-
重构
-
随着代码的演化,有必要重新考虑早期的决策,对部分代码返工,代码需要演化
-
何时该重构
-
你更了解某个技术,更适合时你会重构
-
代码不合适,需要合并。
-
当你发现重复违背DRY的地方,让其正交,过时的代码,使用,性能。
-
复杂的现实世界
-
重构代码相当于切除肿瘤,如若时间越长,切除更加昂贵和危险
-
为编码测试
-
测试和找BUG无关:测试是你思考测试和编写测试的时候,而不是运行测试的时候
-
测试是代码的第一个用户:测试反馈的结果至关重要,可以指导编码过程
-
测试驱动开发(TDD):测试先行开发
-
TDD需要实践,但要时不时看下大局
-
TDD:你需要知道该去何方
-
计费自上而下,也不是自下而上,基于端对端的构建
-
构建软件是增量的
-
单元测试
-
程序员给代码随机数据,看下打印语句,声称测试通过,其实我们可以做的更好。
-
针对契约测试,代码是否符合契约,契约是否具有我所认为的含义
-
为测试做设计
-
临时测试正式化,把它添加到现有的单元测试库中
-
开一扇测试窗口,包含跟踪消息的日志文件,
-
要对软件测试,否则只能留给用户去做
-
测试是编程的一部分,不应该留给别人。测试,设计,编码:都是在编程
-
基于特性的测试
-
契约,不变性和特性
-
使用基于特性的测试来校验假设
-
基于特性的测试能带来惊喜
-
基于特性的测试对设计也有帮助
-
出门在外注意安全
-
程序员要完整编写代码
-
开发完跑通代码实际只做了90%,接下来要做分宜出错的路径,加到测试中
-
考虑错误的参数,泄露的资源或资源不存在等情况
-
安全性的基本原则:务实的程序员有很多偏执,知道自己的缺陷和限制,外部攻击者会抓住机会去破坏系统
-
将攻击面的面积最小化:攻击者输入数据,提取,调用服务总和
-
代码复杂滋生攻击载体,代码越少,意味更少的bug
-
输入数据是一个攻击的载体
-
身份认证的服务变为攻击载体
-
保持代码简洁,让攻击面最小
-
-
最小特权原则
-
安全带默认值
-
敏感数据要加密
-
维护安全更新
-
尽早打上安全不定
-
常识和密码学
-
事物命名
-
思考创建的动机
-
尊重文化:计算机科学的俩件难事:缓存失效和命名
-
一致性
-
更名更难
-
好好取名,需要时更名
|
-
倾听你内心的蜥蜴
-
不要依赖巧合编程
-
评估算法的级别:是否优化降级,实际运行评估
-
对估算测试:
-
尽早重构,经常重构:代码越推迟问题会越多
-
测试和找BUG无关
-
测试是代码的第一个用户
-
非自上而下,也不自下而上,基于端对端的构建
-
为测试做设计
-
要对软件做好测试,否则只能留给用户去做
-
使用基于特性的测试来校验假设
-
保持代码简洁,让攻击面最小
-
尽早打上安全补丁
-
好好取名,需要时更换名称
|
8
|
项目启动之前
项目的最早期,你和团队需要了解需求,有一些关键问题如果能在项目启动前就解决,可以更好避免“分析瘫痪”,从而真正开始项目。
-
需求之坑
-
需求很少停留在表面:通常它们被埋在层层假设,误解和政治之下,最糟糕的,需求通常根本不存在。
-
无人确切知道自己想要什么
-
程序猿帮助人们理解他们想要什么
-
需求是一个过程:需求是从反馈循环中学到的
-
务实的程序猿将所有项目是为采集需求的练习。
-
代入客户的立场
-
深入客户的头脑,找到客户的痛点:成为客户。
-
和用户一起工作以便站在用户角度思考。
-
需求和策略
-
当策略改变时,需要更新该系统的元数据,以这种方式采集需求,自然会导向一个通过良好分解来支持元数据的系统
-
策略既元数据
-
需求和现实
-
需求文档化,最好的需求文档:可以工作的代码
-
需求文档不是为客户准备的
-
需求文档是为计划准备的
-
过度规范化
-
生成需求另一大危险就是过于具体,好的需求是抽象的。
-
需求不是架构,需求无关设计,也非用户界面,需求就是需要的东西。
-
维护一张术语表:来维护各自说的特定意义术语。
-
处理无法解决的难题
-
自由度:识别真正的约束条件
-
不要跳出框框思考,要先找到框框
-
跳出自身的局限:分散注意力的时候,答案总是会突然出现在你的脑海里
-
幸运眷顾有准备的人:不要恐慌,记录日记。
-
携手共建
-
一起工作的真正含义:不仅仅是提问,讨论,做笔记,还要在真正的编码同一时刻提问和讨论。
-
康威定律:设计系统的架构受制于产生这些设计的组织的沟通结构
-
结对编程:相互监督会提高软件质量
-
群体编程:现场编码的紧密合作
-
我该做什么
-
不要一个人埋头钻进代码里
-
敏捷的本质:是一个形容词,敏捷指的是办事风格
-
敏捷不是一个名词,敏捷有关你如何做事
-
任何向你推销开箱即用的方案,没有读过介绍声明,这是生产过程的建议
-
个体和互动高于流程和工具
-
工作的软件高于详尽的文档
-
客户合作高于合同谈判
-
响应变化高于遵循计划
-
永远不可能有一个叫敏捷的工艺流程:关于收集和回应反馈
-
我们应该做什么
-
弄清楚你在哪里
-
朝想去的方向迈出有意义的最小一步
-
评估在哪里终结,把弄坏的东西修好
-
还可以用来驱动设计
-
优秀的设计比糟糕的设计更容易变更
|
-
本章重要的提示
-
无人确切知道自己想要什么
-
程序猿帮助人们理解他们想要什么
-
需求是一个过程:需求是从反馈循环中学到的
-
和用户一起工作以便站在用户角度思考。
-
策略既元数据
-
维护一张术语表:来维护各自说的特定意义术语。
-
不要跳出框框思考,要先找到框框
-
不要一个人埋头钻进代码里
-
敏捷的本质:是一个形容词,敏捷指的是办事风格
|
9
|
务实的项目
-
版本控制,测试和自动化组成的务实入门套件
-
务实的团队:团队是小而稳定的实体,20人不算团队,那是部落。
-
务实的团队很小,充其量也就10-12人左右,成员很少进出,每个人很了解彼此,相互信任和依赖
-
维持小而稳定的团体
-
禁止破窗:质量只能来自团队每个成员的独立贡献,质量是内在的,无法额外保证
-
煮熟的青蛙:保持清醒,对项目范围扩大,任何没有理解的地方都需要留心。
-
为知识组合安排日程
-
团队的工作不应仅致力于开发新功能
-
旧系统的维护
-
流程的反思和精炼
-
实验新技术
-
学习和提升技能
-
排上日程以待其成
-
团队整体对外交流:需要清晰的沟通
-
糟糕的团队会议混乱,电子邮件,项目文档一团糟,
-
优秀的团队开会准备的很充分,文档清晰没准确,激情的工作
-
不要重复自己
-
保持清醒,留意团队的DRY
-
团队的曳光弹
-
无论多么小的局限,都要贯穿整个系统,
-
意味你需要有的技能:前端,UI/UX,服务器,DBA,QA
-
组织全功能的团队:构建团队,端对端,增量的,迭代地构建代码
-
自动化
-
构建工具和部署工具,用其将项目开发和生产部署自动化
-
椰子排不上用场
-
不要模仿外在,要模式落到实地,真正解决问题
-
光环境很重要
-
做能起作用的事,别赶时髦
-
同一尺码无法适应所有人
-
没有那个计划可以照搬的,更别说特定的业务,
-
真正的目的
-
在用户需要时交付
-
务实的入门套件
-
每个团队需要最基本的,最重要的元素是是什么,而不是考虑方法,语言,技术栈。
-
版本控制:使用版本控制来驱动构建,测试和发布
-
版本控制在项目级别驱动构建和发布流程
-
回归测试
-
现在我们主动找到BUG,将来不用忍受别人找到带来的难处
-
尽早测试,经常测试,自动测试
-
通过测试建立对项目的自信心
-
只到所有测试已运行,编码才算真正完成。
-
对破坏者检测你的测试、
-
测试状态覆盖率,而非代码覆盖率
-
每个BUG只能出现一次
-
完全自动化
-
不用使用手动程序
-
取悦用户
-
取悦用户,而不是只是交付代码
-
傲慢和偏见
-
务实的程序员不会逃避责任:我们乐于接受挑战,
-
在作品上签名
-
人们应该在代码上看到你的名字,并对它是可靠的,编写良好的,经过测试的,文档充足,
|
-
务实的团队:团队是小而稳定的实体,成员很少进出,每个人很了解彼此,相互信任和依赖
-
排上日程以待其成:团队整体对外交流:需要清晰的沟通
-
组织全功能的团队
-
做能起作用的事,别赶时髦:同一尺码无法适应所有人
-
在用户需要时交付是真正的目的
-
版本控制:使用版本控制来驱动构建,测试和发布
-
尽早测试,经常测试,自动测试
-
只到所有测试已运行,编码才算真正完成。
-
对破坏者检测你的测试、
-
测试状态覆盖率,而非代码覆盖率
-
每个BUG只能出现一次
-
不用使用手动程序
-
取悦用户,而不是只是交付代码
-
在作品上签名:人们应该在代码上看到你的名字,并对它是可靠的,编写良好的,经过测试的,文档充足,
|
10
|
-
文中重要的提示汇总
-
关注你的技艺,不断的提升自己,不断的学习
-
思考,思考你的工作:每天思考做什么,怎么做最好
-
你有权力选择:用自己的能力完成自己想做的事情
-
提供选择,别找借口:找到解决方式,或提供几个选择的解决方式代替做无用的狡辩
-
不要放任破窗:坏的事物会被传染
-
做推动变革的催化剂:做煮石头的人
-
牢记全景:不做温水里的青蛙
-
将质量要求视为需求问题:质量对项目至关重要
-
对知识组合做定期投资:每天投入时间学习。
-
批判性地分析你读到和听到的东西,你听到的不一定全是对的
-
英语就是另一门编程语言:开始学习
-
说什么和怎么说一样重要:沟通是传达高效率的信息,
-
把文档嵌进去,不要拴在表面:读源码,把注释好好维护下
-
优秀的设计比糟糕的设计更容易变更
-
DRY是什么:在一个系统中,每一处知识必须单一,明确,权威的表达,不要重复自己
-
让复用变得更容易:
-
消除不相关事物之间的影响:独立自主
-
不设定最终决定:项目的变化和迭代有很多不确定性
-
放弃追逐时尚,薛定谔的猫
-
使用曳光弹找到目标:找到目标,不断调整目中目标的几率。也可以多尝试几次
-
用原型学习:忽略细节,注重主旨
-
靠近问题域编程:明白自己的底层语言适不适用
-
通过估算避免意外:给出大体的范围,降低风险
-
根据代码不断迭代进度表:大的问题分解,不断的迭代完成
-
将知识用纯文本保留:用文本记录知识
-
发挥Shell命令的威力
-
游刃有余的使用编辑器:
-
永远使用版本控制:保存你电脑一切文件,当电脑出现问题时,会急速的恢复他们。
-
去解决问题,而不是责备:目的是解决问题
-
不要恐慌:心平气和的解决问题
-
修改代码先让代码测试中失败:找到问题复现
-
读下该死的出错信息
-
Select没问题:你写完代码有问题,大部分是你代码的问题
-
不要假设,要证明:找出BUG和可能涉及的点修改之后验证
-
学习一门文本处理语言:学习Python
-
你无法写出完美的软件:跟司机一样你需要建立防御机制
-
通过契约进行设计:有相关的思考和接口规范
-
尽早的奔溃:测试恢复数据,清理工作和和重新启动
-
使用断言预防不可能的事情:增加发现问题的途径
-
有始有终:分配资源的函数和对象,对释放资源应该有责任
-
在局部行动:在嵌套优雅完成资源分配
-
小步前进,有始有终,使代码可替换,高内聚,解耦和DRY,实现好的总体设计
-
避免占卜:明天会跟今天一样,但不要指望
-
解耦让代码改变更容易:灵活性
-
只管命令不要询问:不应该根据对象的内部状态做出决策,然后更新该对象
-
不要链式调用方法
-
避免全局数据
-
如果全局很重要,将它包装到API当中
-
编程讲的是代码,而程序谈的是数据
-
不要囤积状态,传递下去
-
不要付继承税:继承意味着耦合
-
尽量用接口表达多态:接口和协议给我们不使用继承的多态性
-
用委托提供服务:有一个胜过是一个
-
mixin与特征:类别,协议扩展。利用mixin共享功能
-
使用外部配置参数化应用程序:配置服务化:保持应用程序外部,不放在程序里,也不放在数据库,存储在服务的API里的好处。
-
通过分析工作流提高并发性:通过分析工作流提高并发性:
-
共享状态是不正确的状态:并发的问题是共享状态
-
随机故障通常是并发问题
-
用角色实现并发性时不必共享状态
-
使用黑板来协调工作流
-
倾听你内心的蜥蜴
-
不要依赖巧合编程
-
评估算法的级别:是否优化降级,实际运行评估
-
对估算测试:
-
尽早重构,经常重构
-
测试和找BUG无关
-
测试是代码的第一个用户
-
非自上而下,也不自下而上,基于端对端的构建
-
为测试做设计
-
要对软件做好测试,否则只能留给用户去做
-
使用基于特性的测试来校验假设
-
保持代码简洁,让攻击面最小
-
尽早打上安全补丁
-
好好取名,需要时更换名称
-
无人确切知道自己想要什么
-
程序猿帮助人们理解他们想要什么
-
需求是一个过程:需求是从反馈循环中学到的
-
和用户一起工作以便站在用户角度思考。
-
策略既元数据
-
维护一张术语表:来维护各自说的特定意义术语。
-
不要跳出框框思考,要先找到框框
-
不要一个人埋头钻进代码里
-
敏捷的本质:是一个形容词,敏捷指的是办事风格
-
务实的团队:团队是小而稳定的实体,成员很少进出,每个人很了解彼此,相互信任和依赖
-
排上日程以待其成:团队整体对外交流:需要清晰的沟通
-
组织全功能的团队
-
做能起作用的事,别赶时髦:同一尺码无法适应所有人
-
在用户需要时交付是真正的目的
-
版本控制:使用版本控制来驱动构建,测试和发布
-
尽早测试,经常测试,自动测试
-
只到所有测试已运行,编码才算真正完成。
-
对破坏者检测你的测试、
-
测试状态覆盖率,而非代码覆盖率
-
每个BUG只能出现一次
-
不用使用手动程序
-
取悦用户,而不是只是交付代码
-
在作品上签名:人们应该在代码上看到你的名字,并对它是可靠的,编写良好的,经过测试的,文档充足,
-
先勿伤害:接了一些负责任的项目就必须做好
|
|