開發團隊的效率
我之前寫過一篇叫《加班與效率》的文章,從概念上說了一些我對“效率”的認識,但是那篇文章趨于概念化,對于一些沒有經歷過這樣的環境的同學來說,可能會覺得太抽象了。很早以前就想寫一篇更具體一點的,可執行的文章與《加班與效率》這篇文章相輝映,并再把我兩年前在杭州QCon上的那個“鼓吹工程師文化”的《建一支強大的小團隊》(新浪微盤)的觀點再加強一下。
但是我遇到了一些思維方式上的麻煩——我講的總是從我的經歷背景出發,沒有從其它人的經歷背景來講。這就好像,我在酷殼里說了很多東西(比如:專職的QA,Code Review很重要,編程年齡,創業的,Rework的……),有好些人覺得是不可能甚至太理想,其實我說的那些東西都是實實在在存在的,也是我所經歷過的。于是,不同的經歷,不同的環境,不同的眼界,造成了——有些人不理解我說的,而我也不能理解他們所說的。
所以,過去的這段時間我一有機會就找一些人交流并觀察一些身邊的事情,并去試著跟從和理解那些我不能理解的東西。現在覺得差不多了,所以,寫下了這篇文章。(但越是去理解對方,我就越堅持我的觀點,所以這篇文章可能還是會出現雞同鴨講的情形,無所謂了)
本文不討論任何業務上的效率問題,只討論軟件開發或是軟件工程中的效率問題。雖然產品和業務上的效率問題是根本,但是因為本文不是拉仇恨的,我也不想混在一起談,所以請原諒我在這里先說開發團隊的,以后重新開篇文章專門談產品和業務的。
我下面會羅列幾個非常典型的開發方式——軟件開發中的“鎖”,接力棒式軟件開發,保姆式軟件開發,WatchDog軟件開發,故障驅動式軟件開發。
軟件開發中的“鎖”
如果你搞過并發編程,你一定知道什么是“鎖”,鎖就是用來同步和互斥。我發現有好些開發部門里的各個開發團隊間存在很多鎖。比如:
- 技術能力上的鎖。有一個項目需要在不同的地方做開發,這些模塊用到不同的技術,比如:Java, C/C++, Python,Javascript,但是,這個團隊里的每一個開發人員就只懂一門語言,于是,需要配合,需要任務排期,同步互斥鎖就很多,于是,一個本來只需要2個人干3周的的工作變成了8個人干兩個月。
- 負責模塊上的鎖。同理,不同的人負責不同的模塊,于是一個項目要動好多模塊,那么你就需要把這些模塊的人找過來,和上面一樣。每個人都有自己的時間安排,人越多,鎖越多。于是,一個來來只需要2個人干2兩周的事,變成了7、8個人干一個多月。
我上面并非瞎扯,這都是事實。我們可以看到,
- 時間鎖、進度鎖。這堆有不同技能或是負責不同模塊的開發人員有鎖,有鎖你就要等,他們有自己的安排,所以,要協作起來,你就需要排期,去同步。而參與的人越多,你的鎖就越多。你協調他們的時間就更復雜。
- 溝通鎖、利益鎖。而且,最恐怖的事情是,他們之間的溝通成本巨大。他們會花大量的時間在討論,一個功能是實現在你那邊,還是我這邊,每個人都有自己的利益和算盤。無形中增加了很多推諉、官僚和政治上的東西。
有時候,我們會覺得分工和分模塊是產生效率的前提,但是實際情況并不是這樣。我們也可以看到,所謂的“分工”被徹徹底底的濫用了。他們把“分工”當成了永遠只干一件事的借口。
【解決方案】
一個程序員應該能夠掌握多個語言,也能夠負責多個模塊甚至不同的職責。如果一個程序員覺得多學習一門語言,多掌握一個模塊是件很困難的事,那么這個程序員本質上是不合格的。
“接力棒式”軟件開發
在有各種“工作鎖”的軟件開發團隊里,一般都無法避免“接力棒式”的開發。也就是說,底層的C程序員干完了,交給上層的Java程序員,然后再交給更上層的前端程序員,最后再交給運維人員。這就是接力棒式的開發。
而且,更糟糕的是,如果在引入了軟件流程下,這種“接力棒的方式”真是會把你搞崩潰的。比如下游團隊開發一個月,交給QA測試一個月,再交給運維分步上線一個月,然后,上游團隊拿到下游開發的API后開發一個月,再交給自己的QA測試一個月,然后再交給自己的運維上線一個月,于是,半年就這樣過去了。這是一個由一個一個小瀑布疊出來的一個大瀑布。
哦,你會說,這個好辦啊,上下游不會先商定好接口么?然后做并行開發么?是的,這是其中的一個優化方式,但是需要很好的接口設計。但是,在實際過程中,你會發現(這時我并非信口開河,我說的都是事實),
- 如果這兩個上下游團隊在一起還好辦,要是不在一起,那么,實際情況是,后面的團隊會等到前面的團隊提測了,才開始開發,本質上就是串行開發的。
- 如果有更多的團隊呢?比如:A團隊 -> B團隊 -> C團隊 ->D團隊呢。接口就變得非常地關鍵了。而在實際情況下,因為沒有好的接口設計人員,所以,在開發過程經常性地修改接口,或者是因為接口不好用也只得忍著。
【解決方案】
我以前寫過一篇叫《IoC/DIP其實是一種管理思想》,對于這種接力棒的方式,應該反過來,如果業務應用團隊是A團隊,那B/C/D團隊應該把自己的做成一個開發框架也好,服務化也好,讓應用團隊自己來接入。比如:前端做好一個前端開發框架,PE做好一個運維開發框架、各種工具,共享模塊團隊做好開發框架,讓應用團隊自己來接入,而不是幫他做。你會發現,在這么多團隊各自P2P勾兌出來的很隨意的接口的所帶來的成本已經遠超過一個統一標準的協議。
“保姆式”軟件開發
所謂“保姆式”軟件開發就是——我只管吃飯,不管做菜洗碗,就像——衣來伸手,飯來張口的“小皇帝”一樣,身邊有一堆太監或宮女,不然生活不能自理。這種情況經常見于開發和測試,開發和運維間的關系。很多公司,測試和運維都成了開發的保姆。
我就能看到,很多開發快速寫完代碼后基本上都不怎么測試就交給QA去測試了,QA一測,我草,各種問題,而只會做黑盒的QA并不能馬上就能確定是代碼的問題還是環境的問題,所以還要花大量時間排除不是環境問題,才給開發報BUG。很多問題,可能只需要做個Code Review,做個單測就可以發現了,硬要交給QA。運維也是一樣的,開發出來的軟件根本就沒有考慮什么運維的東西,因為有運維人員,所以我才不考慮呢。
這和我們帶孩子的道理是一樣的,對于孩子來說,如果父母幫孩子做得越多,孩子就越覺得理所應當,就越不會去做。
“保姆式”開發一般會進化成“保安式”開發。
- 因為你的團隊開發人員的能力不行,設計不行,Code Reivew/UT不做,你就只能找堆QA看著他。
- 因為Dev/QA只管功能不管運維,所以,還得找堆運維人員看著他們。
- 因為你的技術人員不懂業務,不懂需求,需要再找個BA,找個產品經理來指揮他。
- 因為你的技術人員不會管理項目,所以,再搞個項目經理,找個敏捷教練、以及SQA來管著他。
就這樣,你不行,我找人來看著你,看你的人不行,我再找人來看著看你的人……層層保姆,層層保安。于是,你就會發現,團隊或部門里的人員越來越多,你整天都在開會,整天都在互相解釋,互相爭吵,會扯淡的人越來越多。那還有個屁的效率。
網絡上一個非常經典的圖片,來源不詳,程序員在挖坑,其它人站在當監工
【解決方案】
1)不要招只會寫代碼的“碼農”,要招懂“需求”,注重“軟件工程”和“軟件質量”和“軟件維護”的“工程師”。
2)最好的管理,不是找人來管人,而是自己管自己。
3)組織和團隊中支持性工作的人越少越好,最好不要。
4)服務化。我服務于你并不代表我要幫你干活,而是代表——我要讓你干活干得更爽。
我在微博上說過下面的話,(大家可以體會一下保姆和服務的差別)
運維要用“云服務”的思路去做。如果一個公司內的運維團隊開發出一堆工具,讓做應用開發團隊可以很容易地申請機器、存儲、網絡、中間件、安全等資源,并很容易管理、監控和部署應用,并提供運維資詢。而不是幫應用開發團隊干活擦屁股當保姆。那么,這個公司就會不經意地做出一個云計算平臺來了。
“WatchDog式”軟件開發
什么是WatchDog?就是說——為了解決某個系統的問題,我要用一個新的系統去看著它。
- 我的系統架構太復雜,出了問題不好查找。咋辦?那就搞個專門的特殊的監控系統吧……
- 我的系統配置太復雜,容易配錯了。咋辦?那就加一個配置校驗系統吧……
- 我的系統配置和真實的情況有時候可能會不一性。咋辦?那就加一個巡檢系統吧……
- 我的系統測試環境和線上環境有時候會搞混了。咋辦?那就為線上環境加一個權限控制系統吧……
- 我的系統有單點,那就加個負載均衡器吧,負載均衡器的單點呢?那就再加個等價路由器吧……
做加法誰不會?就不想去簡化一樣系統嗎?就不能不拆東墻補西墻么?這些了系統加的越來越多,我看你以后怎么運維。
一開始沒有想清楚就放到線上,然后,出了故障后,也無法重新設計和重新架構,只能以打補丁地方式往上打,這就好像一個本來就有缺陷的樓沒有蓋好,你要拆了重蓋是不可能的,也只能不停地打補丁了。字是一只狗,越描越丑。
【解決方案】
1)設計想好了再做,多評估幾個設計沒壞處,簡化,簡化,簡化。
2)殘酷無情地還債,就算是CEO來了,也無法阻止我還債的腳步。
“故障驅動式”軟件開發
WatchDog式的軟件開發通常來說都是“故障驅動式”軟件開發的產物。這種開發方式其實就是在表明自己智力和能力的不足。以上線為目的,上了線再說,有什么問題出了再改。
上面的老大或是業務方基本上會說,沒關系,我們不一開始并不需要一個完美的系統,你先上了再說,先解業務的渴,我們后面有時間再重構再完善。而有的技術人員也會用“架構和設計是逐步演化出來的”這句話來證明“故障驅動”開發是值得的。
我同意逐步迭代以及架構演化論,但是,我覺得“系統迭代說”和“架構演化論”被徹徹底底地成為那些能力有限甚至不學無術的人的超級借口。
你們有沒有搞錯啊?你們知道什么叫迭代,什么叫演化嗎?你們知道,要定位一個線上的故障需要花多大的力氣嗎?(看看這篇文章你就知道了)你們知道,隨隨便便去應付局部上你會快,但總體上來說你會慢。
雖然,我看到那些系統在一個又一個的故障后得到一點又一點的改善,但是我想說,為什么一開始不認真不嚴謹一點呢?我從來就沒有見過一個精良的系統是靠一個一個的故障和失敗案例給堆出來的,就算是Windows 95/98這樣史上最爛的操作系統,如果沒有設計精良Windows NT的補位,Windows也早玩完了(看看IE的下場就知道了)。
【解決方案】
1)基礎知識和理論知識非常重要。多多使用已有的成熟的方案是關鍵。
2)對技術要有一顆嚴謹和敬畏的心。想清楚了再干,堅持高標準,Design for failure! 很多事情都急不得。
其它開發方式
其實,這樣的事情還有很多。比如:
1)配置管理上的問題
對于源代碼的配置管理,其實并不是一件簡單的事情。配置管理和軟件和團隊的組構的結構非常有關系。我看到過兩種非常沒有效率的配置管理,一種是以開項目分支的方式來做項目,同時開很多分支,分支開的時間還很長,導致merge回主干要花大量的時間去解決各種沖突,另一種是N多的團隊都在一個代碼庫中做修改,導致出現很多復雜的問題,比如某團隊的改動出現了一個bug,要么所有的團隊的功能都得等這個bug被修復才能被發布,要么就是把所有的改動回滾到上一個版本,包括其它團隊開發的功能。很明顯,軟件模塊的結構,軟件的架構,以及團隊的組織形式都會嚴重影響開發效率。
2)人肉式的軟件開發
大多數的軟件團隊和主管都會用“人手不夠”做為自己開發效率不夠的借口,而大多數故障發生的時候,都會使用更重的“人肉流程”來彌補自己能力的不足。他們從來沒有想過使用“技術”,使用更“聰明”的方式來解決問題。
3)會議驅動式開發
人多了,團隊多了,想法也就多了,溝通也就多了,于是需要不停得開會開會開會。
總結一下
綜上所述,我有如下總結:
1)軟件工程師分工分得越細這個團隊就越沒效率,團隊間的服務化是關鍵的關鍵。不管是從語言上還是從軟件模塊上的人員分工,越細越糟糕。服務化不是我要幫你做事,而是我讓你做起事來更容易。
2)你總需要在一個環節上認真,這個環節越往前就越有效率,越往后你就越沒效率。要么你設計和編碼認真點,不然,你就得在測試上認真點。要是你設計、編碼、測試都不認真,那你就得在運維上認真,就得在處理故障上認真。你總需要在一個地方認真。另外一篇文章你可以看一下——《多些時間少寫些代碼》
3)“小而精的團隊”+“條件和資源受限”是效率的根本。只有團隊小,內耗才會小,只有條件或資源受限,才會逼著你去用最經濟的手段做最有價值的事,才會逼著你喜歡簡單和簡化。
4)技術債是不能欠的,要殘酷無情地還債。很多事情,一開始不會有,那么就永遠不會有。一旦一個事情爛了,后面只能跟著一起爛,爛得越多,就越沒有人敢去還債。
5)軟件架構上要松耦合,團隊組織上要緊耦合。
6)工程師文化是關鍵,重視過程就是重視結果。只重視結果的KPI等同于“竭澤而漁”和“飲鴆止渴”。