应用设计与开发(一) - 设计原则与思想、编码规范(Desigin Principle)

AI 摘要: 本文主要讨论了编码分析、设计与质量,以及Go语言、微服务和云原生的相关内容。在编码质量方面,文章指出了质量不高的代码的原因,并介绍了面向对象编程、设计原则和重构等相关概念。此外,文章还简要介绍了Go语言作为一种互联网时代的C语言的特点和优势。然后,文章探讨了微服务的概念、微服务与单体架构的区别,以及微服务的复杂性。最后,文章介绍了云原生的概念和未来架构思考。

1. 从 CR 谈开发编码分析、设计与质量

1.1. 质量不高的代码原因

  1. 缺乏系统的编码基础学习
  2. 缺乏整体架构设计意识,导致复杂度提升
  3. 缺乏编码设计方法论
    1. OOA、OOD、OOP
    2. DDD
    3. BDD、TDD
  4. 固有编程方式,不能接受变化

1.2. 面向对象

  1. 面向对象特性:封装、继承、多态、抽象
  2. 抽象类和接口的区别(基础、多态)
  3. 多用组合,少用继承(代码维护性)
  4. 基于接口而非实现编程(契约)
  5. 贫血模型 vs 充血模型(合理分层)

1.3. 设计原则

  1. SOLID 原则
    • SRP:单一职责(design by simple )
      • 感知:代码行数、类属性方法过多、难给类取名、方法过于臃肿
      • 实施:遵循高内聚、低耦合,避免大而全,减少耦合,也不要拆分得过细,会降低内聚性
    • OCP:开闭原则(对扩展开放,对修改关闭)
      • 感知:维护修改扩展时候考虑,时刻具备扩展、封装、抽象意识)
      • 实施:多态、依赖注入、面向接口编程
      • 模式:装饰器、策略、模板、责任链
      • 目标:未来需求变更,做到最小代码的变动
    • LSP:里氏替换原则(design by contract)
      • 感知:和多态的差异,多态 OOP 特性,LSP 是设计原则
      • 实施:按协议约定来设计
      • 约定:对输入、输出、异常的约定
    • ISP:接口隔离原则(design by need)
      • 感知:不要提供我不需要的内容(API 臃肿、类方法臃肿)
      • 实施:侧重接口设计,通过识别接口是否符合单一职责,是否存在接口难命名等情况
    • DIP:依赖倒置原则
      • 控制反转:指导框架设计,程序的流程由框架接管
      • 依赖注入:编码技巧,通过构成方法、函数参数,将外部创建好的对象,注入到框架内来使用;通过注入后,实现
      • 依赖反转:指导框架设计,高层模块不依赖底层模块,而是依赖接口抽象
  2. KISS 原则
    • 少即使多,言简意赅
    • 复杂事情,采用分治思想,拆分成简单事项处理
    • 适度、不重复、不过渡优化
  3. DRY 原则(Don’t Repeat Youself)
    • 感知:事不过三
    • 实施:逻辑重复(mss 对接 18 家平台)、功能重复(多处写 curl)、代码执行重复(复用意识)
    • 不要面向copy c,copy v编程
  4. YAGIN 原则(You Ain’t Gonna Need It)
    • 感知:不要做过度设计
    • 实施:当前不需要做的内容,就不要画蛇添足
    • 反原则:只看当下,局部视野
  5. LOD/LKP 原则(Law of Demeter, 迪米特法则)
    • 可以无依赖的类之间,不要有依赖
    • 有依赖的类之间,考虑采用依赖接口,解耦依赖关系

1.4. 重构

软件之熵

1.4.1. 重构概述

  1. WHY? 为何要重构?
    • 代码腐化、个人成长
    • 痛点问题太多(效率、质量、难扩展、难维护、问题难排查)
  2. WHAT?
    • 大重构:代码分层、模块化、解耦,架构梳理调整
    • 小重构:类、函数、命名、编码规划遵循
  3. WEHN?
    • 持续重构意识,现在开始
    • 严重影响效率
  4. HOW
    • 小重构:日常迭代,马上开始
    • 大重构:有目的、有计划,分批分块进行(分治思想)

1.4.2. 单元测试

  1. TDD 驱动,加速业务熟悉,减少边界问题(前期投入较大,长期收益非常明显)
  2. 代码可测试性的反模式:
    • 滥用全局变量
    • 滥用静态方法
    • 使用复杂的继承关系
    • 高度耦合的代码
    • 函数代码内部中断,非返回退出

1.4.3. 解耦的理解

  1. 时刻记得高内聚、松耦合
  2. 大系统分分层、模块设计
  3. 大系统微服务
  4. 长流程,遵循职责来抽离方法(遵循 KISS 原则)

1.5. 编码规范提升

  1. https://time.geekbang.org/column/article/188622
  2. https://time.geekbang.org/column/article/188857
  3. https://time.geekbang.org/column/article/188882

1.5.1. 命名与注释

译事三难: 信、达、雅 – 信(准确,不偏离,不遗漏)、达(不拘泥于原文)、雅(翻译得体,简明优雅)

  1. 词达意,缩写优先采用通用缩写,不要采用拼音,不要太长或太短
  2. 可读、可搜索,不要用生僻词
  3. 长短命名变量:变量范围越大,考虑命名越具体,反之作用域越小,用短变量
  4. 结合类名、包名上下文,避免口吃效果
  5. 统一约定抽象类名前缀Abstract、接口名前缀Impl
  6. 注释:
    • 说清楚 3W(WHY, WHAT, HOW),即函数或类实现了什么功能、做了什么,怎么做,复杂使用时候,提供适当示例
    • 注释不是越长越好,考虑言简意赅

1.5.2. 代码风格

团队规约,采用统一风格

  1. line,一行多长,写多少代码

  2. 一个函数多长合适?尽量控制在一屏幕左右

  3. {,括号放的位置,推荐放在同行末尾

  4. tab,空格缩进

  5. 缩进对齐

  6. 命名方式,采用驼峰命名

  7. 空行分隔代码逻辑

  8. 成员可见性

1.5.3. 编程技巧

  1. 代码分割成效的单元块,通过合适的空行和注释增加可读性
  2. 函数遵循 SRP、KISS 原则
  3. 函数参数过多(函数没有遵循 SRP 原则、函数封装成对象)
    • 实施:拆分成多个职责明确的函数、拆分成单独的类
  4. 不要使用参数做控制逻辑(违背单一职责、违背接口隔离)
  5. 移除过深的嵌套 if-else 层次(可读性差)
    • 逻辑合并,去掉过多的 if-else
    • continue\break\return 提前退出
    • 基于异常,提前退出(if… return)
    • 嵌套的内容,封装成函数
  6. 使用解释性变量
    • 替换魔法数值
    • 替换复杂表达式

1.5.4. CR

https://mp.weixin.qq.com/s/3M9-I1gS_Niuv4yGoX3vqA

在 cr 时,请务必确保:

  • 代码经过完善的设计
  • 功能性对于使用者们是好的
  • 对于任何 UI 改动要合理且好看
  • 任何并行编程的实现是安全
  • 代码不应该复杂超过原本所必须的
  • 开发者不该实现一个现在不用而未来可能需要的功能
  • 代码有适当的单元测试
  • 测试经过完善的设计
  • 开发者对于每样东西有使用清晰、明了的命名
  • 注释要清楚且有用,并只用来解释 why 而非 what
  • 代码有适当的写下文件(一般在 g3doc)
  • 代码风格符合 style guide
  • 确保你查看被要求 review 的每一行代码、确认上下文、确保你正在改善代码质量,并赞扬开发人员所做的好事与优点吧!

在 cr 中要看些什么:

  • CL 的总体设计
  • 功能验证,功能性对于使用者们是好的,对于任何 UI 改动要合理且好看
  • 是不是很复杂,有没有过度设计
  • 代码有适当的单元测试
  • 测试经过完善的设计
  • 规范命名,看见名字就知道是什么
  • 合适的注释,注释应该是 why 而不是 what
  • 代码风格遵循 style guide,如果需要改代码风格应该在另一个 CL 解决
  • CL 更改了构建、测试、交互、发布的时候,也要更新文档
  • 仔细 review 每一行代码(除了资源文件、生成的代码、大型数据结构)。如果比较复杂得让开发者解释
  • 安全性、并发性、可访问性、国际化等复杂问题时需要更合适的人来 review
  • 以整个系统的角度出发来思考 CL
  • review 的时候,与其告诉开发者做错什么,还不如告诉他们做对了什么

1.6. 设计模式

  1. 创建类型
  2. 组合类型
  3. 行为类型

2. Go 语言

互联网时代的 C 语言,许世伟 - 2012-03-01

  1. 多少人了解 Go,多少人用过 Go?

3. 微服务

  1. 对微服务的了解?
  2. 多少人具体

3.1. 微服务和单体

3.2. 微服务有哪些前置内容

3.3. 为什么说微服务复杂

4. 云原生

  1. 什么是云原生?
  2. 未来架构思考?

5. 结语

Go 语言最终会取代 Java 居于编程榜之首!

本周我打算分享一个《谈谈基于 Go 的应用设计与开发》,时间的话还待定。 分享主要大纲内容:

  1. 从 CR 出发,谈谈对编码分析设计、研发质量的看法
  2. Go 语言
  3. 单体与微服务
  4. 云原生