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