您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“如何寫出可讀性高的代碼”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
代碼的寫法有很多種:有的運行起來很快,有的只會占用少量內(nèi)存,有的更容易測試,而有的代碼則有很高的可讀性。
若要編寫思路清晰的代碼,第一步就是要將可讀性放在第一位。
這也意味著勢必要降低其他因素的優(yōu)先級。如果把所有因素都作為最高優(yōu)先級,就意味著沒有優(yōu)先級。
想要寫出好代碼,首先要知道什么才是好代碼,想要寫出思路清晰的代碼,也要了解什么才是思路清晰。多閱讀一些質(zhì)量上乘的代碼可以讓我們對好代碼有個大概的認(rèn)知。
了解什么才是優(yōu)秀代碼并不能杜絕我們繼續(xù)寫出糟糕的代碼,但至少能讓我們知道代碼的哪里不對勁。
編寫代碼時,我們最初所想的思路未必清晰。在大多數(shù)情況下,只有在第一次完成代碼后,我們才能找到更適合的思路。反復(fù)閱讀已完成的代碼才會帶來更改的空間。
如果我們還搞不清代碼結(jié)構(gòu),那么可以試著想象一下怎樣向他人解釋清楚或者把邏輯思路寫下來,比如“如果刪除賬戶,那么我們需要跳過 xxx。如果 xxx 的進(jìn)程還沒有結(jié)束,那么……”。然后把這套邏輯翻譯成代碼就很順了。
寫程序時,帶入人類溝通方式而不是計算機中的抽象概念要更容易。
代碼中的注釋可以解釋某段代碼的用處,或者是程序結(jié)構(gòu)為什么要這么寫。
單單是閱讀程序并不會告訴我們作者所想就是正確的邏輯。里面可能會有我們不了解的商業(yè)規(guī)則:美國境外的用戶有時會把街道名寫到地址欄第一行的最末尾。里面也可能有一些技術(shù)小技巧:以某種奇怪的方式構(gòu)造查詢,從而讓 Postgres 正確地優(yōu)化它。諸如此類的代碼細(xì)節(jié),都是只有了解邏輯背后的背景情況下才能徹底明白為什么要這么寫的。
代碼不會說話。如果我們決定跳過某些步驟,但又懶得留下注釋解釋為什么,過兩天再回來看這段代碼恐怕就真沒人知道你當(dāng)時在想什么了。
部分代碼可能讀兩遍就能想明白個中緣由,但為了保險起見,還是不要給自己的大腦添加不必要的負(fù)擔(dān)。
不要搞混函數(shù)中的抽象層次。
這段“歡迎”代碼層次混亂:
def welcome(self): results = db.query( 'SELECT EXISTS 1 FROM emails WHERE kind = ? AND user = ?', 'welcome_email', self.user.id, ) if results[0]: return self.send_welcome_email()
這段則是相對整齊的:
def welcome(self): if not self.has_sent_welcome_email(): self.send_welcome_email()
函數(shù)中混亂的抽象層次會讓讀者思考代碼用途和實現(xiàn)方式時被迫進(jìn)行思維跳躍。當(dāng)前抽象層次的代碼告訴我們代碼在做什么,而下一層次的代碼則是關(guān)于代碼要如何實現(xiàn)的。
在例子里的“welcome”函數(shù)中,我們首先在數(shù)據(jù)庫中查詢是否有過往郵件記錄,如果沒有則發(fā)送一封歡迎郵件。請注意,第二個版本中的“welcome”函數(shù)將查詢部分放到了另一個函數(shù)中,“welcome”中僅僅關(guān)注“做什么”,這就是將函數(shù)中的抽象層次保持在了同一層,邏輯也更加清晰。不同函數(shù)分散在不同抽象層次,將較低層次的實現(xiàn)細(xì)節(jié)委托給較低抽象層次的函數(shù)。
有時,分解大體積函數(shù)到子函數(shù)會更便于閱讀。
對于分步驟執(zhí)行的函數(shù),將函數(shù)中的每個步驟都分解成子函數(shù)效果會更好。而對于其他如決策類的函數(shù),不同的決策會引向不同的函數(shù):有的部分負(fù)責(zé)制定決策,有的則是負(fù)責(zé)執(zhí)行決策。分解函數(shù)的方法有很多種維度,只有通過不斷的練習(xí)才能一眼看穿哪種才是正確的。
小體積函數(shù)有以下幾點好處:
每一部分的邏輯都有自己函數(shù)名。知道每一塊邏輯負(fù)責(zé)什么更方便我們找到這些函數(shù)應(yīng)當(dāng)被放在哪
作用域中變量更少
在運行堆棧軌跡和調(diào)試時能更清晰地看出函數(shù)的作用
小型函數(shù)可以被單獨測試
其實,沒有任何函數(shù)計算機也能運行得好好的,函數(shù)的存在只是為了服務(wù)于程序員,所以還請多多利用它們。
不要重復(fù)你自己(don't repeat yourself, DRY)的意思經(jīng)常被過度解讀。
如今,抽取魔法數(shù)常量,以及針對某類特定決策的邏輯副本,已經(jīng)算是公認(rèn)的標(biāo)準(zhǔn)答案。此類重復(fù)的代碼的確不好。而 DRY 的過度解讀是指面對區(qū)區(qū)兩行的重復(fù)代碼,便如臨大敵恨不得除之而后快。完全避免任何的重復(fù)代碼意味著我們最后將面對一堆毫無意義、令人迷惑的代碼,其存在只為了防止程序中的兩三行重復(fù)代碼。再加上由于在邏輯上毫不相干的兩段代碼被迫捆綁在一起,代碼也更加難以修改。
判斷一段代碼的重復(fù)是否可容忍很簡單:修改 A 段代碼,保留 B 段不變,如果程序報錯,那么就把 A 和 B 整理到同一段代碼;如果無事發(fā)生,那么就放著別管。DRY 并不代表我們需要手動壓縮代碼庫,而是為了避免兩段代碼要依賴于手動的同步。請記住,重復(fù)代碼和抽象創(chuàng)造并不是同一件事。
寧可要十個零參數(shù)的小函數(shù),也不要一個帶十個參數(shù)的函數(shù)。
諸位對類似的事一定不陌生:初始干凈的函數(shù),只在三個不同的地方被調(diào)用。而當(dāng)我們想要在第四處調(diào)用時,我們需要做一點小的調(diào)整,添加一個參數(shù)。但這樣第一個 caller 就多了一個新功能,也需要多添加兩個可配置的參數(shù)。等到第五個用例,我們還要再為它添加獨特的參數(shù),以此類推。但反過來我們就又會發(fā)現(xiàn)第二個 caller 跑起來太慢了,所以只好再添加另一個參數(shù)來跳過部分繁瑣的程序。
不知不覺中,我們那個干凈整潔的、只負(fù)責(zé)一件事的函數(shù)現(xiàn)在有了五個配置參數(shù),現(xiàn)在能做的事情甚至可以達(dá)到 2 的五次方種!
這種情況下,將這一整個復(fù)雜的函數(shù)拆分成子函數(shù),每個函數(shù)只負(fù)責(zé)各自的事就會好上很多。
但這樣以來,又不可避免會出現(xiàn)重復(fù)。當(dāng)這些重復(fù)的部分需要保持同步時,我們可以利用 DRY 的思路,將相同的部分抽取到子函數(shù)中。這時,做決策和考慮步驟就會容易很多。
請記住,區(qū)區(qū)幾行重復(fù)代碼是沒問題的!像是在不同 list 上跑 for 循環(huán)的代碼,這類就是可以接受的重復(fù)。
這種方法的好處之一是當(dāng)其中一個用例被刪除時,你可以輕松刪除掉對應(yīng)的函數(shù),而不是在復(fù)雜函數(shù)的邏輯里掘地三尺試圖找到對應(yīng)的選項。只關(guān)注某個特定函數(shù)的讀者也會更容易理解它們的用處。
(注意,當(dāng)你能負(fù)責(zé)所有的 caller 時,這種方法才是正確的。如果你的函數(shù)只是公共 API 的一部分,那么請不要考慮使用這種方法。因為你并不清楚所有的用例都是什么,也不知道未來會有什么樣的用例)
競速賽車跑得比普通轎車要快,這點毋庸置疑。但這也是賽車在犧牲了柔軟座椅、低噪音,以及車載空調(diào)的條件下。如果我們的程序不需要做競速賽車,那就不要過早地拆掉空調(diào)。逐漸熟悉程序的構(gòu)造,先從編寫易于人理解的代碼開始,不要一上來就試圖挑戰(zhàn)計算機的運行速度。
同理,也不應(yīng)過早開始泛化。沒人會在不需要處理大量物品的時候就買入一輛自卸貨車,在沒有過多需求的時候,我們也不用提前編寫多余功能的代碼。
“如何寫出可讀性高的代碼”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。