Notes
  • Introduce
  • Go
    • Grammar
      • Basic
      • Goroutines & Channels
      • Test
    • System Library
      • Module
      • sync
      • context
      • net
    • Concurrency in Go
    • The Go Memory Model
    • Code Snippet
  • Rust
    • The Rust Programming Language
    • Rust by Example
  • JAVA
    • Preface
    • Grammar
      • Basic
      • Data Types
      • Operator
      • Exceptions
    • Class Libraries
      • Collection
      • Stream
      • IO
      • NIO
      • RMI
    • Concurrency
      • Preface
      • JMM
      • Synchronized & CAS
      • Deadlock
      • Thread
      • Lock & Condition
      • Utility Class
      • Thread-safe Collection
      • Atomic Class
      • Fork/Join
      • Concurrency Design Patterns
        • Immutable
        • Copy-on-Write
        • ThreadLocal
        • Multitheading If
        • Division
    • JVM
      • Class & Instance Initialization
      • Runtime Data Area
      • Garbage Collection
    • Web Container
      • Tomcat Architecture
      • Jetty Architecture
    • Spring
    • Tuning
      • Programming
  • Computer Science
    • Computer Organization
    • Algorithm
      • Complexity
      • Linear List
      • Sort
      • Binary Search
      • Skip List
      • Hash Table
      • Tree
      • Graph
      • String Matching
      • Bloom Filter
      • Greedy Algorithm
      • Divide and Conquer
      • Back Tracking
      • Dynamic Programming
    • Network Protocol
      • Pysical Layer
      • Data Link Layer
      • Network Layer
      • Transport Layer
      • Application layer
      • HTTP
      • HTTP/2 in Action
    • Operating System
      • Basic
      • System Initialization
      • Diagnostic Tools
      • CPU Diagnosis
      • Memory Diagnosis
      • Disk Diagnosis
      • Network Diagnosis
      • Monitor System
    • Design Patterns
      • UML
      • OOP
      • Principle
      • Refactoring & Specification
      • Creational
        • Singleton
        • Factory
        • Builder
        • Prototype
      • Structural
        • Proxy
        • Bridge
        • Decorator
        • Adapter
        • Facade
        • Composite
        • FlyWeight
      • Behavioral
        • Observer
        • Template Method
        • Strategy
        • State
        • Iterator
        • Chain of Responsibility
    • Distributed System
      • Protocol & Algorithm
      • Transcation
      • Theory
      • Resource Management
      • Scheduling
      • Computing
      • Message Queue
      • Cache
      • Consistent Hashing
  • database
    • InfluxDB
      • In-Memory Index
      • Meta
    • MySQL
      • SQL
      • Architecture
      • Log
      • Transaction
      • Indexing
      • Lock
      • Storage
    • Redis
    • Elasticsearch
      • Local Debug
    • HBase
    • Kafka
    • ZooKeeper
  • Reading
    • RocketMQ
    • 演说之禅
    • So Good They Can't Ignore You
    • 学会提问
    • Lecture
  • Other
    • v2ray
    • Kubernetes
    • Git
    • Maven
    • Anaconda And Conda
    • Fuck! Shit!
      • Remove Final by Reflection
      • Ingress Host
      • ExecuterService submit
  • Open source contribution
Powered by GitBook
On this page
  • 重构
  • 解耦
  • 单元测试
  • 规范
  • 命名
  • 注释
  • 代码风格
  • 编程技巧

Was this helpful?

  1. Computer Science
  2. Design Patterns

Refactoring & Specification

重构

定义:重构是一种对软件内部结构的改善,目的是在不改变软件的可见行为的情况下,使其更易理解,修改成本更低。

为什么要重构?

  • 时刻保证代码质量。随着代码不停的堆砌,更多的人参与项目,代码会越来越乱,最后重构成本比重新开发还高。

  • 优秀的代码都不能一开始就完全设计好,都是迭代出来的,随着系统的演进,重构是不可避免的。

  • 避免过度设计。在迭代过程中,真正遇到问题的时候再对代码重构,避免前期投入太多精力。

  • 帮助工程师技术成长。

重构什么?

  • 大规模高层次重构:对顶层代码设计重构,包括系统、模块、代码结构、类与类之间的关系,手段有分层、模块化、解耦、抽象可复用组件等。主要利用设计思想、原则、模式。影响面较大、难度较大、耗时较长、引入 BUG 风险较大。

  • 小规模低层次重构:对代码细节的重构,包括类、函数、变量等,如规范命名、规范注释、消除超大类等。主要利用编码规范。

何时重构:持续重构。平时无事时可以做一下小规模重构;在做功能开发时,遇到不规范的代码,也顺手改了。

解耦

过于复杂的代码可读性、可维护性都不友好。解耦是保证代码松耦合、高内聚、控制代码复杂度的有效手段。

根据模块、类与类之间的关系图的复杂性来判断是否需要解耦。

封装、抽象、中间层、模块化以及一些设计原则与思想(单一职责、基于接口而非实现、依赖注入、多用组合少用继承、迪米特等)是常用的解耦方法。

单元测试

单元测试(Unit Testing)是保证重构不出错的有效手段。单元测试是研发工程师自己编写,用于测试代码的正确性。相对于集成测试(Integration Testing)粒度更小。

写单元测试的好处:

  • 能帮你发现代码中的 bug。

  • 能帮你发现代码设计上的问题。代码的可测试性是一个重要的质量标准,若代码很难被测试,那么意味着代码设计不合理。

  • 对集成测试的有力补充。集成测试很难覆盖全面。

  • 写单元测试的过程本来就是代码重构的过程。

  • 阅读单元测试能帮你快速熟悉代码。

尽管单元测试的代码量可能是被测代码的 1~2 倍,但并不耗时,因为代码逻辑简单、重复很多。单元测试不会在线上运行,所以代码质量可以降低。不能用覆盖率作为单元测试质量的唯一标准。写单元测试不需要了解代码实现逻辑。

代码的可测试性就是编写单元测试的难易程度。依赖注入是提高可测试性的有效手段。

规范

命名

  • 长短:在足够表达含义的情况下,命名越短越好。对于常用的词,可以用缩写,如 str(string), num(number) 等。作用域较小的变量,可以用相对较短的命名。

  • 利用上下文简化命名。如 User 类中的成员变量 userName 可以简化为 name。

  • 可读、可搜索。可读(容易发音)是为了在项目沟通时方便。可搜索是为了方便在 IDE 中搜索,如大家都用 selectXXX,而你用 queryXXX,那么在 IDE 中药搜索所有查询相关的代码就不方便。

  • 接口和抽象类:接口两种方式都可以,一种 IUserService 和 UserService,另一种 UserService 和 UserServiceImpl。抽象类前缀 Abstract。

注释

  • 注释的目的是让代码更加容易看懂。注释一般包含:做什么、为什么、怎么做,一些复杂的类和接口还要写如何用。

  • 注释也有维护成本,并非越多越好。一般类和函数要写注释,而函数内部注释相对较少。

代码风格

  • 函数的行数:不要超过一个屏幕的大小。

  • 类的行数:间接判断标准,类读起来头大、实现某个功能不知道用哪个函数、用一个小功能需要整个函数(这个类包含很多无用的函数)时,说明这个类行数过多。

  • 一行代码的长度:不要超过 IDE 显示的宽度。

  • 善用空行分割代码。

  • 缩进:推荐两格,因为可以节省空间。永远不要用 tab 缩进。

  • 大括号推荐不另起一行,因为节省空间。另起一行的好处是左右括号可以对齐。

  • 类中成员的排列顺序:先成员变量后函数,先静态后普通,先 public、再 protected、最后 private。

编程技巧

  • 将复杂的逻辑提炼拆分成函数和类。

  • 避免参数过多。可以拆分成多个函数或将参数封装成类的方式。

  • 不要使用参数来做代码执行逻辑的控制。包括 null 的情况。

  • 函数设计要职责单一。

  • 移除过深的嵌套。方法有:去掉多余的 if 或 else;使用 continue、break、return 提前退出嵌套;调整执行顺序;将部分嵌套逻辑抽象成函数。

  • 字面量取代魔法数。

  • 解释性变量替代复杂表达式。

PreviousPrincipleNextCreational

Last updated 5 years ago

Was this helpful?