寫代碼過程中最忌諱的是什麼?總感覺最近太過於急於求成?
------------%----------------------------------------%---------------------
第一次提的問題得到這麼多人的解答,非常的開萱感動。樂於分享的品質,會讓我們走得更遠!感謝各位哦!
-------------------%-----------------------------------------%-------------
講個真實的故事。
在Stanford的第二個學期,我閑的蛋疼去圖形學lab找個了寫代碼的工作。我的老闆就叫V教授吧,他手下有一個博士生S哥,在做一個室內傢具自動設計的項目。他寫了一個demo,雖然演算法效果還不錯,但是渲染效果很差,而且缺少比如陰影一類的視覺效果。我的工作就是讓demo看上去更牛逼一點。
我看了一下demo之後,感覺難度應該不大,首先是性能有問題,性能問題搞定之後,可以加一些eyecandy的標準效果。畢竟我大三的暑假在activision擼了3個月遊戲引擎優化,也算是輕車熟路了。S哥特別興奮,把cvs賬號給我(對,那個時代還用cvs),說咱們1個月差不多就搞定了吧。我說不用啊就這麼點東西兩周吧。
這種項目優化起來就是那些手段,沒啥難度,我決定推遲到周末再開始,最後總共留了一周左右的時間。
但是當我最終坐下來開始看代碼的時候,就石化了。
這是我見過的最沒有結構的代碼,總共三四個文件,每個都幾萬行,大量重複但是修改過一點點的代碼被複制來複制去。渲染是opengl寫的,但是所有東西都是glbegin/glend畫的,也沒有任何抽象,矩陣運算也全部是gltranslate/glrotate一類的。但是它又是那麼沒有bug的正常運行,讓我嘆為觀止。
任何的性能提升,都建立在大量的重構基礎之上,然而任何的重構都牽一髮而動全身。但是眼前這坨冒著蒸汽的熱翔,又是這麼有機的運作著,簡直就像把C++ feed到一個C++到C++的compiler里,然後吐出來一堆沒有任何抽象的C++。
我其實還是嘗試重構了,但是基本意味著我要把全部渲染的東西重寫一遍,一周(還要上課寫作業啊)看來是肯定搞不完了。最後我寫了一個shadow mapping,連pcf都沒加,然後替換了部分glbegin/glend就報告了V教授,說實在是搞不定了啊。
第二天V教授說你們去買個新電腦吧。
卧槽,那我還優化個什麼勁?
但是這並不是一個關於重構的故事。
我後來打聽了一下S哥的底細,大概是這樣的:這位仁兄在本科和master都是學的建築,並不會寫代碼,後來強行申請了Stanford的CS Phd,居然還進來了。因為沒有受過任何CS的科班訓練,更不知道啥重構,抽象,OO,FP的概念。一切東西能用就行,還tm重構,累不累啊。而且S哥輕輕鬆鬆寫個幾萬行毫無壓力,功能都很正常。
許多年以後我才意識到,這是一位揮舞代碼就像揮舞筆刷的藝術家啊,這才是代碼作為一種表達方式的自然存在啊。無拘無束,放蕩不羈,這才是真正的,自由的寫程序!
急於求成算事嗎?忌諱什麼的算事嗎?最重要的是寫出功能,寫出風骨,寫出浪漫,寫起代碼來猶如李太白寫詩,呼兒將出換美酒,與爾同銷萬古愁啊!
然後你就花$20/hr雇個小弟來幫你重構就好啦。踩坑無數也挖坑無數的人告訴你一下,寫代碼的時候最忌諱的是挖坑,比如:
1. 方法亂命名:如果你看到一個詞不達意或者意思相反的方法名,而且沒有任何注釋,痛罵一通後查查歷史記錄發現原來這個方法原來是自己幾個月前寫的,可以想一下內心是什麼感受。寧可用拼音命名也不不要用一個詞典都查不出來的蹩腳英語命名。
2. Magic Number:如果你看到 if (a = 3) //此處為偽代碼,然後後面帶了一大堆業務代碼,查遍文檔、前中後台代碼、資料庫都沒有任何線索。
3. 萬能方法:為了實現復用,在一個方法裡面加了塞了N個參數、N個開關、N個if else分支、N個flag,代碼膨脹到了幾百行,動一處就可能影響到N個功能。
4. 重複代碼,一段代碼被copy到了N個地方,一個BUG改了N次還沒掃清到底還有那些地方仍有問題。
以上就是代碼裡面常見的坑,其實這些坑有個專有名詞叫Code Smell,可以Google一下,還有很多其他的坑。
寫代碼最鼓勵的是填坑,填坑也有一個專有名詞叫重構:填坑的原則:
- 不要妄圖一次性把坑填完,也不要妄圖一次填完一個大坑,一步一步的填,如果出問題,可以比較容易找到BUG。
- 不要不懂方法的暴力填坑。
- 適可而止,不要不計代價的追求完美主義。
什麼時候填坑:
- Code Review的時候
- 新增功能的時候
- 改BUG的時候
有本比較有名的書《重構》,可以看一下。
最忌諱一條不夠,我給兩條:
第一條:過早優化是萬惡之源 --- 《UNIX編程藝術》,詳細請參考 @八嘎夜 的回答,更詳細請看《UNIX編程藝術》
第二條:90%的時間甚至100%的時間在敲鍵盤(敲代碼、定位問題、改問題),沒有花時間思考!
正確的做法是80%的時間思考,20%的時間敲鍵盤
2016.09.12補充:
=============================================================
實際上我認為第二條比第一條更加關鍵但更加嚴重!第一條至少你還能從優化中學到很多東西,但第二條卻永遠都學不到什麼東西
不寫文檔、不按文檔寫,這是要命的。
// TODO:
如果你只負責自己一個人,寫代碼過程最忌諱的是低估需求的難度(高估自己的能力)。
如果你是團隊合作,最忌諱的就是溝通不到位。
- 低估需求難度的可能原因如下:
- 沒有充分了解需求
- 沒有對需求建立足夠的模型
- 沒有足夠的代碼技術
- 沒有良好的編程習慣
- 沒有良好的測試習慣
- 沒有考慮非編碼的額外工作
- 溝通不到位的可能原因如下:
- 沒有足夠的領域知識
- 沒有良好的需求定義,文檔,測試用例等支撐
- 沒有良好的反饋
- 沒有定義共同語言
- 沒有合理的分工和與其匹配的技能
- 低估需求難度(同上)
- 不同步的工作方式
純編碼的話,
如果是初學者,學會建模,領域知識和設計模式,用工程化的思路寫代碼。
如果是熟練者,學會敏捷和裁剪,放棄過度設計,用目標導向方式寫代碼。
對於新產品不要花太多時間追求完美!
土豪公司除外。
不要花80%的成本過早的解決一些小概率錯誤,
不是我對產品要求不高,是出資人耗不起。
如果不差錢,另當別論。
儘早發布一個版本到市場實驗,有客戶了 有錢了慢慢完善。
一切不考慮實際承受成本能力的過度設計都是耍流氓
教條,碰到問題腦子裡只有一種解,沒有別的可能,哪怕是錯誤的可能。
新入行的程序員一般代碼寫得比較「教條」,還沒忘掉書本的緣故,我個人是有點忌諱的,因為這些同志一般也聽不進去老程序員苦口婆心;科班出身的新人的編程價值觀基本停留在寫程序的目的就是寫出「好」程序上,做得越久越明白寫程序的目的是為別人解決實際問題,長期的問題是問題,短期的問題也是問題,如果銷售部在遠程給客人演示時臨時需要作一些調整,技術應該無條件地滿足,而不是抱著自己的工程合理性不放。新手喜歡把代碼敲得多多的,因為他「喜歡」看到代碼流出來的感覺,老人往往相反,知道多一行不如少一行的道理。
「教條」有很多後果,形式主義,代碼的格式變得比設計好抽象更重要;寫不寫測試變成一個政治問題,選擇不寫或者選擇有節制有取捨地寫也被認為不符合所謂最佳實踐,討論也討論不進去,因為會搬出經典來駁斥,而忽略自己的具體場景。
這和程序寫的快,寫得慢沒有必然關係,優質的程序員可以控制代碼的輸出速度,計劃全盤在腦子裡,能保證進度。把程序寫快了本身也未必是錯,錯的是把程序寫壞了。程序很難一次寫得完美的,只要願意持續改進就行了,沒有更好的策略,新人多幾次反覆,老人少幾次。但讓新人老人都按照一個靜止的規則去開發,或者團隊默認這種靜止的規則是永遠合理正確的,這就比較危險了。完美主義/強迫症/代碼潔癖
花10分鐘實現功能,然後花10個小時來改變數名。
上手一個項目的時候,先罵原有的代碼丑。
EDIT: 我個人非常討厭「不要縮進超過三層」「一個函數不要超過多少行」的說法。它們是很好的rule of thumb,但是如果確實有需要,打破這種規則比為了繞開它而把代碼搞得更糟要好。不寫單元測試
1不搞明白需求的人,就寫代碼的人,死的快。
需求不但在軟體行業一直是一個問題,在其他行業也是,客戶和你說的需求,叫客戶需求,不叫客戶真實需求,和客戶交流了2天,就開始開發,拼死拼活寫代碼,結果不是客戶要的,這種鬱悶的事情估計每個碼農都遇到過,所以搞明白客戶真實需求是代碼開發的第一要素,客戶真實需求,客戶真實需求,客戶真實需求。
2不搞明白流程,就寫代碼的人,死得快。
客戶的商業流程算作需求,上邊講了,不多說,即使你搞明白了客戶的流程,你是否能夠搞清楚如何處理,也就是說,你設計的演算法是否可以實現你需要的商業流程。別把計算機搞得神秘化,計算機實際就是模擬人的行為,如果你自己都說不清楚一個演算法的處理流程,代碼是不可能正確處理這個問題的。你的演算法是要精確的。為什麼有時候一些軟體修改容易,而有一些比較難,如果你仔細研究就會發現,大凡架構合理,演算法好的,修改不用動架構的,修改比較快,否則死的快。演算法要精確、演算法要精確、演算法要精確。
3不考慮異常情況的代碼,想當然的死得快
實現了演算法只叫做原理實現,異常數據必須考慮,最著名的就是除0的問題了吧,在開發的時候是否在編碼的考慮異常情況,實際上是考察一個碼農水平的試金石,一般來說老鳥和菜鳥區別這這裡區別是很大的。所謂的軟體的健壯性在這裡表現的很明顯,說一個題外的話,原來實現,代碼是10%,異常處理,代碼是90%。不多說了,說多了都是淚。異常處理,異常處理,異常處理
4不寫註解的,死的快
一般代碼如果在3個月帶6個月不接觸,就會忘記,不知道大家有沒有發現很多代碼似乎似曾相識,哈哈,也許這些代價就是你原來編寫的,合理的註解,便於你快速回憶,效果奇好。另外寫註解的另外好處就是發現提高,經常看原來的代碼會大罵那個傻逼寫的這個代碼,怎麼是我,靠。哈哈,祝賀你,你水平提高了,註解,註解,註解
5不注重代碼設計的基本規範,死的快
說一個最簡單的原則,單一性原則,一個變數只表示一個事情,一個函數只做一個事情,單一性原則說起來簡單,但搞軟體研發的真正搞懂的人不多,大凡做應用系統的,如果遇到什麼難題,十有八九是哪個地方違反了單一性原則,在軟體開發中,將分散的數據組合起來容易,當將組合的數據分開就麻煩大了。
6搞明白機理,再使用
很多人寫代碼的時候,直接調用,原來是函數,後來是類,現在是架構,但這些東西的機理卻不去理解,一有問題就完蛋,
推薦答主看看這本書
不叫「急於求成」,叫「允許不足,迭代改進」,也就是「publish early, publish often」。這樣的好處也不僅僅是搶佔市場,還能在試錯階段避免過早優化帶來的工作量浪費。
任何複雜架構或模式都不是一下子設計出來的,都是演化出來的,你要是先完成功能的話,在之後的迭代中慢慢做架構,還不至於餓死。我剛剛寫了一篇關於那些操蛋的代碼的文章,你可以看一下:
這些操蛋的代碼,你見過多少? - 知乎專欄
寫代碼中最忌諱的就是不簡單、不清晰、不嚴謹
所以我想給你幾點建議:
Point 1:通用命名規則
函數命名,變數命名,文件命名要有描述性;少用縮寫。儘可能給有描述性的命名,別心疼空間,畢竟讓代碼易於新讀者理解很重要。不要用只有項目開發者能理解的縮寫,也不要通過砍掉幾個字母來縮寫單詞。
Point 2:函數命名
函數命名: 常規函數使用大小寫混合, 取值和設值函數則要求與變數名匹配: MyExcitingFunction(),
Point 3:類型命名
類型名稱的每個單詞首字母均大寫, 不包含下劃線: MyExcitingClass
Point 4:類注釋
每個類的定義都要附帶一份注釋, 描述類的功能和用法。
謝邀
變數命名要規範,要確保你在3個月後,或者其他人過來,仍然可以通過命名看懂你的程序
最忌諱不保存
實、實名反對上面所、所有答案……並不敢。
有些人是寫了一堆看起來 smell 很糟的程序,至少做出來了。
像我這樣,代碼整潔反覆重構,但是東西都還沒做出來已經重構十遍了更加不可取,切記切記,過早優化過早重構比糟糕的代碼可怕一萬倍啊!
血淚
血淚
血淚
QAQ
最忌諱是亂改介面的名字和一些變數名。
被坑過好多次。最忌諱的就是: 寫代碼不是為了實現功能么?
寫代碼是為了看的啊!!!!! 不光是給你看啊, 還有你的同事, 你的繼任啊!!!
推薦閱讀: