======================html
實事求是的講,寫《【野生程序員】:優先招聘》的時候,是帶着情緒的。其後也有反思,是否是我杞人憂天了?尤爲是下面開始的幾條評論,如「都是混口飯吃的不容易」,「何之內外之分,中華兒女非山傾河泄而不能一氣前指,千年亦是如此」等,讓我感受多是我過於敏感了。但隨後一些人長篇大論,讓我明白,這篇博客仍是有意義的。程序員
想想,招聘啓示裏,大家要求「計算機專業本科以上學位」,我「無計算機專業相關專業文憑」優先;而後,大家就炸了!咱們沒有歧視,你這纔是歧視!你自卑你憤青你酸你難成大器……我無力反駁,只是想說,每一個人的言行都是他心靈的鏡子。謝謝大家!數據庫
其實,我沒有想挑起科班/非科班之爭(雖然可能結果會超出個人預料),個人本意是想給「非科班」的同窗鼓氣,緩解他們身上的壓力,讓他們看到但願,給他們力量,讓他們相信,徹底能夠在更艱苦的環境下自學成才,並且結果不會比「科班」的差!但你必定要委下身段踏踏實實的去學,一步一個腳印的去作,自卑自大爭吵辯駁都無助於你的成長。請牢記:言語沒有力量!bootstrap
另外,願意聽一句的「科班」同窗,「無計算機專業相關專業文憑」優先,並不是徹底出於義憤。都是築基,你是名門大派用資源用丹藥堆出來的,他是一路苦修戰鬥領悟突破的,你以爲誰更有潛力?因此啊,放下那些虛榮驕傲,真正的去戰鬥吧!畢業三年之後,是沒人再看你的學歷的。架構
另外聲明一點,對老趙沒有任何意見,除了景仰。他針對的是培訓機構我徹底明白,但仍然不能贊同。因此我說,「每一次看到這一段文字,個人內心就會有一種難以言表的複雜情緒」,至於如何複雜,不是說了嗎?難以言表啊。工具
======================post
好,心平氣和以後咱們繼續討論技術問題。在帶隊的過程當中,性能的問題還比較好解決,最消極的想法,「好啊,多一事不如少一事,你讓我無論還不簡單?」,但要求寫測試代碼,那就炸鍋了!以個人經歷,「測試驅動」是一個最具爭議的話題,沒有之一。吹捧者和反對者涇渭分明,並且都有大量的論據和證實。記得博客園曾經有一篇文章,大意是:「公司付錢給你不是讓你寫測試代碼的」,下面一片狂贊。性能
在我本身的項目開始的時候,我是放棄了測試驅動的(呵呵,還找到了原文),裏面總結得很準確,最大的緣由是「懶」。但最後讓我下定決心開始「測試驅動」實踐的,是我一次花了兩天一晚上都沒調出一個Bug,垂頭喪氣筋疲力盡以後,迫不得已的接受了這個現實:測試仍是頗有用的——即便是本身寫的代碼。我以前的系列博客,也已經反覆的強調,架構是一種「無奈」,是現實是問題驅使你去作一些其實你原本不想作的事情。你沒法理解一些看起來像「脫了褲子放屁」同樣的行爲,一般只是由於你沒有遭遇過那些現實那些問題。(看看,大學能教你這些東西麼?)單元測試
即便你沒有多少開發經驗,你也應該可以想象,單元測試最大的問題,就是它須要花時間花精力去寫,那麼這個花費是否值得呢?這仍是由你架構的目標決定的,或者你的需求決定的。若是系統是一次成型交付使用,此後幾乎不會更改的,那麼一次性的手工測試就夠了;但若是你的系統是會被「千錘百煉」的不斷折騰修改的,那麼這個測試就是頗有必要的。最簡單的考慮:每一次更改,我都要手工測試一次;那還不會如我多花點時間,弄個「自動化」的東西出來。單元測試,其實就能夠理解爲一種自動化的測試工具。測試
可是「自動化」的理由還遠遠不夠。由於你立刻想到的,每一次需求變動代碼調整,測試代碼也得相應的改呀?沒有測試代碼,我就只須要改開發代碼;如今有了單元測試,我還得再改測試代碼。原本我只維護一套代碼,如今我憑空增長了一套代碼也須要維護,這不是增長了維護成本,不是和你「可維護性」的架構目標背道而馳了麼?是一套代碼好維護呢,仍是兩套代碼更好維護?
這是一個很是好的問題,適用於不少情景(好比分層架構,你說分層解耦,實際上還不是一改就得從UI層改到數據庫,每一層都得改?)。我能給出的回答大概有:
1、不管有無單元測試,開發代碼進行修改以後,是否是都要進行測試?沒有單元測試,並不表明你的代碼就不須要測試了,只不過是你手工的去測試了一遍而已。切記:你的工做並不僅是把代碼寫出來而已!
2、進行手工測試,和更改單元測試,二者的耗費比,會根據測試重用的次數而變化。一次手工測試可能須要5分鐘跑完,更改單元測試代碼可能須要20分鐘,但若是這測試會跑100遍,單元測試完勝手工測試。
3、你說,哪裏喲?什麼功能會改100遍?我沒說你的功能會改100遍,我說的是測試會跑100遍。有區別麼?你可能還在犯迷糊,是吧?好吧,咱們講個故事。
有一個小夥子,他很不情願寫測試代碼。老闆拿他沒轍啊,也沒那麼多精力和他磨牙,因而老闆本身寫單元測試。這小夥子的代碼提交以前要review,老闆總能一次次的找出它代碼的問題。他改的是登陸,老闆告訴他積分系統被他改出了問題;他又去改積分,老闆又告訴他消息通知系統被他改壞了;他又去改消息系統,老闆告訴他登陸仍是有問題……因而他崩潰了,「這TM什麼一個爛系統」?最終他終於回過神來了,爲何老闆總能知道這裏的改動會影響那裏呢?老闆的思惟有這麼嚴謹?老闆躲在一旁偷笑,就不告訴你,「其實我就是跑了一遍單元測試而已」。
這個老闆就是我。我故意的,就不一次性的告訴他全部的問題,就要這樣一次次的折磨他,讓他的痛苦能刻入骨子裏去。最後,我還要問他:
這一次,他服氣了。後來他用NUnit用得麻溜麻溜的。每一次改動,若是有意想不到的未經過test case,他都會很激動的給我張截圖,順便發發牢騷。我微笑不語,那種滿屏綠燈經過的踏實,和意外爆出紅燈以後的驚喜,沒有經歷過的人,是沒法體會的。
因此其實當對象間的關係變得愈來愈錯綜複雜,像一張密密麻麻的網同樣以後,一個局部的改動就頗有可能會觸發極其複雜的連鎖反應。因此爲了保險起見,全部可能相關的組件都應該進行測試(所謂的「迴歸測試」)。這時候若是隻有純粹的手工測試,會面臨兩個問題:
好的,我假設你已經認識到了單元測試的重要性,並開始摩拳擦掌,躍躍欲試。接下來我得給你潑一大瓢冷水:單元測試不是那麼好寫的!從某種程度上講,寫單元測試比寫開發代碼還難。可貴我工做的全部公司,沒有一家有過成功的案例。
大概是幾年前,我在公司修bug,老大告訴我,「你這個功能比較核心,跑一下單元測試吧」。
「哇塞!咱們有單元測試?」一種高大上的感受迅速瀰漫全身,終於見到傳說中的Unit了!
搗鼓了一會,能跑了,試試看——個人個媽呀?怎麼這麼多紅燈?我真被嚇住了,這都是個人改動形成的?
老大就是老大,鎮定自若,「數一下有多少個通不過?」
「啊?」我覺得我聽錯了,數多少個通不過有什麼用?得把他們所有弄經過啊?!
搞了一下子,才終於弄明白了,把我改動先後的代碼分別跑一遍,對照一下經過失敗是否是同樣的,只要是同樣的,就OK了。好比,之前是8個通不過,如今仍是8個通不過,這樣就能夠了!
我一直不明白,爲何不把那8個通不過的單元測試給弄成經過呢?這樣擺着究竟算什麼?直到我本身開始寫單元測試。坑爹啊!處處都是坑,跳出小坑進大坑,大坑下面還連着小坑,前面是坑後面是坑,一堆一堆的連環坑……
單元測試寫出來容易跑過難!並且跑不過的緣由還不是你的開發代碼邏輯錯了,而是測試環境/數據出問題。要測試,必定要有數據,這個數據的構建,徹底不是咱們所想象的那麼簡單。以咱們創業家園項目裏的積分系統爲例,假設一個簡單的需求:博客被點贊,博客的做者應該得到必定積分,該積分數量是由點贊人目前全部的可用幣轉換而得來的(已簡化,具體可參考文檔:積分)。要準備的數據就有:博客一篇,要有做者,做者已有積分;點贊人一名,有必定數量可用幣。若是隻是這樣,還能夠接受,但其實下面會有一堆的問題:
反正當時是寫得我直接摔了鼠標!寫得憋屈啊!並且我仍是徹底隔絕了數據庫的,真不知道那些要從數據庫裏取數據來跑單元測試的,是怎麼作的?這時候我一會兒就明白了,實際工做中加班趕進度,一個接一個的填坑,連重構的時間都沒有,怎麼可能還擠得出時間來寫單元測試?就算開始雄心勃勃的寫了,隨着系統日益複雜,維護單元測試的成本也與日俱增,甚至複雜度更甚開發,因此放棄也就成了絕大多數項目的惟一選擇。
在公司上班麼,大多數人都是這樣的,能推就推。咱們開發寫完了代碼,基本上能跑了,就該交給測試人員了呀!天經地義的嘛,是否是?並且測試的時間是不會計算到個人項目開發時間裏的,我總算是按時完成了開發任務。累壞了,休息一下,讓測試的忙活去吧,哈哈……
但我是個光桿司令,我沒測試人員啊!曾經有那麼一兩個時候,我真準備招一兩個測試人員的。但好在我天生的節儉美德(也就是「摳」啦)讓我冷靜下來。我就想啊:測試只能告訴你出了bug,不能告訴你根源啊。沒有單元測試,我單步調試,不也折騰了兩天了麼?這是系統自己的複雜性,或者代碼組織的不合理形成的,不能歸咎於單元測試。不仍是有這麼多開源代碼都有詳盡的單元測試麼?他們是怎麼作到的呢?在單元測試上的付出,最終必定會得到超值回報!想一想沒有單元測試的公司,那超級龐大的測試團隊,或者四處冒煙的系統,你願意走這麼一條路麼?
因此我不斷的告誡本身,不要着急,冷靜細緻。終於一步步抽絲剝繭,把這一團亂麻一點點的概括整理,最終還真被我找到了一條路子,一個個的單元測試都慢慢完成經過了,開發代碼裏潛在的一些問題也浮出水面,被我一個個的消滅。最後再跑一遍單元測試,一路綠燈,哈哈!更奇蹟的是,困擾我兩天的bug不知道何時消失了?
後來,我看到這樣一種說法:可測試的代碼不必定是好代碼,但壞代碼幾乎是不可能被測試的。深覺得然!深度耦合的代碼,寫他們的單元測試,難於上青天;但反過來,咱們能夠以可測試爲標準,不斷的完善重構開發代碼,只要這樣堅持下來,最終代碼的質量怎麼都不會差到哪裏去。
因此,於我而言,單元測試是否有價值的爭論能夠休矣!不如換個角度,想想,怎樣才能把單元測試堅持下去。
最後,若是有心的同窗就會注意到,我一直用的是「單元測試」,而不是「測試驅動」。由於測試驅動是一個更廣闊的概念,是一個更嶄新的天地!單元測試只是其中的一小部分,在下一篇博客,我會講解我是如何試着將測試驅動的概念運用到項目開發管理中去的。這裏,須要強調的一點:先寫測試。
一上手就寫開發代碼,寫完了才寫單元測試。這是不少開發人員的習慣,我也常常犯這樣的毛病,一不留神就忘了。這樣作最大的問題就是,沒有真正實現「測試驅動」。你實際上仍是由開發在驅動,那麼很天然的,測試照着開發的if...else...寫一遍,有什麼意義呢?這樣作下去,就會不斷的強化「測試無用累贅」的印象,由於測試就是簡單的把開發代碼重寫一遍而已。我開的藥方是:
第三條可能有同窗沒法理解,不是說單元測試很重要麼?爲何要等到出了bug才寫?答案是:偷懶唄!記住,咱們程序員是世界上最懶的人,沒意義的事歷來不作!你先寫開發代碼再寫測試真的沒意義,沒意義就乾脆不要作了。但你能夠開啓「樂觀模式」(或者「Lazy模式」?),先樂觀的認爲,個人代碼沒問題,或許真的就沒問題呢,是吧?若是真出了問題,作一個補救,這個時候就應該用單元測試把這個問題表現出來,由於他根據墨菲定律,它這裏出了問題,之後就頗有可能繼續出問題。這個時候,就不要再偷懶了。
(未完待續)