二十七、沙場秋點兵
前幾個月,公司旁邊的寫字間又搬進一家公司,好似也是做軟體的,而且好像是剛成立的公司,程式員們天天加班,神情很年輕,頭髮很油,穿著大背心大褲衩人字拖,男的女的都有,經常站在通道裡成群的吸煙,或者乾脆席地而坐圍成一堆開會,都不下食堂吃飯,都訂便當,中午晚上都是如此,我經常晚上下班,看見他們不時有人捧著一個便當從辦公室走出來把吃完的飯盒扔進垃圾筒,不知道他們會工作多晚。
近來發現,他們開始有人正常下班了。他們也很少聚在一起抽煙開會了。通道裡有的只是單個的人在打電話,聲音很低,神情普通。偶爾看見他們在外面通道裡開會,也是個個神情緊張或肅穆或很累或木然或沉默。
我想起了一句話:Boy,Slowly,Slowly。
新的產品,新的夢想,大家都很希望能夠把多年積累的知識都用上去,做一個業界一飛衝天的產品。但是,這這個新的團隊呀。
我想起了我剛出道的時候。我現在仍然很慶幸我能經曆一個產品的從萌芽規划到實現到銷售到規模銷售的整個過程,讓我看到了一個產品是如何成長起來的,在成長過程中會遇到哪些問題,是如何克服的。很多程式員沒有這樣的機會,往往一出道,就加入了一家運行N久的公司,團隊是現成的,產品是現成的,自己就是做維護開發而已,沒有完整經曆一個產品生命週期。所以一旦遇到新開發一個產品的時候,就很茫然,不知道如何下手,而且心情很激動,過去一直維護別人的代碼了,很多弊病想推翻重做都不行,現在終於自己可以一展身手了,這回要把自己的想法都加進去,不能留有遺憾,不能重蹈覆轍。於是撲入了自己全部的心血,就連睡覺也不踏實,每日心情澎湃。但時間不長,兩個多月,各種問題就都來了。新技術、新團隊、新產品,一切都是新的,很多交叉出現的問題讓解決異常困難,團隊也出現了煩躁,看淡,疲憊的情緒,大家想儘快結束,但開發才到中間,正是關鍵攻堅要命的時候。
我剛出道的時候,加入了一個新成立的研發中心,才成立四個月,我是第六人。產品還在規劃當中,團隊還在建設當中,技術還在學習摸索當中。
當時的技術總監做了兩件我現在也認為很對的事情:一、他讓所有人閱讀上一代產品的原始碼,整理上一代產品的功能,並且得出上一代產品的功能所映射的客戶商務程序。並且要求指出上一代產品商務程序中的漏洞和矛盾。二、他讓大家通過改造原始碼來學習新技術。
他不僅僅讓大家整理業務,還要畫出來詳細的流程圖,整理出詳細的資料結構。然後安排集中會議讓大家講,講的時候,以流程圖為主,走到哪一步,就進入軟體介面講解,並且講明背後的資料存取到底是處理了哪些欄位標誌, 表之間是怎麼關聯的,到底從哪些表中取出來,表結構設計的有什麼不合理的。
這次沒講明的,這次提問沒有確切答案的,下次繼續講,而不僅僅是講一回。我發現,很多團隊缺乏這種不斷追根到底的魄力。總是虎頭蛇尾,第一次講的很起勁,講的期間出現了自己也沒有理解透的東西,領導只是安排下去再去研究一下,但就沒有了下文。自己下去了看了一下,認為找到了答案,但就沒有再次校正的機會了,於是最應該細究的地方被這樣放過了。我們知道,編寫程式,往往是最細節差異的地方最容易出現問題,而且很少能被測試到,而且維護代碼的程式員往往不清楚這塊是幹什麼的,一旦出現問題很難閱讀懂。
技術總監還讓我們改造原始碼。但這個也是有目標的,就是把控制項都修改成一個統一的體驗風格,沒有DB的控制項,就去尋找。尋找到了,就把這部分代碼摘出來,然後形成我們自己的控制項包,力求不要為了一個小小的控制項,就安裝整個的控制項套件包。實在尋找不到,就自己開發控制項。
學習新技術,我認為這種方法是最好的一種方法。我現在也是這樣指導我的下屬的。
學習新技術,為了怕誤導,一是閱讀官方的例子,如JAVA的寵物店或.NET的寵物店。但我後來我明白了,不能這麼學。因為本來就對新技術陌生,一開始入主的就是這樣的代碼,那麼以後的編寫程式的風格就往往會像這些例子一樣。其實,我們編寫商務應用程式,並不需要這樣的架構風格,也不需要秀那麼多代碼模式。照貓畫虎把我們畫的很累,還扭轉不了已經固有的思維。我們不需要這種看上去很美的代碼。
學習新技術,第二種方法就是找一個網上開源的什麼系統,如某些新技術嘗鮮者做了論壇系統或什麼什麼管理系統。但這種方法也有個弊病,就是他自己寫的代碼有他自己的風格,而且他還處於嘗試期,寫這個東西可能是他為了學習這個技術,而非目標是開發這個管理系統。本來咱們對於新技術就是一張白紙,這下被他帶到溝裡去了。
學習新技術,第三種方法就是閱讀這個新技術本身的原始碼。可惜本來就對新技術不熟悉,而新技術本身的原始碼更是複雜,看的雲裡霧裡,吃力看不到進展,欲想放棄。
所以,學習新技術,最好是學習基於新技術的第三方的外國開源原始碼。他們對新技術理解快理解深入,他們應用新技術不是為了嘗試新技術或者秀新技術,他們是為了完成他們的一個實用產品。我們當時為了摘出某個控制項,幾乎閱讀了那個控制項套件包的所有原始碼,並且理出了原始碼的結構思路,否則我們無法確定我們遺漏了什麼,會不會有BUG。
但是,現在回過頭來看,方法是對的,時機卻是錯的。
我們是新團隊、新產品、新技術,很多我們尚未瞭解清楚的,我們卻把我們學習新技術後得到的控制項應用到了我們以後的正式產品中,並且作為基礎應用。這給以後的發展帶來了幾乎是災難性的打擊,我最後費了好大的勁才算把基礎重構並且穩定住,否則基礎崩盤了,上面的應用就不可收拾了。
所以,我現在都是盡量限制使用新技術。也就是說,不會讓新產品、新團隊、新技術這三個新都同時出現,風險太大了。而且堅決不使用新技術作為基礎技術。
我們還犯了一個錯誤,就是正式開發的時候,我們一上手就開發基礎架構。大家都知道一個系統的基礎架構的重要性。但是我們卻用剛剛學會的新技術開發我們以後業務模組都要深度依賴的基礎架構。我想起了某公司一套戰略性的大型產品的開發:用的是新技術JAVA,大家都還是新團隊,做的也是新產品,全體程式員都已經封閉開發了,居然有人提出了一套自己也未經過商業規模應用驗證的基礎架構,並且自己實現了一個小DEMO。大家一看這個小DEMO非常有思想,就決定讓整套產品線都應用這套基礎架構。
我想象他們的痛,和我很神似。所以,我現在如果面臨新產品、新團隊、老技術,我都不會讓大家一上手就開發基礎架構。
去年,我就面臨了一個老團隊、老技術,但是是全新一代產品的開發。
具體情況是這樣的,經過幾年發展,我們的現有產品漸漸老化,所以決定要開發新一代的產品。上一代的產品是C/S結構,而且是適合單客戶使用的。這次,我們要開發B/S結構,而且是適合集團客戶使用的。
讓上一代產品的Team Dev繼續維護上一代產品。讓新一代開發由新的Team Dev去執行。所以,我們就招聘了新的團隊(當時公司對開發新產品有不同的利益衝突團體,還沒有達成一致,招聘新團隊既有為新一代產品開發做準備的目的,也有其他的目的,造成這支新團隊的打造過程中往往出現兩種極端:要麼好幾個人都管,要麼三不管)。剛開始並沒有去動手設計與開發新一代系統,而是為客戶定製開發了一兩個其他IT項目。所以說還算接觸了客戶行業,大家彼此在一起工作也快八個月了,算是一個老團隊。
但是這支團隊對客戶、對現有的產品並不深刻瞭解,雖然我給團隊多次講解過業務,也讓大家分析學習現有產品,閱讀現有產品的說明書,根據新的業務模式也組織大家一起分析業務設計功能、編寫功能設計說明書,但理解上確實還不夠令人滿意,大部分人還是似懂非懂。遺憾的是,在老闆的規划下,新一代的系統開發必須啟動。
如果這時候開發基礎架構,大家根本不理解以後這個基礎架構之上要編寫什麼樣的應用代碼,那麼這個基礎架構就會變成形式,以後的應用代碼怎麼都覺得這個基礎架構沒什麼用,用起來也是格格不入,不像是螺絲對螺母那樣合縫。
所以,我先安排團隊開發了系統管理工具。這是個沒有具體業務的,而且通用的,而且也是基礎架構的一部份的開發工作。但是,由於系統管理工具,涉及到了新的組織圖模式,新的許可權控制模式,這是大家不太熟悉的。而且編碼架構風格和他們以往的開發不太一樣。所以開發起來也是疑問不斷,需要即時複查代碼,即時解答問題。
終於開發完畢,我們開了一個總結會。大家都總結了對這次開發的體會,並且討論出來以後再遇到這樣的問題要如何解決,每個人的分工和人員配合流程再次確定,功能和功能的用意再次給大家講了一次,對於新的編碼架構風格再次講了一次好處和用意。大家都說:如果在開發前就把這些講清楚了,那麼開發就不會遇到這麼多問題了。我說:開發前我就是這麼講的,但是大家都不理解。這次經曆過來了,就明白了。
接下來該怎麼辦?
我說:重新開發一次系統管理工具。時間為期十個工作日。
大家都啊了一聲。幹嗎要重新開發,好不容易開發出來就這麼廢了?
我對大家說了我的經曆,我說:系統管理工具是基礎架構的一部份,是以後使用者很常用的工具,而這個工具卻是我們在不清晰不熟練的階段開發的,我們如何能把這麼重要的基礎功能交付給客戶呢?尤其以後這個工具要和需要系統結合,這個工具的資料結構目前還無法支撐以後的眾多串連,你們也看到了許多遺憾,我們不能一起步就是個瘸子。
大家又問:那過去的代碼我們還能用嗎?
我說:你們自己看需要。我既不贊同你們盡量使用過去代碼,也不贊同全部重新編碼。如果你們想把一個有殘疾的代碼上改造成一個優秀的代碼,我說不可能,過去的很多缺陷會牽絆著你。你為了保留過去的代碼,你就會向過去妥協,而把絲絲缺陷帶了進來。每個人每個功能都留了一點點小尾巴,那麼所有開發的功能總和出來的缺陷就是一個大問題。所以大家自己看著辦,先重新寫,需要用的時候自己就COPY出來。
果然,理解了清晰的功能和功能用意的程式員,開發起來很快,畢竟都寫過一次系統管理工具了,也是老技術、老團隊了。半個月完成工作。
我問:上一次你們編寫的系統管理工具代碼用了多少?
他們回答說:不到20%。明白了思路,重寫起來很快,反正沒有什麼高難度技術。本來想COPY舊代碼,發現老有關聯,摘不乾淨,還不如重新寫一個來的快。
我說:好。咱們下一步就實現一個咱們系統中最簡單的也是比較邊緣的一個業務子系統。在開發中大家重點發現需要什麼公用功能,咱們都提煉出來,就會形成咱們的基礎架構的一部份。
這個簡單的業務子系統開發了出來,我又開了總結會。
大家這次都發言熱烈:我現在終於發現了系統管理工具和業務子系統之間的關聯關係了,他們有很多代碼能夠共用。由於這次開發業務簡單,而且經過上次系統管理工具的開發,開發方法和代碼方法都已經熟悉,對於系統管理工具的認識也深刻了許多,所以這次我開發業務系統的時候,還順便把過去的系統管理工具的代碼進行了重構,發現了不少可以共用的部分。我發現,這些基礎代碼總結了出來之後,好像系統管理工具也是從這些公用代碼基礎之上開發出來的一個特殊的業務子系統了,所有子系統都依賴這個基礎代碼架構。過去本來系統管理工具的風格和業務子系統不一致,這次重構,一下子都統一了。
我笑的很開心,似乎我過去的心結終於可以解開了。