7.40 《程序员修炼之道》20210224

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