帶老弟做項(xiàng)目,涼了
總結(jié)程序員在團(tuán)隊(duì)開發(fā)中常犯的問題,千萬(wàn)注意!
大家好,我是魚皮,還記得我的老弟小阿巴么?
之前,我曝光了這個(gè)初學(xué)前端的孩子第一次寫后端代碼時(shí)出現(xiàn)的囧事:前端老弟第一次寫后端,崩了!
這篇文章發(fā)出來(lái)后,更多人認(rèn)識(shí)了小阿巴,覺得他是個(gè)有趣的編程小辣雞。但小阿巴是一個(gè)孤傲有志向的孩子,不想一直在大家面前出笑話。于是,這貨不服氣,又來(lái)找我,想跟著我做新項(xiàng)目。

正好,要開發(fā)一個(gè)新功能,就拉小阿巴一起吧。而且這次,整個(gè)大功能交給他全權(quán)負(fù)責(zé)!
沒想到,小阿巴依然很快就完成了開發(fā),興致沖沖地提交了代碼,拉著我來(lái)評(píng)審。

然而,當(dāng)我看了他寫的代碼后,我發(fā)現(xiàn),事情并不簡(jiǎn)單。
小阿巴真是太牛逼了,一些編程新手在團(tuán)隊(duì)開發(fā)中常犯的問題,這貨一個(gè)也沒避開,全都踩雷上了。
于是我決定再次曝光他,并且總結(jié)了他的問題,希望大家引以為戒。
?? 團(tuán)隊(duì)開發(fā)雷區(qū)
格局小了
小阿巴寫的代碼中,有很多 “死” 值,比如有好幾個(gè)地方用到了同一個(gè)機(jī)器的 IP 地址:
// 文件 1
getConnectByIp("8.8.8.8");
// 文件 2
getLinkByIp("8.8.8.8");
// 文件 3
return {
ip: "8.8.8.8"
}
我問他為啥這么寫,他的回答不出所料:就是圖省事兒~

這就跟我們復(fù)制粘貼一樣,把重復(fù)的代碼粘貼很多遍,寫的時(shí)候是挺爽,但萬(wàn)一后面要修改了呢?要一個(gè)個(gè)地把所有粘貼的代碼都改掉?
如果都是一個(gè)人寫代碼還好,自己可能還記得有哪些重復(fù)的代碼,但如果是一個(gè)團(tuán)隊(duì)呢?
假如同事 A 寫了一段代碼,同事 B 和同事 C 都復(fù)制了他的代碼:

但后來(lái)同事 A 發(fā)現(xiàn)自己的代碼有 Bug!于是就只修改了代碼 A,然而代碼 B 和代碼 C 依舊存在 Bug。
畢竟大家都喜歡復(fù)制代碼的,尤其是在大團(tuán)隊(duì)中,你根本不知道自己的代碼究竟被多少人復(fù)制了!一個(gè) Bug 永流傳啊。
所以無(wú)論是從可擴(kuò)展性還是可維護(hù)性的角度,盡量少寫 “死” 代碼、少寫重復(fù)的代碼,可以將重復(fù)的值抽離成獨(dú)立的變量、常量或配置文件,將重復(fù)的代碼封裝成組件,并編寫文檔和注釋指引他人使用。一般代碼重復(fù) 3 次,就可以考慮抽象了,別偷懶,要不然以后更慘。
過于自我
小阿巴在實(shí)現(xiàn) “計(jì)算指定日期和當(dāng)前日期相差的天數(shù)” 功能時(shí),新引入了一個(gè)依賴庫(kù)叫 Day.js 。
但事實(shí)上,項(xiàng)目已有日期處理庫(kù) Moment.js ,完全可以輕松地實(shí)現(xiàn)上述功能,沒必要再去重復(fù)引入一個(gè)同類的日期處理庫(kù)。
我問小阿巴,為啥要再引入新庫(kù),他的回答不出所料:俺用的熟!

大家可能覺得給項(xiàng)目引入重復(fù)依賴庫(kù)并沒有什么錯(cuò)對(duì)吧,但是對(duì)于團(tuán)隊(duì)項(xiàng)目來(lái)說(shuō),每個(gè)人如果都因?yàn)樽约旱牧?xí)慣而引入重復(fù)庫(kù),可能存在很多問題:
依賴沖突:同事 A 引入 Log4j 日志庫(kù),同事 B 引入 Logback 日志庫(kù),項(xiàng)目可能就跑不起來(lái)了。
項(xiàng)目加重:每人都引入自己熟悉的庫(kù),那整個(gè)項(xiàng)目就會(huì)像滾雪球一樣越滾越大,而且想拆分或去除某一部分,說(shuō)不定雪球就碎了。
再舉個(gè)夸張的例子,三位不同技術(shù)棧的前端開發(fā)一起來(lái)做項(xiàng)目,結(jié)果出現(xiàn)了三大框架出現(xiàn)在同一項(xiàng)目的三足鼎立局面:

這種項(xiàng)目的維護(hù)難度可想而知。
所以在團(tuán)隊(duì)中,架構(gòu)師還是很重要的,最好事先給項(xiàng)目定下規(guī)矩:項(xiàng)目都給我用這個(gè)框架!日期處理都要用這個(gè)庫(kù)!日志都要用那個(gè)庫(kù)!
這就是技術(shù)選型的問題了,要綜合考慮業(yè)務(wù)適應(yīng)性、團(tuán)隊(duì)成員學(xué)習(xí)成本等。
但無(wú)論如何,謹(jǐn)慎給項(xiàng)目引入新依賴,不要一言不合就另辟蹊徑!最好先仔細(xì)掃一遍項(xiàng)目現(xiàn)在的依賴,如果已經(jīng)有能滿足需求的,那直接用豈不美哉?實(shí)在要引入新依賴,也最好跟你的合作伙伴一起商量下,萬(wàn)一出了什么沖突可就不好了~

急不可耐
我看了小阿巴寫的功能,驚訝地發(fā)現(xiàn)他根本就理解錯(cuò)需求了啊!
我讓他擰個(gè)螺絲,這貨給我造了個(gè)汽車?
// 預(yù)期
luoSi = ningLuosi();
// 小阿巴
car = buildCar();
連做什么都沒搞清楚,就迫不及待直接上手寫代碼了,這可是大忌,典型的出力不討好。
在企業(yè)中,我們作為開發(fā),經(jīng)常會(huì)和產(chǎn)品經(jīng)理友好交流,要把需求徹底理解了,才能去設(shè)計(jì)方案,方案設(shè)計(jì)好才能去寫代碼,在整個(gè)過程中一定要和需求方反反復(fù)復(fù)確認(rèn)清楚!
我打算再給小阿巴一個(gè)機(jī)會(huì),這次過了好幾天他才提交了代碼,我一看,這貨真的是擰好螺絲了,只不過。。。
項(xiàng)目里已經(jīng)有扳手給他擰螺絲,結(jié)果這貨自己造了個(gè)扳手?
function ningLuosi() {
// 預(yù)期:一行代碼解決
useBanShou();
// 小阿巴,省略 1000 行代碼
const tool = buildBanShou();
xxxxxxx
}
這也是新手常犯的問題,不看項(xiàng)目文檔就上手寫代碼,結(jié)果有現(xiàn)成的輪子、簡(jiǎn)單的寫法不用,非要自己再去造輪子,費(fèi)事費(fèi)力。
盲目自信
我感覺小阿巴有一行代碼寫的有問題,于是就本地運(yùn)行了一下,果然發(fā)現(xiàn)了一個(gè) Bug,頁(yè)面直接崩潰了!
我把小阿巴叫過來(lái)問:你寫完代碼測(cè)試了不?你覺得功能有問題不?
他一臉自信地回答:沒測(cè),這功能不就是增刪改查,能有啥問題?
于是我給他演示了一遍 Bug,他瞬間羞紅了臉,啞口無(wú)言。

大家想象中好像經(jīng)驗(yàn)豐富的程序員寫代碼更快,但事實(shí)上,經(jīng)驗(yàn)越豐富,他們?cè)綍?huì)小心謹(jǐn)慎,在寫完代碼后認(rèn)認(rèn)真真地測(cè)試,而不是盲目相信經(jīng)驗(yàn)和直覺。測(cè)試也千萬(wàn)不要只是草草地自己點(diǎn)一遍沒問題就算了,而是要盡量覆蓋所有正常,尤其是 異常 的情況。畢竟用戶不聽話,你無(wú)法想象這些家伙能在你的系統(tǒng)中干出什么事!

制造屎山
小阿巴的代碼非常干凈清爽,一個(gè)文件千行代碼,一樣注釋都沒有,我把他叫過來(lái)給我講講自己的代碼,他竟然都支支吾吾說(shuō)不出來(lái)!

一行注釋沒有也就罷了,代碼還寫的歪歪扭扭,不遵循代碼規(guī)范,如果人人都是小阿巴,巨型屎山指日可待。
public static void main( String[] args) {
System.out
.println("i"
+ "am"
+ "shuai");
}
過眼云煙
通讀一遍小阿巴的代碼,除了上面的問題外,我還發(fā)現(xiàn)了很多小的錯(cuò)誤。
于是我問他:你寫完代碼后,自己會(huì)再通讀幾遍呢?
結(jié)果這貨竟然害羞極了,支支吾吾地說(shuō):沒。。。沒讀過。。。
天??!還有多少朋友和小阿巴一樣,自己的代碼猶如過眼云煙,寫完就再也不看了呢?

自己寫過的代碼一定要多讀幾遍,就和考試做卷子一樣的,檢查一遍能發(fā)現(xiàn)很多問題。而且自學(xué)編程的時(shí)候,又沒人逼你交卷對(duì)吧,還是要花些時(shí)間養(yǎng)成好習(xí)慣。
我現(xiàn)在寫完代碼至少會(huì)讀三遍:寫完一個(gè)子功能讀一遍、測(cè)試前讀一遍、提交前讀一遍。即便如此,仍然出現(xiàn)過 Bug。
再說(shuō)了,你自己寫過的代碼自己都不愿意看,還要?jiǎng)e人審查的時(shí)候來(lái)看你的爛代碼,發(fā)現(xiàn)問題再給你打回去修改,這不是浪費(fèi)別人的時(shí)間么?久而久之,誰(shuí)愿意看你的代碼?誰(shuí)愿意和你合作呢?
此外,即使有別人幫你審查代碼,但有些問題也很難發(fā)現(xiàn),線上出了問題肯定還是你背大鍋。沒有人可以拯救你的 Bug,除了你自己。
敷衍了事
最后這點(diǎn),就是我之前專門寫文章提到的大部分同學(xué)寫代碼的現(xiàn)狀:僅僅滿足于代碼可運(yùn)行、功能可用,而不注重細(xì)節(jié)、不做優(yōu)化。
比如小阿巴的這段代碼:
for(int i = 0; i < maxNum; i++) {
doSomething1();
}
for(int i = 0; i < maxNum; i++) {
doSomething2();
}
實(shí)際上是可以將兩個(gè)同樣的循環(huán)進(jìn)行合并的:
for(int i = 0; i < maxNum; i++) {
doSomething1();
doSomething2();
}
很多同學(xué)一直抱怨自己整天增刪改查,項(xiàng)目沒競(jìng)爭(zhēng)力。但實(shí)際上,你在做每個(gè)項(xiàng)目的過程中,都有很多進(jìn)步空間。要仔細(xì)挖掘,而不是敷衍了事。
關(guān)于這點(diǎn),大家可以看看我的編程習(xí)慣:我寫代碼時(shí)的小倔強(qiáng) 。
怎么樣,這些雷你是否也踩過呢?團(tuán)隊(duì)開發(fā)可千萬(wàn)不能像自己寫代碼那樣隨意,希望大家把這些問題熟記于心,做一名優(yōu)秀的程序員、可靠的隊(duì)友。
那么問題來(lái)了,后面還要不要帶小阿巴做項(xiàng)目呢???
我是魚皮,原創(chuàng)不易,如果覺得文章還不錯(cuò)的話,希望 點(diǎn)贊 + 在看 支持下,給俺點(diǎn)創(chuàng)作動(dòng)力。

往期推薦
