怎樣才能寫得一手好代碼?

「壹期壹問」VOL.4 收錄的問題

真正優質的代碼具有什麼條件?如何高效的編寫優質代碼?——來自用戶 yuklngphp

來自 LeanCloud iOS 開發工程師陳宜龍的回答

真正優質的代碼具有什麼條件?

優質的代碼基本的條件:輕量級、低耦合(鬆耦合)、易替換、易刪除。html

什麼叫低耦合?ios

你若是能夠從你的代碼中刪除某一模塊而不用所以去重寫其餘模塊的話,你的代碼就一般被稱爲是低耦合的。程序員

咱們都喜歡輕量級的框架,由於你應該時刻保持着這樣的警覺:早晚有一天,這個庫、這坨代碼會被替換、移除掉。數據庫

這可能讓你聯想起了 iOS 領域一個教科書級別的事件—— ASI 切換 AFN。ASI 曾經是 iOS 開發首選的第三方網絡框架,後來做者宣佈中止維護,開發者紛紛開始遷移到 AFN。它教會咱們一個道理:編程

讓你的代碼「易替換、易刪除」,第三方框架代碼質量是一方面,使用者也有責任。設計模式

如何高效的編寫優質代碼?

想寫優質代碼,首先要勇於寫垃圾代碼。網絡

正如程序員心中的上古巨神 Alen Jay Perlis 在 《Epigrams on Programming 編程警句》 所說:架構

Everything should be built top-down, except the first time.框架

凡事都應該高屋建瓴,除非你是第一次幹。

因此,在 beta 版本里犯錯,上帝都會原諒。

不要在開始寫一個應用以前就去想着能寫一個萬全的架構。道理很簡單,就像你在早上 8:00 出門上班前許願「一路綠燈」,即便當時願望實現了,8:00 全北京的燈都變綠了,但等你到下個路口,同樣仍是該紅燈時紅燈。咱們是很難預先猜想,但咱們卻能夠在發生小變化時,就及早去想辦法應對發生更大變化的可能。也就是說,等到變化發生時當即採起行動。

第一次的時候儘管大膽的去寫一堆亂七八糟的代碼。

但垃圾代碼始終仍是要轉換成優質代碼的,如何轉換?遵循「開放-封閉原則」,即 The Open-Closed Principle(簡稱 OCP)去轉換:

這個原則實際上是有兩個特徵,一個是說 「對於擴展是開放的,Open for extension」,另外一個是說 「對於更改是封閉的,Closed for modification」。咱們在作任何項目的時候,都不要期望項目一開始時需求肯定就不再會變化,這是不現實也不科學的想法,而既然需求是必定會變化的,那麼如何在面對需求的變化時,設計的軟件能夠相對容易修改,不至於說新需求一來,就要把整個程序推倒重來。

上面是《大話設計模式》中的一段話,書中也給出了一個例子:

好比你在寫一個加法程序,你很快在一個 client 類中就完成。此時變化尚未發生。而後我讓你加一個減法功能,你發現,增長功能須要修改原來這個類,這就違背了「開放-封閉原則」,因而你就該考慮重構程序,增長一個抽象的運算類,經過一些面向對象的手段,如繼承、多態等來隔離具體加法和減法與 client 耦合,需求依然能夠知足,還能應對變化。這時我又要你再加乘除法功能,你就不須要再去更改 client 以及加法減法的類了,而是增長乘法和除法子類就可。即面對需求,對程序的改動是經過增長新代碼進行的,而不是更改現有的代碼這就是「開放-封閉原則」的精神所在。

你應該大膽嘗試,在每一次嘗試時都開新的坑,去犯新的錯,而後經過迭代慢慢來完善。成爲一個專業的軟件開發者的過程就是不斷積累後悔和「error check list」 的過程。你從「Run Success」身上學不到任何東西,知道優質代碼長什麼樣,做用也微乎其微,你須要的是:對垃圾代碼記憶猶新。

Perlis 也說過:

In programming, as in everything else, to be in error is to be reborn.

同時敢不敢寫垃圾代碼,徹底取決於心態。寫程序其實有兩種心態,一種是作 Demo 的心態,一種是作項目的心態。讓咱們來對比下這兩個心態:

<img src="https://blog.leancloud.cn/wp-content/uploads/2016/04/c6fc633cc3da8f1aa3d73a755e84b53b-625x607.png" alt="兩種狀態" width="625" height="607" class="alignnone size-medium wp-image-4514" />

對於業務邏輯,垃圾代碼有時候是更好的選擇,不然極小的封裝均可以將你再次帶入「過分封裝」的陷阱。業務邏輯是那種有着無盡的 if else、邊界狀況和快速而 dirty 的 hack 的代碼。

如今你再回過頭來思考下:一大坨垃圾代碼,和過分封裝的業務邏輯代碼,哪一個更好?

有時候刪掉一個大的錯誤比刪掉 18 個彼此相關聯的小錯誤更爲容易。

摒棄代碼潔癖,擁抱合理的冗餘

冗餘同樣被貼着「垃圾代碼」的標籤,難道冗餘就沒有一點好處?你必須試着擁抱合理的冗餘。

咱們會經過複製和粘貼來將部分代碼重複使用以免引入依賴性,提升靈活度,但代價就是冗餘。

「一坨代碼被使用兩次,就應該封裝」這個論調不該該被提倡。每每是剛開始很方便,越日後,隨着需求的變動,越成爲一種累贅。 爲了一個小功能就去寫一個庫,甚至這個庫只有一個方法,這樣會帶來什麼問題?你削減了使用到了這個庫的全部模塊之間的獨立性,這樣作毫無必要。

想寫優質代碼,要學會如何不寫代碼

代碼越少,Bug 越少,代碼也就越優質。

正如 iOS Architecture Patterns 這篇博客所言:

The less code you have, the less bugs you have.

The best code is the code that has never been written.

你應該始終明白什麼是最優雅的解決方式。

爲第三方庫寫工具類、模板類

咱們構建模塊不是爲了複用,而是爲了易於修改。

建工具類,出於兩個徹底相反的緣由:低耦合、緊耦合。

低耦合

上面提到的「ASI 切換 AFN」教會咱們:要爲第三方庫封裝。儘可能不要直接使用第三方庫,而是爲它們封裝一層,一般咱們叫這些類 Tool、Handler、Helper、Manager(先不吐槽命名了)。考慮到的是替換需求,由第三方庫而衍生出來的工具類,一般也放在叫 Tool 的文件夾下。這樣作的目的是儘量將變化頻繁的部分和相對更穩定的部分隔開來實現低耦合。這也一樣適用於數據庫以及各類可能會變動的 UI 組件。

緊耦合

但也不要一味追求「低耦合」,要根據實際狀況來選擇「緊耦合 tight coupling」。好比錯誤處理就是一個須要與項目緊密結合在一塊兒的操做。這個緊耦合的部分,咱們就要放到 Tool 裏,這也是建 Tool 的另外一要考慮的緣由:庫老是試圖迎合全部的需求,而咱們只會用到其中小部分功能,並且只會對相應的響應作出特定的處理。因此建工具類能夠隱藏沒必要要的細節。

好的 API 老是大而全,而建 Tool 則是咱們意識到咱們不能同時讓全部人都高興。開發一個好用的 API 和開發一個具備擴展性的 API 一般是互相沖突的。Tool 的做用就是讓他們好用。

造輪子

你在建 Tool 時應該已經體會到緊耦合的好處了,但有時 Tool 已經徹底知足不了咱們的緊耦合需求,這時咱們就須要造輪子。

iOS 裏 Star 數最多的一個庫是 AFNetworking,爲何?當年 iOS 五、iOS 6 時代尚未 NSURLSession 的時候,NSURLConnection 作斷點續傳和斷點下載是很是困難的,並且蘋果的 API 不對外隱藏任何細節,這也就造就了 AFNetworking——它爲你們隱藏了不少細節,因此好用。

一樣的道理,在日益複雜化的 App 開發中, Auto layout 逐漸成爲最佳選擇。但複雜的 VFL 語法,以及開發者不太買帳的 Storyboard、XIB 可視化操做,也成就了 Masorny。Masorny 以其優雅的鏈式純代碼操做,漸漸成爲自動佈局的主流框架。

設計模式的「單一責任」原則告訴咱們:

每個模塊都應該只去解決一個難題

但咱們更須要:

每個難題都只應該由一個模塊去解決

當一個問題須要兩個模塊去作的時候,一般都是由於改變一部分須要另一部分的改變。

一個寫得很糟糕可是有着簡單接口的組件,一般比須要互相協調的兩個組件更容易使用。

你應該像 AFNetworking、Masorny 那樣,寫出這樣的優質代碼:能將寫起來、維護起來,或者刪除起來最困難的部分互相隔離開。

如何參與「壹期壹問」?

你們能夠經過問題提交通道來向 LeanCloud 提問。

相關文章
相關標籤/搜索