

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、代碼質(zhì)量隨想錄(四):排版,不只是為了漂亮作者:愛飛翔 發(fā)布時(shí)間:2012-06-15 21:18針對(duì)排版這個(gè)問(wèn)題,不同的公司、團(tuán)隊(duì)都有自己的一套方案,有時(shí)網(wǎng)絡(luò)上也能下載到很多 大型的權(quán)威代碼規(guī)范,其中亦含有程序排版相關(guān)的規(guī)則,我也經(jīng)常與眾友人一起討論某個(gè)項(xiàng)目 所用的排版約定。在看到The Art of Readable Code 一書中有關(guān)此話題的章節(jié)時(shí),我的感覺是,很難總結(jié)出一套萬(wàn)用的宇宙排版律”來(lái),多半要根據(jù)自身環(huán)境、團(tuán)隊(duì)和項(xiàng)目的特點(diǎn)來(lái)擬定,所給出的建議僅僅是參考,并不能強(qiáng)行照搬。1.功能相似的代碼,版式也應(yīng)相似public classPerformanceTester public s
2、tatic final TcpConnectionSimulator wifi =new TcpConnectionSimulator(500 /*以 Kbps 計(jì)量的吞吐量*/,80 /*以毫秒計(jì)的網(wǎng)絡(luò)延遲 */,200 /*包抖動(dòng)*/,1 /*丟包百分比*/;public static final TcpConnectionSimulator t3Fiber =new TcpConnectionSimulator(45000 /*以 Kbps 計(jì)量的吞吐量*/,10 /*以毫秒計(jì)的網(wǎng)絡(luò)延遲 */,0 /*包抖動(dòng)*/,0 /*丟包百分比*/;public static final TcpCo
3、nnectionSimulator cell =new TcpConnectionSimulator100 /*以 Kbps 計(jì)量的吞吐量*/,400 /*以毫秒計(jì)的網(wǎng)絡(luò)延遲 */,250 /*包抖動(dòng)*/,5 /*丟包百分比*/;上面這個(gè)例子是 ARC 書中所舉的,我認(rèn)為很恰當(dāng)。該類的三個(gè)靜態(tài)字段功能類似,都指 代某種環(huán)境下的網(wǎng)絡(luò)模擬器,所以排版也應(yīng)該相似。每行都只寫一個(gè)實(shí)參,而且后面用行內(nèi)注 釋的形式解釋該實(shí)參的意思。在垂直方向上的對(duì)齊做得也很好:字段申明前面空2 格,實(shí)例化語(yǔ)句前面空 4 格,各實(shí)參前面空6 格(以上數(shù)字非實(shí)指,僅是舉例而已)。這樣要修改某個(gè)參數(shù),很快就能定位到它,而且以后
4、如果增加類似的字段,如badWIFI ,也可以比照這個(gè)格式來(lái),便于維護(hù)。由以上范例還可引出一個(gè)問(wèn)題,那就是在實(shí)例化或方法調(diào)用中,經(jīng)常會(huì)遇到一些孤立的魔 法數(shù)字(magic number ),如果確有必要為它起名,那么不妨執(zhí)行一個(gè)小的重構(gòu),以常量 來(lái)代替它。反之,如果是大段的硬數(shù)值,則不一定非要為每個(gè)值都起一個(gè)名字,例如:TcpConnectionSimulator wifi =newTcpConnectionSimulator(WIFI_KBPS_THROUGHPUT,WIFI_LATENCY,WIFI_JITTER,WIFI_PACKET_LOSS_PERCENT;這樣反而顯得累贅。不妨像上
5、例那樣采用行內(nèi)注釋的辦法來(lái)解釋這些硬值的意思。承上,ARC 的作者又推導(dǎo)出一條建議,就是將相似的方法調(diào)用參數(shù)注釋提取到一處,例 如:public classPerformanceTester / TcpConnectionSimulator(throughput, latency, jitter, packet_loss/ Kbps ms ms percentpublic static finalTcpConnectionSimulator wifi =new TcpConnectionSimulator(500, 80, 200, 1 ;public static final TcpConn
6、ectionSimulator t3Fiber =new TcpConnectionSimulator(45000, 10, 0, 0 ;public static final TcpConnectionSimulator cell =new TcpConnectionSimulator(100, 400, 250, 5 ;說(shuō)實(shí)在的,以前在工作中還沒(méi)太重視這個(gè)問(wèn)題,一來(lái)是覺得我在寫Javadoc 時(shí)一貫非常完備,出現(xiàn)這種情況時(shí)只需靠鼠標(biāo)懸停就可知道某個(gè)方法或構(gòu)造器的具體信息了;二來(lái)嘛,也 是想著如果使用大量數(shù)值的調(diào)用代碼多到無(wú)法管控,我可能會(huì)祭出配置文件這個(gè)大旗來(lái),將它 們?nèi)考{入配置中了事。
7、所以關(guān)于以上例子中談到的這些問(wèn)題,我覺得還是根據(jù)大家的具體實(shí) 踐來(lái)理解為好,不要機(jī)械地尋求一致。2.將大量相似的嵌套式、接續(xù)式調(diào)用邏輯整合到共用方法之中,即利于排版,又可凸顯 重要數(shù)據(jù)在測(cè)試用例等代碼中,經(jīng)常會(huì)出現(xiàn)類似下面這種狀況:/某受測(cè)類中:/ 將類似Doug Adams這樣的不完整稱呼進(jìn)行補(bǔ)全,擴(kuò)展為Mr. Douglas Adams的形式。/如若不能(查不到數(shù)據(jù)或無(wú)法補(bǔ)完),則于 error 參數(shù)中填充錯(cuò)誤信息并返回空串。/此方法會(huì)置空錯(cuò)誤信息接收參數(shù)。public String expandToFullName(DatabaseConnection conn,String parti
8、alName,ErrorMessageReceiver error./某測(cè)試方法中:DatabaseConnection connection.;ErrorMessageReceiver error=;assertEquals(expandToFullName(connection, Doug Adams ,error ,Mr. Douglas Adams;assertEquals(error.getMessage(,;assertEquals(expandToFullName(connection, Jake Brown ,error ,Mr. Jacob Brown III;assertE
9、quals(error.getMessage(,;assertEquals(expandToFullName(connection, No Such Guy “ ,error ,Illi .assertEquals(error.getMessage( ,no match found;assertEquals(expandToFullName(connection, John “, error ,Illi .assertEquals(error.getMessage( ,more than one result;這符合上面所說(shuō)的量大” 形似”嵌套”等特征,而且諸如輸入字串、預(yù)期結(jié)果、預(yù)期錯(cuò)誤消息
10、等重要的數(shù)據(jù),被埋沒(méi)于conn ection、error、getMessage(等技術(shù)細(xì)節(jié)之中。所以可以借由美化版式之機(jī)進(jìn)行重構(gòu):checkPartialToFull(Doug Adams , Mr. Douglas Adams,;checkPartialToFull( Jake Brown , Mr. Jake Brown III,;checkPartialToFull( No Such Guy, , no match found;checkPartialToFull( John , , more than one result;private void checkPartialToFull
11、(String partialName,String expectedFullName,String expectedErrorMessage / connection 已被提取為測(cè)試固件類的成員變量ErrorMessageReceiver error=;String actualFullName = expandToFullName(connection, partialName, error;assertEquals(expectedErrorMessage, error.getMessage(;assertEquals(expectedFullName , actualFullName;
12、如此一來(lái)一舉三得:既消除了重復(fù)代碼,同時(shí)美化了版式,凸顯了輸入字串、預(yù)期結(jié)果、 預(yù)期錯(cuò)誤消息等重要數(shù)據(jù),順帶著還方便了后續(xù)測(cè)試數(shù)據(jù)的維護(hù)。這種藉由版式整理帶來(lái)的重 構(gòu),我看可以有!3.明智地使用縱向?qū)R來(lái)減少拼寫錯(cuò)誤、厘清大量同組數(shù)據(jù)。我覺得這一條和第 1 條有重復(fù),其實(shí)也屬于類似功能的代碼應(yīng)具類似版式之意,不過(guò)既然 ARC作者將它單列,我想可能是為了強(qiáng)調(diào)縱向?qū)R的好處吧。/將 POST 參數(shù)中的屬性分別提取至各個(gè)局部變量中ServletRequest requests.;String details = request.getParameter(details;String location
13、 = request.getParameter(location;String hone = request.getParameter(phon;String email = request.getParameter(email;String url = request.getParameter(url;經(jīng)由縱向?qū)R,很容易看出第三個(gè)局部變量這行的錯(cuò)誤:將變量名“phone”誤寫為“ hon e,參數(shù)名的“pho ne 則錯(cuò)成了 ” phon。“另外,在進(jìn)行結(jié)構(gòu)體數(shù)據(jù)、數(shù)組成員等這種同組數(shù)據(jù)排列時(shí),也可以充分利用版式來(lái)厘清 每個(gè)元素的意義。ARC 的作者就大贊 wget 這個(gè)命令行工具在指定參
14、數(shù)結(jié)構(gòu)體時(shí),代碼排列 地很工整。/非原文,小翔以 Java 形式改寫Object commands = /參數(shù)名,默認(rèn)值,類型 timeout,null, TIMEOUT , timestamping , defOpt.timestamp, BOOLEAN , tries, defOpt.tryCount, NUMBER , useproxy, defOpt.useProxy, BOOLEAN , useragent,null, USER_AGENT ;這一條建議如果與第 1 條合并起來(lái)說(shuō),那就是:任務(wù)相似的代碼塊應(yīng)該具有相似的輪廓 (ARC 的作者叫它 silhouette ),如行數(shù)、縮進(jìn)
15、、縱向?qū)R等。4.使用適當(dāng)空行與注釋,將代碼按功能分段有時(shí)候經(jīng)常在考慮代碼與散文或詩(shī)的聯(lián)系,如果從隱喻(metaphor)的觀點(diǎn)來(lái)看,的確有相似性:都是信息的載體,都可以用一定的段落來(lái)整合文意。要說(shuō)區(qū)別嘛,前者服務(wù)于軟件需求,后者服 務(wù)于社會(huì)關(guān)系。前者為了向更低階的執(zhí)行機(jī)制去接合,所以更加注重語(yǔ)法格式。我可不是第一個(gè)進(jìn)行 這種思維比擬的人,記得臺(tái)灣的技術(shù)暢銷書作者侯捷先生(侯俊杰)就曾寫過(guò)一本左手程序右手詩(shī)的書。class FrontendServer public :Fronten dServer(;void ViewProfile(HttpRequest*request;void Open
16、Database(string location, string user;void SaveProfile(HttpRequest*request;string ExtractQueryParam(HttpRequest* request, string param;void ReplyOK(HttpRequest* request, string html;void FindFriends(HttpRequest*request;void ReplyNotFound(HttpRequest*request, string error;void CloseDatabase(string lo
17、cation; FrontendServer(;上面的代碼挺蝸居的,如果加上適當(dāng)?shù)目招信c說(shuō)明,就顯得清晰多了。class FrontendServer public :Fronten dServer(; FrontendServer(;/與用戶配置相關(guān)的處理函數(shù)void ViewProfile(HttpRequest*request;void SaveProfile(HttpRequest* request;void FindFriends(HttpRequest* request;/回覆及應(yīng)答工具函數(shù)string ExtractQueryParam(HttpRequest* request,
18、 string param;void ReplyOK(HttpRequest* request, string html;void ReplyNotFound(HttpRequest* request, string error;/數(shù)據(jù)庫(kù)操作工具函數(shù)void OpenDatabase(string location, string user;void CloseDatabase(string location;上述類將聲明區(qū)按照構(gòu)建子/析構(gòu)子、社交功能函數(shù)、工具函數(shù)這個(gè)標(biāo)準(zhǔn)劃分為的三大思維區(qū)段,工具函數(shù)區(qū)又按題材劃分為消息操作與數(shù)據(jù)庫(kù)操作兩小段。這樣一來(lái),以后再要維護(hù) 這份聲明代碼就會(huì)很清爽了
19、。同理,如果聲明一個(gè)集合類的接口,也應(yīng)該按照增、刪、改、查”等概念來(lái)將 API 劃分為若干小組,以便幫助代碼閱讀者理順?biāo)悸贰>退闶窃诹魉降臉I(yè)務(wù)代碼中,也可以用段落來(lái)襯托出邏輯的起、承、轉(zhuǎn)、合”。/導(dǎo)入用戶電子郵件賬戶中聯(lián)系人,同本產(chǎn)品中已有的聯(lián)系人相比對(duì)。/然后展示正在使用本產(chǎn)品但未與用戶建立朋友關(guān)系的聯(lián)絡(luò)人列表。public ListDataModel suggestNewFriends(User user,Password emailPasswordSocialCircle friends = user.friends(;Emails friendEmails = friend.dump
20、AIIEmails(;Contacts contacts = importContacts(user.email, emailPassword;Emails contactEmails = contacts.extractAIIEmails(;Emails productUserEmails = UserDataCenter.selectEmails(contactEmails;Emails suggestedFriends = productUserEmails.subtract(friendEmails;ListDataModel displayModel = new ListDataMo
21、del(user,friends,suggestedFriends;return displayModel;上面的代碼給人的壓迫感很強(qiáng)列,沒(méi)有思維喘息的機(jī)會(huì)。不如把注釋拆解,按其邏輯將代 碼分成小段,為每一段冠以簡(jiǎn)短標(biāo)題。public ListDataModel suggestNewFriends(User user,Password emailPassword/取得當(dāng)前用戶全部朋友的郵件地址SocialCircle friends = user.friends(;Emails friendEmails = friend.dumpAIIEmails(;/引入當(dāng)前用戶電子郵件賬戶中的聯(lián)系人Con
22、tacts contacts = importContacts(user.emaiI, emailPassword;Emails contactEmails = contacts.extractAIIEmaiIs(;/找出正在使用本產(chǎn)品但尚未與本用戶建立朋友關(guān)系的聯(lián)系人Emails productUserEmails = UserDataCenter.selectEmails(contactEmails;Emails suggestedFriends = productUserEmails.subtract(friendEmails;/返回待顯示列表的數(shù)據(jù)模型ListDataModel dis
23、playModel = new ListDataModel(user,friends,suggestedFriends;return displayModel;欣賞一下上面這段代碼吧,每小段以一句概括性的注釋引領(lǐng),然后是兩句實(shí)現(xiàn)代碼,排列 得非常整齊,代碼的閱讀者根據(jù)此的版式,很容易就能抓住代碼的思維走向:“2(獲取朋友列表)-2 (獲取聯(lián)系人郵箱)-2 (找出潛在友人)-2 (返回?cái)?shù)據(jù)模型)”。怎么樣,是不是有點(diǎn) 兒起、承、轉(zhuǎn)、合”的意思了?(大誤)由上例可見,適當(dāng)?shù)剡M(jìn)行代碼分段并通過(guò)注釋來(lái)充當(dāng)代碼段的概括語(yǔ),有助于梳理代碼閱 讀者的思路,也有助于代碼修改、維護(hù)和后續(xù)查錯(cuò)。比如想做一個(gè)向未使
24、用本社交網(wǎng)站的電郵聯(lián)絡(luò)人發(fā)送邀請(qǐng)”的功能,掃一眼上述這段清晰排版的代碼,大家立刻就能看出,只需要寫 好測(cè)試用例,復(fù)制一份suggestNewFriends 的代碼,把 selectEmails 改成excludeEmails,就能找到這些潛在的被邀請(qǐng)人了。給新的方法起個(gè)名字,叫in viteC on tacts ,刪去多余的程序,然后通過(guò)重構(gòu)提取一下共用代碼,再確保測(cè)試無(wú)誤,就可以收工了。思路順了,編碼的過(guò)程自然也就更加流暢了。好了,小小總結(jié)一下吧。其實(shí)代碼排版這種略帶個(gè)人化的東西,不僅僅是讓代碼看起來(lái)更 漂亮,其根本目的還是著眼于代碼的可讀性,要有助于代碼的理解、維護(hù)、糾錯(cuò)。具體到執(zhí)行 層面
25、,除了可以參考上述 4 條建議外,還要注意兩方面的問(wèn)題。第一個(gè)問(wèn)題,ARC 的作者也提到了,那就是很多朋友對(duì)代碼排版有排斥心理,不愿意認(rèn) 真排版。有一部分原因是怕浪費(fèi)時(shí)間,還有就是擔(dān)心代碼管理系統(tǒng)會(huì)將排版后的代碼與排版之 前的代碼判定為兩份截然不同的程序,在版本比對(duì)時(shí)導(dǎo)致滿屏的diff,非常難看。其實(shí),在現(xiàn)有的成熟 IDE 之中(抑或各位 Geek 們慣用的文本編輯器之中)已經(jīng)有非常完備的功能來(lái)支 援代碼版式的調(diào)整了。比如Eclipse、Netbeans等開發(fā)環(huán)境,都可以把版式定義文件導(dǎo)出為xml 等數(shù)據(jù)格式,到了陌生的環(huán)境時(shí),只需導(dǎo)入即可。而且代碼排版一旦確定,就可以一次性 地更改所有項(xiàng)目源
26、碼的版式然后提交,這樣就可以避免在版本比對(duì)時(shí)顯示過(guò)多的修改提示了。第二個(gè)問(wèn)題就是應(yīng)該在必要的范圍內(nèi)保持代碼排版的一致性。雖然我剛也說(shuō)了,代碼排版沒(méi)有絕對(duì)的真理,不過(guò),它卻應(yīng)該有一個(gè)相對(duì)的底線。在公司與公司之間、團(tuán)隊(duì)與團(tuán)隊(duì)之間,的確 沒(méi)有必要強(qiáng)行要求一致的版式。例如我們不宜妄自菲薄,說(shuō)I 記或 G 社的代碼排得如何如何漂亮,同時(shí)也不能過(guò)分地自高自大,說(shuō)自己團(tuán)隊(duì)的版式是天下最美觀、最養(yǎng)眼的。但是,如果 具體到某個(gè)項(xiàng)目,尤其是中小型項(xiàng)目里面,那么就要想方設(shè)法達(dá)成一致的版式規(guī)范了,否則將 會(huì)給代碼的閱讀、理解與維護(hù)造成不必要的障礙。為此,項(xiàng)目組的成員應(yīng)該富有的妥協(xié)精神,在堅(jiān)持個(gè)人風(fēng)格這個(gè)問(wèn)題上稍作讓步
27、,以求達(dá)成大家對(duì)代碼版式的共識(shí)。比如,小翔在個(gè)人項(xiàng)目或由我?guī)ш?duì)的項(xiàng)目中,通常使用以下版式:public class MyArrayList extends MyAbstractList implementsMyCollection/靜態(tài)部分在前:/靜態(tài)內(nèi)部類型區(qū)。同區(qū)成員按存取級(jí)別排序,高者在前。/* *列表容量參數(shù)。*/public static classCapacityOptions/* 初始容量。*/private final intinitialElementCount;/*擴(kuò)容時(shí)新增的容量與擴(kuò)容前容量之比。*/private final intexpandRatio;/靜態(tài)初始化塊與靜態(tài)字段區(qū)。private static final Map commonCapacityOptions=.staticcom mon CapacityOpti ons.put(normal,new CapacityOptions(12,1;/靜態(tài)方法區(qū)。/*從既有數(shù)組中構(gòu)建列表。* param elements 用以構(gòu)建的數(shù)組,不能為 null* return 構(gòu)建好的列表*/public staticList create(Object elements/動(dòng)態(tài)部分在后:/動(dòng)態(tài)內(nèi)部類型區(qū)。public classMylterator
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫(yī)藥咨詢采購(gòu)合同范本
- 倉(cāng)儲(chǔ)貨架合同范本
- 勞動(dòng)合同范本醫(yī)療
- 會(huì)計(jì)臨聘用合同范本
- 展廳工程合同范本
- 出貨協(xié)議合同范本
- 義賣贊助合同范本
- 北京和杭州租房合同范本
- 勞務(wù)用工勞務(wù)合同范本
- 出售高端養(yǎng)老房合同范例
- 電子商務(wù)數(shù)據(jù)分析基礎(chǔ)(第二版) 課件 模塊1、2 電子商務(wù)數(shù)據(jù)分析概述、基礎(chǔ)數(shù)據(jù)采集
- YB-T+4190-2018工程用機(jī)編鋼絲網(wǎng)及組合體
- 高大模板安全施工施工安全保證措施
- 比亞迪公司應(yīng)收賬款管理的問(wèn)題及對(duì)策分析
- 【高考真題】2024年新課標(biāo)全國(guó)Ⅱ卷高考語(yǔ)文真題試卷(含答案)
- 委托辦理報(bào)廢汽車協(xié)議書
- 旅游服務(wù)質(zhì)量評(píng)價(jià)體系
- 義烏市建筑工程質(zhì)量通病防治措施100條(2022版本)
- 蘇教版(SJ)《四年級(jí)下冊(cè)數(shù)學(xué)》補(bǔ)充習(xí)題
- 體育足球籃球排球體操教案
- 統(tǒng)編版高中政治必修3必背主觀題
評(píng)論
0/150
提交評(píng)論