读《程序员修炼之道·通向务实的最高境界》思考

这本书真的是值得读两遍以上的,以下内容每句都是精华,值得反复斟酌,它可以教会你怎样从'小工'到'工匠'

第一章 务实的哲学

习惯

  • 当你看到不懂的名词时候,请google它

注释

  • 已经能表达的代码没必要全部写注释,注释一些思路,选择决定更重要
  • 把文档嵌入到工作中,生活中,就像现在记录一样

随记

  • 首先让产品看起来不错
  • 一定要及时回应别人
  • 明白自己想说什么
  • 让听众参与其中
  • 选择一个较好的时机去诉说
  • 关注身边的事情,因为身边的事情是与你相关的

第二章 务实的方法

ETC(Easier To Change)

  • 他是一种价值观,并不是规则
  • "我刚刚做的事情,让整个系统更容易改变,还是更难改变"
  • DRY:不要重复
  • 不要依赖你无法控制的东西
  • 改变某对象的状态,让他自己来完成
  • 可逆性:不要只有一个想法
  • 不要追求时髦
  • 学习另一门语言(C/YALM/Python)
  • 使用曳光弹完成项目
  • 最好使用内部语言测试

第三章 基础工具

学习一门文本处理/辅助语言

  • 就决定是你了,Python!!!!

第四章 务实的偏执

DBC(契约式编程)

  • 前置条件:传递良好的数据/前置环境,是调用者的责任,前置条件不匹配,抛出异常(语言不支持的话,只能在用例里手动assert触发)
  • 后置条件:履行的职责结果保证为真,结果是准确的
  • 类的不变式:精准的前置条件访问权限
  • 简短的代码块,职责少的代码块

尽早崩溃

  • 不要捕获一个函数所有异常,然后再抛出去,没有任何意义
  • 因为异常随时新增,捕获不全,有异常的程序并不会让程序黯然失色
  • 防御式编程是在浪费时间,让他崩溃!
  • 统一提供监管去处理异常是优秀的设计
  • 死掉的程序比瘫痪的程序损失要小得多
  • 不要彻底的关闭断言

资源平衡

  • 释放资源的顺序要与分配资源的顺序相反
  • 在多处代码块申请不同资源的时候,申请资源顺序要保持一致
  • 以上是运行时的资源问题,非运行时资源,譬如说日志,统计,是否滚动日志同时做了清理
  • 随时提醒自己,是否有资源还未考虑到
  • 技巧:当异常处理会影响到资源管理时,把资源管理嵌入到里,这种情况,会有特别的好处
  • 处理异常资源释放的正确姿势
thing = allocate_resourece()
negin
    process(thing)
finally
    deallocate(thing)
end
  • 无法保证平衡时(上述平衡将不能保证)
    • 原因:动态类型的程序,分配一个内存,并且把此数据交给更大结构中
    • 处理方案大约有三种:
      • 顶层负责释放它所包含的所有子结构,然后将这些结构递归的删除包含他们的子数据等
      • 顶层结构只做简单的释放,他所指向的每个结构,都变得无处引用
      • 如果包含子结构,则顶层拒绝释放自己

不要冲出前灯

  • 小步前进-有始至终
    • 深思熟虑的小步骤,同时检查反馈,不断推进调整
  • 什么是大步骤
    • 我们只能看到两小时,最多两三天,超过则不能
    • 预估未来几个月的之后的完成日期
    • 为将来的维护和可拓展做预设(适可而止,把当前代码做成可替换的,将来更有效)
    • 猜测用户将来有什么需求
    • 猜测将来有什么技术可用

第五章 宁弯不折

编写更少的代码,配置将细节移除代码

解耦

  • 耦合的症状:
    1. 不相关的库和模块,发生古怪的依赖关系
    2. 对一个模块简单的修改,会传播到其他系统模块,或者会破坏掉他们
    3. 开发人员会害怕修改代码,因为他们不确定会造成什么影响
  • 铁道事故(链式的调用)
    • 譬如这样,只要有任何一个地方需求改变,拓展将变得复杂繁琐
      public void applyDiscount(customer, order_id, discount){
          customer
          .orders
          .find(order_id)
          .getTotal()
          .applyDiscount(discount);
      }
      
    • 正确做法
      • 只管命令,不要询问
      • 不要根据对象的状态,去做决策,然后更新它(这也是不会划分职责的重要原因)
      public void applyDiscount(customer, order_id, discount){
          customer
          .findOrder(order_id)
          .applyDiscount(discount);
      }
      
    • 例外
      • 语言提供的库非常稳定,可以使用
  • 邪恶的全局化
    • 尽可能避免全局化,只提醒一点
    • 如果非要全局化,包装一层吧

响应式程序

  • 事件
    1. 有限状态机
      • 不要惧怕他,他只是工作流的一种控制方式
      • 当非常适合状态切换的时候,使用它
      • 把状态保存在外部储存器中,并使用状态来驱动流程迭代
      • 缺点
        1. 并不能解决任何问题
    2. 观察者模式
      • 声明函数注册列表在被观察者处,外部注册,行为产生式调用注册函数
      • 缺点
        1. 注册的函数列表和被观察者在一处,产生依赖
        2. 事件的抛出式同步的,容易产生性能瓶颈(订阅/发布解决此问题)
    3. 订阅/发布
      • 发布者订阅者,两者是通过信道通信,不管内部实现方式,解耦,提升效率
    4. 响应式编程/流与事件
      • 通过流来分析事件,可以理解为是一种思想
      • 例如:双击事件,250ms内每点一次写进流,250ms过后把流打包,传输给订阅者,订阅者解析是否有两次点击,触发双击事件
      • 因为是流,所以异步
    5. 变换式编程(管道)
      • 完成一个目的,输入到输出通过一些流程进行转换,得到最终结果
      • 这种思想是优秀的
      • 在OO思想里,InputStream变换比较像
      • 不要囤积状态,传递下去
      • 错误处理:
        • 永远不要在变换之间传递原始值,因为这样你无法验证有效性,取而代之的是封装在一个结构里,传递下去,验证有效性
        • 首先选择一个表达式(如Elixir语言的:{:ok, value},{:error, reasion})
        • 在变换函数内部处理,通过元组的第一个参数是否是ok,来执行不同版本的函数,把结果添加到元组里返回元组
        • 加强版:包装一个执行函数,取出结果ok才执行下一个
      • 在平时工作中使用这种思想,代码会越来越简洁
  • 继承税(不要扛着大山去兜风)
    • 接口
    • 委托
    • 拓展方法(mixin)
      • 譬如拓展接口是个不错的选择
    • 用以上方式代替继承
  • 配置
    • 一个比较优秀的方案是:把配置做成一个服务,通过服务的api去查询配置,不要写成全局变量
    • 当决策出现两个方案的时候,不要懒惰的做成配置方案,决策出来,选择一个

第六章 并发

打破时域耦合

  • 定义
    1. 依赖时间
    2. 依赖调用顺序('滴滴'必须在'哒哒'之后执行)

PS:欢迎评论(。^▽^)

posted on 2020-10-09 15:16  点赞机器人  阅读(314)  评论(0)    收藏  举报