天天看點

研發體系這點事

早在讀研究所學生的時候,自己負責着實驗室的項目,就一直在思索如何建立一套簡單又高效的研發管理體系,能夠在保證項目高品質順利進行的同時還能夠提升團隊成員的技術level。後來在自己在校的幾次小的創業中,也做過一些嘗試。直到畢業後進入前東家,在幾個項目的參與過程中,見到了大公司的研發管理是如何進行的。直至加入目前的公司,将研發體系梳理一遍,且學且抄且實踐,對這一套東西算是有了一定的實踐感悟。

對于一個研發管理體系,其核心是圍繞着産品的整個生命周期來進行的。是以,根據一個産品的生命周期,可以把研發體系劃分為幾個關鍵的環節,如圖所示:

更為具體的一個研發流程則如下圖所示,标注了每一個環節的參與角色。

可知,即時溝通和技術提升雖然不屬于研發流程中的某一個環節,但它們是貫穿整個研發體系不可或缺的一部分,有着不可替代的作用。此外,任務管理需要對任務做整個研發生命周期的管理,除了作為其中的一個關鍵環節,也是貫穿整個研發流程的。

任務管理

文檔協作

代碼協作

品質保證

自動化部署

故障管理

即時溝通

技術提升

任務管理是産品整個生命周期首要的環節,其對研發體系也是至關重要的。項目生命周期模型,傳統的有五種:瀑布模型、原型模型、螺旋模型、增量模型、V模型,而現在最為流行的是疊代開發模型,靈活開發則是采用疊代模型的一種典型項目管理方法集合。Scrum是目前靈活開發中最為大家熟知的開發模式(XP極限程式設計也是一種比較常見的靈活開發模式),其開發流程的概覽如下圖所示:

簡單來說,Scrum是依賴于三種角色、四種會議的自組織、資訊透明化、成員平等的一種靈活開發流程。更為詳細的描述,可參見此篇文章:http://blog.devtang.com/2014/09/13/scrum-introduction/。

除了Scrum之外,看闆是最近興起的另一種開發模式,在最近很火的美劇《矽谷》裡面“魔笛手”就是采用的這種方式。看闆将工作流程形象化,首先把工作細分成任務并根據需要将任務分為Pending、Analysis、Development、Test、Deploy等狀态,然後根據任務的進行,在幾種狀态之間進行轉換。對比Scrum,看闆使用開發周期作為計劃和過程改進的度量資料,不強調疊代的概念,也沒有很強的時間期間概念,也不需要制定任何團隊角色。對于看闆方法論的詳細介紹可見此篇文章:http://kanbanblog.com/explained/,http://www.jianshu.com/p/e44b1038c9cf這篇則做了比較形象具體的說明。這裡有一點需要注意,Scrum和看闆并非是對立的,它們是可以結合起來使用的。使用看闆來管理每一次疊代的任務是一種可取也是很常見的精益實踐。

依賴于任務管理方法論,市面上很多軟體都做了相應的支撐,自己曾經使用過的任務管理軟體如下:

Redmine: 這個是自己最開始接觸的任務管理軟體,使用也比較廣泛。比較遺憾的是,redmine安裝有點繁瑣,而且基于ROR,如果需要二次開發,需要重新學習ROR。

Tower.im: 這是一個任務管理雲服務,界面設計的簡單優雅,一目了然。很多小的私有項目,我都會用這個進行任務管理。類似的還有teambeation等。

Jira: 這款軟體是商業版的任務管理軟體,對于這一塊做的是非常專業的,很多大公司都在使用。但是,它是收費的。是以,如果你要用,要麼付錢,要麼去破解。。。

禅道:這款軟體最早是叫做bugfree, 是開源且主要針對Bug管理的,後面慢慢發展成現在的集任務管理、bug管理、團隊管理等的項目管理軟體,并開啟了收費政策。總體來說,功能很全,也比較專業,但是ui上有種傳統it系統的感覺,流程上也不具有現在靈活開發的一些優勢。

Kanboard: 是實作了Kanban方法論的任務管理軟體。

對于個人的項目,其實依賴于tower.im這種第三方雲服務完全足夠了。如果擔心資料安全的話,那麼推薦在内網搭建Kanboard進行看闆任務管理。

研發中首當其沖的就是文檔撰寫,這個很多情況下都決定了項目的可維護、可管理性。有人會說現在流行的是靈活開發,根本不需要寫文檔,但其實這是對靈活的誤解。靈活開發強調的是快速試錯、快速疊代,而非簡單粗暴,對比傳統開發模型雖然并不強調文檔,但并不代表不需要。對于一個項目,從開始就需要需求文檔、産品原型文檔、項目進度文檔等等,而到了研發這一步,在系統實作、寫代碼之前最好的就是先“想”再做,而“想”的一種比較好的輸出形式就是文檔。對于一個軟體系統,一般來說需要寫的文檔有以下幾種:

系統業務流程文檔:描述系統業務邏輯的文檔,能清晰的說明真個業務的流程。

系統架構設計文檔:對整個系統的架構的描述,需要包含系統的各個關鍵組成子產品以及相關的各個關鍵技術點等。

系統功能子產品概要設計/詳細設計文檔:對于某一個子產品的流程、邏輯的描述。

資料DDL/DML文檔: 與系統相關的資料庫的DDL和DML文檔,對于前者,是需要包含所有的操作的,而對于後者,必不可少的是查詢語句,用來提供給DBA,來做查詢sql的review,以保證索引的正确建立和查詢語句的合理等。

系統部署文檔:描述系統關鍵部分部署在哪裡,需要做哪些配置。

系統釋出ChangeLog:對系統每次釋出的改動進行描述,包括資料庫、緩存、資料隊列、新增/變動了哪些依賴服務等。此外,對資料庫、緩存這種關鍵服務的量化分析也可以寫在這裡。

尤其對于一些相對複雜的功能來說,整理思路形成文檔,不僅可以讓自己邏輯清晰,也讓後續維護的人能夠更快地接手。當然,這些并不是死闆要求的,應該根據實際的業務選擇,不一定所有的文檔都是必須的,也不一定要分開這幾個文檔寫(可以将這些内容內建在一個文檔中,這也是目前我經常采用的方式)。這些文檔的範例可以見:https://github.com/superhj1987/awesome-tech-collections/tree/master/document。

而對于文檔撰寫協作的方式,我自己經曆過的有以下幾種:

使用word撰寫各種文檔,送出到svn等版本管理工具上

使用google doc進行協作

使用word撰寫文檔,然後送出到項目管理軟體中進行管理

使用markdown撰寫文檔,送出到版本管理工具上

我自己比較推崇的是使用markdown撰寫文檔,然後使用git、svn版本管理工具或者是其他團隊協作工具做版本管理。之是以使用markdown, 能夠極大地節省使用word時調各種格式、樣式耗費的時間。對于程式員來說真的是如虎添翼。如果是對文檔多人協同編輯有剛需的團隊,可以選擇使用google doc或者國内的石墨(http://shimo.im)。

此外,在移動app開發中,還有一個非常關鍵的文檔就是api文檔,是服務端提供給用戶端調用接口的說明文檔。比較簡單直接的方法就是定制一套api文檔模闆,然後在寫接口代碼之前或者之後,按照模闆編寫接口文檔。此外,可以實作一套根據源碼自動生成文檔的機制,在代碼編寫的同時就能自動生成相應的接口說明文檔。在使用Spring MVC開發的後端應用中,個人推薦SpringFox,使用此項目能夠通過在Controller中加入相應的注解資訊進而自動生成Api接口文檔,同時也提供了線上調試的功能,極大減少了api文檔的工作量。

對于一個技術團隊,最最關鍵的肯定是寫代碼。一個人單打獨鬥那倒好說,但是這就像籃球場上,一對一靠個人硬實力,但是5對5,那就不僅僅是一個人實力強就赢得了的了。是以對于技術團隊來說,代碼協作是至關重要的一個部分。

代碼版本管理:Git + SVN

幾年前最流行的代碼版本管理工具是svn(當然此前,更加古老的還有cvs之流),的确為程式員們的代碼管理帶來了很多便捷。但到了現在,相比起這種集中式代碼管理,目前最為火熱的當屬git這種分布式代碼管理工具,在Linux上直接搭建git伺服器來建構項目的git系統的。而這幾年随着Github以及類似系統的湧現,對于很多私人項目我都是采用oschina或者gitcafe提供的git私有代碼管理來做代碼版本管理的。當然,對于公司來說,有很多開源類github系統可以搭建在企業内網。詳細的可以參見:搭建自己的github。當然,對比svn,git也是有缺點的。無法天然的支援對于目錄級别的權限管理和基于目錄的版本管理操作是目前不得不結合svn和git一起使用的重要原因。通常情況下,可以使用git做版本管理,輔以svn做基于目錄級别的釋出包管理。

代碼分支/Tag管理: Git Flow

其實分支/Tag管理是代碼版本管理包含的内容,之是以單獨出來,是因為對于分支的使用其實還是有一定的原則和技巧的。并非如很多人一樣,所有項目就一個master分支,所有修改都往這裡塞。目前,最為流行的一種基于分支的工作方式就是:Git flow。介紹可以見: 基于git的源代碼管理模型——git flow。簡單概括就是:

master和develop作為主分支。主分支是所有開發活動的核心分支。所有的開發活動産生的輸出物最終都會反映到主分支的代碼中。master是可以随時釋出的分支,而develop則時刻保持最新的開發代碼。

輔助分支是用于組織解決特定問題的各種軟體開發活動的分支。輔助分支主要用于組織軟體新功能的并行開發、簡化新功能開發代碼的跟蹤、輔助完成版本釋出工作以及對生産代碼的缺陷進行緊急修複工作。這些分支與主分支不同,通常隻會在有限的時間範圍記憶體在。包括:

用于開發新功能時所使用的feature分支;

用于輔助版本釋出的release分支;

用于修正生産代碼中的缺陷的hotfix分支。 對于此種開發模型,這裡也提供了一個指令行工具:https://github.com/nvie/gitflow

代碼品質保證:結對程式設計 + 定期review + PR目前一種比較好的方式。結對程式設計這個是一個老生常談的方式,兩個人共同承擔某一開發任務,互相保證對方的代碼品質,在很大程度上能夠提高代碼品質。而定期review則是讓團隊所有的成員都能夠參與到這個過程中,不僅僅能夠保證被review者的代碼品質,也能夠讓團隊成員學習到好的代碼是怎樣的而差的代碼又是怎樣的。PR是Pull Request的簡寫,當開發完成的代碼送出到主分支時,需要發起pull request,此時團隊負責人需要review相關代碼,確定沒有問題之後,才能accept此次pr。當然,上面講述的是如何通過人來保證代碼品質。除此之外,還可以通過技術上的手段在一定程度上保障代碼的品質,這一部分在後續的自動化測試機制會講述。

此外,在移動app項目中,一個很普遍的問題就是:在定義好Api文檔之後,用戶端如何在後端并沒有完成接口開發的情況下開發或者調試程式?這裡有兩種方案:

用戶端做好接口封裝,在後端接口未完成前,用戶端不經過網絡io直接傳回靜态格式資料。這種方式最好是由用戶端定義接口格式資料。

後端将示例接口傳回資料寫在檔案裡,接口直接傳回靜态檔案資料。此種方式,由後端定義接口資料格式。另外,有一個開源的工具: httpbin可以用來提供接口傳回指定格式的資料,中文介紹可見:https://blog.phpgao.com/how-to-httpbin.html。

關于用戶端和後端的接口代碼協作,還有一個Chrome插件POSTMAN可以使用。後端可以使用此插件在編寫完接口後進行自我功能測試,測試無誤後可以将接口以檔案或者url的形式分享給用戶端供用戶端參考和調試。

當代碼開發完成之後,需要品質保證機制的介入來保證功能的正常運作,進而保證代碼是可釋出的。一般來說,品質保證的手段就是測試,分為:

代碼品質測試

功能測試

性能測試

代碼品質測試一般是在編譯打包代碼之前進行,通常是自動化進行的。針對Java項目,自動化代碼品質測試可以分為以下幾步:

源代碼規範檢查:對于Java來說,代碼規範的檢查一般使用checkstyle來檢查。預設的規範非常嚴格,這裡大家可以根據需要放寬一些規範。

源代碼靜态品質檢查: 常用的工具是pmd, 可以檢查Java源檔案中的潛在問題, 比如空try/catch/finally/switch語句塊等。

位元組碼bug檢查:常用工具是findbugs,基于Bug Patterns概念,查找javabytecode(.class檔案)中的潛在bug。如NullPoint空指針檢查、沒有合理關閉資源、字元串相同判斷錯(==,而不是equals)。

單元測試:使用junit即可,當然在這裡當使用mvn時,其test phrase會預設生成測試報告到${project.build.directory}/surefile-reports檔案夾中。這裡建議使用coverage生成單元測試報告,其中一個關鍵的單元測試覆寫率名額達到98%以上才為合格(根據需要自己調整即可)。

以上提到的工具,都是有maven插件的。通常情況下,也推薦使用這些工具的maven插件來調用。目前流行的自動化ci工具jenkins、QuickBuild等結合各種豐富的插件可以提供這些功能,将他們內建到一個測試流程并形成最終的測試結果報表。

在代碼釋出到線上環境之前,一個關鍵的步驟就是功能測試,通常都是工程師來進行的。需要測試工程師根據産品需求,形成測試用例,然後根據這些用例做相應的測試。測試用例的一個模闆如下:

用例ID

功能名稱

用例名稱

測試資料

前置條件

操作步驟

預期結果

測試結果

備注

review說明

-

需要測試工程師根據需求建立并經過研發人員reivew确定測試用例,待到釋出前進行測試以及回報,直到所有測試用例都通過。

對于移動app功能的測試,目前市場上有類似bugtags這種所見即所得送出測試工具,可以很友善的送出bug。

功能測試通過之後,對于一些對性能有要求的項目,還需要進行性能測試。對于這種測試來說,通常有以下幾種方式:

測試工程師寫性能測試代碼來進行測試

使用性能測試工具測試,如LoadRunner、ab等

當然,所有這些測試都是在項目釋出上線之前進行的,通常是在項目的測試、預釋出環境中進行的。

此外,對于測試任務的管理工作一般在任務管理軟體中都做了內建。也有類似Mantis這種事專門做缺陷管理的。

對于Java項目的釋出流程,如下圖所示:

使用ci軟體可将以上步驟自動化的。

如上圖所示,對于一個項目,我們是劃分為三種或者四種環境的。

測試環境: 這個環境是一個相對來說比較寬松的環境,所有代碼的送出都會觸發jenkins的自動代碼品質檢查和部署。測試工程師也是首先在這個環境下進行功能、性能測試的。隻有通過了,才能部署到後續的下一個環境。

內建環境:這個環境不是必須的,隻有當項目出現了兩個大的分支并行開發,釋出前需要內建兩部分代碼時才需要這樣一個環境。一般來說隻使用jenkins進行部署前的打包流程,部署流程由相關人員進行。這個環境也是需要測試工程師進行測試的。

預釋出環境:這個環境和線上環境是一模一樣的,不同的是此環境下的伺服器是不線上上伺服器叢集中的,并不為使用者提供服務。此環境下的項目釋出也是需要人工參與的,也必須由測試保證功能和性能的正常。

線上環境:這個環境是比較嚴格的一個環境。在釋出前,一般來說會進行釋出确認等一系列上線評審工作後,由項目負責人或者運維人員部署釋出。

功能清單 vs 實作情況:檢查是否已經實作所有計劃的功能?如果有某些功能沒有實作需要說明原因。

軟體示範

測試結果和遺留問題清單:測試用例的情況,遺留的Bug以及情況說明

上線确認

後續任務計劃

其中,上線确認書的一個例子如下:

xx項目上線确認書

需求方驗證結果

意見:

确認人:[由各個負責人簽字]

開發确認

确認人:

測試确認

伺服器是否需要重新開機

[是否需要自動更新那些App?]

伺服器配置影響

[是否需要增加新的伺服器ip,是否需要修改nginx/tomcat,是否新裝軟體,是否建立域名?]

資料庫更改

[是否需要修改線上資料庫?是否有初始化語句?索引是否正确建立?查詢語句是否合理?量化分析資料(包括緩存)是否無誤?]

資料初始化

[是否有初始化資料?如價格,預設分類等]

上線評審結論

[ ]通過 

[ ] 未通過,不能上線 

[ ] 未通過,但修改完制定Bug後可直接上線

計劃上線時間

2016-08-01

後續任務計劃,示例如下:

問題描述

責任人

計劃完成時間

狀态

xx

由于各種客觀原因如帶寬、主機配置、流量異常或者程式邏輯不夠嚴謹等原因,線上服務并非100%可用的。研發體系中最後把關的就是這一道故障應急機制。也就是說,一旦發生線上故障,如何快速反應并修複問題,如何避免下一次犯同樣的錯誤。

對故障的快速反應需要依賴于運維的監控機制,包括基礎設施層面的監控以及業務層面的監控,一旦發生故障應該立刻發出告警到相關人員。這裡可以使用nagios、cacti或者第三方服務(如:監控寶)實作,當然,如果你使用的是雲服務,一般也會有相應的雲監控服務提供給你的。後續的故障問題定位很多情況下則是取決于你的應用日志打的是否合理,是否有足夠的覆寫面的,是否有足夠的資訊。ELK和請求鍊路監測系統(同染色日志系統)是目前比較流行的基于日志的故障定位解決方案。問題一旦定位到了,那麼修複就是水到渠成的事情了。

這裡需要說明的一點是,上面講述的是後端的故障快速反應和修複。針對用戶端的故障,一般情況下都是由使用者發現的。但是由于用戶端釋出流程的繁瑣,很難及時修複一次釋出版本的故障,隻能等到下次解決。但是,目前一些用戶端使用混合開發,其中的h5頁面是可以線上修複的,另外,很多安卓app熱更新方案也都能線上修複一些代碼故障,如Nuwa、HotFix、dexposed。

故障解決完并非最終的結果,之後的故障總結也是故障管理尤為關鍵的一點。大公司會根據故障産生的影響不同定義不同的故障級别,進而追責到個人,再進一步影響個人的職級評定或者績效考核、獎金之類的。但這一套卻并不适用于小公司,畢竟大多數小公司沒有那麼完善或者說根本就沒有職級和績效這麼一說。其實,追責并不是主要目的,最主要的是如何避免再次出現問題。是以,對于小的創業公司來說,最需要做的就是如何對已經發生的故障做總結,吸取教訓。建構一套故障總結wiki則是一種很好的方式。下面是一次故障總結模闆;

2016.08.01xxx故障總結

故障等級

[故障等級]

故障描述

[描述故障發生的現象]

故障發現時間及發現人

[xxx于xxxx年xx月xx日 HH:mm 如何發現該問題。]

故障影響

[影響時間範圍、影響版本範圍、影響産品範圍]

故障原因

[闡述故障發生的原因]

解決方案

[詳細記錄如何解決此次的故障]

故障教訓

[如何避免下次出現類似的事故]

[責任人簽名]

顯而易見,即時溝通是任何團隊都必不可少的一個機制,同樣也是研發團隊必不可缺的。常用的就是QQ、釘釘或者企業内部的im軟體。那麼對于小公司或者創業公司,不想用第三方服務的該怎麼辦呢?之前蘑菇街開源過一個teamtalk的軟體,不過後來由于某些原因已經下線。目前,有一款開源的web im軟體可以供大家選擇:Rocket.Chat,能夠搭建出内網的slack服務(将分散的溝通方式聚集到一個地方,融入到一個資訊流中)。

此外,我自己還嘗試過使用intellij自帶的IDE TALK來進行研發團隊的線上交流。使用這個比較好的一點是可以直接做基于代碼的即時交流,比如能夠發送一個代碼片段給同僚,他那邊接收到之後是直接能在他的項目裡相關代碼處進行操作的。

一個研發團隊,很重要的一點是如何提高團隊的戰鬥力。對于個人來說,在平時的工作中,提高技術的熟練度和深度,在業餘補充學習專業知識,提升技術廣度,這些都無須多言。那麼如何在整體層面或者說是管理上促進團隊成員的技術提升呢?可以采取的方式有以下幾種:

建構内部的技術wiki并建立技術分享機制,鼓勵大家以演講或者技術部落格的方式分享自己的技術經驗或者教訓,既可以對自己進行review又可以給其他成員以啟示。這一點,很多公司都是納入績效中的。

将一些項目開源,讓團隊成員能夠享受到開源項目帶來的各種好處,比如提升個人在業界的知名度、提高編碼的水準(畢竟不好的代碼,你也不好意思放出去)。

定期舉辦類似黑客馬拉松的比賽,提高團隊成員的凝聚力,也能夠提升成員解決實際問題的技術能力。

自己比較推崇的是第一種方式,但是開始的時候往往會發現很多人是不會主動去分享的。要麼是覺得自己的東西技術含量都很低,要麼就覺得自己的知識為何要分享給别人。可以采取的辦法就是從最初的周期性安排人員進行技術分享,然後慢慢形成一種氛圍和習慣,再到後續鼓勵大家主動分享。當然,輔以獎品激勵或者績效獎勵也是一種不錯的方式,但切忌不要忽視一些業務能力很強但不愛或者不善于分享的工程師。

至于項目開源,前提一定是團隊的項目真的是高品質并且會對開源社群有貢獻的,不能為了開源而開源。尤其是對于一個公司來說,一個開源的項目直接展現了公司技術水準的高低,會對公司的pr、招聘等都帶來一定程度的影響。

而黑客馬拉松比賽這種方式,尤為關鍵的一點是要選擇合适的主題。一般來說,圍繞現實的業務場景來出題不僅能夠提升大家解決問題的能力,也能順便解決實際問題。比如”根據使用者已有行為日志預測使用者未來的行為”、“怎樣建構合适的使用者品質模型”都是比較合适的主題。此外,借鑒黑客馬拉松的這種形式,可以采取類似“每周一題”的做法:在每周例會上給出一道和線上業務相關的問題,如“如何提高資訊流的點選轉化率”,然後每個人發散思維給出自己的解決方案,最終形成文章釋出在内部的技術wiki上。對于每次主題,都會在下周的例會上針對每個人的解決方案進行讨論。

此外,在安排團隊成員去調研一種将要使用的新技術的時候,務必要深入到源碼層面,這個觀念是需要灌輸到團隊每一個人的意識中去的。去使用一個沒有看過源碼或者沒有掌握其運作原理的開源軟體是一件風險非常大的事情,極有可能造成巨大的線上故障。

以上,是自己對于研發體系的一些實踐和感悟,很多地方仍然有所欠缺或者并非最佳實踐,也一直在探索更好的方案。

原文出處:後端技術雜談

<a href="http://www.rowkey.me/blog/2016/08/17/dev-manage/" target="_blank">原文連結</a>

轉載請與作者聯系,同時請務必标明文章原始出處和原文連結及本聲明。