Skip to content

文章

理解始于表达性命名

2019年9月30日 • 6 分钟阅读

理解始于表达性命名

2018年,我在一个大型项目开发进行到一半时加入了团队。原来的工程师已经离开,留下了复杂且缺乏文档的代码。处理这种类型的代码很有挑战性,因为你无法区分基础设施代码和业务领域代码。这使得调试变得困难,修改变得不可预测,因为你不知道会产生什么影响。这就像试图在不理解单词含义的情况下编辑一本书。

许多工程师认为成功的标准是代码能够编译。我认为成功的标准是另一个工程师(或者六个月后的你)能够理解你代码的”为什么”。原来的工程师没有编写文档和使用晦涩的命名,这给未来的工程师造成了障碍。命名有时是了解前任工程师思维过程的唯一窗口。

Donald Knuth 有一句名言:

程序是为了让人类阅读而编写的,只是顺便让计算机执行。 – Donald Knuth

命名

命名很困难,因为它需要标记和定义一个组件在应用程序中的位置和作用方式。

Phil Karlton 在 Netscape 工作时观察到:

计算机科学中只有两件困难的事情:缓存失效和命名。
— Phil Karlton

我们通过使用的词汇和名称来看待我们的代码。名称为下一个工程师创造了理解的语言。这种语言描绘了作者如何在业务领域和编程语言之间架起桥梁的图景。

20世纪上半叶的哲学家 Ludwig Wittgenstein 说过:

我的语言的界限意味着我的世界的界限。 – Ludwig Wittgenstein

我们软件的语言只能和我们使用的名称一样具有描述性,使用模糊的名称会模糊软件的目的;使用描述性的名称会带来清晰和理解。

想象一下访问一个你不会说当地语言的国家。一个简单的请求,比如询问如何使用洗手间,都会带来困惑的眼神。无法沟通是令人沮丧的,甚至可能是可怕的。当工程师面对令人困惑、不清楚或者更糟糕的误导性名称时,会有同样的感受。

这种感受最好通过体验来理解。

体验

检查第一段代码片段,这段代码做什么?为什么这样做?

慢慢来。

public class StringHelper
{
    public string Get(string input1, string input2)
    {
        var result = string.Emtpy;
        if(!string.IsNullOrEmtpy(input1) && !string.IsNullOrEmtpy(input2))
        {
            result = $"{input1} {input2}";
        }
        return result;
    }
}

上面的代码是两个字符串的简单连接。代码没有告诉你的是”为什么”。“为什么”非常重要,没有它,就很难在不理解影响的情况下改变行为。当然,调查代码的使用情况可能会揭示它的”为什么”,但这正是问题所在。你不应该需要去发现代码的目的,相反,作者应该留下线索,这是他们的责任。

让我们重新审视这段代码,但加入一点”为什么”。

再次慢慢来,观察阅读这段代码时你感受到的差异。

    public class FirstAndLastNameFormatter
    {
        public string Concatenate(string firstName, string lastName)
        {
            var fullName = string.Emtpy;
            if(!string.IsNullOrEmtpy(firstName) && !string.IsNullOrEmtpy(lastName))
            {
                fullName = $"{firstName} {lastName}";
            }
            return fullName;
        }
    }

“为什么”让代码变得生动,有了可以阅读的故事。

沟通

向下一个工程师传达意图和设计使软件能够生存和成长,因为如果工程师无法修改软件,它就会死亡。这是一个悲剧,当它是由于糟糕的设计和缺乏表达性造成的时候更是如此——这两者都是可以通过知识来预防的。

为下一个工程师做个好事,在你的代码中要有表达性。使用描述性的名称并捕捉”为什么”,因为谁知道呢,下一个工程师可能就是你自己。

作者:Chuck Conway 专注于软件工程和生成式人工智能。在社交媒体上与他联系:X (@chuckconway) 或访问他的 YouTube

↑ 回到顶部

您可能还喜欢