HTTP是一個(gè)域,有請(qǐng)求和回復(fù)。但如果我們把一個(gè)叫做car的成員放進(jìn)HTTP,那么我們就不能再叫它HTTP了。在這個(gè)案例中,這個(gè)類(lèi)變得很混亂。
public is {
/* methods for a car */
public void gas();
public void brake();
/* methods for an HTTP client */
public (String param);
示例2: 詞語(yǔ)的連接
一個(gè)普遍的模式是在類(lèi)名后面加上Builder或者其它er結(jié)尾的詞。比如:. , , , , .
從名字上解析,我們可得到三層意思。
類(lèi)名里的動(dòng)詞Build,表示程序上這是一個(gè)類(lèi)中包含有過(guò)程,具有復(fù)合功能;
它有兩個(gè)內(nèi)在的、隱藏的實(shí)體,一個(gè)User一個(gè)Builder,所以可能會(huì)有違反封裝原則的危險(xiǎn);
Builder可以訪(fǎng)問(wèn)User的內(nèi)部工作機(jī)制,因?yàn)锽uilder和User就是相互纏繞的啊。
這就像是一個(gè)工廠(chǎng)模式。當(dāng)這個(gè)類(lèi)在濫用代碼庫(kù)的時(shí)候,我們的示例就會(huì)帶來(lái)問(wèn)題。需要提醒的是,在工廠(chǎng)模式里,我們并不需要?jiǎng)?chuàng)建一個(gè)類(lèi)。應(yīng)用的()就可以很好地實(shí)現(xiàn)工廠(chǎng)模式。
示例3: Base
讓我們來(lái)看一些真實(shí)的示例。第一個(gè)I18n Ruby gem(為了簡(jiǎn)潔起見(jiàn),只提供類(lèi)和方法的名字):
class Base
def config
def
?(locale)
def
end
在這里,Base這個(gè)類(lèi)沒(méi)有表達(dá)任何含義。它可以設(shè)置()、翻譯(),以及判斷l(xiāng)ocale是否可得()。它做的是一些不同的、無(wú)關(guān)聯(lián)的事情。
示例4: 取名對(duì)設(shè)計(jì)的指導(dǎo)意義
當(dāng)我們討論到這些類(lèi)名是如何影響我們的設(shè)計(jì)時(shí),有一些例子。以下的例子引起了我們的興趣:
def
def
def
def
def
def
def
end
這個(gè)名字表示這個(gè)類(lèi)的功能是提醒人們接收新聞發(fā)布信息。
但是,和,這些很明顯地是在說(shuō)其它的事情,這就使得這個(gè)類(lèi)名不是那么理想。把以上三個(gè)放進(jìn)一個(gè)的類(lèi)里,就會(huì)使類(lèi)更加清晰明了,便于新人理解。
Class
def
def
def
def
end
end
示例5: 怪獸名字們
Spring框架里有一些例子,因?yàn)槌蓡T太多,所以起了一些怪獸一樣的類(lèi)名。以下是一個(gè):
{
public ()
public Object ()
public ()
public void (String )
public void (ry)
示例6:一個(gè)好名字的例子
壞名字的例子已經(jīng)夠多了,在D3’sarc()可以找到好的取名例子,比如:
export default () {
/* ... */
arc. = () { /* ... */ }
arc. = () { /* ... */ }
arc. = () { /* ... */ }
arc. = () { /* ... */ }
arc. = () { /* ... */ }
arc. = () { /* ... */ }
arc. = () { /* ... */ }
arc. = () { /* ... */ }
return arc;
這里的所有的方法都表達(dá)了一個(gè)意思:它們都表示了圓弧的組成。我特別欣賞下面這張圖,清晰明了。
方法1:分解
什么時(shí)候使用:這個(gè)類(lèi)找不到好的名字,但是你對(duì)各成員已經(jīng)有了獨(dú)立的概念,這時(shí)候你想為這些小組取個(gè)好名字。
分成兩步:
識(shí)別概念
對(duì)它們進(jìn)行分解
在坐便器+床這個(gè)場(chǎng)景中,我們把床推到左邊、坐便器推到右邊。這樣,我們就有了不同的事物,我們可以自然而然地給出不同的命名。
當(dāng)你不能為一些事物給出好的名字時(shí),可能在你面前的不止一件事物;目前你所知道的,給不同的事物命名很難。當(dāng)你遇到麻煩的時(shí)候,試著分解你面前的事物。
示例
我們有一個(gè)未命名的類(lèi),包含了request、、headers、URLs、body、caching和timeout.把所有的成員從主類(lèi)(main class)中拉出來(lái),我們就有了Request、、Headers、URLs、、Cache、Timeout等等。如果我們所擁有的只是這些類(lèi)的名字,我們可以非常肯定我們是在處理一個(gè)網(wǎng)頁(yè)請(qǐng)求。對(duì)于網(wǎng)頁(yè)請(qǐng)求一個(gè)很好的命名就是。
當(dāng)這個(gè)代碼很難取名,不要首先想到整體!不要!想一想部分。
方法2:發(fā)現(xiàn)新概念
什么時(shí)候使用:當(dāng)類(lèi)不簡(jiǎn)單或者不連貫。
發(fā)現(xiàn)新概念需要商務(wù)領(lǐng)域的知識(shí)。當(dāng)軟件與商務(wù)使用相同的術(shù)語(yǔ)時(shí),一切就進(jìn)行了統(tǒng)一,不同領(lǐng)域的專(zhuān)家用著同一種語(yǔ)法。
示例1:將多種元素封裝于一個(gè)新概念中
曾經(jīng),有個(gè)公司幾乎要丟失一單大合同,為什么呢?因?yàn)槟莻€(gè)團(tuán)隊(duì)在開(kāi)發(fā)新功能和問(wèn)題處理方面,速度特別慢。
這個(gè)市場(chǎng)電子商務(wù)為不同國(guó)家的學(xué)生提供不同規(guī)則的多個(gè)支付網(wǎng)關(guān),需求確實(shí)比較復(fù)雜。當(dāng)我讀到支付代碼的時(shí)候震驚了,這是有多么復(fù)雜啊。代碼里面還有相當(dāng)一部分依賴(lài)條件,包括:User,, , , , ,,等等。這個(gè)巨大的構(gòu)造函數(shù)使得他們很難再添加新規(guī)則,因?yàn)樘砑尤魏我粭l規(guī)則都會(huì)打破其他規(guī)則,并需要去改動(dòng)網(wǎng)管適配代碼。
這個(gè)問(wèn)題甚至影響到了支付之外的服務(wù)。為了聚集消息類(lèi)數(shù)據(jù),他們給學(xué)生發(fā)送了郵件。技術(shù)支持有自己獨(dú)立的屏幕來(lái)看數(shù)據(jù)的第三次匯聚,除了這個(gè)特別的用到了名為類(lèi)的地方(類(lèi)名也就是本義)。
于是,我們不得不做點(diǎn)什么,來(lái)挽救這個(gè)架構(gòu)缺陷。
處理這個(gè)問(wèn)題,我想到了一些主意:我需要你( )為我處理一些支付細(xì)節(jié)。如果我是一張課桌,或許我需要把這些發(fā)票幫我整理好。所以說(shuō)如果我創(chuàng)建一個(gè)名為 invoice的類(lèi),僅用來(lái)處理這些細(xì)節(jié)信息的匯聚,那么網(wǎng)關(guān)是不需要知道那些細(xì)節(jié)的,因?yàn)閕nvoice會(huì)處理的,對(duì)嗎?與其注入無(wú)數(shù)個(gè)對(duì)象,我是否可以嘗試只傳遞一個(gè)給你?
Invoice這個(gè)術(shù)語(yǔ)之前從來(lái)沒(méi)有應(yīng)用過(guò)。我們花了一個(gè)月的時(shí)間進(jìn)行重組,然后我們就能夠更為靈活地對(duì)代碼進(jìn)行改動(dòng)。Invoice是一個(gè)很好的實(shí)例,它描述了匯聚的概念而且大多數(shù)人都能看懂。最終解決方案是向Gateway單獨(dú)注入了Invoice類(lèi)作為接口,用于屏蔽其他更多類(lèi)。
好的命名不僅僅是優(yōu)美的詞匯,而是要用精準(zhǔn)的語(yǔ)言去表達(dá)代碼的內(nèi)涵。
示例2: 根據(jù)業(yè)務(wù)領(lǐng)域的調(diào)整命名
在一個(gè)未開(kāi)發(fā)的拼車(chē)項(xiàng)目中,我們從頭設(shè)計(jì)我們的系統(tǒng)。在對(duì)其它交通方案的研究中,對(duì)于某人在某天從某處出發(fā)到某目的地的這一旅行,最合適的詞是trip;而這一些旅行的人,就被稱(chēng)為ride。我們打印了一個(gè)詞匯表,這樣公司的人就可以討論并且分享使用這些共同的詞匯。
但產(chǎn)品發(fā)布之后,我們的客戶(hù)總是把我們的trips稱(chēng)為rides。很快,我們就在將客戶(hù)的請(qǐng)求轉(zhuǎn)換為我們需要做的事情上,產(chǎn)生了問(wèn)題。痛定思痛,我們覺(jué)得是時(shí)候該把trips改變?yōu)閞ides、rides改變成。這樣就解決了一個(gè)公司說(shuō)著兩種不同語(yǔ)言的問(wèn)題。
示例3:抽象級(jí)別
一個(gè)人說(shuō),移動(dòng)右腿然后左腿再右腿,另一個(gè)說(shuō)走路。兩者都是一樣的意思,但后者說(shuō)法更抽象。
理想情況下,當(dāng)代碼越來(lái)越接近其公共API,它越接近于企業(yè)術(shù)語(yǔ)。隨著它接近數(shù)據(jù)庫(kù)和金屬,它會(huì)使用更多的計(jì)算機(jī)術(shù)語(yǔ)。在這之間,抽象程度逐步降低。
在一家公司中,一個(gè)業(yè)務(wù)人員會(huì)說(shuō),所以例如()這樣的一個(gè)名字,將在公共API比()更說(shuō)得通。在一家擁有更多技術(shù)服務(wù)的公司中,后者的表達(dá)方式也足夠清楚。
二,考慮特異性。()是非常具體的,因?yàn)椋ǎ┦峭ㄓ玫模梢杂糜诨蚧旧仙婕癏TTP的任何內(nèi)容。一個(gè)通用名稱(chēng)可以輕易地被重復(fù)使用,會(huì)導(dǎo)致含義不清晰。這就解釋了為什么框架代碼與商業(yè)軟件代碼有如此大的區(qū)別。
Example 4: 概括
很久以前,一個(gè)CMS有數(shù)據(jù)庫(kù)表的新聞,歷史,視頻,文章,頁(yè)面等。他們大多數(shù)有相同的列,標(biāo)題,摘要,文本。有額外的屬性例如url(嵌入YouTube)和有adate屬性的歷史,所以網(wǎng)頁(yè)會(huì)顯示一年的歷史事件列表。所有這些表格看起來(lái)都是副本,在這里和那里有一些差異,如果要添加新功能,就需要重寫(xiě)大量樣板。
我拆散了所有那些表,整合進(jìn)一個(gè)類(lèi),名為,并用一個(gè)外部指針指向一個(gè)表格,名為section,包含新聞,歷史,視頻等清單。現(xiàn)在,一段代碼的就足夠了。幾年后,一個(gè)朋友不得不寫(xiě)一個(gè)小的CMS,我建議他說(shuō),我把所有這些表折疊成一個(gè)被稱(chēng)為的外鍵,指向一個(gè)叫做“”的表,其中列出了相同的方法。一旦管理content的表單完成,它花費(fèi)1/N的時(shí)間來(lái)執(zhí)行,因?yàn)閷?duì)于同一類(lèi)型的每個(gè)新的部分來(lái)說(shuō),都是一樣的。
通過(guò)命名的方式將過(guò)程通用化,會(huì)在很大程度上提高生產(chǎn)力。新聞是一個(gè)Content,文章是一個(gè)Content。歷史是一個(gè)Content。所有這些都可以共享相同的屬性嗎?是。那調(diào)查是不是Cintent?哦,不,不是Content。
方法三:分組標(biāo)準(zhǔn)
什么時(shí)候使用:當(dāng)名字很好,但他們不能很好地相配時(shí)。
組件可以通過(guò)各種標(biāo)準(zhǔn)進(jìn)行分組,包括物理性質(zhì),經(jīng)濟(jì)性,情感性,社會(huì)性和軟件中最常用的功能。相框根據(jù)情感方面分組,而產(chǎn)品則根據(jù)經(jīng)濟(jì)動(dòng)機(jī)分組。沙發(fā)和電視留在同一個(gè)房間,根據(jù)功能標(biāo)準(zhǔn)分組在一起,因?yàn)樗鼈兙哂邢嗤墓δ芑蛱峁┬蓍e的相同目的。
在軟件中,我們傾向于按功能對(duì)組件進(jìn)行分組。列出你的項(xiàng)目文件,你可能會(huì)看到像 /,models /, /, /等等。然而,有些時(shí)候,這些分組并不讓人舒服,這就是時(shí)候來(lái)重新評(píng)估模塊結(jié)構(gòu)了。
示例:按策略分組
一個(gè)用于自動(dòng)化文檔操作的庫(kù)(如API藍(lán)圖)根據(jù)代碼生成規(guī)范文件,lints所述文件(保證格式正確)并上傳到云(如S3)。
根據(jù)文件格式,將自動(dòng)進(jìn)行各種后續(xù)決定。選擇API藍(lán)圖將會(huì)選擇不同的linter,不同的測(cè)試器和不同的API 轉(zhuǎn)換器。這里的關(guān)鍵詞策略是基于一個(gè)輸入來(lái)組合所有這些不同的功能。此后,該庫(kù)包括一個(gè)稱(chēng)為策略的模塊(或名稱(chēng)空間),該模塊將文件格式,linter,文檔測(cè)試器和存儲(chǔ)供應(yīng)商組合在一起。這使得庫(kù)可以將業(yè)務(wù)核心策略中的普通操作文件(如上傳者,解析器和命令行)分開(kāi)。
利用上下文
每個(gè)應(yīng)用程序都有不同的上下文,同樣的,其中的每個(gè)模塊,它們內(nèi)的每個(gè)類(lèi),到每個(gè)功能也是這樣。User這個(gè)名字可以單獨(dú)表示系統(tǒng)用戶(hù),也可能是數(shù)據(jù)庫(kù)表或者第三方服務(wù)憑證。lib/billing/user 與lib/booking/user不同,但仍然是用戶(hù)。
想象一下,每個(gè)容器,如模塊,都是一個(gè)bucket。在其中,組件被封裝,與外界絕緣。你可以自由命名這些類(lèi),無(wú)需為一些尋常的事物去創(chuàng)建出生僻的名稱(chēng)。
一個(gè)在整體式架構(gòu)(一個(gè)大容器,其中有一些小容器)中的微服務(wù)(許多獨(dú)立的容器)的強(qiáng)有力的論據(jù)是,它強(qiáng)制限制每個(gè)服務(wù)中的責(zé)任,因?yàn)槟銦o(wú)法輕松地將完全不相關(guān)的事情互相糾纏在一起。 內(nèi)部的幾張同能,內(nèi)預(yù)訂功能等等。在一個(gè)單一的架構(gòu)中,這些相應(yīng)的服務(wù)名稱(chēng)可以是簡(jiǎn)單的模塊名稱(chēng),但并不是每個(gè)人都會(huì)恪守原則保持代碼井井有條的。
示例:命名空間
馬克正在建立一個(gè)需要生產(chǎn)成千上萬(wàn)條廣告的廣告平臺(tái),然后發(fā)送到AdWords(谷歌),臉書(shū)和必應(yīng),所有這些都通過(guò)圖形用戶(hù)界面進(jìn)行管理。
馬克從一個(gè)稱(chēng)為Ad的實(shí)體開(kāi)始,很快開(kāi)始膨脹。AdWords的廣告有和,臉書(shū)不會(huì),而必應(yīng)只有。他需要想辦法分裂他的實(shí)體。他思考不同的語(yǔ)境,以及如何利用語(yǔ)言的命名空間來(lái)表達(dá)這一點(diǎn)。他想出了以下結(jié)構(gòu):
?API :: Ad:廣告的HTTP端點(diǎn)將具有自己的自定義屬性,因此序列化邏輯存在于此處。
詞語(yǔ)可以意味著不同的東西,這取決于上下文,當(dāng)我們利用上下文時(shí),我們可以為組件選擇更簡(jiǎn)單的單詞。在這個(gè)例子中,我們不需要復(fù)雜的過(guò)程就能找到這些組件名稱(chēng),因?yàn)樗鼈兪且换厥拢瑥V告。
無(wú)意詞和新詞
年復(fù)一年,名字也在發(fā)展并被賦予獲得新聞的含義。新詞不斷涌現(xiàn),填補(bǔ)空缺。
助手(helper):助手是支持應(yīng)用程序的主要目標(biāo)的功能。但是,那么定義應(yīng)用程序的主要目標(biāo)是什么?應(yīng)用程序中的所有內(nèi)容都支持應(yīng)用程序的主要目標(biāo)。
在實(shí)踐中,它們被集中在一個(gè)非自然的分組中,為一些其他混雜的,常用的操作提供可重用性。他們傾向于Feature Envy,他們需要訪(fǎng)問(wèn)另一個(gè)組件的內(nèi)部數(shù)據(jù)來(lái)工作。他們是找不到正確名稱(chēng)東西的借口。
基礎(chǔ):名為Base的類(lèi)是很久以前在C#中指定繼承的慣例,缺少一個(gè)更好的名稱(chēng)。例如,汽車(chē)和自行車(chē)的父類(lèi)將是Base而不是Vehicle。
盡管微軟的建議避免了這個(gè)名字(Cwalina,2009),但它顯然通過(guò)影響了了Ruby界。到目前為止,我們?nèi)匀粚ase看作開(kāi)發(fā)人員找不到名稱(chēng)的類(lèi)名。
Base的變體包括。例如,JSON Ruby gem 的具有解析(parse),生成(),加載(load)和jj的方法,但是常見(jiàn)的是什么意思呢?
任務(wù):在社區(qū)有一個(gè)習(xí)慣來(lái)調(diào)用異步函數(shù),叫tasks。它從task.js開(kāi)始,即使原始庫(kù)不存在,該術(shù)語(yǔ)也被使用。
團(tuán)隊(duì)中的每個(gè)人都明白嗎?如果真是那樣就好了。但是,當(dāng)一個(gè)某人新加入團(tuán)隊(duì),遇到了和60年代以來(lái)存在的已然被拋棄在垃圾中命名法,會(huì)發(fā)生什么情況呢?
我在一個(gè)項(xiàng)目中工作,猜一下這個(gè)類(lèi)的名字,亞特蘭大。是的,亞特蘭大。真見(jiàn)鬼,沒(méi)人說(shuō)的清楚為啥叫那名字。
溝通
“現(xiàn)實(shí)僅存在于人的思想,而非其他任何地方。”喬治·奧威爾(George Orwell)
我認(rèn)為溝通交流的做法是一個(gè)利他主義的行為,我們提高技能的努力與我們對(duì)別人的關(guān)心有關(guān)。我們希望人們?nèi)菀桌斫猓覀兿胍芎驼系K。
其次,我們希望別人了解我們。令收到消息的人理解這條消息是發(fā)件人的責(zé)任,如果能夠接受這個(gè)觀點(diǎn),我們營(yíng)造一個(gè)共情的環(huán)境,一個(gè)雙贏的局面。沒(méi)有任何借口不去刻意練習(xí)我們的溝通技巧 - 除非你住在叢林中。
隨著寫(xiě)作,我們優(yōu)化閱讀,練習(xí)共情等方面的技巧可能是很辛苦的。但是,正如生活中的一切,熟能生巧是最樸素的真理。
書(shū)目提要:
Cwalina, . 2009. Design : , Idioms, and for .NET , Second Edition. Boston: Pearson , Inc. 206.
Evans, Eric. 2003.Domain-Driven Design: in the Heart of . Boston: Addison-Wesley .
掃碼報(bào)名Strata Data 大會(huì)
大數(shù)據(jù)文摘專(zhuān)享優(yōu)惠截至5月5日
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。