在小型團隊中如何做技術儲備
如果要利用第一步的成功,來擴展一個事業,就必須要想辦法滿足更多的需求,從而占領更大的市場份額,因此需要在“產品”和“團隊”兩方面都做準備。
特種兵小隊在踏出項目成功的第一步之后,老板往往都希望他們能達到更多的目標,比如更多的功能需求,更好的性能表現等等, 因此,他們也會獲得更多的資源。當然,在這個過程中,特種兵小隊必須要改變的之前的工作方法,否則就會陷入“再而衰”的危機之中。
作為項目經理或者制作人,他們有可能會需要“兌現”之前因為付出努力所對應的回報,否則就會覺得工作沒有得到認可。而對于主程序員等主要開發人,除了他們希望有所“兌現”以外,還可能覺得這個項目對于自己的專業發展已經沒有價值了,沒有更多的學習空間和應用知識的空間,因此就會想換一個項目去做。對于支援人員來說,他們往往認為既然項目已經“上了軌道”,就沒理由讓他繼續兼著“打苦工”了,對于分派的任務可能會有所懈怠。
因此在項目轉型的過程,是問題最集中爆發的時期。所以我們必須要在小型項目轉型之前,做好幾個事情:
-
論功行賞 :小型項目的艱苦加班和多種不同工作的壓力,是需要給予一定回報的,不管是加工資、發獎金、升職位,還是一些別的晉升和嘉獎手段,都必不可少。這對安撫團隊的“急躁”心理具備重要作用。
-
溝通轉型之后的需求 :人對于改變總是害怕的。因此這個團隊和這個項目,為什么要變化,為什么要加入更多的人和別的資源。目標是想做成什么樣,都需要有充分的溝通。否則一方面容易給成員過高的期望,另外一方面也讓原本大家都很清楚的項目目標變得模糊,從而增加猜忌。
-
總結經驗教訓 :項目有變化,總會有人離開。而項目的經驗和教訓卻不應該隨著人的離開而消失,特別是人數本來就少的情況下。爭取時間記錄整理項目經驗,是為下一個階段做好工作所必須的準備。
-
優化程序代碼,提高重用性 :小型項目代碼結構都不會特別的完美,有很多修補的痕跡。但是如果要進入一個新的階段,讓很多人去維護這樣的代碼,那么開發的效率就會降低。并不是說一定要整體重構,而是應該檢視所有的代碼,把那些明顯的業務功能模塊,特別是詳細的、復雜的商業邏輯或者業務細節的實現代碼,切分的更細,都包裝好。因為項目發展,可能對于技術需求,比如性能、穩定性、擴展性會有更多要求,但是對于業務邏輯,修改并不會很多,所以這些業務邏輯代碼,實際上是更常被“重用”的部分。根據業務邏輯封裝代碼本身就是一門技術,所以在做這個事之前,程序員除了要學習重構的種種知識,還要對業務需求本身進行思考和總結。只有完成了這些工作,團隊在需要增加一些功能時,也能更加輕松簡單的去完成。曾經有一個電子商務網站,在第一版面世的時候,為了提高開發速度,代碼的結構并沒有得到特別的關注;但是面世后隨之而來的各種性能需求、特殊的商家的要求、甚至來自政府和法規的需求,都讓這個系統急速的變得更加復雜。面對這個局面,負責開發的技術團隊毅然做了一次全面的重構,把以前開發的功能都封裝了一次,形成了自己的“業務 API ”庫,不但重用了大部分以前開發的代碼,還為之后的開發提供了規則和范本,從而很好的度過了需求激增的危險期。
完成了準備工作之后,正式進入新的項目體制時,在管理上,準備長期作戰的最重要工作,就是改變“只看結果不管過程”的觀念,對于項目開發的過程,開始要足夠的關注。可以讓原來的“特種兵”利用之前開發的經驗,制定一些開發的流程和規范。然后關注這些規范的執行情況。而不是去挑戰規范和流程是否完備。
一般我們需要準備的流程和規范包括:
-
制定項目開發計劃的流程 :一個功能需求如何進入計劃,需要有一個確定的流程,不管是民主討論,還是獨裁的決定方式,都必須要有一個明確的流程,用來記錄下要做什么,誰去做,什么時候做完。
-
產品開發規范和接口流程 :這個包括了《需求文檔規范》、《程序代碼規范》、《美術資源規范》、《外包資源規范》等各種產出的規范。同時也應該為每個工種或者崗位,都制定“入口”(接收任務)和“出口”(完成任務)的處理流程。產出規范可以利用前階段的工作內容作為模板,而流程是那些實踐中的經驗和教訓。
-
產品發布流程 :資源充分之后,測試和發布是首先應該被重視起來的部分。一般來說開發流程是經過“設計 - 編碼 - 測試”這種順序的,但是這種方法在投入運營期的項目顯得過于“笨重”,而應該采用“發現需求 - 編寫實現 - 發布 - 測試驗證”的模型。在項目初創階段,發布往往并不是核心的工作,很多時候測試是直接在開發環境里面做的,但是到了運營階段,測試必須在專門的測試環境里面進行,因此“發布”工作必須成為一個必要的環節。這種運營階段的開發流程,以通過測試作為項目開發的目標,而不是完成設計方案作為目標,節省了設計階段的繁文縟節,更加重視對客戶的質量保證。因此應該讓測試、發布、客服三個流程統一結合,成為反過來輸入到開發流程中的一條工作流程。發布流程是在小型項目中最容易被忽視的,也是現在最迫切需要建立的。
從項目上,準備長期作戰則需要去完善“三板斧”:首先是自動運維部署工具,其次是統計監控管理,最后是代碼層次劃分。
因為互聯網項目通常都是一邊運營一邊開發,如果開發人員變多,運維部署和版本管理的復雜程度一定會上升,而這一類工作原本是比較容易從代碼開發中劃分出來。做好這一步,還能進一步提高 “測試”工作的質量。對于運營中的事故“救火”,也是有很大好處。特別是能讓開發團隊從特種兵時代的高強度 7x24 超高工作強度,轉換成日常工作的強度,這對于長期性運作有基礎性作用。
另外一方面,監控和統計是兩個非常容易被忽視的工作,因為這兩個并非是客戶需求,也和產品功能無關,因此常常在設計的時候壓根就沒有考慮。往往是在進入運營準備階段之后,才在市場部同事多方央求之下,或者在老板的強烈要求之下,開發部門才會認真的做起來。
然而,一個不斷運營的項目是否正常,完全需要有一個自我診斷的工具。如果不去做這個事情,反而會令正常的開發過程中被很多的“查問題”“看日志”“查數據”所打斷。有很多“大牛”程序員,在項目上線,出于責任心和項目穩定的需要,被迫每天上班都去花很多時間看日志,以確保已經上線的產品正常。這就是對人力資源的極大浪費。還不如一開始就多花一點時間做好監控的功能和統計的功能。
我曾經參加過一個公司的重點項目,經過大概半年緊張的開發,產品最終上線了,但是這個產品的特點是用戶需求很單一,但是用戶網絡環境對于這個產品的使用有很大影響,因此在隨后的一年多時間里,我就被迫每天的根據用戶投訴的情況,去搜集網絡環境的數據,并且試圖從海量的用戶使用日志中搜尋問題的線索,找出可能有問題的網絡區域報告給專門處理網絡問題的部門。因為缺乏前期的準備,也沒有安排足夠的開發時間來做這方面的開發,我一直只能使用低效的工具做著重復的工作。
一般的小型系統需要增加的系統和工具:
-
構建工具 :需要準備一個專門的、干凈的環境作為構建環境。構建環境可以是一個空白的虛擬機,也可以是一個很久的 PC ,但是最重要的是只用于構建,不得再有別的無關進程和服務。否則在構建環境中引入了問題,將會非常難查,這就是所謂“兼容性問題”的來源。另外還需要一套腳本工具,可以只運行一個簡單命令,就可以直接從最新的代碼庫和配置庫中,構建出最新的版本來,同時也不需要有保留備份舊版本的功能。自動構建腳本并不容易開發,但是若開發出來了日后工作中許多復雜的情況會變得比較好解決。實踐中,開發團隊有用 shell script 配合 make 開發自動構建工具的,也有使用 scons 腳本的,或者用 ANT 等其他工具開發的。另外 Hudson 也是一款不錯的自動構建 CI 工具。
-
部署工具 :現代互聯網應用都會部署在多臺服務器上,而且每臺服務器都有可能在運行著不同的進程。這種非常復雜的運行配置,以及代碼的版本兼容問題,困擾著很多互聯網服務提供商。因此專門抽調人員,針對多臺服務器,專門編寫部署程序,管理各種運行配置,是非常有必要的。而且還有一點,就是程序本身,就應該想辦法降低部署的復雜性,比如 IP 地址自己讀網卡而不是依賴配置;多個不同功能的進程使用同一份可執行程序,通過參數不同來區別啟動等等。業界的自動部署工具有 chef 和 puppet 等軟件可供選擇。
-
監控工具: 項目變大通常意味著用戶變多,更多的用戶意味著需要更多的服務器,而這些更多用戶和更多的服務器通常會導致運營事故的多發,維護工作也就變得更加困難。所以這就必須要有一套自動的監控工具,取代程序員每天主動上線去看日志,看負載。而這套自動監控工具,必須要和業務功能結合起來,才有意義。比如說對于業務數據的平均處理速度的監控,還有服務進程的運行狀態。關于操作系統的監控項目就更多了,但是我始終覺得網卡流量和 CPU 負載的圖形監控是最容易找到問題的,因為業務如果有問題,使用人數通常都會下降,流量就會隨之下降。對于操作系統的監控工具現在網上很多可以找到下載,而業務數據的監控,則是更直接,也更有意義的,這種監控工具,也是應該安排開發團隊著手編寫。 JAVA 系統則可以通過 JMX 規范來制作監控插件,具有良好的規范性。
-
統計工具 :項目的日志初期都是比較散亂的,帶有 DEBUG 信息的比較多。而正式轉入運營后,需要的是更多關于業務數據的日志,以及這些業務數據的統計。因此必須要讓系統能夠靈活的加入更多的業務數據日志,并且一定要安排專門的服務器和程序來做日志的過濾、合并、統計、查詢。一般來說這些工作都需要安排專人負責,對接市場和產品人員接受統計需求,然后在開發中不斷完善統計工具。
代碼層次的劃分非常有利于多人協作,因此也是項目走向多人共同開發的重要事項,沒有良好的代碼層次,就不會有良好的程序人力運用基礎。如果有一個比較好的代碼層次結構,那么在代碼中自然就會定義出很多“接口”,這些接口就是項目自身的 API 。這樣水平較低的人員可以開發重用率較差的代碼。而高水平程序員則專心于改進重用率更高的代碼,這樣在質量和效率兩方面都能得到平衡。
很多人認為多人合作開發,注釋和文檔是第一重要的。實則不然,如果代碼層次過于混亂,縱有再多文檔和注釋,也難以讓新進項目的程序員加入進來。而且就算勉強開始開發,也會碰到很多“以前犯過的錯”。
需要說明的是,對于軟件架構或者代碼結構的“重構”或者修正,實際上是跟隨著整個項目一直進行的。
在軟件行業發展到今天,軟件系統架構已經積累了很多經驗,并且形成了多個知識體系。學習和應用這些知識體系,具有非常重要的意義。其中一個重要的知識,就是代碼設計原則:
-
開閉原則 :代碼應該對修改代碼關閉,對增加代碼開放。這個是代碼結構的最高目標,符合這種原則的代碼重用性最高。
-
里氏代換原則 :父類可行的調用,子類一定可行。這個原則保證了代碼在重用情況下的穩定性。
-
依賴倒轉原則 :代碼應該針對抽象接口編程,而不應該依賴實現的細節。這一點在 C++ 語言開發中尤為重要。
-
接口隔離原則: 針對每個功能組合定義一個角色,不要做那種大而全,但是功能多到人腦無法理解的接口。
-
最小知識原則 :盡量少的產生不必要的耦合代碼
對于以上的開發原則,雖然看起來繁文瑣節,卻是代碼重用的重要原則,因此有必要對既有代碼在每一個可能的機會里進行重構。
另外如果項目的復雜程度已經需要進行整體性構造,那么可能還需要參考學習更多架構模式:
-
分層模式 :構架大型復雜代碼,有效管理耦合性的方法
-
微核模式 :對于需要單獨開發調試模塊,所有效的代碼架構
-
管道和過濾器模式 :對于構造高靈活性互相協作模塊群,所需要考慮的架構
-
MVC 及其衍生模式 :對于 GUI 系統需要使用的架構
編寫代碼的知識、設計模式、架構模式這些軟件開發知識,對于項目從小型轉向更大規模,是至關重要的。因為這些技術會直接影響整個團隊的開發效率。作為項目經理,如果不精通這些知識,很容易陷入無法推動程序開發進度的困境之中。推動和支持代碼在結構上的進化、優化是項目經理必須要去做的功課,這些工作正如磨刀不誤砍柴工一樣,對于項目進度有極大的好處。軟件工程類知識和項目管理知識,看起來是不相干的兩個方面,但是實際上都是為了提高開發效率所創造的。他們的關系是互相促進互相關聯的。
對于軟件結構來說,抽象是一個最主要的劃分工具,而抽象是否有效,并不是由程序員或者架構師的天馬行空的想象力決定,而是由具體的項目,在不斷的實踐中,經過無數次用戶溝通反饋,無數次需求變更的情況下,才能準確的做出來的。抽象本身就是開發團隊對于現實項目的一種理解,這種理解會隨著實踐而不斷逼近現實,沒有人的洞察力高到完全不需要實踐就理解一個事物,所以代碼結構和軟件架構的調整,就是結合了既有的模式知識和現實的需求變更經驗,所做出最符合開發效率的一種結果。如果說項目經理在軟件開發上的知識上升空間在哪里,我覺得這個地方就是一個無窮大的空間。好的項目經理往往是他做過的項目領域的專家或者是優秀架構師,而不僅僅是個婆婆媽媽的高級秘書。
往期精彩內容回看:
回復 服務器架構 ——經典游戲服務器架構概述
回復 程序員 ——如何提高程序員的生產率
回復 RPC ——如何設計一個RPC系統
回復 架構模式 ——經典軟件架構模式
回復 游戲服務器 ——可復用的游戲服務器端開發框架
回復 技術總監 ——如何做一個小型公司的技術總監
感謝大家的閱讀,如覺得此文對你有那么一丁點的作用,麻煩動動手指轉發或分享至朋友圈。如有不同意見,歡迎后臺留言探討。