衡量代码质量的唯一有效标准:WTF/min

这是我最近在看的一本书 《代码整洁之道》 ,很早以前看过一次,不过基本都忘得差不多了,现在重新来看,发现现在写的代码隐约还是从中吸取了不少经验,本文是这本书的读书笔记和自己的一些思考,这本书也推荐给你。

衡量代码质量的唯一有效标准:WTF/min_第1张图片(这图很有意思,看懂了的点个'在看')

关于命名

给变量、函数、类、包取名字时要做到名副其实,见名知义。如果名称需要用注释来补充说明,多半就不是一个很好的名字。例如:

int d

def bar():
    pass

不要与系统内置名字一样,例如id、sum、len 之类的名字都是内置函数名字,你可以取一个和业务相关的名字,例如:account_id。

用可搜索的常量名代替常量值,例如有个分页参数是每页10条大小,我们可以定义一个常量 PAGE_SIZE=10,其它地方都可以使用。如果孤零零的写成10,后面要修改的时候找起来就麻烦。

get_data(10)

vs

PAGE_SIZE = 10
get_data(PAGE_SIZE)

名字没有最好只有更好,这次没有找到合适的名字,下次找到合适的名字时利用重构手法将其修改掉,但是对于已经对外暴露的API,改名字可要小心了。

关于函数

函数应该短小,函数应该只做一件事,并且做好这件事,不要同时做两件事,keep it simple and stupid。多少行算短小并没有严格的定义,如果你能把一个函数所做的事情拆分成12345等多个步骤,那么它做的事情就不是一件而是5件了。

举个爬虫的例子:通过某个url链接爬取数据并保存到数据库可分为几个步骤:

  1. 发起网络请求并得到数据

  2. 对数据进行清洗

  3. 保存数据库

也就是说这个操作至少可以拆分成三个函数,而且每个步骤可能有涉及到一些更少的步骤,例如发送请求的时候需要封装参数,包括请求头参数、代理参数、查询参数等等。如果所有逻辑全部写在一个函数就像一坨屎。把每个小功能拆分成更小的函数不仅能清晰地体现代码逻辑还有你的编程思路。

函数参数同样尽可能少,最理想的是没有参数,其次是一个参数,再次是两个参数,尽量避免三个以上的参数,除非你有足够的理由必须使用3个参数。参数多了怎么办?想办法把参数抽象成对象。

函数中要消除冗余,减少重复,很多时候你做的事情都是类似的,例如获取各种模型的数据列表涉及的分页等操作,就可以把通用代码抽象成公用逻辑。

关于注释

说起注释,我们都认为它是个好东西,好虽好,但是它却不能美化烂代码,所以不要太过于依赖注释来解释代码意图,而尽量要通过代码本身来解释代码逻辑。没用的代码注释通常有

废话式注释

def get_all(cwd):
    get_dir = os.listdir(cwd)  #遍历当前目录,获取文件列表
    for i in get_dir:
        sub_dir = os.path.join(cwd,i)  # 把第一步获取的文件加入路径
        if os.path.isdir(sub_dir):     #如果当前仍然是文件夹,递归调用
            get_all(sub_dir)
        else:
            ax = os.path.basename(sub_dir)  #如果当前路径不是文件夹,则把文件名放入列表
            result.append(ax)
     print(len(result))   #对列表计数

这段代码是从github截的,所有的注释都是对api的解释,并没其它意义。

长串注释掉的代码

def merge_cookies(cookiejar, cookies):	

	
    if not isinstance(cookiejar, cookielib.CookieJar):	
        raise ValueError('You can only merge into CookieJar')	
    if isinstance(cookies, dict):	
        cookiejar = cookiejar_from_dict(	
            cookies, cookiejar=cookiejar, overwrite=False)	
    # elif isinstance(cookies, cookielib.CookieJar):	
    #     try:	
    #         cookiejar.update(cookies)	
    #     except AttributeError:	
    #         for cookie_in_jar in cookies:	
    #             cookiejar.set_cookie(cookie_in_jar)

总担心哪天代码又会改回来,舍不得删除。如果你的代码还不是用git这样的版本控制系统的话,可以暂时保留。但是现在不用git都不好意出门打招呼是不。

误导性注释,这种注释是最要命的,最初写了注释,几个月后代码逻辑发生了翻天覆地的变化,注释却还是保留在最初的版本。

话说如此,但是有些注释还是有必要的,例如函数的文档注释,用来说明函数的作用,如果你的函数名字不能很好的自我阐述时,配上注释就是退而求其次的方法。还有一种注释就是对意图的解释,例如:

try:
    current_position = o.tell()
except (OSError, IOError):
    # This can happen in some weird situations, such as when the file
    # is actually a special file descriptor like stdin. In this
    # instance, we don't know what the length is, so set it to zero and
    # let requests chunk it instead.
    if total_length is not None:
        current_position = total_length

这里的注释向读者解释什么场景下会发生这种异常,以及如何处理。这是把作者的思路告诉读者的一种方式。

TODO 注释也是一种常用的注释,例如有些地方展示用一种临时的替代方案实现,未来你将对其进行优化时可以用 # TODO 标记,现在大部分IDE都支持TODO注释高亮显示。

先写这么多,后面还有关于类、单元测试、错误处理方面的内容,下次再写。

640?

欢迎关注并置顶公众号,方便第一时间收看最新内容

你可能感兴趣的:(衡量代码质量的唯一有效标准:WTF/min)