Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

shen2/zen-coding-notes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

19 Commits

Repository files navigation

禅意编程札记

基本编码习惯

  • 写出能解决问题的程序有100种方法,但是优秀的工程师能找到最好的一种。
  • 代码自描述
    • 代码是写给人看的,不是写给机器看的,只是恰好能运行而已
  • 每条语句皆有作用,不做无谓的赋值
  • 减少上下文依赖,编写显而易见是正确的代码
  • 最小化参数要求
    • 传ID就能解决问题的时候不需要传对象
  • 减少函数内多余的中间变量
    • 减少中间变量的命名的意义
    • 直接return
  • 在一个作用域内,变量的类型保持不变(仅对脚本语言)
  • 不要滥用语法糖,少用奇技淫巧

项目工程

  • 如果你的整体代码结构变得极其复杂,往往是产品需求有问题
  • 从整体到细节,自顶向下的工作顺序
    • 基础库的编写顺序,优先写 guide / example
  • 全新的业务工程,先不考虑架构
  • 好的代码不是写出来的,是重构出来的
    • 在项目发展的合适时机进行重构,项目规划过程中应该留出明确的重构时间
    • 这份札记是如何编写出来的
    • 重构的过程中不一定要保证每次修改均可运行

逻辑控制结构

  • 防御式编程
  • 循环结构优化
    • 不同的语言有不同的最佳实践
  • 不要轻易使用while(true)
  • 错误和异常是常态,错误处理像业务代码本身一样必不可少

代码拆分规则

  • 原子化函数
    • 举例,微博三步授权流程代码
  • 业务逻辑分层
  • 最好的代码拆分方式是,清晰定义每一层的程序各自解决什么问题,不关注什么问题
    • 基于清晰的分层原则,即使在很多类里面出现一行代码的函数,你也会非常自信地认为这是合理的
    • 如果无法定义分层,就只能根据代码复杂度来拆分。通常情况下,这是因为你的理解还不够深刻,或者需求的复杂度还没有充分展开。
  • 类的层次
  • 什么样的代码应该写成独立业务,什么样的代码应该写在公共流程中(并加启用条件)
    • 如果使用率很高,就写在主流程里
    • 如果只是业务的一个分支,则不应该给主程序增加复杂度
  • 不要把业务相关代码和基础库代码混在一起
    • 始终以要开源的标准去写基础库,绝不耦合业务逻辑
  • 业务逻辑的不同层次的实现方式
    • 大量需要变更和管理的业务,存在数据库
    • 很少更新,并且无逻辑的,写在配置文件里
    • 很少更新,但是有逻辑的,写在独立的程序文件里
    • 尽量不要写在主程序里
  • 一个功能全面的大方法还是多个功能简单的小方法
    • 与其用复杂的配置参数,不如用多个简单的原子化方法
    • 然后写一个通过多个原子化方法实现功能的shorthand方法
    • 善用fluence interface
    • 如果一个函数要接受5个以上参数,你可以先想想这些参数真的是用来解决同一个问题的吗?
  • 什么情况下用配置文件的方式接受配置,什么情况下用函数来接受配置?
    • 配置文件虽然看起来不需要编程,但实际上额外需要一份冗长的配置参数文档
    • 配置文件方式限制了灵活性,但保证了安全性,适用于提供给对外部用户的功能
    • 函数方式提供了更强的灵活性可塑性,比如TensorFlow之于Caffe
    • 函数方式要求使用者具备编程能力,适用于中间件,适用于需要二次开发的场景
  • 除非有特别需求,提供一种初始化/配置方法就够了,不要玩参数列表的花活
  • 一个可以处理多种情况的多if-else函数,还是处理单一情况的简单函数
  • 区分有状态对象和无状态对象
  • 类内尽量少维护状态变量
  • public的方法必须在自己函数体内完成对所有状态变量的维护
    • 所有public方法,调用前和调用后,类的状态应该是自洽的
  • shorthand方法
  • 不要在局部函数里修改全局变量
  • 如果你很难给某个函数起名字,往往是因为代码拆分有问题
  • 如果你很难给某个类起名字,可能这个类就不应该存在
  • 对于脏的输入,明确地在一层代码中做参数校验,而在后续的代码层中完全信任传入的参数,因为都已经被校验过
  • 正确看待封装
    • 不要为了封装而封装
    • 封装的时候,最重要的不是选择隐藏什么细节,而是暴露什么细节
    • 不要惧怕学习,或者阻止别人学习。不要为了避免别人的学习而封装

问题跟踪和解决

  • fail-fast
    • 服务端,如果请求hang住会导致服务器被打满,需要尽快把有问题的请求抛弃掉,保证普通请求的正常执行
    • 引申,如果有错误,不要遮着掩掩,而应该让错误及时暴露出来,更早发现更快解决
  • 如果这个问题可以在开发过程中被发现并解决,就不是什么问题
    • 不要在代码里为不会使用API的程序员报错误
  • 开发过程中,应该让错误出现得越明显越好,能crash能抛异常,而不要静默处理
  • 用户层,不要掩盖错误细节,至少提供错误码或者保存日志

复用,还是冗余?

  • 什么样的代码应该写成函数?
    • 不是代码写了两遍就需要写成函数,而是这个函数有明确的功能和清晰的参数列表
    • 不要因为一段代码只写过一遍,就不抽成函数
  • 合理冗余代码
    • DRY原则永远是对的吗?
    • 少写代码并不是架构设计的主要目标,甚至都不是目标
    • 明智而自豪地复制代码
    • 面向未来编程,如果两段代码目前很相似,但未来会分化,就不要复用它
  • 三行以内的代码不值得复用
  • 不要因为自己查资料写出了一段自己原来不会写的代码,就一定要把这段代码抽成函数
  • 恶心自己,方便大家
    • 类的内部合理冗余代码,外部调用足够简单
  • 复用的代价
    • 实际处理过程被隐藏
    • 灵活性损失
    • 性能损失
  • 通用和性能之间的平衡点
  • Lazy Load
    • 在用户主路径上的业务和开销极小的业务不需要 Lazy Load

命名

  • 变量名的原则
  • 变量的命名要符合上下文场景
    • 一个参数传递的链条中,不一定是同一个名字
  • 学好英语,起好名字
    • 用意义准确的特殊词,少用组合词,比如: SiteUser -> Member
    • 英文动词不只有get和set,用好动词准确表达
    • 正确使用单复数
    • 梳理出明确的命名原则
  • 建立一个产品概念到开发概念的映射词典
  • 能用批量替换解决的问题,就不是问题

注释

  • Don't comment WHAT, comment WHY.
  • 不要寄希望于用注释来解释清楚代码
  • 和业务相关的脏代码必须注释
  • 删除历史遗留代码,而不要注释它
  • 善用 FIXME, TODO 等特殊注释关键词,以便日后检索整理方便

面向对象的设计原则

  • 多层继承还是多个独立的类
    • 尽量在一个类中呈现出完整的业务逻辑,同一个层次的业务逻辑,不要写在不同层的类中
    • 多层继承的代码可读性和可维护性远比你想象得要糟
  • 善用trait/mixin
  • 每一个public函数的切面,整个对象状态都自洽
  • 将对成员变量的变更和维护,集中到有限几个函数中,原子化的功能函数不维护状态变量

目录结构和文件命名

  • 用唯一确定的属性作为定位的规则,避免歧义
    • 按层放置文件
  • 文件名和类名有一致的对应规则

安全和可靠性

  • All Input is Evil
    • 所有来自用户自由输入的参数,都必须检查

PHP技巧

  • spl库的运用
  • yield的运用
  • 命名空间的运用

Javascript技巧

Web服务技巧

About

禅意编程札记

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

AltStyle によって変換されたページ (->オリジナル) /