作為一名開發(fā)人員,我們所要做的不僅僅是會(huì)用一種編程語(yǔ)言和實(shí)現(xiàn)一款軟件或項(xiàng)目。
作為開發(fā)人員,要站在更高的視角去看待一個(gè)項(xiàng)目,通過(guò)一些優(yōu)秀的開發(fā)習(xí)慣,可以讓寫的代碼更加容易理解、更加容易擴(kuò)展,也可以具有更強(qiáng)的通用性。
雖然養(yǎng)成這些好的習(xí)慣在前期需要一些學(xué)習(xí)和理解成本,但是一旦應(yīng)用于實(shí)際的項(xiàng)目開發(fā)中,在后續(xù)的功能迭代、場(chǎng)景新增過(guò)程中,就會(huì)減少重構(gòu)、重復(fù)造輪子的痛苦。
那么什么才是優(yōu)秀的代碼?
我認(rèn)為優(yōu)秀的代碼具有如下特征:
- 可讀性
- 結(jié)構(gòu)設(shè)計(jì)優(yōu)雅
- 容易理解,遵循單一責(zé)任原則(SRP)
- 容易擴(kuò)展和修改
- 經(jīng)歷全面的驗(yàn)證和測(cè)試用例
為了寫好代碼,滿足這些要求,我這些年一直堅(jiān)持一些習(xí)慣,今天,就分享給大家。
1. 使用有意義的名稱
命名是開發(fā)過(guò)程中非?;A(chǔ)、非常普遍的一項(xiàng)任務(wù),也是決定代碼簡(jiǎn)潔性、可讀性的核心所在。
在編程開發(fā)過(guò)程中,變量、函數(shù)、類、參數(shù)、模塊、包、目錄等,很多地方都會(huì)涉及到命名問(wèn)題。
所以,就如同給人起名一樣,在開發(fā)過(guò)程中的命名也至關(guān)重要,能夠在最短的時(shí)間內(nèi)讓我們自己或者其他閱讀者能夠獲取到有價(jià)值的信息。
我在命名過(guò)程中一直堅(jiān)持3個(gè)原則:它是做什么?它為什么存在?以及它是如何使用的?
比如下面這個(gè)例子:
int b; // 用戶數(shù)量.
在上面的例子中,你需要在聲明變量名稱的同時(shí)給出一個(gè)注釋,這不是一個(gè)好代碼的特征。
我之前看到過(guò)一篇文章:注釋越多就越好嗎?
我認(rèn)為答案是否定的,清晰的代碼結(jié)構(gòu)和有意義的命名,讓閱讀者一眼看上去就能夠理解它的功能、作用,這樣再加注釋就是多余沒(méi)有意義的。
但是,在上面這個(gè)示例代碼中,我們很難從它的命名中看出它到底要干嘛,因此,就不得不加上注釋說(shuō)明。
按照前面提到的3個(gè)原則,我們可以在變量命名中說(shuō)明它的作用和目的:
int number_of_users
這樣再看上去,代碼就會(huì)簡(jiǎn)潔很多,而且對(duì)于自己和其他閱讀者也更加容易閱讀。
需要補(bǔ)充一點(diǎn),雖然要求有意義的命名,但是也沒(méi)有必要把要表達(dá)的含義逐字的翻譯成英文,這樣就會(huì)更加繁瑣,盡量將名字限制在三到四個(gè)字即可。
2. 單一責(zé)任原則(SRP)
在任何編程語(yǔ)言中,類、函數(shù)或方法都是組織代碼的好方法,所以當(dāng)在寫代碼時(shí),就特別需要注意如何寫一個(gè)能傳達(dá)其意圖的函數(shù)。
大多數(shù)初學(xué)者都會(huì)犯這樣的錯(cuò)誤,他們寫的函數(shù)幾乎可以處理和完成所有的事情(執(zhí)行多項(xiàng)任務(wù))。
這使得代碼對(duì)開發(fā)者來(lái)說(shuō)更加混亂,并在他們需要修復(fù)一些bug或?qū)ふ乙恍┐a的時(shí)候造成更多麻煩。
因此,在寫函數(shù)、類的過(guò)程中,我一直堅(jiān)持2個(gè)原則:
- 盡量簡(jiǎn)潔
- 只做一件事,而且要做得好
以上兩點(diǎn)明確提到,函數(shù)應(yīng)該遵循單一責(zé)任原則。這意味著它不應(yīng)該有嵌套結(jié)構(gòu),也不應(yīng)該有超過(guò)兩個(gè)縮進(jìn)層次。遵循這種技術(shù)可以使代碼更具有可讀性。
另外,要確保函數(shù)不應(yīng)該超過(guò)三個(gè)參數(shù)。傳遞三個(gè)以上的參數(shù)會(huì)使代碼變得混亂,如果有任何問(wèn)題,也很難調(diào)試。
此外,如同前面所說(shuō),要注意函數(shù)名稱。為你的函數(shù)使用一個(gè)描述性的名字,它應(yīng)該清楚地說(shuō)明函數(shù)的作用:
function subtract(x, y) { return x – y;}
在上面的例子中,函數(shù)名稱清楚地表明它的目的是為兩個(gè)數(shù)字做減法,而且它只有兩個(gè)參數(shù)。
3. 避免寫不必要的注釋
這個(gè)在前面提到過(guò),注釋越多就越好嗎?
有很多博主會(huì)反反復(fù)復(fù)強(qiáng)調(diào)注釋的重要性,無(wú)論如何都要盡量寫注釋。
的確,必要的注釋對(duì)解釋代碼很有幫助,但它也需要對(duì)代碼進(jìn)行更多的維護(hù),而且隨著代碼的變動(dòng),注釋也需要相應(yīng)的改動(dòng),否則會(huì)引入更多歧義。
此外,如果命名能夠清晰的解釋一個(gè)參數(shù)、一個(gè)函數(shù)的作用,那么再多加一些注釋也沒(méi)有意義。
4. 為人們寫可讀的代碼
很多人,尤其是初學(xué)者,在寫代碼時(shí)都會(huì)犯這樣的錯(cuò)誤:他們把所有的東西都寫在一行里,而不在代碼中留出適當(dāng)?shù)目瞻?、縮進(jìn)或換行。
這使得他們的代碼很混亂,難以維護(hù)。
尤其,當(dāng)其他開發(fā)者試圖閱讀和理解混亂的代碼時(shí),這就浪費(fèi)了他們的時(shí)間。
所以要時(shí)刻注意你的代碼的格式,寫代碼不僅僅是為了讓它不報(bào)錯(cuò)的跑出結(jié)果,還需要讓人能夠更好的理解它。
而且,當(dāng)你在幾天后回到自己的代碼中做一些修改時(shí),你也會(huì)節(jié)省你的時(shí)間和精力。
所以要確保你的代碼應(yīng)該有適當(dāng)?shù)目s進(jìn)、空間和換行,以使它對(duì)其他人來(lái)說(shuō)可讀:
// 不好的代碼class CarouselRightArrow extends Component{render(){return ( );}};// 好的代碼class CarouselRightArrow extends Component {render() { return ( );}};
5. 編寫單元測(cè)試
編寫單元測(cè)試在開發(fā)中是非常重要的,它使你的代碼變得干凈、靈活和可維護(hù),對(duì)代碼進(jìn)行修改和減少錯(cuò)誤變得更加容易。
在軟件開發(fā)中,有一個(gè)過(guò)程被稱為測(cè)試驅(qū)動(dòng)開發(fā)(TDD),在這個(gè)過(guò)程中,需求被轉(zhuǎn)化為一些特定的測(cè)試案例,然后軟件需要不斷改進(jìn)以通過(guò)新的測(cè)試。
這樣 ,我們的代碼才能夠擁有更強(qiáng)的穩(wěn)定性和健壯性。
6. 謹(jǐn)慎對(duì)待依賴關(guān)系
在軟件開發(fā)中,需要謹(jǐn)慎對(duì)待你的依賴關(guān)系。
如果可能的話,依賴關(guān)系應(yīng)該始終是一個(gè)單一的方向。
舉一個(gè)單向依賴的例子。
假設(shè)我們有一個(gè)廚房類,它依賴于洗碗機(jī)類。只要洗碗機(jī)不依賴于廚房類,這就是一個(gè)單方向的依賴關(guān)系。廚房類只是在使用洗碗機(jī),但洗碗機(jī)并不關(guān)心在什么場(chǎng)景下使用。
然而,不可能總是有單向依賴,但我們應(yīng)該盡量多的有單向依賴。當(dāng)依賴關(guān)系向多個(gè)方向發(fā)展時(shí),事情會(huì)變得更加復(fù)雜。在雙向依賴中,兩個(gè)實(shí)體都互相依賴,所以它們必須一起存在,盡管它們是分開的。當(dāng)一些系統(tǒng)的依賴關(guān)系沒(méi)有形成一個(gè)單一的方向時(shí),就很難更新,很難解耦。
因此,要始終小心管理你的依賴關(guān)系。
7. 讓項(xiàng)目井然有序
這是軟件開發(fā)中一個(gè)很常見的問(wèn)題,我們?cè)陧?xiàng)目中添加和刪除了很多文件或目錄,有時(shí)會(huì)變得很復(fù)雜,讓其他開發(fā)者無(wú)法理解項(xiàng)目并為此工作。
當(dāng)然,我們不可能在第一天就設(shè)計(jì)出一個(gè)完美的文件夾或文件組織,但以后,當(dāng)你的項(xiàng)目變得更大時(shí),就需要注意文件夾、文件和目錄的組織結(jié)構(gòu)。
一個(gè)結(jié)構(gòu)良好的文件夾和文件使一切都變得清晰,理解一個(gè)完整的項(xiàng)目,搜索一些特定的文件夾并在其中進(jìn)行修改變得更加容易。
8. 避免不必要的嵌套
在代碼中嵌套是我們經(jīng)常做的事情,雖然嵌套本身并沒(méi)有什么問(wèn)題,但有時(shí)會(huì)使代碼更難讀。
一種幫助避免這種情況的方法是使用 “Return Early “設(shè)計(jì)模式。
它允許我們將if語(yǔ)句作為一個(gè)保護(hù)子句,在執(zhí)行下一步的代碼之前檢查錯(cuò)誤并返回。
它有助于避免使用if/else和不必要的嵌套,舉個(gè)例子:
修改前
function deleteItem(item) { if (item != null) { console.log(“Deleting item”); item.delete(); }}
修改后
function deleteItem(item) { if (item == null) return; console.log(“Deleting item”); item.delete();}
這是我在寫代碼過(guò)程中堅(jiān)持了很久的8個(gè)習(xí)慣,總結(jié)了很久,希望對(duì)大家有所幫助!
如果覺(jué)得不錯(cuò)的話,就點(diǎn)個(gè)贊支持一下吧!
hello,大家好,我是 Jackpop,碩士畢業(yè)于哈爾濱工業(yè)大學(xué),曾在華為、阿里等大廠工作,如果你對(duì)升學(xué)、就業(yè)、技術(shù)提升等有疑惑,不妨交個(gè)朋友:
我是Jackpop,我們交個(gè)朋友吧!