Skip to content

漫谈编程之编程规范 #25

@WGrape

Description

@WGrape

目录

一、介绍

不同的人习惯不一样,写出的代码也千奇百怪,质量更会参差不齐。本文主要讨论编程的一个重要问题,即编程规范。

二、理论

1、设计模式

(1) 设计原则

查看大图

image

(2) 设计模式

查看大图

image

2、编程风格

编程风格一直是编程规范中常见的争论点,但由于不同的语言有着不同的设计理念、编程规约和历史包袱,所以很难去统一所有编程语言的风格。

我们能做的,就是尊重每一个不同语言的编程风格,在不同语言中使用它所提倡的编程风格。

3、代码注释

注释本质是为了提高代码的可读性,但是滥用注释,不但违背了其本质,更为项目代码埋下隐藏的风险。

(1) This is Cat 问题

如图,大部分代码的注释都是多余的解释

(2) 注释与文档

文档分为产品型和技术型两种,以下指技术型文档

  • 注释的目标对象是代码,即解释的对象是代码,是对代码实现的记录,强调重要性、简短性
  • 文档的目标对象是技术,即解释的对象是技术,是对技术过程的描述,强调完整性、详细性

不能混乱了注释与文档的角色与作用,且应尽可能的减少注释,增加文档。

(3) 注释代码问题

在代码中经常见到使用暂时注释掉某段代码的情况,以表示暂时废弃。随着时间的增加和人员的变动,再重新接手的时候,导致不敢随便删除代码,在这种担心的心理下,会导致废弃代码越来越多,代码的冗余就越来越多。所以为了解决废弃代码的问题,应该做到以下几点

  • 通过Git找到历史代码,而不要通过注释代码的方式方便下次直接使用
  • 敢于正确删除看到的注释代码,否则只会导致冗余越来越多

(4) 简洁且无歧义

很多代码难以维护,是因为之前注释过于简单且有严重歧义,导致后来记不得其实际含义

-- 已支付金额,具体是支付给谁呢 ?是运营商A还是销售商B ?
ALTER TABLE pay_record ADD COLUMN paid_fee int(10) NOT NULL DEFAULT 0 COMMENT '已支付金额' AFTER amount;
 
-- 修改后
ALTER TABLE pay_record ADD COLUMN paid_fee int(10) NOT NULL DEFAULT 0 COMMENT '已支付给运营商A的金额' AFTER amount;

(5) 权衡是否需要注释

PS :写自解释性的代码是一件极其不容易的事情,需要长时间研究思考并实践

同很多优秀工程师提出的看法一样 :代码即注释 ,最好的注释就是代码本身。

所以一定要先本着简单易懂的语义化原则编写代码,只有当代码不是自解释性的时候,才需要写注释。主要遵从以下原则

  • 注释能减则减,能抽象则抽象
  • 如果注释超过一行或特定行数时,应考虑把这些内容写进文档中,而非写进注释里(DOC注解除外)。

(6) 如何写好注释

  • 提高代码自解释性以减少代码注释量 ,这样就会随之减少所有与注释相关的问题。
  • 尽量从类似概括架构的高度来解释功能,而非解释一行一行的代码过程。

4、命名规则

无论是文件名、包名、命名空间、类名、函数名、变量名等任何命名规则都必须做到以下几点

  • 不要使用各种奇怪的缩写(常见缩写除外)
  • 命名规则必须统一,不能混用
  • 命名必须简练且无歧义
  • 命名尽量不要使用Data等抽象的概念

5、数据库三范式

(1) 第一范式1NF

1NF强调字段的原子性约束,要求字段具有原子性,不可再分解。

例子 :用户表<userid, nickname, userinfo>的userinfo字段用来表示用户性别、年龄、生日等众多信息时,这个字段可以再分解,所以此字段不具有原子性,不符合第一范式。

(2) 第二范式2NF

2NF强调字段对主键的完全性依赖,不能存在部分依赖。

例子 :订单表<orderid, fee, userid, count>的count字段用来表示用户的购买次数,由于count字段存在对userid的部分依赖,而不是完全只对orderid主键有完全性依赖。所以此count字段不符合第二范式

问题:字段数据有重复冗余,修改时需要同时修改多条记录等

正确 :把count字段从订单表中移出来,放到user表中。

(3) 第三范式3NF

3NF强调字段间的独立性,要求任何字段不能由其他字段派生出来,即不存在传递依赖;

例子 :用户表<orderid, userid, name, age>的nameage字段可以由userid字段派生出来,即存在传递依赖。所以不符合第三范式。

问题:字段数据有重复冗余,修改时需要同时修改多条记录,否则会出现数据不一致的情况 。

正确 :把nameage字段从订单表中移出来,放到user表中。

6、反模式的设计

在理论的程序设计、数据库设计中,提倡数据不能有冗余。但是在实践中,为了性能考量,经常会基于空间换时间的思想,使用一些反模式的设计。

(1) 数据缓存

读完数据后存储至缓存中,以提高下次读取的速度。

(2) 字段冗余

如果从A表中读完记录后,需要再从B表中读取数据才能完全读取完数据。在这种情况下,一般会把B表中的数据在A表中冗余存储。

三、最佳实践

以下为PHP语言为例的最佳实践。

1、设计模式问题

2、编程风格问题

(1) Case 1

在C、C++等语言中有代码块的概念,可以使用代码块语法锁住不同区域的变量。但在PHP语言中,这种语法首先不会起到原有的作用,而且这种小众的语法会提高理解成本。

如果想要提高代码模块的整洁清晰程度,应该从代码设计入手,而不是简单投机取巧的使用代码块这种小众且毫无实际作用的方式。

  • Bad
<?php

{
    $a = "hello";
    $b = "world";
}
  • Good
<?php

$a = "hello";
$b = "world";

(2) Case 2

在C语言历史中,经常能看到有省略if语句中花括号的代码风格。但是随着时代的发展,这种语法已经越来越不受推荐。

  • Bad
<?php

if($success)
    echo "success";
  • Good
<?php

if($success){
    echo "success";
}

3、代码注释问题

注释不是让灵感大发大写文章用的,更不是随意到像写日记一样。请简化注释内容,不需要的代码就请直接删掉它,而不要只是简单的注释它。

  • Bad
// 现在已经不需要这段代码了,因为XXXXX,
// whatever 谁想删掉的话就删掉吧
// $a = $this->compute();

$a = $this->getAFromDB();
  • Good
$a = $this->getAFromDB();

四、总结

本文关于编程规范的讨论,总结为四字 :大道至简。

Metadata

Metadata

Assignees

No one assigned

    Labels

    经验之谈系列分享一些常见的技术问题和经验之道

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions