不要相信程式設計師在加班時間寫的程式碼
作為一個最底層的程式設計師,我先記錄一些只有底層程式設計師才會知道的事情。如果多年後,我違背自己進入這個行業的初心,走上管理崗位,也能回想起一些禁忌,避免一些錯誤。
其中最重要的就是這條:不要相信一個程式設計師在加班時間寫出來的程式碼。
(軟體工程的學說表明,連正常時間好好寫的程式碼,也不要太相信。不過這不是本文的重點,略過不提。)
(不懂程式碼的人,看到本文中的Java程式碼可以略過,不影響理解。)
創造力的時限
寫程式碼,與寫文章、繪畫、思考複雜問題,並沒有本質上的區別,都是創造性的活動。
每個人的創造力,都會隨著身體狀態而波動。廣為人知的是,一個人年老體衰後,相比年富力強時,創造力會急劇下降。其實,人每天的狀態起伏,也同樣會劇烈影響這一點。
如果是擰螺絲,那麼在精疲力盡、擰不動以前,身體狀態對結果不會產生太大影響。因為擰螺絲的指標非常簡單——擰緊,要做的事也非常機械化——擰,直到它緊,換下一個。
但如果是寫程式碼,有些事,是不能在狀態不好的時候完成的。
比如,在Java裡,遍歷一個外部的List
,做一些處理。如果狀態不佳、做事前想的東西少了點,那麼很可能直接這麼做:
public void handleAList(List<Integer> aList) { for (int i = 0; i < aList.size(); ++i) { // Do sth with List#get(int) } }
這樣做是從C/C++帶來的一種很直觀的做法。有什麼問題嗎?
假如外面傳入的aList
是一個ArrayList
,那麼List.get(int)
的時間複雜度是O(1),算上外面那重迴圈則是O(n);而假如aList
是一個LinkedList
,那麼List.get(int)
的時間複雜度是O(n),算上外面那重迴圈則是O(n2)!
(為不懂演算法時間複雜度評估的人解釋下:在這個場景下,O(n)代表最優、最快,而O(n2)代表不可接受地慢。)
如果時間充分,那麼可以去檢視handleAList()
的呼叫位置,看看它傳遞的是哪種List
;而如果思考得夠充分,考慮到這兩種情況都有可能,那麼程式碼就會做相容處理,改成這樣:
public void handleAList(List<Integer> aList) { for (int i : aList) { // Do sth with i } }
這使用了for-each語法,實際上是用Iterator來做遍歷,無論對哪種List都是總共是O(n)的開銷。
注意,這通常不被看做一個bug,普通的黑盒與白盒測試都是無法發現的。只是你的App會比較卡,或者後臺會比較慢。當需要解決這種效能問題時,可能需要非常經驗豐富的程式設計師,在海量程式碼裡找數週時間——而這一切,在開發之初,只要那個程式設計師狀態好一點,就可以避免。
一個人,每天的創造力是有時限的。在時限外,他不再是一個優秀的創造者,而是一個笨蛋。
(為了便於理解,這個例子非常簡單,以至於不夠貼切。對Java來說,優先使用for-each或Iterator來遍歷,已經是一個共識,是技術素養的一部分。)
失誤率的飆升
程式設計師在寫程式碼的過程中,每天做得最多的應該就是等價變換。
把
if (isSthTrue()) { // Take some actions. }
變換成
if (!isSthTrue()) return; // Take some actions.
這只是最簡單的一種邏輯反轉,實際上還有更多、更復雜的形式。通過這類變化,對程式碼做出調整後,程式設計師可以把程式碼變得更好,或者做到以前不能做的事。
而在加班時間、大腦不那麼清醒的情況下,很可能會寫成這樣:
if (isSthTrue()) return; // Take some actions.
區別僅僅只是少了一個符號,而意義則完全走樣。
這個例子比較簡單,出錯後也很容易在除錯過程中發現、糾正。但是,請不要懷疑,的確會有程式設計師為了這麼個簡單的問題,除錯整整一個晚上!
(
、!
、i
,(字型未配置好時)本就難以區分,眼睛疲勞昏花時,在數百個字元裡掃來掃去,難以分辨(!i
中是否少了個符號,也並不奇怪。而如果換成第二天早晨,很可能只需要瞥一眼。
大多數管理者,往往會對熬夜的程式設計師給出一些肯定,並且允許第二天可以休息一天(有些甚至只給一早上)。但如果他們知道內情,會發現自己其實虧了一天。如果程式設計師正常下班,第二天花一小時解決這個問題,剩下的七個小時可以繼續開發。
還有很多比這複雜得多的變換,或其它型別的程式碼改動,即使在大腦清醒的情況下也需要花費一些時間,認真思考、小心除錯。而如果來了一個問題,你說“必須要今天下班前搞定”,那麼程式設計師會很煩躁,並且越來越煩躁。
煩躁的後果
一件需要冷靜思考、謀定後動的事,如果逼迫人們在煩躁的情況下去做,那麼往往會得到意想不到的糟糕結果。
我有一位前同事,技術實力且不論,心性也不太穩(實際上,像我這種少年老成、未老先衰、找不到妹子都不急的青年,還真不多)。他是一個可以解決問題的人,但是在煩躁的情況下,也經常做出令我瞠目結舌的事。
比如,有一天,專案組要求某個bug必須解決。他搞到晚上9點還沒搞定,找我幫忙。我當時水平也很差,不然也不會那時還在加班,沒能幫他解決,只是因此而知道這件事。他後來在10點半時採用了一個規避方案,然後下班了事。
具體一點是這樣的:在一個class中,有多個地方呼叫同一個Method。其它地方沒有問題,唯獨某個位置的結果不正確。他改成這樣:
private boolean isSthTrue(int sth) { // Implementation A } private boolean isSth1True() { // Implementation B } private boolean isSth2True() { // Implementation C }
本來isSthTrue()
是可以做通用判斷的,他沒有在規定時間內找到根本原因(Root Cause),實際上當時他也根本沒有往發現根本原因的方向去查詢程式碼,而是一晚上都在做一些無效的除錯。最後沒辦法除錯出好的結果,於是給出問題的地方一個特殊處理——新增了isSth1True()
和isSth2True()
去那個出錯的地方頂替。結果,那個bug的確是解決了,但是後來帶出來了另外一個bug。
不過他也達到了目的,當天下班了。
而後來,我在程式碼裡發現了另外一組更早就有的介面。
private boolean isTrueSth1() { // Implemented like B } private boolean isTrueSth2() { // Implemented like C }
我問了一下這兩個Method的作者(另一位同事),他根本沒有看到有isSthTrue()
。
這件事的最終結果是,解決了一個bug,後來又引起了多個bug,連我也跟著一起焦頭爛額。
藉著這個例子,回頭再說一下創造力的時限。
這位同事,之所以不去找Root Cause,是因為專案組的催逼和自身的煩躁,他平時是可以解決問題的。但是為什麼一個簡單問題會這麼難解決,為什麼程式碼裡之前就有一套他要的Method,他卻新寫一個?
外部程式碼環境就不說了,這個class共有2000行。2000行可能並不是特別直觀的數目,既不能說多,也不能說少,取決於這個class幹什麼事。
後來,另一個比較老道的同事,重構(refactor)了這個class,只用了不到500行——這就說明了一個問題,這個class之前就太過冗餘。
約半年後,我水平也提高了些,總體的專案時間也鬆散了些,我花了六週重寫(rewrite)了這個不大的程式碼庫。這個class最終只用了100行,部分功能都獨立封裝到了其它class中。
如果之前,在這個程式碼庫寫就之初,就能有一個充分的時間做一個好的架構設計,不需要rewrite就可以只有100行;而如果時間不太充分,卻能給應有的時間好好寫,也起碼能有refactor後的水平,也就是500行。無論是100行,還是500行,後面出的一大堆問題,都不會出現,或者更容易解決。
這個程式碼庫是怎麼來的?
當初某領導,交給了一個比較厲害的同事,只給一週時間。這位同事加班加點,一週當成兩週用,從別的程式碼裡剝離、拼湊出來了一個編譯能通過的東西——這就是交給我們維護的程式碼庫。
來自專案最底層的復仇
前面說的,無論是寫出隱蔽的bug,還是解決一個帶出倆,其實都是這類事情的陽光面。你沒看錯,這是陽光的一面。
還有我不想多說的陰暗面。
前面說的事情,沒有一類是故意的。無論出事的原因是程式設計師的技術素養不足、加班情況下大失水準、還是原先的程式碼就非常容易誘導失誤,都是程式設計師在認真努力的情況下,不可自控地犯錯。
還有一類是故意的。
比如,去年(2015)攜程那小哥兒,就是怒刪資料庫。當然,他不是為了加班嚴重而如何如何,而是心愛的運營妹子被公司某高層給……(另有一說,雖然有什麼內部的QQ、微信截圖,但這仍然是謠言,實際上是黑客攻擊。)
什麼程度的壓迫,就會得到什麼程度的反抗。
要知道,即使是很努力地去做,也仍然可以出各種問題。而如果要故意搗亂,很多手段,雖然不會引起老闆的注意,甚至可以不被認真的程式碼審查者(reviewer)警覺,但是會客觀地影響產品的品質,讓使用者討厭一個產品,或者讓一個爆款產品最終失敗。
反正埋了雷,領了工資,跳下一家便是——要麼給股票、期權,要麼充分洗腦,或至少給出足夠的加班費(幾年後的醫療費),否則就是這個後果。
我只能說,就我個人而言,最多辭職,不會故意亂搞。這關乎職業道德,關乎我是否意念通達、心境澄明。(坐等穿越去修真:P)
但是,我不能用自己的道德準繩去要求別人,對吧?
而且,永遠不要指望一個人在承受不道德的對待時,仍然能謹守原來的道德。
結語
作為一個軟體專案的領導者,你在要求某個程式設計師加班時,其實就已經在冒險;而如果你經常這麼幹,不要奇怪為什麼專案總是延期,或者一到關鍵時候,總有突發事件。
只要試驗次數夠多,可能性再小的事也會發生;而只要試驗次數更多,小概率事件也會連續發生。
所以,最理智、客觀的觀念就是:欲速則不達,不要相信一個程式設計師在加班時間寫的程式碼。
相關文章
- 千萬不要相信程式設計師在加班時間寫的程式碼!程式設計師
- 程式設計師,千萬不要重寫程式碼程式設計師
- 程式設計師在高鐵上加班寫程式碼被抓拍,網友熱議:苦命的程式設計師!程式設計師
- 幽默:不要相信 10 倍程式設計師/設計師/領導者!程式設計師
- 程式設計師相信的關於時間方面的謊言程式設計師
- 為什麼程式設計師千萬不要重寫程式碼?程式設計師
- 不要浪費時間寫完美程式碼
- 忠告:不要在愚蠢時間寫程式碼
- 三個程式設計師在寫程式碼程式設計師
- 程式設計師十誡:第三誡:不要在休息時間談論程式碼程式設計師
- 不要浪費時間寫完美的程式碼
- 十年程式設計師的告誡:千萬不要重寫程式碼!程式設計師
- 請相信程式設計師的愛情程式設計師
- 相信我,我是程式設計師程式設計師
- 程式設計師的時間估算程式設計師
- 不要浪費時間去寫所謂的完美程式碼
- 為什麼 .NET 程式設計師不需要加班 而Java 程式設計師老加班程式設計師Java
- 最好的程式是程式設計師在處理其他事情時編寫的程式!程式設計師
- 程式設計師只配加班?有錢有閒的程式設計師都在哪?程式設計師
- 程式設計師如何寫出好程式碼?程式設計師
- 好程式設計師不寫程式碼程式設計師
- 程式設計師這樣寫程式碼程式設計師
- 不要將時間浪費到編寫完美程式碼上
- 中國程式設計師與美國程式設計師寫程式碼的區別分析程式設計師
- 為什麼程式設計師喜歡在半夜寫程式碼?程式設計師
- 程式設計師如何寫出更好的程式碼程式設計師
- 程式設計師一週花多少時間程式設計?程式設計師
- 程式設計師,請你不要在坑程式設計師了?程式設計師
- Java程式設計師在寫SQL程式時候常犯的10個錯誤Java程式設計師SQL
- 《程式碼大全》程式設計師們怎樣花費自己的時間程式設計師
- 論跟程式設計師談話的技巧:千萬不要跟程式設計師說,你的程式碼有bug程式設計師
- 程式設計師的時間換算表程式設計師
- 一個程式設計師的時間管理程式設計師
- 當程式設計師寫不出程式碼了……程式設計師
- 程式設計師應該每天寫程式碼程式設計師
- 寫給.NET程式設計師:不要困在自己建造的盒子裡程式設計師
- 程式設計師悲催博弈的加班日子…程式設計師
- 程式設計師最多能用多少時間來程式設計?程式設計師