摘要:軟件的復(fù)雜性命名的藝術(shù)在計(jì)算機(jī)科學(xué)中只有兩件困難的事情緩存失效和命名規(guī)范。到目前為止,我們依然將看做為開發(fā)人員找不到合適命名的一種替代方式。
軟件的復(fù)雜性:命名的藝術(shù)
前言在計(jì)算機(jī)科學(xué)中只有兩件困難的事情:緩存失效和命名規(guī)范。
—— Phil Karlton
編寫優(yōu)質(zhì)代碼本身是一件很困難的事情,為什么這么說?因?yàn)榱己玫木幋a風(fēng)格是為了能更好的理解與閱讀。通常我們會(huì)只注重前者,而忽略了后者的重要性。我們的代碼雖然只編寫一次,但是在閱讀復(fù)審時(shí)會(huì)閱讀許多次。
良好的編碼習(xí)慣可以提高我們的閱讀質(zhì)量,比寫作本身要輕松許多,我們可以站在宏觀角度看待問題,遠(yuǎn)觀大局,而不失細(xì)節(jié)。首先我們需要理解、分析清楚某個(gè)問題,然后用特有的,高效的,言簡(jiǎn)意賅的方式讓更多人明白。對(duì)我來說,應(yīng)該明確的把軟件工程歸屬到社會(huì)科學(xué)領(lǐng)域。我們?yōu)檎l編寫代碼,難道不是為了人類嗎?(感覺原文作者裝的有點(diǎn)過)
向其他人傳遞我們的想法以及編程思想,這就是我們?cè)诰幋a時(shí)要做的。
命名構(gòu)造為了說明我們的第一個(gè)概念,首先來做一個(gè)游戲,游戲名為 “我們住在哪個(gè)房間?”,如下會(huì)為你提供一張圖片,請(qǐng)你說說看這是什么房間。
問題 1/3
從上面的圖片不難看出,這肯定是客廳?;谝患锲?,我們可以聯(lián)想到一個(gè)房間的名稱,這很簡(jiǎn)單,那么請(qǐng)看下圖。
問題 2/3
基于這張圖片,我們可以肯定的說,這是廁所。
通過上面兩張圖片,不難發(fā)現(xiàn),房間的名稱只是一個(gè)標(biāo)簽屬性,有了這個(gè)標(biāo)簽,甚至我們不需要看它里面有什么東西。這樣我們便可以建立第一個(gè)推論:
可以將這個(gè)推論理解為 鴨子類型。如果有一張床?那么它就是臥室。我們也可以反過來進(jìn)行分析。
問題:基于一個(gè)容器名稱,我們可以推斷出它的組成部分。如果我們以臥室為例,那么很有可能這個(gè)房間有一張床。這樣我們便可以建立第二個(gè)推論:
推論2:根據(jù)容器(函數(shù))的名稱推斷其內(nèi)部組成元素現(xiàn)在我們有了兩條推論,據(jù)此我們?cè)囍聪旅孢@張圖片。
問題 3/3
好吧,床和馬桶在同一個(gè)房間?根據(jù)我們的推論,如上圖片使我們很難立即做出判斷,如果依然使用上述兩條推論來給它下定義的話,那么我會(huì)稱它為:怪物的房間。
這個(gè)問題并不在于同一個(gè)房間的物品數(shù)量上,而是完全不相關(guān)的物品被認(rèn)作為具備同樣的標(biāo)簽屬性。在家中,我們通常會(huì)把有關(guān)聯(lián)的,意圖以及功能相近的東西放在一起,以免混淆視聽,所以現(xiàn)在我們有了第三條推論:
推論3:容器(函數(shù))的明確度與其內(nèi)部組件的密切程度成正比這可能比較難理解,所以我們用下面這一張圖來做說明:
如果容器內(nèi)部元素屬性關(guān)聯(lián)性很強(qiáng),那么我們更容易找到一個(gè)用來說明它的名字。反之,元素之間的無關(guān)性越強(qiáng),越難以描述說明。屬性維度可能會(huì)關(guān)系到他們的功能、目的、戰(zhàn)略,類型等等。關(guān)于命名標(biāo)準(zhǔn),需要關(guān)聯(lián)到元素自身屬性才有實(shí)際意義。跟著我的思路,我們將很快明白這一點(diǎn)。
在軟件工程方面,這個(gè)觀點(diǎn)也同樣適用。例如我們熟知的 組件,類,函數(shù)方法,服務(wù),應(yīng)用。羅伯特·德拉奈曾說過:“我們的理解能力很大程度與我們的認(rèn)知相關(guān)聯(lián)”,那么在這種技術(shù)背景下,我們的代碼是否可以使閱讀者以最簡(jiǎn)單的方式感知到業(yè)務(wù)需求以及相關(guān)訴求?
Example 1:HTTP 域與汽車HTTP 自身是一個(gè)域環(huán)境,它包含著我們的網(wǎng)絡(luò)請(qǐng)求與響應(yīng)狀態(tài)。如果我們把一個(gè) Car 的組件放入它的內(nèi)部,那么我們不能再稱它為 HTTP了,在這種情況下,它會(huì)變得讓人困惑。
public interface WhatIsAGoodNameForThis { /* methods for a car */ public void gas(); public void brake(); /* methods for an HTTP client */ public Response makeGetRequest(String param); }Example 2:?jiǎn)卧~的耦合
有一種常見的命名模式,在名稱時(shí)后綴附加上 Builder 或 er 一類的結(jié)束詞,例如:SomethingBuilder,UserBuilder,AccountCreator,UserHelper,JobPerformer 等等。
例如上圖中的名字,我們可以推斷出三件事情。第一,在類名中使用動(dòng)詞 Build 意味著它是具備功能性的。第二,它由兩部分組成,一個(gè)是 User 用戶,另一個(gè)的 Builder 構(gòu)造者,這意味著它們之間可能在封裝、維度歸類上存在歧義。第三,Builder 構(gòu)造者 可以在類內(nèi)部訪問 User 用戶 的相關(guān)邏輯、數(shù)據(jù),因?yàn)樗麄冊(cè)谕痪暥瓤臻g內(nèi)。
這一點(diǎn)與工廠模式很相似,有自己的應(yīng)用場(chǎng)景,當(dāng)它在我們的工程中泛濫使用時(shí),這將會(huì)是一個(gè)很麻煩的問題。另外,需要提醒大家,在工廠模式中,并不一定需要有一個(gè)類,通過一個(gè) createUser 的方法足矣很好的實(shí)現(xiàn)工廠模式的功能。
Example 3: 基類讓我們先看幾個(gè)生活中真實(shí)的例子。首先是 i18n Ruby gem(它的類與方法名稱都是非常簡(jiǎn)練)。
class Base def config def translate def locale_available?(locale) def transliterate end
這里,Base 這個(gè)命名本身并沒有傳達(dá)太多含義,其中內(nèi)部結(jié)構(gòu)包含了配置、翻譯,區(qū)域設(shè)置,音譯。它們可以看似無關(guān)的聚合在一起。
Example 4: 命名與構(gòu)建一個(gè)合理的命名可以引導(dǎo)我們構(gòu)建出更為嚴(yán)瑾的組件容器。如下例所示。
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 從這個(gè)名字本身可以發(fā)現(xiàn),它意味著在內(nèi)部會(huì)做一些類似提醒通知的功能。然而,其中 unread_posts,unread_count,group_status 并不在這個(gè)功能的主要范疇內(nèi),從這一點(diǎn)來看,這個(gè)類的名稱并不是很理想。我們可以將這個(gè)三個(gè)方法移動(dòng)到一個(gè)名為 PostStatistics 的類中,這樣解耦后,事件功能會(huì)變得更加清晰,更可預(yù)測(cè)。
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 endExample 5: 奇怪的命名
在 Spring 框架中有一些例子,組件做的事情太多,其名稱都非常冗長(zhǎng)奇怪。這里只舉一個(gè)例子(因?yàn)閷?shí)在太多了):
class SimpleBeanFactoryAwareAspectInstanceFactory { public ClassLoader getAspectClassLoader() public Object getAspectInstance() public int getOrder() public void setAspectBeanName(String aspectBeanName) public void setBeanFactory(BeanFactory beanFactory) }Example 6: 說說好的名稱
我們聊了許多不太合理的命名,在 D3 的 arc 中就有許多不錯(cuò)的命名定義,例如:
export default function() { /* ... */ arc.centroid = function() { /* ... */ } arc.innerRadius = function() { /* ... */ } arc.outerRadius = function() { /* ... */ } arc.cornerRadius = function() { /* ... */ } arc.padRadius = function() { /* ... */ } arc.startAngle = function() { /* ... */ } arc.endAngle = function() { /* ... */ } arc.padAngle = function() { /* ... */ } return arc; }
上面這個(gè)例子中,每一個(gè)方法都是完全有意義的:他們都是以 arc 開頭。并且他命名風(fēng)格就像繪制下面的圖片一樣簡(jiǎn)練,令人歡喜。
方法 1: 拆解應(yīng)用場(chǎng)景:當(dāng)你不能為類或方法找到一個(gè)合適的命名,但是你知道如何拆解它們,并且期望給他們的組合找到一個(gè)好的名稱。
主要有兩個(gè)步驟:
分辨出他們之間的特點(diǎn)和概念
將它們拆分開
在床和馬桶這種特定耦合的場(chǎng)景下,為了拆解他們的不同之處,我們將床移動(dòng)到左側(cè),將馬桶移動(dòng)到右側(cè)。這樣我們便將兩個(gè)不同的事物分離開了。
當(dāng)你不能為某個(gè)事物找到一個(gè)好的名稱時(shí),也許是因?yàn)槟闼媾R的不止一件事物。不過現(xiàn)在我們已經(jīng)知道,對(duì)多個(gè)事物進(jìn)行命名是一件非常困難的事情,當(dāng)我們遇到這類問題時(shí),不妨確認(rèn)一下構(gòu)造這個(gè)事物的組成部分,以及動(dòng)作行為。
事例:
我們現(xiàn)有一個(gè)未命名的類,其中包含了 request,reponse,headers,URLs,body,caching,timeout,把所有這些從類中拉取出來,我們剩下這樣一些組件:Request,Respone,Headers,URLs,ReponseBody,Cache,Timeout 等。如果我們已知這些類的名稱,那么我們可以確定這個(gè)類是用于處理 Web 請(qǐng)求的,HTTPClient 是一個(gè)不錯(cuò)的 Web 請(qǐng)求組件的命名。
當(dāng)我們編碼遇到困難時(shí),先不要想著整體,先考慮一下局部細(xì)節(jié)。
方法 2: 發(fā)現(xiàn)新概念應(yīng)用場(chǎng)景:當(dāng)一個(gè)類并不簡(jiǎn)單或者內(nèi)容并不相干。
發(fā)現(xiàn)新的概念需要大量業(yè)務(wù)領(lǐng)域的知識(shí),當(dāng)軟件的命名和業(yè)務(wù)保持一致時(shí),一個(gè)普遍的語言便建立起來,它允許來自不同專業(yè)領(lǐng)域的人來使用相同的語言。
方法 3: 分組標(biāo)準(zhǔn)應(yīng)用場(chǎng)景:當(dāng)有一個(gè)好的命名,但是他們他們之間并不適合。
組件元素之前可以通過各種標(biāo)準(zhǔn)進(jìn)行分組,譬如組件元素的物理性質(zhì),經(jīng)濟(jì)性,情感性,社會(huì)性以及軟件中最常用的功能。
在軟件工程中,我們傾向于按功能對(duì)組件元素進(jìn)行分組。如果列出你的項(xiàng)目文件,你可能會(huì)看到像 controller/,models/,adapters/,templates/ 等等目錄名稱,然后,有些時(shí)候,這些名稱組合在一起并一定適合,這也是重新評(píng)估模塊,重新定義,規(guī)劃命名的時(shí)候。
每個(gè)應(yīng)用程序都有自己不同的上下文環(huán)境,每個(gè)模塊、每個(gè)類、每個(gè)方法也同樣都有。User 這個(gè)詞所代表的含義可以是操作系統(tǒng)用戶,或是一張數(shù)據(jù)表,也可以是一個(gè)第三方的服務(wù)憑證,不同的上下文環(huán)境,它所表示的含義不盡相同。
無意義的詞與新詞多年以來,命名規(guī)范的演變上變得更具有意義,有更多的人來填補(bǔ)這個(gè)陳舊的空缺。
Helper,helpers 是一個(gè)支持應(yīng)用程序?qū)崿F(xiàn)的主要方式。應(yīng)用程序?qū)崿F(xiàn)與定義的標(biāo)準(zhǔn)是什么呢?應(yīng)用程序中的所有內(nèi)容都應(yīng)該支持并實(shí)現(xiàn)其主要目標(biāo)。
在實(shí)踐中,它們被擊中在一個(gè)非自然的分組中,為一寫其他常用的操作提供可重用性。一般情況下,helpers 需要另一個(gè)組件元素的內(nèi)部數(shù)據(jù)的依賴。這種命名一般會(huì)在找不到合適的名稱時(shí)折中使用。
Base,許久之前,在 C# 中有需要繼承類的命名方式都是以 Base 命名。例如:汽車和自行車的父類都是 Base 而不是 Vehicle。盡管微軟提出建議去避免這類命名方式,但他依然影響了 Ruby 這門語言,其中最具代表性的是 ActiveRecord 類的繼承。到目前為止,我們依然將 Base 看做為開發(fā)人員找不到合適命名的一種替代方式。
變動(dòng)調(diào)整后的 Base 含括了 Common 和 Utils,例如,JSON Ruby gem 的 Common 類具有 parse,generate,load 以及 jj 等方法,但這里 Common 真的具備它的含義嗎?
Tasks,在 JavaScript 社區(qū)興起了一種通過異步調(diào)用函數(shù)的方式,這種方式起源于 task.js,即使目前這個(gè)開源庫(kù)很少再被提使用,但是這個(gè)術(shù)語流傳了下來。
如果團(tuán)隊(duì)中所有人都能清楚的理解它的含義,那是可喜的。但如果有新人加入團(tuán)隊(duì),并且他遇到了被拋棄在垃圾堆中的 60 年代便存在的古怪命名,那又怎么辦呢?
在我之前的項(xiàng)目工作中,曾遇到過這樣的一個(gè)類的命名,你們猜猜看,Atlanta,是的,亞特蘭大,操蛋的亞特蘭大。沒人知道或者可以告訴我為什么要起這么個(gè)名字,以及含義是什么。
參考資料Cwalina,Krzysztof.2009,框架設(shè)計(jì)指南:可重用 .NET 庫(kù)的約定、慣用語和模式,第二版。 Boston: Pearson Education, Inc. 206。
Evans, Eric. 2003。域驅(qū)動(dòng)設(shè)計(jì):解決軟件核心復(fù)雜性。Boston: Addison-Wesley Professional。
原文鏈接:https://medium.com/hacker-dai...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/82530.html
摘要:軟件的復(fù)雜性命名的藝術(shù)在計(jì)算機(jī)科學(xué)中只有兩件困難的事情緩存失效和命名規(guī)范。到目前為止,我們依然將看做為開發(fā)人員找不到合適命名的一種替代方式。 軟件的復(fù)雜性:命名的藝術(shù) 在計(jì)算機(jī)科學(xué)中只有兩件困難的事情:緩存失效和命名規(guī)范?!?Phil Karlton 前言 編寫優(yōu)質(zhì)代碼本身是一件很困難的事情,為什么這么說?因?yàn)榱己玫木幋a風(fēng)格是為了能更好的理解與閱讀。通常我們會(huì)只注重前者,而忽略了后者...
摘要:軟件的復(fù)雜性命名的藝術(shù)在計(jì)算機(jī)科學(xué)中只有兩件困難的事情緩存失效和命名規(guī)范。到目前為止,我們依然將看做為開發(fā)人員找不到合適命名的一種替代方式。 軟件的復(fù)雜性:命名的藝術(shù) 在計(jì)算機(jī)科學(xué)中只有兩件困難的事情:緩存失效和命名規(guī)范?!?Phil Karlton 前言 編寫優(yōu)質(zhì)代碼本身是一件很困難的事情,為什么這么說?因?yàn)榱己玫木幋a風(fēng)格是為了能更好的理解與閱讀。通常我們會(huì)只注重前者,而忽略了后者...
摘要:軟件的復(fù)雜性命名的藝術(shù)在計(jì)算機(jī)科學(xué)中只有兩件困難的事情緩存失效和命名規(guī)范。到目前為止,我們依然將看做為開發(fā)人員找不到合適命名的一種替代方式。 軟件的復(fù)雜性:命名的藝術(shù) 在計(jì)算機(jī)科學(xué)中只有兩件困難的事情:緩存失效和命名規(guī)范?!?Phil Karlton 前言 編寫優(yōu)質(zhì)代碼本身是一件很困難的事情,為什么這么說?因?yàn)榱己玫木幋a風(fēng)格是為了能更好的理解與閱讀。通常我們會(huì)只注重前者,而忽略了后者...
摘要:原文管理圖表的藝術(shù)第一小部分有人翻譯過了,鏈接用和管理圖表樣式有五個(gè)預(yù)設(shè)好的主題和。如上文提到的,網(wǎng)格讓圖表的布局成為了查找大量信息的表格,并且白線灰底讓網(wǎng)絡(luò)不會(huì)影響代表數(shù)據(jù)的線的顯示。盡管主題非常簡(jiǎn)潔,但是它更適用于數(shù)據(jù)元素較大的布局。 原文: http://web.stanford.edu/~mwaskom/software/seaborn/tutorial/aesthetics....
閱讀 3219·2021-11-22 13:54
閱讀 3538·2021-11-15 11:37
閱讀 3676·2021-10-14 09:43
閱讀 3581·2021-09-09 11:52
閱讀 3700·2019-08-30 15:53
閱讀 2538·2019-08-30 13:50
閱讀 2128·2019-08-30 11:07
閱讀 937·2019-08-29 16:32