专栏名称: 伯乐在线
关注职业资讯;学习各类职业感悟、心得和经验分享,扩大职业视野;体会求职、工作和创业的历程 - 就在JobBole.com 伯乐在线
目录
相关文章推荐
码农翻身  ·  微软发明了世界上最流行的编程语言! ·  昨天  
程序员小灰  ·  跌爆了。。。 ·  3 天前  
程序员的那些事  ·  突发!4 个程序员被抓,维护赌博网站每月赚 ... ·  3 天前  
程序员的那些事  ·  董事长十几刀刺死 ... ·  2 天前  
程序员的那些事  ·  西部数据突然宣布:退出 SSD 市场! ·  4 天前  
51好读  ›  专栏  ›  伯乐在线

软件的复杂性:命名的艺术

伯乐在线  · 公众号  · 程序员  · 2019-06-05 20:45

正文

(给 伯乐在线 加星标,看经典文章

英文:hackernoon  译文:开源中国

https://www.oschina.net/translate/the-art-of-software-naming



想把一个东西写好很难。为什么呢?因为只要写好了,才会有很好的阅读体验。我们往往关注了前者而忽略了后者。我们忘记了代码只写一次,但要读很多次。


写得好是指写出来的东西读起来容易,而不是指写作本身,这一过程会产生大量的共鸣。它是指,退后一步,从读者的角度来理解所写的东西。人们必须以人的思维来理解问题,然后用其它人能够理解的方式表达出来。在我看来,软件属于社会科学的一部分。我们要搞清楚代码写出来是给谁看的,不是给人看的吗?


因此,理解如何将思想和过程传达给我们的同行甚至我们自己,这就是编程的核心。


为组件命名


为了说清楚第一个概念,我们来玩一个叫“我们在哪个房间?”的游戏。我会给出一张图,然后你告诉我这是哪个房间。


3个问题中的第1个



从这个图很容易判断出来是在客厅。我们从一个组件就能知道所处的房间。这非常容易,我们继续。


3个问题中的第2个



从这个物体很清楚的知道这是在卫生间。


发现什么规律了吗?房间的名称是一个标签,它定义了这个房间里有什么。有了这个标签,我们不知道进去看也知道里面有些什么东西。这足以建立我们的第一个推论:


推论 1: 容器的名称包含了其功能元素


注意这是最基本的“鸭子类型”[译者注:如果它的动作像一只鸭子,那它就是鸭子]。如果有一张床,那这里就是卧室。


反过来也是如此:基于容器的名称,我们可以推断出它的组成部分。如果我们谈论一个卧室,很可能它有一张床。这样产生了我们的第二个推论:


推论 2: 可以根据容器的名称推断其中的组件


显然我们已经有了一些规则,让我们把这些规则应用到下一个房间。


3个问题中的最后一个



哇,床和马桶怎么会在同一个房间?这个房间的定义很模糊,朦朦胧胧,如果一定要用前面的两个推论来为这个房间命名,它只能称为怪物房间。


这里的问题不在于房间里物体的数量,而在于完全无关的事物被看作有同样的功能。在家里,我们会把相关的有类似作用或意图的物品放在一起。如果把作用不同的东西胡乱放在一起,就让人搞不明白架构师到底想怎么来使用这些东西。由于混乱,我们在这里不知所措。


推论 3: 容器定义的明确程度与其内部组件的紧密程度成正比。


这似乎不容易理解,那来看看图示:



如果组件相关,就很容易找到一个好名字[译者注:指容器的名字]。如果事务各不相干,找个合适的名字就会变得困难。这里提到的关系,可能是指它们的功能、目的、策略、类型等。在我们谈到标准之前,关系本身并不包含太多意思。现在先不要急,我们很快就会讲到。


这对于软件同样适用。我们有组件、类、函数、服务、应用程序和其它一些东西。Robert Delaunay 曾经说过“我们的理解与我们的感知相关。”在当前的技术背景下,我们的代码是否能让读者以最简单的方式感知到业务需求呢?


示例 1: HTTP 领域和汽车 domain and a car


HTTP 是一个领域,它有请求和响应。如果我们我们在其中放入一个汽车组件,那就不能再称这为 HTTP。这种情况下它就已经变得混乱了。


public interface WhatIsAGoodNameForThis {

/* methods for a car */

public void gas (); public void brake (); /* methods for an HTTP client */

public Response makeGetRequest ( String param );

}



示例 2: 通过词语来耦合


在类名中添加 Builder 或者其它以 er 结尾的单词是种常见的模式。SomethingBuilder、UserBuilder、AccountBuilder、AccountCreator、UserHelper、JobPerformer。



通过名称,我们可以了解三件事情。首先,在类名中使用 Build 这个动词意味着它是穿着类这件外衣的程序。第二,它有两个隐藏在内部的元素,User 和 Builder,这意味着可能违反了封闭性原则。第三,这意味着 Builder 可以访问到 User 的内部工作,毕竟它们彼此纠缠。


这类似于工厂模块。我们的示例代码在整个代码库中滥用时,它就会成为一个问题。此外,我得提醒你,在工厂模式中不需要什么类。应用程序的 createUser() 就能完成工厂的工作。


[译者注:Builder 也是一种模式,所以关于作者的这个观点,请慎思]


示例 3: Base


来看一点实际项目中的例子。第一个例子是 I18n(国际化)的 Ruby Gem (为了简便起见,只列出了类和方法的名称):


class Base

def config

def translate

def locale_available ?( locale )

def transliterate

end


这里的 Base 并不能表达什么意思。它可以进行配置和翻译,也可以描述一个位置是否可用。它做了一些各不相同,毫不相干的事情。


示例 4: 名称引导设计


我们在谈论名称如何引导我们的设计时,提到了好几个例子,让我们感兴趣的例子中,有一个如下:


class PostAlerter

def notify_post _ users

def notify_group _ summary

def notify_non_pm _ users

def create _ notification

def unread _ posts

def unread _ count

def group_stats

end


PostAlerter 这个名称暗示我们它的功能是在提交的时候提醒某人。然而,unread_posts、unread_count 和 group_stats 却很明显在干别的事情,这就使得类名称不太理想。如果把这三个方法改到名为 PostsStatistics 的类中,表达出来就更清晰,让新接触的人一看就能明白。


class PostAlerter

def notify_post _ users

def notify_group _ summary

def notify_non_pm _ users

def create_notification

end

class PostsStatistics

def unread _ posts

def unread _ count

def group_stats

end


示例 5: 奇怪的名称


Spring 框架中有一些例子说明组件做的事情太多,其名称类似于我们的怪物房间。这里就有一个 (因为这个就太多了点):


class SimpleBeanFactoryAwareAspectInstanceFactory { public ClassLoader getAspectClassLoader () public Object getAspectInstance () public int getOrder ()

public void setAspectBeanName ( String aspectBeanName )

public void setBeanFactory ( BeanFactory beanFactory )

}


示例 6: 改变一下,说说好名称


我们讲了太多不好的名称。D3 的 arc 中就定义了不错的名称,比如:


export default function () { /* ... */

arc . centroid = function () { /* ... */ }

arc . innerRadius







请到「今天看啥」查看全文