精华内容
下载资源
问答
  • 代码整洁 vs 代码肮脏

    万次阅读 多人点赞 2019-09-16 12:05:12
    写出整洁代码,是每个程序员的追求。《clean code》指出,要想写出好的代码,首先得知道什么是肮脏代码、什么是整洁代码;然后通过大量的刻意练习,才能真正写出整洁代码。 WTF/min是衡量代码质量的唯一标准,...

    写出整洁的代码,是每个程序员的追求。《clean code》指出,要想写出好的代码,首先得知道什么是肮脏代码、什么是整洁代码;然后通过大量的刻意练习,才能真正写出整洁的代码。

    WTF/min是衡量代码质量的唯一标准,Uncle Bob在书中称糟糕的代码为沼泽(wading),这只突出了我们是糟糕代码的受害者。国内有一个更适合的词汇:屎山,虽然不是很文雅但是更加客观,程序员既是受害者也是加害者。

    对于什么是整洁的代码,书中给出了大师们的总结:

    • Bjarne Stroustrup:优雅且高效;直截了当;减少依赖;只做好一件事
    • Grady booch:简单直接
    • Dave thomas:可读,可维护,单元测试
    • Ron Jeffries:不要重复、单一职责,表达力(Expressiveness)

    其中,我最喜欢的是表达力(Expressiveness)这个描述,这个词似乎道出了好代码的真谛:用简单直接的方式描绘出代码的功能,不多也不少。

    本文记录阅读《clean code》之后个人“深有同感”或者“醍醐灌顶”的一些观点。

    一、命名的艺术

    坦白的说,命名是一件困难的事情,要想出一个恰到好处的命名需要一番功夫,尤其我们的母语还不是编程语言所通用的英语。不过这一切都是值得了,好的命名让你的代码更直观,更有表达力。

    好的命名应该有下面的特征:

    1.1 名副其实

    好的变量名告诉你:是什么东西,为什么存在,该怎么使用

    如果需要通过注释来解释变量,那么就先得不那么名副其实了。

    下面是书中的一个示例代码,展示了命名对代码质量的提升

    # bad code
    def getItem(theList):
       ret = []
       for x in theList:
          if x[0] == 4:
             ret.append(x)
       return ret
    
    # good code
    def getFlaggedCell(gameBoard):
       '''扫雷游戏,flagged: 翻转'''
       flaggedCells = []
       for cell in gameBoard:
          if cell.IsFlagged():
             flaggedCells.append(cell)
       return flaggedCells
    

    1.2 避免误导

    • 不要挂羊头卖狗肉
    • 不要覆盖惯用缩略语

    这里不得不吐槽前两天才看到的一份代码,居然使用了 l 作为变量名;而且,user居然是一个list(单复数都没学好!!)

    1.3 有意义的区分

    代码是写给机器执行,也是给人阅读的,所以概念一定要有区分度。

    # bad
    def copy(a_list, b_list):
        pass
    
    # good
    def copy(source, destination):
        pass
    

    1.4 使用读的出来的单词

    如果名称读不出来,那么讨论的时候就会像个傻鸟

    1.5 使用方便搜索的命名

    名字长短应与其作用域大小相对应

    1.6 避免思维映射

    比如在代码中写一个temp,那么读者就得每次看到这个单词的时候翻译成其真正的意义

    二、注释

    有表达力的代码是无需注释的:The proper use of comments is to compensate for our failure to express ourself in code.

    注释的适当作用在于弥补我们用代码表达意图时遇到的失败,这听起来让人沮丧,但事实确实如此。The truth is in the code, 注释只是二手信息,二者的不同步或者不等价是注释的最大问题。

    书中给出了一个非常形象的例子来展示:用代码来阐述,而非注释

    bad
    // check to see if the employee is eligible for full benefit
    if ((employee.flags & HOURLY_FLAG) && (employee.age > 65))
    
    good
    if (employee.isEligibleForFullBenefits())
    

    因此,当想要添加注释的时候,可以想想是否可以通过修改命名,或者修改函数(代码)的抽象层级来展示代码的意图。

    当然,也不能因噎废食,书中指出了以下一些情况属于好的注释

    • 法务信息
    • 对意图的注释,为什么要这么做
    • 警示
    • TODO注释
    • 放大看似不合理之物的重要性

    其中个人最赞同的是第2点和第5点,做什么很容易通过命名表达,但为什么要这么做则并不直观,特别涉及到专业知识、算法的时候。另外,有些第一感觉“不那么优雅”的代码,也许有其特殊愿意,那么这样的代码就应该加上注释,说明为什么要这样,比如为了提升关键路径的性能,可能会牺牲部分代码的可读性。

    最坏的注释就是过时或者错误的注释,这对于代码的维护者(也许就是几个月后的自己)是巨大的伤害,可惜除了code review,并没有简单易行的方法来保证代码与注释的同步。

    三、函数

    3.1 函数的单一职责

    一个函数应该只做一件事,这件事应该能通过函数名就能清晰的展示。判断方法很简单:看看函数是否还能再拆出一个函数。

    函数要么做什么do_sth, 要么查询什么query_sth。最恶心的就是函数名表示只会query_sth, 但事实上却会do_sth, 这使得函数产生了副作用。比如书中的例子

    public class UserValidator {
        private Cryptographer cryptographer;
        public boolean checkPassword(String userName, String password) {
            User user = UserGateway.findByName(userName);
            if (user != User.NULL) {
                String codedPhrase = user.getPhraseEncodedByPassword();
                String phrase = cryptographer.decrypt(codedPhrase, password);
                if ("Valid Password".equals(phrase)) {
                    Session.initialize();
                    return true;
                }
            }
            return false;
        }
    }
    

    3.2 函数的抽象层级

    每个函数一个抽象层次,函数中的语句都要在同一个抽象层级,不同的抽象层级不能放在一起。比如我们想把大象放进冰箱,应该是这个样子的:

    def pushElephantIntoRefrige():
        openRefrige()
        pushElephant()
        closeRefrige()
    

    函数里面的三句代码在同一个层级(高度)描述了要完成把大象放进冰箱这件事顺序相关的三个步骤。显然,pushElephant这个步骤又可能包含很多子步骤,但是在pushElephantIntoRefrige这个层级,是无需知道太多细节的。

    当我们想通过阅读代码的方式来了解一个新的项目时,一般都是采取广度优先的策略,自上而下的阅读代码,先了解整体结构,然后再深入感兴趣的细节。如果没有对实现细节进行良好的抽象(并凝练出一个名副其实的函数),那么阅读者就容易迷失在细节的汪洋里。

    某种程度看来,这个跟金字塔原理也很像
    file

    每一个层级都是为了论证其上一层级的观点,同时也需要下一层级的支持;同一层级之间的多个论点又需要以某种逻辑关系排序。pushElephantIntoRefrige就是中心论点,需要多个子步骤的支持,同时这些子步骤之间也有逻辑先后顺序。

    3.3 函数参数

    函数的参数越多,组合出的输入情况就愈多,需要的测试用例也就越多,也就越容易出问题。

    输出参数相比返回值难以理解,这点深有同感,输出参数实在是很不直观。从函数调用者的角度,一眼就能看出返回值,而很难识别输出参数。输出参数通常逼迫调用者去检查函数签名,这个实在不友好。

    向函数传入Boolean(书中称之为 Flag Argument)通常不是好主意。尤其是传入True or False后的行为并不是一件事情的两面,而是两件不同的事情时。这很明显违背了函数的单一职责约束,解决办法很简单,那就是用两个函数。

    3.4 Dont repear yourself

    在函数这个层级,是最容易、最直观实现复用的,很多IDE也难帮助我们讲一段代码重构出一个函数。

    不过在实践中,也会出现这样一种情况:一段代码在多个方法中都有使用,但是又不完全一样,如果抽象成一个通用函数,那么就需要加参数、加if else区别。这样就有点尴尬,貌似可以重构,但又不是很完美。

    造成上述问题的某种情况是因为,这段代码也违背了单一职责原则,做了不只一件事情,这才导致不好复用,解决办法是进行方法的细分,才能更好复用。也可以考虑template method来处理差异的部分。

    四、测试

    非常惭愧的是,在我经历的项目中,测试(尤其是单元测试)一直都没有得到足够的重视,也没有试行过TDD。正因为缺失,才更感良好测试的珍贵。

    我们常说,好的代码需要有可读性、可维护性、可扩展性,好的代码、架构需要不停的重构、迭代,但自动化测试是保证这一切的基础,没有高覆盖率的、自动化的单元测试、回归测试,谁都不敢去修改代码,只能任其腐烂。

    即使针对核心模块写了单元测试,一般也很随意,认为这只是测试代码,配不上生产代码的地位,以为只要能跑通就行了。这就导致测试代码的可读性、可维护性非常差,然后导致测试代码很难跟随生产代码一起更新、演化,最后导致测试代码失效。所以说,脏测试 - 等同于 - 没测试。

    因此,测试代码的三要素:可读性,可读性,可读性。

    对于测试的原则、准则如下:

    • You are not allowed to write any production code unless it is to make a failing unit test pass. 没有测试之前不要写任何功能代码
    • You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures. 只编写恰好能够体现一个失败情况的测试代码
    • You are not allowed to write any more production code than is sufficient to pass the one failing unit test. 只编写恰好能通过测试的功能代码

    测试的FIRST准则:

    • 快速(Fast)测试应该够快,尽量自动化。
    • 独立(Independent) 测试应该应该独立。不要相互依赖
    • 可重复(Repeatable) 测试应该在任何环境上都能重复通过。
    • 自我验证(Self-Validating) 测试应该有bool输出。不要通过查看日志这种低效率方式来判断测试是否通过
    • 及时(Timely) 测试应该及时编写,在其对应的生产代码之前编写

    该文章通过 https://openwrite.cn/ 工具创造并群发。

    展开全文
  • 代码整洁之道 英文版 代码整洁之道 英文版 代码整洁之道 英文版
  • 代码整洁之道(英文版

    热门讨论 2010-04-30 18:01:02
    clean code a handbook of agile software,即代码整洁之道,追求清晰整洁的代码者应该读一下,追求敏捷开发者也应该读一下
  • Clean Code 英文 清晰 PDF。 代码整洁之道的原版。
  • Clean Code-代码整洁之道 中文 pdf

    千次下载 热门讨论 2012-04-15 21:57:04
    Clean Code-代码整洁之道 中文 pdf Clean Code-代码整洁之道 中文 pdf
  • [Prentice Hall] 代码整洁之道 [Prentice Hall] Clean Code A Handbook of Agile Software Craftsmanship (E-Book) ☆ 出版信息:☆ [出版机构] Prentice Hall [出版日期] 2008年08月01日 [图书页数] 466页 ...
  • 代码整洁之道(中文

    热门讨论 2012-01-12 09:33:57
    代码整洁之道》:细节之中自有天地,整洁成就卓越代码 尽管糟糕的代码也能运行,但如果代码不整洁,会使整个开发团队泥足深陷,写得不好的代码每年都要耗费难以计数的时间和资源。然而这种情况并非无法避免。 著名...
  • 代码整洁

    2016-04-09 15:44:03
    关于代码整洁刚开始写代码没有去关心代码写得好不好看,而只是专注在功能的实现。后来随着代码量越来越多就出现了很多问题,当代码中发生错误时,自己面对自己写的代码却很头疼,请教别人帮忙时,别人看我的代码更是...

    关于代码整洁

    刚开始写代码没有去关心代码写得好不好看,而只是专注在功能的实现。后来随着代码量越来越多就出现了很多问题,当代码中发生错误时,自己面对自己写的代码却很头疼,请教别人帮忙时,别人看我的代码更是头疼。这让我慢慢意识到代码整洁的重要性,首先,整洁的代码易读性强,在查找错误的时候可以避免不必要的时间浪费,其次,在团体工作中,别人更容易理解你写的代码,可以提高大家的工作效率。
    要写出整洁的代码,可以从以下几个方面去实现:
    1、注释的编写
    首先要在代码头部写出该模块的功能是什么,然后在每个方法前都要注释该方法的作用,最后是关键语句的注释(包括变量的注释、类方法的注释等)
    2、变量命名规范
    一定要要求自己在给变量命名时要用英语单词命名,不要使用拼音或者其他没有制定意义的字母。变量及对象命名的规则如下(级别_+数据类型简写_+变量名称):
    模块级变量:M_int_xx
    全局变量:G_int_xx
    局部变量:P_int_xx
    模块级常量:Mc_str_xx
    全局常量:Gc_dbl_xx
    过程级常量:Pc_dbl_xx
    常用控件命名规则
    Form  frm
    TextBox  txt
    Button btn
    ComboBox cbox
    Lable lab
    ListBox lb
    DataSet ds
    3、代码的优化
    首先要优化代码的逻辑,再者能做一行写的代码不要分3-4行去写,还有要增加代码的复用性。
    这些只是自己的一些体会,前段时间看到过一本书《代码整洁之道》。以后有时间去把这本书看了再来整理。
    
    展开全文
  • CleanCode(代码整洁之道)中英文合集。
  • python版代码整洁之道

    千次阅读 2020-01-29 19:30:00
    总第 113 篇文章,本文大约 8000 字,阅读大约需要 20 分钟原文:https://github.com/zedr/clean-code-pythonpython 代码整洁之...

    总第 113 篇文章,本文大约 8000 字,阅读大约需要 20 分钟

    原文:https://github.com/zedr/clean-code-python

    python 版的代码整洁之道。目录如下所示:

    1. 介绍

    2. 变量

    3. 函数


    1. 介绍

    软件工程的原则,来自 Robert C. Martin's 的书--《Clean Code》,而本文则是适用于 Python 版本的 clean code。这并不是一个风格指导,而是指导如何写出可读、可用以及可重构的 pyhton 代码。

    并不是这里介绍的每个原则都必须严格遵守,甚至只有很少部分会得到普遍的赞同。下面介绍的都只是指导而已,但这都是来自有多年编程经验的 《Clean Code》的作者。

    这里的 python 版本是 3.7+


    2. 变量

    2.1 采用有意义和可解释的变量名

    糟糕的写法

    ymdstr = datetime.date.today().strftime("%y-%m-%d")
    

    好的写法

    current_date: str = datetime.date.today().strftime("%y-%m-%d")
    

    2.2 对相同类型的变量使用相同的词汇

    糟糕的写法:这里对有相同下划线的实体采用三个不同的名字

    get_user_info()
    get_client_data()
    get_customer_record()
    

    好的写法:如果实体是相同的,对于使用的函数应该保持一致

    get_user_info()
    get_user_data()
    get_user_record()
    

    更好的写法:python 是一个面向对象的编程语言,所以可以将相同实体的函数都放在类中,作为实例属性或者是方法

    class User:
        info : str
    
    
        @property
        def data(self) -> dict:
            # ...
    
    
        def get_record(self) -> Union[Record, None]:
            # ...
    

    2.3 采用可以搜索的名字

    我们通常都是看的代码多于写过的代码,所以让我们写的代码是可读而且可以搜索的是非常重要的,如果不声明一些有意义的变量,会让我们的程序变得难以理解,例子如下所示。

    糟糕的写法

    # 86400 表示什么呢?
    time.sleep(86400)
    

    好的写法

    # 声明了一个全局变量
    SECONDS_IN_A_DAY = 60 * 60 * 24
    
    
    time.sleep(SECONDS_IN_A_DAY)
    

    2.4 采用带解释的变量

    糟糕的写法

    address = 'One Infinite Loop, Cupertino 95014'
    city_zip_code_regex = r'^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$'
    matches = re.match(city_zip_code_regex, address)
    
    
    save_city_zip_code(matches[1], matches[2])
    

    还行的写法

    这个更好一点,但还是很依赖于正则表达式

    address = 'One Infinite Loop, Cupertino 95014'
    city_zip_code_regex = r'^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$'
    matches = re.match(city_zip_code_regex, address)
    
    
    city, zip_code = matches.groups()
    save_city_zip_code(city, zip_code)
    

    好的写法

    通过子模式命名来减少对正则表达式的依赖

    address = 'One Infinite Loop, Cupertino 95014'
    city_zip_code_regex = r'^[^,\\]+[,\\\s]+(?P<city>.+?)\s*(?P<zip_code>\d{5})?$'
    matches = re.match(city_zip_code_regex, address)
    
    
    save_city_zip_code(matches['city'], matches['zip_code'])
    

    2.5 避免让读者进行猜测

    不要让读者需要联想才可以知道变量名的意思,显式比隐式更好。

    糟糕的写法

    seq = ('Austin', 'New York', 'San Francisco')
    
    
    for item in seq:
        do_stuff()
        do_some_other_stuff()
        # ...
        # item 是表示什么?
        dispatch(item)
    

    好的写法

    locations = ('Austin', 'New York', 'San Francisco')
    
    
    for location in locations:
        do_stuff()
        do_some_other_stuff()
        # ...
        dispatch(location)
    

    2.6 不需要添加额外的上下文

    如果类或者对象名称已经提供一些信息来,不需要在变量中重复。

    糟糕的写法

    class Car:
        car_make: str
        car_model: str
        car_color: str
    

    好的写法

    class Car:
        make: str
        model: str
        color: str
    

    2.7 采用默认参数而不是条件语句

    糟糕的写法

    def create_micro_brewery(name):
        name = "Hipster Brew Co." if name is None else name
        slug = hashlib.sha1(name.encode()).hexdigest()
        # etc.
    

    这个写法是可以直接给 name 参数设置一个默认数值,而不需要采用一个条件语句来进行判断的。

    好的写法

    def create_micro_brewery(name: str = "Hipster Brew Co."):
        slug = hashlib.sha1(name.encode()).hexdigest()
        # etc.
    

    3. 函数

    3.1 函数参数(2个或者更少)

    限制函数的参数个数是很重要的,这有利于测试你编写的函数代码。超过3个以上的函数参数会导致测试组合爆炸的情况,也就是需要考虑很多种不同的测试例子。

    没有参数是最理想的情况。一到两个参数也是很好的,三个参数应该尽量避免。如果多于 3 个那么应该需要好好整理函数。通常,如果函数多于2个参数,那代表你的函数可能要实现的东西非常多。此外,很多时候,一个高级对象也是可以用作一个参数使用。

    糟糕的写法

    def create_menu(title, body, button_text, cancellable):
        # ...
    

    很好的写法

    class Menu:
        def __init__(self, config: dict):
            title = config["title"]
            body = config["body"]
            # ...
    
    
    menu = Menu(
        {
            "title": "My Menu",
            "body": "Something about my menu",
            "button_text": "OK",
            "cancellable": False
        }
    )
    

    另一种很好的写法

    class MenuConfig:
        """A configuration for the Menu.
    
    
        Attributes:
            title: The title of the Menu.
            body: The body of the Menu.
            button_text: The text for the button label.
            cancellable: Can it be cancelled?
        """
        title: str
        body: str
        button_text: str
        cancellable: bool = False
    
    
    
    
    def create_menu(config: MenuConfig):
        title = config.title
        body = config.body
        # ...
    
    
    
    
    config = MenuConfig
    config.title = "My delicious menu"
    config.body = "A description of the various items on the menu"
    config.button_text = "Order now!"
    # The instance attribute overrides the default class attribute.
    config.cancellable = True
    
    
    create_menu(config)
    

    优秀的写法

    from typing import NamedTuple
    
    
    
    
    class MenuConfig(NamedTuple):
        """A configuration for the Menu.
    
    
        Attributes:
            title: The title of the Menu.
            body: The body of the Menu.
            button_text: The text for the button label.
            cancellable: Can it be cancelled?
        """
        title: str
        body: str
        button_text: str
        cancellable: bool = False
    
    
    
    
    def create_menu(config: MenuConfig):
        title, body, button_text, cancellable = config
        # ...
    
    
    
    
    create_menu(
        MenuConfig(
            title="My delicious menu",
            body="A description of the various items on the menu",
            button_text="Order now!"
        )
    )
    

    更优秀的写法

    rom dataclasses import astuple, dataclass
    
    
    
    
    @dataclass
    class MenuConfig:
        """A configuration for the Menu.
    
    
        Attributes:
            title: The title of the Menu.
            body: The body of the Menu.
            button_text: The text for the button label.
            cancellable: Can it be cancelled?
        """
        title: str
        body: str
        button_text: str
        cancellable: bool = False
    
    
    def create_menu(config: MenuConfig):
        title, body, button_text, cancellable = astuple(config)
        # ...
    
    
    
    
    create_menu(
        MenuConfig(
            title="My delicious menu",
            body="A description of the various items on the menu",
            button_text="Order now!"
        )
    )
    

    3.2 函数应该只完成一个功能

    这是目前为止软件工程里最重要的一个规则。函数如果完成多个功能,就很难对这个函数解耦、测试。如果可以对一个函数分离为仅仅一个动作,那么该函数可以很容易进行重构,并且代码也方便阅读。即便你仅仅遵守这一点建议,你也会比很多开发者更加优秀。

    糟糕的写法

    def email_clients(clients: List[Client]):
        """Filter active clients and send them an email.
           筛选活跃的客户并发邮件给他们
        """
        for client in clients:
            if client.active:
                email(client)
    

    好的写法

    def get_active_clients(clients: List[Client]) -> List[Client]:
        """Filter active clients.
        """
        return [client for client in clients if client.active]
    
    
    
    
    def email_clients(clients: List[Client, ...]) -> None:
        """Send an email to a given list of clients.
        """
        for client in clients:
            email(client)
    

    这里其实是可以使用生成器来改进函数的写法。

    更好的写法

    def active_clients(clients: List[Client]) -> Generator[Client]:
        """Only active clients.
        """
        return (client for client in clients if client.active)
    
    
    
    
    def email_client(clients: Iterator[Client]) -> None:
        """Send an email to a given list of clients.
        """
        for client in clients:
            email(client)
    

    3.3 函数的命名应该表明函数的功能

    糟糕的写法

    class Email:
        def handle(self) -> None:
            # Do something...
    
    
    message = Email()
    # What is this supposed to do again?
    # 这个函数是需要做什么呢?
    message.handle()
    

    好的写法

    class Email:
        def send(self) -> None:
            """Send this message.
            """
    
    
    message = Email()
    message.send()
    

    3.4 函数应该只有一层抽象

    如果函数包含多于一层的抽象,那通常就是函数实现的功能太多了,应该把函数分解成多个函数来保证可重复使用以及更容易进行测试。

    糟糕的写法

    def parse_better_js_alternative(code: str) -> None:
        regexes = [
            # ...
        ]
    
    
        statements = regexes.split()
        tokens = []
        for regex in regexes:
            for statement in statements:
                # ...
    
    
        ast = []
        for token in tokens:
            # Lex.
    
    
        for node in ast:
            # Parse.
    

    好的写法

    REGEXES = (
       # ...
    )
    
    
    
    
    def parse_better_js_alternative(code: str) -> None:
        tokens = tokenize(code)
        syntax_tree = parse(tokens)
    
    
        for node in syntax_tree:
            # Parse.
    
    
    
    
    def tokenize(code: str) -> list:
        statements = code.split()
        tokens = []
        for regex in REGEXES:
            for statement in statements:
               # Append the statement to tokens.
    
    
        return tokens
    
    
    
    
    def parse(tokens: list) -> list:
        syntax_tree = []
        for token in tokens:
            # Append the parsed token to the syntax tree.
    
    
        return syntax_tree
    

    3.5 不要将标志作为函数参数

    标志表示函数实现的功能不只是一个,但函数应该仅做一件事情,所以如果需要标志,就将多写一个函数吧。

    糟糕的写法

    from pathlib import Path
    
    
    def create_file(name: str, temp: bool) -> None:
        if temp:
            Path('./temp/' + name).touch()
        else:
            Path(name).touch()
    

    好的写法

    from pathlib import Path
    
    
    def create_file(name: str) -> None:
        Path(name).touch()
    
    
    def create_temp_file(name: str) -> None:
        Path('./temp/' + name).touch()
    

    3.6 避免函数的副作用

    函数产生副作用的情况是在它做的事情不只是输入一个数值,返回其他数值这样一件事情。比如说,副作用可能是将数据写入文件,修改全局变量,或者意外的将你所有的钱都写给一个陌生人。

    不过,有时候必须在程序中产生副作用--比如,刚刚提到的例子,必须写入数据到文件中。这种情况下,你应该尽量集中和指示产生这些副作用的函数,比如说,保证只有一个函数会产生将数据写到某个特定文件中,而不是多个函数或者类都可以做到。

    这条建议的主要意思是避免常见的陷阱,比如分析对象之间的状态的时候没有任何结构,使用可以被任何数据修改的可修改数据类型,或者使用类的实例对象,不集中副作用影响等等。如果你可以做到这条建议,你会比很多开发者都开心。

    糟糕的写法

    # This is a module-level name.
    # It's good practice to define these as immutable values, such as a string.
    # However...
    name = 'Ryan McDermott'
    
    
    def split_into_first_and_last_name() -> None:
        # The use of the global keyword here is changing the meaning of the
        # the following line. This function is now mutating the module-level
        # state and introducing a side-effect!
        # 这里采用了全局变量,并且函数的作用就是修改全局变量,其副作用就是修改了全局变量,
        # 第二次调用函数的结果就会和第一次调用不一样了。
        global name
        name = name.split()
    
    
    split_into_first_and_last_name()
    
    
    print(name)  # ['Ryan', 'McDermott']
    
    
    # OK. It worked the first time, but what will happen if we call the
    # function again?
    

    好的写法

    def split_into_first_and_last_name(name: str) -> list:
        return name.split()
    
    
    name = 'Ryan McDermott'
    new_name = split_into_first_and_last_name(name)
    
    
    print(name)  # 'Ryan McDermott'
    print(new_name)  # ['Ryan', 'McDermott']
    

    另一个好的写法

    from dataclasses import dataclass
    
    
    @dataclass
    class Person:
        name: str
    
    
        @property
        def name_as_first_and_last(self) -> list:
            return self.name.split() 
    
    
    # The reason why we create instances of classes is to manage state!
    person = Person('Ryan McDermott')
    print(person.name)  # 'Ryan McDermott'
    print(person.name_as_first_and_last)  # ['Ryan', 'McDermott']
    

    总结

    原文的目录实际还有三个部分:

    • 对象和数据结构

      • 单一职责原则(Single Responsibility Principle, SRP)

      • 开放封闭原则(Open/Closed principle,OCP)

      • 里氏替换原则(Liskov Substitution Principle ,LSP)

      • 接口隔离原则(Interface Segregation Principle ,ISP)

      • 依赖倒置原则(Dependency Inversion Principle ,DIP)

    • 不要重复

    不过作者目前都还没有更新,所以想了解这部分内容的,建议可以直接阅读《代码整洁之道》对应的这部分内容了。

    精选文章

    欢迎关注我的微信公众号--算法猿的成长,或者扫描下方的二维码,大家一起交流,学习和进步!

    如果觉得不错,在看、转发就是对小编的一个支持!

    展开全文
  • 代码整洁之道(Clean code)(美)马丁的中-英文版
  • 代码整洁之道

    2015-11-16 15:26:55
    代码整洁之道:1.什么是整洁的代码;2.怎么才能写出整洁的代码

    一、什么是整洁的代码

    有多少程序员,就有多少定义。但共性都有以下几点:
    - 高效(性能)
    - 优雅&简单直接(可读性)
    - 消除重复

    二、怎么才能写出整洁的代码

    1.有意义的命名

    • 名副其实 —- 命名要有实际意义 重构方法实现时方法名是否还能否清晰表意,是否需要同步修改
    • 避免误导 —- 命名不全、不合适的缩写
    • 有意义的区分 —- ProductData、ProductInfo 避免废话冗余,NameString or Name
    • 读的出来的名称 —- 切记不要造词 genymdhms —> generateTimestamp
    • 避免思维映射 —- 不应当让读者把你的命名翻译成他们熟知的的名称
    • 有意义的语境 —- name or companyName or productName

    PS:类名:名词或名词短语,避免使用Mananger、Processer、Info等
    方法名:动词或动词短语

    2.函数

    • 短小 —- 少嵌套
    • 只做一件事(单一职责)
    • 函数中的语句处于同一抽象层
    • 使用描述性的名称
    • 参数越少越好 —- 参数组合 避免标识参数boolean 多个参数是否应该合并封装成类
    • 无副作用 —- 该做的事没做好 or 做了不该做的事
    • 消除重复

    3.类

    • 类应该短小
    • 单一职责
    • 内聚

    4.注释

    • 注释不能美化糟糕的代码
    • 对意图的解释 — 简洁
    • 警示
    • 误导性注释 — 理解不够精确 or 代码变迁
    • 多余的注释
    • 注释的代码 — 干掉它

      不要给糟糕的代码加注释——重写吧!

    5.对象与数据结构

    • 对象隐藏数据,暴漏行为 —- 便于添加新对象类型而无需修改既有行为,但难以在既有的对象中添加新行为
    • 对象暴漏数据,隐藏行为 —- 便于向既有数据添加新行为,但难以向既有函数添加新的数据结构

    6.错误处理

    • 使用异常而非错误码 —- 返回码需要在条用之后即可检查处理,扰乱调用者代码
    • try-catch-finally —– 只try明确存在异常的代码 明确catch类型,切记不要通吃导致问题掩盖
    • 返回值尽量别传null用空列表等代替

    7.边界

    • 谨慎使用第三方代码
    • 未知的代码
    展开全文
  • Java代码整洁之道

    千次阅读 2020-06-10 20:35:29
    Java代码整洁之道,介绍了什么是好代码,从命名规范、包整洁、类整洁、函数征集、异常征集、注释征集等几个方面介绍了怎么写好Java代码。
  • 为什么保持代码整洁如此重要?

    万次阅读 多人点赞 2021-02-05 10:47:21
    对于代码整洁,没有唯一的或者严格的定义,而且可能无法正式地衡量怎样才算代码整洁,因此你不能在代码仓库上运行一个可以告诉你代码是好是坏、可维护性如何的工具。当然,你可以运行检查器、代码校验器、静态分析器...
  • 代码整洁之道 总结

    千次阅读 2019-05-19 17:31:15
    1.什么样的代码才是整洁的 从字面意思上理解,整洁的代码,对于程序员来说非常的一目了然,简单、整洁,结构清晰,逻辑清楚。代码其实是一种语言,传递的...首先便是要有保持代码整洁的意识,书中反复提到的提到的...
  • 前言:一直以来,我都非常喜欢整洁规则的代码,我痛恶那些杂乱不堪的代码,然而《代码整洁之道》将要告诉我的远不止这些,那么,我希望将自己欣赏的、能够给我帮助的、指引我前进的方案记录下来,以用来我日后翻看。...
  • 在本章中,将介绍C++代码整洁的一些基础知识,这些通常是通用的知识,但是有些却是编程语言所特有的。例如,在所有编程语言中,起一个好名字是必不可少的。其他几个方面,如const的正确使用,智能指针的使用,或Move...
  • 代码整洁之道
  • 代码整洁之道 - 读感

    2017-08-11 10:51:56
    最近翻看了下代码整洁之道这本书,下面简单说下这本书都写了些啥,要告诉我们哪些东西。 能学到些什么? 阅读《代码整洁之道》需要你做些什么呢?你将阅读代码——大量代码。《代码整洁之道》促使你思考代码中何谓...
  • [代码整洁之道].(美)马丁.扫描.pdf

    千次下载 热门讨论 2012-11-29 22:29:47
    Martin携同ObjectMetltor公司的同事,从他们有关整洁代码的最佳敏捷实践中提炼出软件技艺的价值观, 以飨读者,让你成为更优秀的程序员——只要你着手研读《代码整洁之道》。 阅读《代码整洁之道》需要你做些什么...
  • 代码整洁之道》阅读分享

    千次阅读 多人点赞 2019-03-28 13:58:51
    代码整洁之道》是世界级软件开发大师Martin Folwer的著作,软件开发行业不朽的经典。养成保持代码整洁的好习惯,才能走得更远。
  • 代码整洁之道》读书笔记

    万次阅读 多人点赞 2015-04-10 15:52:23
    代码整洁之道》是Bob大叔神一样的作品,这本书从引言到附录都无比精彩,书中的插图也非常好,代码是用Java语言书写的,程序员尤其是Java程序员赶紧去阅读吧!
  • [代码整洁之道]-整洁代码

    千次阅读 2016-11-15 20:40:22
    1.1要有代码代码是我们最终用来表达需求的语言,所以代码永存1.2糟糕的代码 糟糕的代码代价很大,足以毁掉一个公司。 稍后等于永不——现在时间太紧,先完成功能...花时间保持代码整洁不但有关效率,还有关生存1.3.2
  • 代码整洁之道:程序员的职业素养》 《代码整洁之道:程序员的职业素养》读书笔记 代码整洁之道 读书笔记 《代码整洁之道》一书学习总结笔记,正在完善中。觉得有问题之处希望同学能提出宝贵的建议,一起交流学习...
  • 代码整洁之道教给大家如何编写整洁的代码,而不仅仅是能运行的代码,这对于编程者而言很重要。我在读这本书的第一遍时没什么感觉,但在读第二遍时觉得它确实挺不错的,如果有机会的话我会读第三遍。下面是我在读书...
  • 5分钟了解《代码整洁之道》精华

    万次阅读 多人点赞 2019-02-27 10:24:24
    能做到代码整洁,说明你已经不是一般人了。   本文内容主要分以下几点: 什么样的代码是整洁的 取个好名字 让函数再整洁一点 注释的好与坏 格式化 异常处理和边界 整洁的类 1.什么样的代码是整洁的 ...
  • 代码整洁之道--读书笔记代码整洁之道这本书首先给出了代码整洁的重要性。同时在工作中,我们也深有体会,整洁的代码能够提高我们阅读代码和改动需求的效率。在这本书中也加深了我对整洁代码认识,我对整洁的代码的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 60,551
精华内容 24,220
关键字:

代码整洁英文版