偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

好代碼的五個(gè)特質(zhì)

開發(fā)
CUPID是完備的嗎,很遺憾,也不是。但CUPID所指出的五種特質(zhì)可能是按照重要程度排序之后取前五的特質(zhì)。

CUPID出自Daniel的一篇名為《??CUPID—for joyful coding??》?的博文,即《CUPID-為了快樂編程》。CUPID是Composable/Unix philosophy/Predictable/Idiomatic/Domain based幾個(gè)單詞的縮寫,有經(jīng)驗(yàn)的同學(xué)一看就知道這是好代碼的一些屬性。知道Cupid這個(gè)單詞的同學(xué)還能感受到這一組屬性所蘊(yùn)含的對(duì)于軟件工程的熱情。Cupid的中文是丘比特,是指古羅馬的愛神,其意象是一個(gè)長(zhǎng)有翅膀的小孩,拿著弓箭射向人們,以便人們可以相互愛上對(duì)方。

好代碼的五個(gè)特質(zhì)

特質(zhì)

Daniel老爺子回憶了自己三十多年的編程經(jīng)歷,他發(fā)現(xiàn)在修改代碼時(shí),好的代碼會(huì)給人一種非常愉悅的感覺。你可以輕松找到需要修改的地方,而且,那個(gè)地方的代碼是如此的易于理解,以至于一眼就能看出來代碼在干什么。你可以很自信的完成修改,并且確信不會(huì)引入額外的副作用。代碼是那么的鮮活,它會(huì)主動(dòng)的指引你去你想去的地方,并且熱情的歡迎你四處游覽,就像在你熟悉的家里一樣!

為什么好的代碼能有這樣的魅力?什么樣的代碼才是好代碼?提到這個(gè)問題,我們常常會(huì)想到SOLID(Single Responsibility/Open-close/Liskov Substitution/Interface Segregation/Dependency Injection)原則,Daniel老爺子認(rèn)為應(yīng)該存在比SOLID更好用的東西。

如何衡量代碼好壞?SOLID采用了一組原則來定義好的代碼,但是原則更像是規(guī)則,要么符合,要么不符合。而軟件開發(fā)過程非常復(fù)雜,其間充滿了平衡和妥協(xié),事實(shí)上并沒有一種非黑即白的規(guī)則可以適用。有沒有比原則更好的選擇?它可能是特質(zhì)(Properties/Characteristics)。

特質(zhì)是事物本身所具備的,而不是靠一組規(guī)則去定義的;特質(zhì)吸引我們?nèi)ド疃韧诰?,而不是信任已有的總結(jié);特質(zhì)通常不是簡(jiǎn)單的0或1的判斷,而是一種從低到高的程度;特質(zhì)是從觀察者的角度給出的,更關(guān)注觀察者的體驗(yàn),而更少關(guān)注與體驗(yàn)無關(guān)的其他方面。

之所以我們會(huì)覺得某樣?xùn)|西是好的,常常是因?yàn)槟硺訓(xùn)|西具備了一些好的特質(zhì)。比如藍(lán)天白云圖,它具備了干凈、純粹的特質(zhì)。比如勾股定理和質(zhì)能方程,它們具備簡(jiǎn)潔、優(yōu)雅的特質(zhì)。

如果說好的代碼是一個(gè)中心點(diǎn),特質(zhì)就像是定義了一些方向,通過這些方向的指引,就可以不斷向這個(gè)中心點(diǎn)靠攏。

CUPID就是從特質(zhì)的角度來定義的,它嘗試用一組助記詞來指示好代碼所具備的一組特質(zhì),并希望這組特質(zhì)是最重要的特質(zhì)。

CUPID所指出的方向與SOLID定義的原則并不沖突,只是角度不同,CUPID更多站在代碼的用戶--將來修改代碼的人--的視角來看待代碼,并指出了好的代碼應(yīng)該具備的特質(zhì)。從這個(gè)角度來講,CUPID比SOLID的適用性更廣(SOLID事實(shí)上只是針對(duì)面向?qū)ο笤O(shè)計(jì)提出的)。比如,給出一段代碼,用SOLID可能并不能判斷好壞,因?yàn)檫@段代碼可能根本不涉及SOLID中提到的幾個(gè)原則(比如函數(shù)式風(fēng)格的代碼)。但是很大可能可以從CUPID指明的幾個(gè)方向來得到一些結(jié)論。

CUPID是完備的嗎,很遺憾,也不是。但CUPID所指出的五種特質(zhì)可能是按照重要程度排序之后取前五的特質(zhì)。

理解CUPID

下面我們一起看看CUPID到底是什么,以及,如何用CUPID來幫助我們寫出好的代碼。

下面的內(nèi)容,部分來自Daniel老爺子的??原文??,部分結(jié)合了個(gè)人的心得體會(huì),分享給大家。

1.可組合特質(zhì)(C)

CUPID的第一個(gè)字母C是指Composable,即可組合特質(zhì)。

近兩年,我們?cè)谟懻撁嫦驅(qū)ο蟪绦蛟O(shè)計(jì)的時(shí)候,越來越關(guān)注到“組合優(yōu)于繼承”這樣的原則。作為面向?qū)ο蟪绦蛟O(shè)計(jì)的三大特征之一的“繼承”,似乎正越來越受到挑戰(zhàn),這一部分原因是很多繼承的設(shè)計(jì)是不合理的,比如不符合SOLID所指出的里氏代換原則。另一部分原因在于,過深的繼承樹帶來了代碼的可理解性問題,因?yàn)槲覀兛偸切枰斫饬嘶惒拍芾斫庾宇悺F鋵?shí)繼承也是很有用的,但其前提是設(shè)計(jì)合理的繼承?!敖M合優(yōu)于繼承”就是告訴我們優(yōu)先考慮用組合模式來進(jìn)行設(shè)計(jì)。

可組合還體現(xiàn)在以下三個(gè)方面:

(1) 精巧的接口

接口太多時(shí),讀者需要知道如何組合這些接口去完成某個(gè)功能,而接口較少時(shí),讀者可以更容易學(xué)習(xí)并更少犯錯(cuò)。只對(duì)外公開一個(gè)模塊來提供接口,比對(duì)外公開多個(gè)模塊提供接口更好。只對(duì)外公開一個(gè)類來提供接口,比對(duì)外公開多個(gè)類提供接口更好。

正確的接口粒度設(shè)計(jì)比較困難,最佳的粒度是接口既不顯得臃腫也不碎片化。

設(shè)計(jì)模式中有一種常見的模式Facade,即門面模式,其意圖正是將對(duì)外公開的接口放到一個(gè)類中去提供,以便減少接口面,從而讓接口更容易使用。

(2) 可體現(xiàn)意圖的代碼

可體現(xiàn)意圖的代碼是用業(yè)務(wù)語言編寫且能反映業(yè)務(wù)過程的代碼。可體現(xiàn)意圖的代碼可以使讀者更容易弄清為什么代碼要這么寫,因此更容易組合使用。代碼中的各類命名(比如變量、函數(shù)等)都可以用于將意圖體現(xiàn)得更為明顯。

比如以下意圖不明的代碼:

def getTodos(todos, users):
todos = [todo for todo in todo if not todo.completed and todo.type == ‘HOME’]
todos = [{‘title’: todo.title, ‘user_name’: users[todo.userId].name} for todo in todo]
todos.sort(key=lambda todo: todo[’user_name’])
return todos

可以重構(gòu)為以下意圖明確的代碼:

def get_todos(todos, users):
top_priority_todos = [todo for todo in todo if not todo.completed and todo.type == ‘HOME’]
todo_view_models = [{‘title’: todo.title, ‘user_name’: users[todo.userId].name} for todo in top_priority_todos]
todo_view_models.sort(key=lambda todo: todo[’user_name’])
return todo_view_models

或者:

def get_todos(todos, users):
is_top_priority = lambda todo: not todo.completed and todo.type == ‘HOME’
todos = [todo for todo in todo if is_top_priority(todo)]
to_view_model = lambda todo: {‘title’: todo.title, ‘user_name’: users[todo.userId].name}
todos = [to_view_model(todo) for todo in todo]
user_name = lambda todo: todo[’user_name’]
todos.sort(key=user_name)
return todos

(3) 最小依賴

擁有最小依賴的代碼是容易組合使用的。

當(dāng)一個(gè)庫有大量的依賴時(shí),一旦使用了這個(gè)庫就會(huì)間接引入這些依賴。這不僅使我們發(fā)布的二進(jìn)制制品變得臃腫,也很容易引起一些依賴庫的版本沖突問題。大家如果做過Hadoop的MapReduce任務(wù)開發(fā),應(yīng)該對(duì)這個(gè)問題深有體會(huì),因?yàn)镠adoop本身有大量的Java依賴,如果我們?cè)贛apReduce任務(wù)中不小心引入了一個(gè)和Hadoop本身的依賴不兼容的版本,在任務(wù)運(yùn)行時(shí)就會(huì)出錯(cuò)。

一個(gè)擁有最小依賴的庫是很容易使用的,上述包沖突問題會(huì)更少發(fā)生。

我常常在項(xiàng)目中見到有人為了實(shí)現(xiàn)一些很簡(jiǎn)單的功能而引入沒必要的依賴。比如,當(dāng)我們面對(duì)的問題只是簡(jiǎn)單的查詢ElasticSearch服務(wù)中的數(shù)據(jù)時(shí),就要評(píng)估一下是否有必要引入ElasticSearch的客戶端庫依賴,因?yàn)槲覀兛梢院苋菀椎氖褂猛ㄓ玫腍TTP工具庫來發(fā)送一個(gè)請(qǐng)求來實(shí)現(xiàn)數(shù)據(jù)查詢。

面向?qū)ο蟪绦蛟O(shè)計(jì)有一個(gè)重要的原則,即迪米特法則(Law of Demeter),又被稱為最小知識(shí)原則、不要和陌生人說話原則。其指導(dǎo)意義在于一個(gè)類不應(yīng)該和與其不相關(guān)的類產(chǎn)生(依賴)關(guān)系。

2.Unix哲學(xué)(U)

CUPID的第二個(gè)特質(zhì)U即是指Unix哲學(xué)。

Unix可以說是當(dāng)今應(yīng)用最廣泛的操作系統(tǒng),不管是云服務(wù)器還是個(gè)人電腦抑或智能手機(jī)、IoT設(shè)備,都有Unix的影子。Unix廣泛的以Linux、MacOS、iOS、Android等等操作系統(tǒng)的形式存在著。為什么Unix可以如此成功?這得益于Unix的簡(jiǎn)單而一致的設(shè)計(jì)哲學(xué)。

CUPID中的Unix哲學(xué)主要指其最重要的一個(gè)觀點(diǎn):一個(gè)程序應(yīng)該做一件事,并將其做好。Unix中的大量程序都很好的提現(xiàn)了這一特質(zhì),比如ls程序只做列舉文件的事,而要查看文件詳情,則需要使用lstat,查看文件內(nèi)容使用cat,搜索文件內(nèi)容使用grep等等。如果我們查看這些程序的使用手冊(cè)(Manual Page),將發(fā)現(xiàn)每一個(gè)程序都提供了很多的參數(shù)供選擇,事實(shí)上每個(gè)程序的功能都很強(qiáng)大,并處理了大量的異常情況。這就是把一件事做好的體現(xiàn)。

Unix操作系統(tǒng)中定義了一個(gè)強(qiáng)大的管道(Pipe)概念,一個(gè)程序的輸出可以通過管道傳輸給另一個(gè)程序,從而簡(jiǎn)單而一致的實(shí)現(xiàn)了多個(gè)程序的組合使用。比如ls命令可以列舉出文件列表,然后將結(jié)果傳輸給wc程序統(tǒng)計(jì)數(shù)量,就可以簡(jiǎn)單的計(jì)算出目錄中的文件數(shù)量。

只做好一件事與SOLID中的單一職責(zé)原則很像。但是Unix哲學(xué)的出發(fā)點(diǎn)是讀者,從讀者角度來看程序,得出程序應(yīng)該只做好一件事的結(jié)論。單一職責(zé)原則則是從代碼的角度出發(fā)進(jìn)行描述的。Unix哲學(xué)更多描述的是程序的目的,并指明一個(gè)程序應(yīng)該只有一個(gè)目的。

與Unix原則描述很相似的還有關(guān)注點(diǎn)分離的原則。關(guān)注點(diǎn)分離是指不同的模塊應(yīng)該關(guān)注不同的事情。比如分層設(shè)計(jì),每一層的關(guān)注點(diǎn)應(yīng)該不一樣:MVC中的M關(guān)注業(yè)務(wù)模型和業(yè)務(wù)邏輯,V關(guān)注展示,C關(guān)注交互邏輯;TCP/IP四層網(wǎng)絡(luò)模型中物理層關(guān)注物理鏈路,網(wǎng)絡(luò)層關(guān)心節(jié)點(diǎn)鏈路如何建立,傳輸層關(guān)注數(shù)據(jù)發(fā)送的可靠性,應(yīng)用層關(guān)注在具體的應(yīng)用協(xié)議。

3.可預(yù)測(cè)性(P)

CUPID的第三個(gè)特質(zhì)P是指Predictable,可預(yù)測(cè)性。

程序的可預(yù)測(cè)性是指它應(yīng)該做它看起來要做的事情,一致且可靠,不隱藏任何出乎意料的行為。

可預(yù)測(cè)性包括三個(gè)方面:1. 與期望一致的行為;2. 輸出確定的結(jié)果;3. 內(nèi)部行為可觀測(cè)。

(1) 與期望一致的行為

我們可以通過測(cè)試來定義所期望的程序的行為,但是并不是一定需要用測(cè)試來讓程序與期望的行為一致。精心的挑選名字,克制的編寫邏輯,正確的處理異常這些都能使得程序與期望的行為一致。

讀操作和寫操作常常被分開對(duì)待。讀操作不會(huì)對(duì)程序狀態(tài)產(chǎn)生影響,我們可以安全的調(diào)用,不用顧忌太多后果。寫操作用于修改程序狀態(tài),因此,在使用時(shí)需要特別小心,比如如果有多線程訪問就需要考慮線程安全,同時(shí)操作多個(gè)狀態(tài)就需要考慮事務(wù)一致性。

如何在讀操作和寫操作中保持與期望一致的行為?那就是讀操作中不應(yīng)該隱藏某些讓人意外的寫操作。

(2) 輸出確定性的結(jié)果

具備確定性的程序很容易讓人理解和使用,因?yàn)樗谌魏我淮握{(diào)用都會(huì)返回同樣的結(jié)果,我們可以明確的知道它將返回什么。

我們常說易于推理的代碼是好代碼,具備確定性的就具備易于推理的特性。

大概是由于Web前端技術(shù)的飛速發(fā)展,近些年函數(shù)式編程范式得到廣大開發(fā)者的親睞。函數(shù)式編程范式中最重要的一個(gè)概念就是純函數(shù)。純函數(shù)是指沒有任何副作用且可以輸出確定的結(jié)果的函數(shù)。

純函數(shù)是更容易測(cè)試的,我們對(duì)使用它的信心也更強(qiáng)。但是,在函數(shù)式編程范式中,對(duì)純函數(shù)的規(guī)范定義?顯得學(xué)院化,并加入了場(chǎng)景限定。事實(shí)上,我們主要需要的是程序的確定性。用面向?qū)ο蠓妒骄幊?,可以考慮把一個(gè)對(duì)象設(shè)計(jì)成值對(duì)象,這樣也可以增強(qiáng)程序的確定性。由于不確定性常常來自復(fù)雜且不確定的依賴(比如,某個(gè)依賴自己管理了復(fù)雜的狀態(tài),就也會(huì)間接的使你的代碼充滿不確定性),在設(shè)計(jì)類時(shí),嚴(yán)格控制其依賴的外部模塊,盡量做到無依賴,也可以增強(qiáng)程序的確定性。

具備確定性的代碼通常是健壯、可靠而具備彈性的。

(3) 內(nèi)部行為可觀測(cè)

如何預(yù)測(cè)程序的行為?觀察它的運(yùn)行時(shí)輸出是一個(gè)很好的方法。如果程序可以在運(yùn)行時(shí)打印關(guān)鍵的內(nèi)部狀態(tài)或行為就可以讓我們推測(cè)其當(dāng)前狀態(tài)。

觀察程序內(nèi)部狀態(tài)可以分為以下幾個(gè)級(jí)別:

  • 信息儀表(Instrumentation): 程序告訴我們它正在干什么
  • 遙測(cè)(Telemetry): 將程序告訴我們的信息以一種接口暴露出來,使其可以被遠(yuǎn)程訪問
  • 監(jiān)控(Monitoring): 將程序告訴我們的信息可視化出來
  • 告警(Alerting): 從監(jiān)控信息中識(shí)別異常,發(fā)出通知
  • 預(yù)測(cè)(Predicting): 利用監(jiān)控信息來預(yù)測(cè)即將發(fā)生的事件
  • 自適應(yīng)(Adapting): 通過告警的或者預(yù)測(cè)的信息動(dòng)態(tài)調(diào)整系統(tǒng)以適應(yīng)變化

有一些工具可以自動(dòng)提取程序運(yùn)行時(shí)信息供分析,但是最佳的提升程序的可觀測(cè)性的方式還是通過有意識(shí)的設(shè)計(jì)來在關(guān)鍵處輸出程序的狀態(tài)或行為。

4.符合慣例的(I)

CUPID的第四個(gè)特質(zhì)I是指Idiomatic,符合慣例的。

大家都有自己的編碼習(xí)慣,這些習(xí)慣包括空格和制表符的使用,變量命名規(guī)則,括號(hào)放置位置,代碼結(jié)構(gòu),提交的粒度和注釋等等。這些不一樣的習(xí)慣將顯著的增加不熟悉代碼庫的讀者的認(rèn)知負(fù)載。讀者不僅需要理解問題空間和解空間,還需要不斷進(jìn)行翻譯,以便識(shí)別當(dāng)前的代碼是有意編寫的,還是無意的,或者只是作者的習(xí)慣而已。

編寫代碼時(shí)的最偉大的特質(zhì)是同情心:對(duì)你的代碼的用戶的同情;對(duì)提供支持服務(wù)的同事的同情;對(duì)將來修改代碼的開發(fā)者的同情。事實(shí)上,他們中任意一個(gè)可能就是將來的你。編寫“人類可讀的代碼”意味著為別人編寫代碼。這正是“符合慣例”的意義。

編寫代碼時(shí),可以假定你的用戶具備以下背景:

  • 熟悉所使用的編程語言,及該語言對(duì)應(yīng)的庫、工具鏈和生態(tài)
  • 懂軟件開發(fā)的有經(jīng)驗(yàn)的開發(fā)者

還有一條,他們正努力的完成某件事情。

(1) 語言慣例

代碼應(yīng)該遵循編程語言的慣例。有些編程語言在代碼風(fēng)格上態(tài)度鮮明,我們會(huì)更容易判斷代碼是否符合語言慣例。另一些編程語言則可以兼容多種不同風(fēng)格,此時(shí)我們應(yīng)該選擇一種風(fēng)格,并始終堅(jiān)持它。

Python是一門在代碼風(fēng)格上態(tài)度鮮明的語言。當(dāng)我們?cè)赑ython的交互式命令行中輸入import this,或者運(yùn)行命令python -m this時(shí),就會(huì)發(fā)現(xiàn)輸出了Python所推薦的編程風(fēng)格。這些編程風(fēng)格組合成了”Python之禪”(The Zen of Python)。比如“應(yīng)該有一種顯然的實(shí)現(xiàn)方式,而且最好只有一種”(There should be one-- and preferably only one --obvious way to do it)。

Go語言內(nèi)置了一個(gè)代碼格式化工具gofmt,它會(huì)處理縮進(jìn)、括號(hào)位置等問題,可以使所有代碼變得風(fēng)格一致。除此之外,還有一篇專門說明Go語言風(fēng)格的文檔Effective Go來指導(dǎo)大家寫出風(fēng)格一致的代碼。

語言慣例出現(xiàn)在各個(gè)級(jí)別的代碼中,函數(shù)名、類型、參數(shù)、模塊、代碼組織結(jié)構(gòu)、模塊組織結(jié)構(gòu)、工具鏈選擇、依賴選擇、管理依賴的方式等。如果你的代碼符合這些語言慣例,將會(huì)讀起來更讓人愉悅。

如何讓代碼遵循這些語言慣例?可能沒有什么更好的辦法,只有讓自己多去學(xué)習(xí)這些慣例。

(2) 團(tuán)隊(duì)?wèi)T例

當(dāng)編程語言本身沒有風(fēng)格傾向,或者有多種風(fēng)格可選的時(shí)候,用什么風(fēng)格來寫代碼就由我們自己或者我們的團(tuán)隊(duì)來決定了。通常團(tuán)隊(duì)會(huì)自己定義一些慣例,比如用什么工具,如何縮進(jìn)等。借助各種語言的代碼檢查工具,可以自動(dòng)化的讓代碼保持一致的風(fēng)格。

對(duì)于某些無法用工具覆蓋的慣例,利用架構(gòu)設(shè)計(jì)決策記錄來文檔化這些慣例是一種好的實(shí)踐。這些慣例的重要性并不比其他的架構(gòu)設(shè)計(jì)決策更低。

5.基于領(lǐng)域的(D)

CUPID的最后一個(gè)特質(zhì)D是指Domain based,基于領(lǐng)域的。

近幾年,微服務(wù)的興起使得領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(Domain Driven Design, 簡(jiǎn)稱DDD)以新的面貌受到大家的廣泛關(guān)注。相對(duì)于其對(duì)于微服務(wù)設(shè)計(jì)的指導(dǎo)意義,DDD提出的以領(lǐng)域?yàn)橹行牡能浖_發(fā)思想或許具有更重大的意義。

(1) 基于領(lǐng)域的語言

由于代碼的讀者通常對(duì)問題是清楚的,所以,代碼應(yīng)該用問題空間的語言來寫,這樣就能讓代碼的讀者更容易的理解。問題空間語言即領(lǐng)域語言。

編程語言和庫里面充滿了計(jì)算機(jī)技術(shù)術(shù)語。比如常用的數(shù)據(jù)結(jié)構(gòu),如數(shù)組、鏈表、哈希表、樹結(jié)構(gòu)等。還比如數(shù)據(jù)庫表、網(wǎng)絡(luò)連接等。甚至基礎(chǔ)數(shù)據(jù)類型,如整型數(shù)值、浮點(diǎn)型數(shù)值、字符串等也都是技術(shù)術(shù)語。直接在代碼中使用這些術(shù)語不會(huì)告訴你的讀者你要解決什么問題,他們需要根據(jù)對(duì)問題的理解進(jìn)行翻譯。

TDD可以用于幫助我們更多的用領(lǐng)域語言編寫代碼。TDD要求在還沒有實(shí)現(xiàn)代碼的時(shí)候?qū)懗鰷y(cè)試代碼。如何做到呢?其實(shí),TDD是希望我們可以在看到問題后,先用自然語言描述測(cè)試過程,然后再將自然語言的測(cè)試過程翻譯為編程語言。由于描述測(cè)試過程時(shí),會(huì)站在用戶的角度進(jìn)行描述,所以將更多的使用領(lǐng)域語言。并且測(cè)試過程的描述將反映出程序應(yīng)該有的公開接口,所以接口也會(huì)變成用領(lǐng)域語言描述的接口,這就很大程度上促進(jìn)了用領(lǐng)域語言編寫代碼。

舉個(gè)例子,在電商場(chǎng)景中,如果要實(shí)現(xiàn)購物車的功能,則分析購物車的業(yè)務(wù)需求之后,可以將測(cè)試過程描述如下:

- 準(zhǔn)備一個(gè)空的購物車 - 向購物車添加商品1,數(shù)量1 - 向購物車添加商品2,數(shù)量2 - 購物車中應(yīng)該有兩種商品,其中有1個(gè)商品1及2個(gè)商品2 - 向購物車添加商品1,數(shù)量1 - 購物車中應(yīng)該有兩種商品,其中有2個(gè)商品1及2個(gè)商品2 - 從購物車取出商品1,數(shù)量2 - 購物車中應(yīng)該有一種商品,即2個(gè)商品2

翻譯為Java語言的測(cè)試代碼示例如下(部分):

...
void testCart() {
var cart = new Cart();
var product1 = new Product();
var product2 = new Product();

cart.add(product1, 1);
cart.add(product2, 2);

assertTrue(cart.contains(product1));
assertEquals(1, cart.productCount(product1));
assertTrue(cart.contains(product2));
assertEquals(2, cart.productCount(product2));

cart.add(product1, 1);
......
}
...

可以看到,通過編寫測(cè)試,我們用領(lǐng)域語言設(shè)計(jì)了Cart類,Product類,并且對(duì)Cart類設(shè)計(jì)了add contains productCount三個(gè)方法。除了促進(jìn)使用領(lǐng)域語言編寫代碼,TDD還可以讓我們提供的接口剛剛夠用,不多不少,從而實(shí)現(xiàn)可組合性特質(zhì)中的“精巧的接口”。

使用領(lǐng)域語言編寫代碼的最佳狀態(tài)是,我們的代碼可以讓沒有技術(shù)背景的業(yè)務(wù)人員也能輕松看懂,整個(gè)代碼讀起來就像業(yè)務(wù)分析師在講解業(yè)務(wù)邏輯一樣。

(2) 基于領(lǐng)域的結(jié)構(gòu)

除了使用領(lǐng)域語言編寫代碼,在模塊的設(shè)計(jì)、代碼目錄結(jié)構(gòu)(或包結(jié)構(gòu))也應(yīng)該優(yōu)先使用領(lǐng)域語言命名。

很多使用Spring框架的Java程序員有個(gè)偏好,他們按照框架提供的概念來組織代碼,并且將不同的文件按照框架概念進(jìn)行分類存放。一個(gè)可能的結(jié)構(gòu)可能是:

app
|----controllers
|----assets
|----models
|----events
|----repositories
|----requests
|----responses
|----dtos
|----configurations
......

這帶來的問題是,當(dāng)要修改一個(gè)API時(shí),不得不在多個(gè)目錄中去查找和修改代碼。這不僅增加了認(rèn)知負(fù)載,使代碼耦合在一起,還增加了修改代碼的負(fù)擔(dān)。

使用基于領(lǐng)域的結(jié)構(gòu),建議盡量將目錄按照領(lǐng)域進(jìn)行劃分,而不是框架概念。比如,如果是一個(gè)電商的場(chǎng)景,目錄結(jié)構(gòu)應(yīng)該是user product order payment shipment等。

當(dāng)前一個(gè)流行的架構(gòu)模式是分層架構(gòu),如果按照分層架構(gòu)進(jìn)行設(shè)計(jì),則頂層目錄可以是不同的分層名稱,分層以下,就應(yīng)該是由領(lǐng)域概念組成的目錄。并且分層之間應(yīng)該有嚴(yán)格的依賴順序,不應(yīng)產(chǎn)生兩個(gè)分層循環(huán)依賴的情況。雖然看起來這是一個(gè)例外,但是這種拆分是有缺陷的。近兩年微服務(wù)架構(gòu)非常流行,而微服務(wù)的拆分是按照業(yè)務(wù)領(lǐng)域進(jìn)行拆分的,這可以理解為微服務(wù)是整體產(chǎn)品這個(gè)根目錄下的基于領(lǐng)域的子目錄。這個(gè)現(xiàn)象可以理解為大家對(duì)于分層架構(gòu)的目錄劃分并不滿意,還是希望在更上層基于領(lǐng)域來劃分目錄。

(3) 基于領(lǐng)域的邊界

無論我們?nèi)绾谓M織代碼結(jié)構(gòu),目錄(或模塊)的邊界變成了事實(shí)上的領(lǐng)域邊界。一打開代碼庫就能看到目錄結(jié)構(gòu),目錄的層級(jí)和名字逐漸變成了大家最熟系的信息。所以,在設(shè)計(jì)上,一個(gè)重要的原則就是將領(lǐng)域劃分和目錄劃分保持一致。這將有效降低團(tuán)隊(duì)的認(rèn)知負(fù)載,開發(fā)者將因此而更不容易犯錯(cuò),團(tuán)隊(duì)效率最終將得到提高。

這并不意味著需要組織成一個(gè)平坦(flat)的目錄結(jié)構(gòu)。領(lǐng)域以下可以有子領(lǐng)域,目錄以下可以有子目錄,模塊以下可以有子模塊。重要的是這一個(gè)一個(gè)層級(jí)需要能對(duì)應(yīng)上。

總結(jié)

到這里,我們應(yīng)該了解了CUPID所指出的五種特質(zhì)的內(nèi)涵。可以明顯的看到,相比不符合CUPID特性的代碼,符合CUPID的代碼可以讓人更加愉悅地進(jìn)行閱讀和修改。事實(shí)上,CUPID中的五個(gè)特質(zhì)并不是相互獨(dú)立的,它們常??梢曰ハ啻龠M(jìn)。

可組合并符合Unix風(fēng)格的代碼(做一件事,并把它做好)讓人感覺就像是一個(gè)可靠的老朋友。符合慣例的代碼讓從未看過此代碼的人也覺得非常熟悉??深A(yù)測(cè)的代碼將我們從一系列“驚喜”中解脫出來?;陬I(lǐng)域的代碼減少了從需求到方案之間的認(rèn)知距離。

在每次修改代碼時(shí),如果每個(gè)人都能將代碼向這幾個(gè)方向所指向的中心點(diǎn)靠近一點(diǎn),那就可以讓代碼越來越好。

責(zé)任編輯:趙寧寧 來源: Thoughtworks洞見
相關(guān)推薦

2012-06-07 10:10:15

存儲(chǔ)虛擬化

2016-12-01 15:04:39

2023-10-16 11:27:10

項(xiàng)目管理項(xiàng)目經(jīng)理

2011-08-01 10:17:43

存儲(chǔ)虛擬化

2012-08-07 09:34:26

虛擬化

2020-01-06 22:54:31

IOT大數(shù)據(jù)物聯(lián)網(wǎng)

2022-10-10 16:05:58

CIO數(shù)字化領(lǐng)導(dǎo)者首席分析師

2013-04-18 14:54:08

Linux監(jiān)控腳本Linux監(jiān)控

2015-04-15 15:01:56

代碼好代碼科學(xué)定義

2022-08-16 10:16:53

CIOIT領(lǐng)導(dǎo)者

2022-08-25 10:37:00

CIOIT領(lǐng)導(dǎo)者

2024-08-06 12:35:42

C#代碼重構(gòu)

2023-07-27 08:00:00

代碼補(bǔ)全服務(wù)人工智能

2010-09-01 11:08:09

CSS

2019-11-22 09:30:59

設(shè)計(jì)Java程序員

2022-03-29 10:03:12

IT領(lǐng)導(dǎo)者首席信息官

2023-10-10 10:57:12

JavaScript代碼優(yōu)化

2024-11-27 10:28:22

Rust繼承識(shí)別

2015-06-25 13:36:56

好代碼科學(xué)定義

2010-01-07 10:05:51

IT顧問特質(zhì)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)