如何提高程序员的生产率 (2)
版權(quán)聲明:本文由韓偉原創(chuàng)文章,轉(zhuǎn)載請注明出處:?
文章原文鏈接:https://www.qcloud.com/community/article/252
來源:騰云閣?https://www.qcloud.com/community
?
接上篇?如何提高程序員的生產(chǎn)率 (1)
三. 開發(fā)過程
溝通
軟件通常都需要經(jīng)過很多人和很多次的溝通才能生產(chǎn)出來,但是溝通本身又往往會影響軟件的開發(fā)速度。這是一段很矛盾的關(guān)系。好的溝通方法能降低開發(fā)中因為信息不透明導(dǎo)致的開發(fā)資源浪費(fèi),而又盡量減少溝通所占用的精力。
1. 需求溝通
在任何一個軟件產(chǎn)品中,如何應(yīng)對需求的變更,都是至關(guān)重要的。需求一直是軟件工作得以成功或者失敗的最重要因素。軟件開發(fā)中很多技術(shù)和方法都是圍繞著需求來設(shè)計的。
需求的溝通是需求工作的第一個環(huán)節(jié)。首先溝通的對象必須是經(jīng)過挑選的,以免添加不必要的需求混亂。最佳的需求溝通是和用戶或者用戶代表。但是他們往往他們?nèi)狈Ρ匾挠嬎銠C(jī)知識。而程序員卻很少有豐富的需求領(lǐng)域的知識。這個鴻溝需要雙方共同去彌補(bǔ),最重要的做法是,不要光靠口說。
程序員應(yīng)該認(rèn)真研究需求領(lǐng)域的知識,仔細(xì)查看涉及的單據(jù)、原型產(chǎn)品、現(xiàn)有工作流程等,而且必須用筆記錄下來,之后再去整理問題,逐條咨詢用戶。在仔細(xì)了解情況之前,不宜開始設(shè)計整體程序結(jié)構(gòu)。
當(dāng)你有一定了解之后,程序員就可以動手開發(fā)一個快速的原型,如果沒有足夠資源,一組界面圖也是很好的。以程序的外觀來幫助用戶來協(xié)助設(shè)計,是最有力的需求溝通方式之一。不斷的在用戶的幫助下完善這些界面圖,標(biāo)識上那些可能需要的數(shù)據(jù)和流程,然后完善,然后再繼續(xù)找用戶確認(rèn)。這個過程在前期可能會相當(dāng)枯燥,因為那些溝通用的原型也許一點(diǎn)都不會給后續(xù)的開發(fā)帶來重用。但是能明確需求,卻是對開發(fā)最大幫組。
2. 需求評審
在需求基本有一個思路之后,需要開始準(zhǔn)備需求評審。首先說說評審的材料,一般會是《用例圖》,《領(lǐng)域建模的模型》,用例規(guī)約,一些《非功能需求點(diǎn)列表》,甚至軟件的一些經(jīng)過用戶確認(rèn)的使用流程和使用界面。
評審的過程其實遠(yuǎn)沒有溝通的過程重要。這個環(huán)節(jié)主要是給大家一個明確的開端:現(xiàn)在我們開始做系統(tǒng)設(shè)計了。作為在一些公司內(nèi)部,需求評審是否得到通過還是產(chǎn)品是否能正式開始立項的一個流程。
對于評審,很多時候會認(rèn)為是,提交評審者來寫報告,然后向一堆專家或者上級來介紹,最后他們提出問題,幸運(yùn)的話就蓋章認(rèn)可。但我認(rèn)為評審不應(yīng)該是這樣的。因為如果上級和專家沒有參與項目需求的溝通,他們對項目的了解是片面的,靠一些文檔和口頭介紹,一定會以“挑毛病”的姿態(tài)出現(xiàn)。而項目本身是否真的可行,卻不負(fù)擔(dān)真正的責(zé)任。
因此我認(rèn)為需求評審應(yīng)該是項目發(fā)起者,也就是有權(quán)拍板是不是做這個項目的人,來主持這個評審會議,所有的材料由他宣講,疑問由他回答。而其他的與會者包括專家團(tuán)和可能的開發(fā)團(tuán)隊,紛紛向他提出問題,以確認(rèn)真正的可行性。最后主持者在搜集了眾多意見后,篩選出有意義的意見,改善需求評審的材料,最后拍板是否完成需求評審。這種流程,無疑會要求公司的權(quán)力下放,而事實上,如果不是下放,又或者不是老板親自主持,很多項目最后就輸在了起跑線上。
3. 合作溝通
程序員的溝通講求的是效率,準(zhǔn)確是最重要的要素,如果無法表達(dá)“準(zhǔn)確”,那就只是在創(chuàng)作,而非溝通。對于需要高度注意力的工作——開發(fā)軟件來說,群體創(chuàng)作的效率實在不夠高。因此提高溝通的“準(zhǔn)確”程度是至關(guān)重要的效率因數(shù)。
開發(fā)中的溝通有很多種,其中最重要的一種是需求溝通。特別是作為技術(shù)人員,和策劃、美術(shù)的溝通最多。這里需要重視的就是,和非技術(shù)人員溝通,快速原型:如假的界面圖或者手畫稿,填寫了假數(shù)據(jù)的表格等等,是很重要的溝通手段。很多時候我都會要求把這些溝通過程中的手畫稿掃描保留下來作為設(shè)計文檔的一部分。
另外一種溝通是程序員之間的。我一直認(rèn)為程序員之間最好的溝通就是“不用溝通”。客戶端和服務(wù)端之間調(diào)整協(xié)議,最好的方法是直接兩個IDE聯(lián)調(diào)。關(guān)于工作任務(wù)的接口,最好是定義出接口代碼,并且有單元測試針對接口代碼做處理。當(dāng)然拉,對于這些接口的設(shè)計,還是需要當(dāng)面溝通的。
最后要說說會議。我認(rèn)為溝通不應(yīng)該打斷開發(fā)。不管是5分鐘還是1個小時,會議都是一種打斷。而很多會議需要開前準(zhǔn)備很多東西,大家試圖用這種方法減少會議的時間,但實際上卻占用了同樣多的時間。我們應(yīng)該關(guān)注如何減少會議,以及減少會議對開發(fā)的打斷。在午餐的時候開會,我認(rèn)為是一個比較好的方式,這種打斷是天然的,不會產(chǎn)生額外的打斷。而且與會者通常不會睡著。午餐時的討論氣氛也會比較好,比起一本正經(jīng)的會議要活躍的多。
4. 測試溝通
程序員和測試人員之間的溝通一定是密切與頻繁的,雖然我們有JIRA、BugZilla之類的BUG跟蹤系統(tǒng),但是往往很多問題還是要通過口頭的溝通來解決,我認(rèn)為和測試人員的溝通關(guān)鍵是要分出優(yōu)先級,對于“可重現(xiàn)”的BUG應(yīng)該優(yōu)先溝通,因為可以很快解決。而那些偶現(xiàn)的問題,可能溝通中一大半都會是猜測,其實可以先放后,這不表示那些問題不重要,而是應(yīng)該在確定能解決的問題都先解決掉,這些時間內(nèi)測試人員也可以努力把偶現(xiàn)變成必現(xiàn)。
測試溝通的內(nèi)容中,對于“名詞”一定要明確,因為我們會有很多個環(huán)境,必須要讓每個概念有個清晰的表達(dá)方法。我們經(jīng)常會在“測試”這個詞上犯糊涂,比如“測試版”到底是哪個版本,“測試網(wǎng)”又是哪個網(wǎng)?甚至“測試機(jī)”是個PC還是個手機(jī)?這些都必須明確下來。比如用alpha網(wǎng),beta網(wǎng)就清晰的多。
設(shè)計
1. 設(shè)計意見搜集
負(fù)責(zé)設(shè)計方案的人必須負(fù)責(zé)搜集設(shè)計意見。我不贊成方案由下屬設(shè)計,意見由下屬向上級搜集。我認(rèn)為方案應(yīng)該由上級負(fù)責(zé),而意見向下屬爭取。如果有一個上級并不負(fù)責(zé)設(shè)計方案,那么他也不應(yīng)該有權(quán)力去“評審”這個方案。這樣做看起來風(fēng)險很大,因為我們很多的上級并不負(fù)責(zé)具體的“設(shè)計”工作,但是對比起上級提供一些不知道該怎么辦的“指示”,而非要加到方案中去的情況,可能危害要少的多。
一般來說我們認(rèn)為上級會比下屬的經(jīng)驗更豐富,如果“無權(quán)”評審方案,就必須換一種工作方式:要不自己來做設(shè)計,要不采用建議的方式說服下屬——這樣做的好處是能讓上級對自己的概念講解的更清晰、更細(xì)致。否則不足以說服下屬。
2. 設(shè)計評審
設(shè)計評審的形式往往是一個結(jié)論是yes or no的會議。但是實際上要用好這個溝通工具,卻不能怎么簡單。首先,方案的評審提交者應(yīng)該是最后決定者,當(dāng)然應(yīng)該在一個機(jī)制的監(jiān)督下決定。這個決定就是,對于與會者提出的問題,包括提交者提出的問題,都要有明確的答案。
與會者可能會與提交者就一些問題有分歧,但提交者會有最終決定權(quán)。這個機(jī)制聽起來很荒謬,好像自己指定法律自己又可以修改。但是,實際的開發(fā)上,如果方案和執(zhí)行者并不統(tǒng)一,最后執(zhí)行者還是會有辦法“規(guī)避”一些決策。這里也涉及一個重要的問題,就是要把權(quán)力給有能力承擔(dān)他的人。不能想著只是讓某些自己還不放心的人去做方案,然后試圖在評審的時候“把關(guān)”了事。
最后把關(guān)固然比不把關(guān)要好,但是把關(guān)要避免成為扯皮或者陽奉陰違,就必須要權(quán)事統(tǒng)一。真正的把技術(shù)的知識灌輸?shù)降?#xff0c;這樣會耗費(fèi)指導(dǎo)者較多的精力,因為需要在提交評審前更多的溝通。當(dāng)然了,雖然方案又提交者決策,但是,作為業(yè)績考核和技能評定,上級還是可以針對這些設(shè)計方案來給出專業(yè)評判意見。對于非常頑固者,實際上也有一個“秋后算賬”的“威懾”。
設(shè)計方案,也是開發(fā)者的一個重要輸出,代表了開發(fā)者的技術(shù)水平和工作績效。
對于設(shè)計方案的組成部分,下面架構(gòu)設(shè)計章節(jié)會有更多的討論。
測試
1. 單元測試
單元測試的好處是讓你在設(shè)計代碼之前,就要考慮別人如何去使用你的代碼。代碼的可讀性是建立在讀者的前提上的,如果強(qiáng)迫第一個讀者和使用者就是作者本人,那么在設(shè)計API和接口部分,就會考慮更少的耦合。因為強(qiáng)耦合會讓單元測試非常難寫。IDE和單元測試結(jié)合是一個很好的實踐,雖然并不能節(jié)省多少輸入的代碼量,但起碼會給與一個正式的環(huán)境。
每個細(xì)節(jié)組成部分的正確性測試,會增強(qiáng)你重構(gòu)代碼的信心。對于單元測試,我認(rèn)為最少應(yīng)該覆蓋所有正確的路徑,以及重點(diǎn)防御的錯誤路徑。對于覆蓋了這些重點(diǎn)關(guān)注的地方之后,放開手重構(gòu)代碼就很方便了。雖然很多語言能通過編譯就已經(jīng)消滅了很多的BUG,但是起碼還是要運(yùn)行一下。而單元測試可以分區(qū)域的運(yùn)行完成的代碼,避免的整個系統(tǒng)一起運(yùn)行,突然爆發(fā)一長隊的錯誤,讓DEBUG工作無從入手。
單元測試應(yīng)該是代碼的一部分,和源代碼一起存放。自動構(gòu)建時也應(yīng)該進(jìn)行檢查輸出結(jié)果。通常提交代碼的時候都會自動運(yùn)行單元測試,但是當(dāng)版本樹有分支合并的時候,單元測試尤為重要,而最重要的是在分支上建立的單元測試,這些測試會大大加強(qiáng)系統(tǒng)的穩(wěn)定性,因為檢驗了“合并”功能產(chǎn)生的代碼——這些代碼是最容易出錯的。
2. 系統(tǒng)測試
系統(tǒng)測試的自動化程度決定了其重要性。系統(tǒng)測試一定要先辦法找到測試的“切入點(diǎn)”,如對WEB系統(tǒng)測試,使用HTTP請求列表作為測試發(fā)起事件。對于WINDOWS測試,則使用窗口消息。對于服務(wù)器,使用協(xié)議包。一定要想辦法把手工操作“記錄”成可編程控制的操作。第二個重點(diǎn)就是要有辦法用程序鑒別測試目標(biāo)的輸出,這里可能會用到正則表達(dá)式,詞法分析,圖形辨認(rèn)等,但是如果一個好的系統(tǒng)設(shè)計,在考慮到測試時候,應(yīng)該設(shè)計出盡量簡單的測試輸出點(diǎn)數(shù)據(jù)。如一些結(jié)構(gòu)化網(wǎng)絡(luò)數(shù)據(jù),或者客戶端數(shù)據(jù)中的模型數(shù)據(jù)等。
系統(tǒng)測試的環(huán)境自動化部署是關(guān)鍵,其中測試數(shù)據(jù)還原也很重要。一般系統(tǒng)測試需要反復(fù)執(zhí)行——每次發(fā)版本都要。而測試結(jié)果很多和數(shù)據(jù)結(jié)果有關(guān),因此一定要有辦法把系統(tǒng)的數(shù)據(jù)(數(shù)據(jù)庫內(nèi)容)還原成每次測試的初始狀態(tài)。這個在建立系統(tǒng)測試的環(huán)境的時候就應(yīng)該考慮,并且做成每次測試執(zhí)行前都自動還原數(shù)據(jù),否則最后的“斷言”測試很可能會失敗。
3. 壓力測試
我們必須要做壓力測試。因為我們要提供有限服務(wù)。服務(wù)器或者客戶端都應(yīng)該對系統(tǒng)的最大能力值有一個設(shè)定,然后通過壓力測試獲得最可靠的數(shù)據(jù),用以設(shè)定這個值。這樣能保證程序在合理環(huán)境下正常運(yùn)行。
壓力測試可以通過搜集、復(fù)制產(chǎn)生數(shù)據(jù)。比如服務(wù)器可以記錄網(wǎng)絡(luò)請求包,然后按會話記錄成一個個隊列,最后通過并發(fā)一起回訪,就可以模擬多人同時的情況。如果還不夠壓力,可以復(fù)制隊列,然后修改一些互斥數(shù)據(jù)(如用戶ID),產(chǎn)生更大的并發(fā)壓力。這種測試往往能很真實的反應(yīng)情況,缺點(diǎn)是必須要搜集一定的用戶操作。但是我覺得公司一般的QA的操作就是很好的復(fù)制源。
壓力測試如果用自己構(gòu)建的壓力數(shù)據(jù),需要注意的事項:密度、順序、覆蓋率。有時候需要自己構(gòu)造壓力數(shù)據(jù),我認(rèn)為最少應(yīng)該有幾個可輸入的調(diào)控相:每秒并發(fā)發(fā)起多少請求,每個請求的間隔時間;每個請求的順序是否按預(yù)定順序排列好(因為有的操作是需要先后次序的),請求包是否覆蓋了系統(tǒng)的所有處理邏輯,而覆蓋的密度比例是否和真實的環(huán)境大體類似。如各種協(xié)議格式的包,是否按外網(wǎng)的比例來產(chǎn)生。
壓力測試必須要注意專用環(huán)境:帶寬、磁盤、硬件、測試數(shù)據(jù)還原。高速的局域網(wǎng),最好和辦公網(wǎng)分開,否則會影響工作。磁盤要清空足夠大,否則可能會讓日志把磁盤填滿。要用專用的測試硬件,以免造成別的工作數(shù)據(jù)的破壞——同時也提供了性能指標(biāo)的硬件基準(zhǔn),這個尤其重要。壓測的數(shù)據(jù)包數(shù)量巨大,一定會產(chǎn)生巨大的持久性數(shù)據(jù),為了可以重復(fù)操作,這些數(shù)據(jù)一定要能自動還原。同時也是保證自動化重復(fù)壓力測試的需要。
編寫
1. 需求分析
KISS:保持簡單。需求之所以復(fù)雜,是因為人的思想難以界定,充滿了是和否的中間地帶。所以第一原則是:只承認(rèn)確定是的需求。未來的需求暫時不考慮,在第一批需求完成后,真實的第二批需求就會確定下來。人類不可能未卜先知,所以不要妄想一開始就能準(zhǔn)確的預(yù)測需求,只需要把確定的需求理解清楚,就打下了基礎(chǔ)。以學(xué)習(xí)的心態(tài)去了解需求,不要被固定的合同束縛,才真正能跨過需求的第一關(guān)。軟件領(lǐng)域最大的、永恒的挑戰(zhàn),正是需求變更!
面向?qū)ο蠓治?#xff1a;尋求領(lǐng)域概念。計算機(jī)把世界抽象為0和1的序列,這種方式也影響了程序員。但是世界是復(fù)雜而多變的。固定的數(shù)據(jù)建模已經(jīng)被證明了無法很好的應(yīng)對需求變更,所以真正的方法應(yīng)該是去先認(rèn)識世界,對于業(yè)務(wù)領(lǐng)域中的概念做學(xué)習(xí)和界定,然后用面向?qū)ο蟮姆椒ㄈタ蚱饋怼_@樣“對象”和現(xiàn)實世界與0、1之間,就搭起了一個人類可以理解的橋梁。因此我們的需求應(yīng)該從領(lǐng)域模型出發(fā),使用業(yè)務(wù)領(lǐng)域的名詞作為系統(tǒng)中對象的名詞,盡量用對象去“描述”這個領(lǐng)域中的概念,而不是急著去完成一個個概念供使用者交互的“流程”。
需求分析有很多工具,如領(lǐng)域建模。UML中的用例圖和用例規(guī)約。針對非功能需求的“場景-決策”表格。還有著名的魯棒圖,可以轉(zhuǎn)變成UML的模塊圖。這些都是值得學(xué)習(xí)的需求分析工具。而且不會太花費(fèi)時間。
2. 代碼風(fēng)格
這個方面《編寫可讀性代碼的藝術(shù)(ARC)》里面說的已經(jīng)很詳細(xì)。只需要認(rèn)真的按照里面所說的去做就可以了。
另外有一些慣例,我覺得明確一點(diǎn)的好:
- 關(guān)于英文縮寫命名,為了簡單,一般只取前三個非元音字母為好,而且單詞長度超過5個字母的才縮寫。
- 對于C++這類兼容過程式的語言,如果是過程式的變量或函數(shù),應(yīng)該采用下劃線連接小寫單詞,如arg_num, get_file_name(),如果是和類與對象相關(guān)的,包括屬性、方法,就采用JAVA風(fēng)格的命名,如argNum,?getFileName()。
3. 代碼重用
理論上代碼重用這是個大話題,不應(yīng)該放在這么小的位置來說。但是實際上軟件開發(fā)很多地方都涉及重用。所以這里只提一些我認(rèn)為最重要的:能下載到的代碼絕不開發(fā)。——事實上很多程序員都以重新發(fā)明輪子為榮,并且都認(rèn)為別人的輪子不好用,比如鄙視STL的C程序員比比皆是。我認(rèn)為老板給你的工資很多時候并不包括重新發(fā)明輪子,不管你覺得怎樣,學(xué)會使用已有的輪子都是一個程序的義務(wù)。否則等于浪費(fèi)老板的投資,對于自己來說雖然好像技術(shù)長進(jìn)了,但是整個項目都被你脫了后腿。與其你自己去寫STL,不如去認(rèn)真讀一讀STL源碼,掌握它的內(nèi)容,然后教更多的程序員去用他。否則我懷疑最后你只能去寫匯編了,那就隨便你了。
代碼重用往往和機(jī)器性能有一定沖突,但是在我看來,很少項目因為性能差那么一點(diǎn)點(diǎn)而掛掉。但是因為代碼開發(fā)效率太低,跟不上項目需求變化而掛掉的項目多的多。所以那些只以性能作為技術(shù)水平標(biāo)桿的程序員,某些時候是項目的毒瘤!
4. 設(shè)計范式
過程式:C語言
結(jié)構(gòu)化編程當(dāng)中,最重要的設(shè)計方法是:自頂而下,逐步細(xì)化。無論你是否在寫過程式范式的代碼,這個方法都應(yīng)該遵守,否則一定會出現(xiàn)劃分粒度不一,難以重用的代碼塊。大部分的巨大函數(shù)體都是忽略這個原則造成的。
一般來說C語言會要求對一個內(nèi)存進(jìn)行操作,并且反應(yīng)執(zhí)行結(jié)果在其之上。所以通常都會有一個類似g_Env之類的全局變量,用來存放多個過程需要的數(shù)據(jù)。為了避免多個函數(shù)需要反復(fù)的通過不同的輸入?yún)?shù)和返回值來“串接”調(diào)用,通常都會設(shè)計成一起去修改 g_Env變量。
同時也會有一個g_Cfg的全局變量充當(dāng)配置文件。面向過程的代碼則很少使用全局變量作為“操作臺”來處理數(shù)據(jù),因為都被封裝到對象里面了。
C語言的回調(diào)模式一般通過函數(shù)指針來實現(xiàn),這個幾乎是做框架代碼的最好用的方法。而面向?qū)ο髣t采用多態(tài)來取代函數(shù)指針,會更安全一些。
對于函數(shù)的返回值,一般來說不會用來真正的“返回”某些數(shù)據(jù),而是返回的是處理的結(jié)果是否正常\異常。而處理結(jié)果的數(shù)據(jù)往往通過輸入?yún)?shù)(指針)來得到,這個是和面向?qū)ο蟠a很大的區(qū)別。面向?qū)ο蟮恼Z言一般支持異常,取代了返回值的“錯誤報告”功能,而返回值則真正是一個處理的結(jié)果。這樣減少了輸入?yún)?shù),會讓API更容易使用,符合理解習(xí)慣,也更不容易出錯。
總體來說,注意抽象好函數(shù)的層次,使用統(tǒng)一的,盡量少一點(diǎn)的全局變量,使用函數(shù)指針實現(xiàn)回調(diào),使用返回值作為函數(shù)的錯誤報告,使用輸入?yún)?shù),就是過程式C語言的主要特點(diǎn)。
OO:設(shè)計模式
對于封裝、多態(tài)、繼承的玩法,最后演變成GOF23種設(shè)計模式。說到底都是為了實現(xiàn)幾個主要的原則,其中最關(guān)鍵的就是“開閉原則”。這方面的書籍也是汗牛充棟,特別需要關(guān)注的是《重構(gòu):改善既有代碼的設(shè)計》。
面向?qū)ο缶幊谭绞绞乾F(xiàn)在最利用適應(yīng)需求變化的一種技術(shù)。包括泛型這種靜態(tài)化的對象技術(shù)。所以無論什么原因,都應(yīng)該掌握一定的這方面知識。
面向?qū)ο笤O(shè)計范式的核心點(diǎn)是去描述現(xiàn)實世界的概念,而非用算法和數(shù)據(jù)去模擬這個世界的運(yùn)行。因為關(guān)注點(diǎn)在概念這種名詞特征上,所以可以先初略后精致的逐步細(xì)化設(shè)計,正好符合需求變化的特征。
動態(tài)模式:JS/PHP/PYTHON……
動態(tài)類型語言以其極致快速的開發(fā)效率,容易掌握的語法而聞名。其中最能提高效率的是動態(tài)數(shù)據(jù)類型。減少了大量的聲明、定義和局限的代碼。甚至減少了大量的數(shù)據(jù)結(jié)構(gòu)的使用。如PHP里面所有的數(shù)組都是哈希表,而JS/PYTHON里面的Object就是哈希表。實際上AS3.0也是有類似的特性。更好的利用這些語法糖和數(shù)據(jù)類型是提高開發(fā)效率的關(guān)鍵。所以我也反對在這類語言里面自己重新包裝一套類似C語言的數(shù)據(jù)結(jié)構(gòu)或者容器類庫,實在是沒必要。
動態(tài)類型語言另外一個特點(diǎn)是腳本化解釋運(yùn)行,不需要維護(hù)堆棧,也不需要考慮編譯的定義。甚至還有交互式終端一行行的去命令式運(yùn)行代碼。把盡量多的業(yè)務(wù)邏輯的處理細(xì)節(jié)“過程”用動態(tài)類型語言(腳本)來執(zhí)行,是提高開發(fā)效率的重要手段。如果你比較一下用C語言編寫CGI和PHP比較一下,你就知道效率相差有多少了。
特定領(lǐng)域:SQL/SHELL
SQL這類語言和一般的語言有比較大的設(shè)計差別,他更多的設(shè)計為“表示”而非“命令,所以需要另外一種思考方式。而這類語言因為和領(lǐng)域結(jié)合很緊,所以是強(qiáng)大的領(lǐng)域工具,包括SHELL和AWK這種腳本語言,具備別的語言非常費(fèi)勁才能實現(xiàn)的功能。在這些領(lǐng)域,盡量使用這些語言會有事半功倍的功效。
SQL中的函數(shù)和存儲過程,是強(qiáng)大的工具,有時候整個統(tǒng)計系統(tǒng)都可以直接在數(shù)據(jù)庫里面運(yùn)行。而很多運(yùn)維的系統(tǒng)工具,用shell來實現(xiàn)則會簡單高效,因為需要操作的功能是操作系統(tǒng)本身。
函數(shù)式:強(qiáng)大的數(shù)學(xué)表達(dá)力
Lisp,schema,erlang這些函數(shù)式語言,采用鏈表來描述一切,只需要棧而無需堆,用遞歸代替循環(huán),這些都很符合多核并行運(yùn)行的要求,而且還能很方便的中斷和恢復(fù)程序運(yùn)行。在業(yè)務(wù)需求變化較少的,而計算任務(wù)比較多的場景,是一種非常強(qiáng)悍的編程工具。對此我了解不是很多,但是很希望有機(jī)會能用函數(shù)式語言做一個東西看看。
構(gòu)建-集成-部署-測試
版本管理-構(gòu)建腳本-自動構(gòu)建-構(gòu)建包管理:
所有的源代碼都必須進(jìn)入版本管理;所有的構(gòu)建、部署、測試腳本也需要進(jìn)入版本管理,所有的一切都應(yīng)該進(jìn)入版本管理。一個構(gòu)建系統(tǒng)的運(yùn)行,應(yīng)該是可以完全從版本管理服務(wù)器上重建一切的。
Hudson是一個很好的自動構(gòu)建服務(wù)器,但是構(gòu)建腳本你還是需要自己去寫。確保你的腳本可以從零開始構(gòu)建,并且在所有你可能碰到的平臺上正常構(gòu)建,如32位和64位系統(tǒng)。
構(gòu)建出來的軟件包,應(yīng)該讓hudson這類系統(tǒng)自動發(fā)布給所有相關(guān)的人,而且可以很方便的通過網(wǎng)絡(luò)獲取到,如HTTP或者SVN。并且需要保留多個歷史版本以備回滾。
部署腳本-部署環(huán)境-自動部署
部署腳本往往是用動態(tài)語言寫成,還會帶有數(shù)據(jù)庫操作等復(fù)雜的內(nèi)容,因此必須也納入版本管理。部署環(huán)境應(yīng)該是足夠安全而且和生產(chǎn)環(huán)境有足夠快速的網(wǎng)絡(luò)連接的。有了這些保障,才最后有自動部署的可能性。最好就是有一個部署服務(wù)器是和生產(chǎn)環(huán)境和辦公網(wǎng)絡(luò),都屬于內(nèi)網(wǎng)(局域網(wǎng))連接的。簡單的自動部署工具必須要運(yùn)維人員能掌握,并且取消開發(fā)人員的使用權(quán)限,避免開發(fā)人員直接修改線上服務(wù)產(chǎn)生的故障。
各類測試-自動測試-結(jié)果報告
代碼提交前應(yīng)該運(yùn)行完成單元測試,代碼在自動構(gòu)建以及自動部署后,應(yīng)該自動運(yùn)行一定的系統(tǒng)測試腳本,結(jié)果放置到構(gòu)建報告中。
一般來說,測試環(huán)境有幾種:開發(fā)環(huán)境、內(nèi)測環(huán)境、外測環(huán)境、運(yùn)營環(huán)境。
在開發(fā)環(huán)境應(yīng)該是單元測試的運(yùn)行環(huán)境。內(nèi)測環(huán)境則應(yīng)該是在自動部署后的其中一個環(huán)境,用以和產(chǎn)品人員溝通和驗證基本功能。外測環(huán)境應(yīng)該和運(yùn)營環(huán)境盡量一致,自動部署后,所有的測試失敗和人員手工測試缺陷,都應(yīng)該視之為BUG進(jìn)入跟蹤系統(tǒng)。而且外測環(huán)境應(yīng)該是運(yùn)維人員的工作范圍,不應(yīng)該讓開發(fā)人員上去搗鼓。經(jīng)過了這三層的測試環(huán)境,不管是代碼功能還是部署設(shè)置,應(yīng)該都能自動化的在運(yùn)營環(huán)境上可靠的運(yùn)行了。
重構(gòu)
兩頂帽子:加功能、改結(jié)構(gòu)
關(guān)于重構(gòu)有很多經(jīng)典的書籍可以參考,比如《重構(gòu):改善既有代碼的設(shè)計》《重構(gòu)與模式》。但其中很重要的一點(diǎn),就是重構(gòu)的時候禁止添加新的特性,因為會讓代碼在修改的時候陷入復(fù)雜的“連鎖”修改,從而讓重構(gòu)困難增加。同時如果你修改了特性,也需要新的單元測試來保障重構(gòu)的正確性,這些都是自己攪合自己的做法。而在增加特性的時候最好也不要重構(gòu),因為你在努力通過測試的時候,也是在整理和驗證需求。只有需求確定了,重構(gòu)的目標(biāo)才會清晰。
單元測試的重要性
重構(gòu)的一個最大的困難,就是怕改的代碼太多,從而出現(xiàn)BUG。但是如果你有一個覆蓋率很高的單元測試集合,你就可以比較放心的去修改代碼,因為一旦出錯你立刻就能知道。當(dāng)然有很多時候單元測試并非萬能,有些情況單元測試確實無法覆蓋,或者架設(shè)測試本身比較復(fù)雜。所以說重構(gòu)還是一個比較高風(fēng)險的動作。測試的工作本身是重構(gòu)成功的最重要保障。
明確重構(gòu)目標(biāo)
很多時候重構(gòu)起源于某些需求難以加入現(xiàn)有系統(tǒng),但是如果只以這個作為重構(gòu)目標(biāo),往往結(jié)果并非完全讓人滿意。實際上重構(gòu)的目標(biāo)應(yīng)該是一個對于需求變更的總結(jié)以及前瞻。某些時候是以實現(xiàn)某種設(shè)計模式作為重構(gòu)的目標(biāo)。而選取的模式就是對于需求分析的結(jié)果。重構(gòu)中目標(biāo)的選取是至關(guān)重要的,這個需要對業(yè)務(wù)和技術(shù)有深入的理解,從另外一個角度看,重構(gòu)目標(biāo)和一開始的設(shè)計工作是同等的工作。所以說軟件開發(fā)的“架構(gòu)設(shè)計”實際上是持續(xù)在進(jìn)行的。
加班
加班的原因:學(xué)習(xí)、體力活
程序員的加班司空見慣,究其原因,有兩種,一種是不知道如何實現(xiàn),另外一種是工作量大。
對于第一種情況,有些人會寫一堆代碼然后調(diào)試,發(fā)現(xiàn)不對又改。而我建議是應(yīng)該把“不確定”的部分,設(shè)計一些代碼片段功能(單元),然后使用單元測試作為驗證,通過逐步掌握這些功能,最后形成可重用的代碼。這會是最節(jié)省時間的方法。
對于第二種情況,應(yīng)該多考慮設(shè)計一些工具。比如使用一些腳本語言來代替一些數(shù)據(jù)的體力活,嘗試抽取可重用代碼來簡化邏輯。做這些可能一開始會比較費(fèi)時間,但是長期來看,卻是可以節(jié)省下大量的加班時間。
實際每個程序員都知道生命寶貴,并不會有意的拖延工期,除非覺得這個工作實在是不值得去做。所以因為進(jìn)度原因?qū)е碌膹?qiáng)制加班,最后都會被“減班”還回來。損失比不加班還要大。《人件》里對于這個有詳細(xì)的論述,我也不去重復(fù)了。
如果是自愿性加班,本節(jié)會有用。如果是被迫性加班,實際上是無論如何不會增加整體的開發(fā)效率。所以如果真的要用加班這招,最重要的是變“被迫”為“自愿”。
如果作為團(tuán)隊領(lǐng)導(dǎo)者,你看到整個團(tuán)隊已經(jīng)能在每天6小時內(nèi)高效的工作,再強(qiáng)迫加班最后只能是降低開發(fā)速度。原因不再細(xì)速,可以參考《人件》。因此,如何讓團(tuán)隊加班的方法,應(yīng)該改成如何讓團(tuán)隊不用加班的思考。改進(jìn)開發(fā)工具,提高開發(fā)技術(shù),加強(qiáng)團(tuán)隊建設(shè),這些都是有效的方法,唯一需要避免的就是如何“強(qiáng)迫”團(tuán)隊加班。
避免加班的方法:思考設(shè)計、學(xué)習(xí)提高工作效率的方法、在上班時間內(nèi)加班
根據(jù)我的經(jīng)驗,如果一個程序員一天有6小時都高度注意力的做開發(fā),實際上開發(fā)效率已經(jīng)可以達(dá)到很高,而很多一天工作12小時的程序員,其高度注意力時間往往只有4個小時。所以不加班完全是可能的,除去別的因數(shù),對于個人來說,避免自己玩死自己是最用的知識。在動手之前先仔細(xì)考慮清楚細(xì)節(jié),可以避免后期邏輯BUG的折磨,這種BUG是最難調(diào)試的。而學(xué)習(xí)各種工具以及關(guān)注代碼在提高開發(fā)效率上的知識,則是另外一個重要的手段。因此再次吐槽那些不重視開發(fā)效率的程序員,你們輕視面向?qū)ο?#xff0c;輕視軟件工程知識,輕視那些對程序性能無關(guān)的知識,最后的苦果就是——一輩子加班!
程序員的狀態(tài)起伏
【設(shè)計-編碼-調(diào)試-總結(jié)】的循環(huán)
程序員在開發(fā)程序的過程中,往往會經(jīng)歷以上幾個階段,在編碼階段是狀態(tài)的高峰,調(diào)試階段開始陷入痛苦,很多時候會跳過總結(jié)。整個循環(huán)完成后,則是疲憊不堪,注意力無法集中。因此我們可以注意幾個重要的環(huán)節(jié),減輕這些壓力。
首先設(shè)計階段如果能盡快熱身,直接更專注的深入細(xì)節(jié),則會避免無休止的修改方案,對于開發(fā)的指導(dǎo)也會更明確。而編碼環(huán)節(jié)采用更多的工具和技巧減少體力和腦力的消耗。如果設(shè)計階段和編碼階段的工作能關(guān)注代碼可讀性和結(jié)構(gòu),最后的調(diào)試往往也不會非常困難,然后為了獎勵一下自己,可以寫一點(diǎn)總結(jié)。
打破循環(huán)造成的心理影響
如果在每個階段中能盡量多的融入下一個階段的工作,同樣也可以起到降低壓力的作用。比如在設(shè)計階段就把很多重要的代碼命名工作做了,在編碼的時候就順手解決所有的語法錯誤,調(diào)試階段的測試用例就可以用來作為工作匯報的材料。
避免疲勞戰(zhàn)術(shù)的方案:縮小循環(huán)體
在開發(fā)的循環(huán)中,每個階段越長,最后的疲勞就會越大,而每個過程越短,則越容易被接受。所以盡量在設(shè)計階段劃分的細(xì)致一些,可以明顯的降低后續(xù)的工作壓力。縮小開發(fā)流程也是敏捷開發(fā)模式的重要觀點(diǎn)。這對需求分析、代碼結(jié)構(gòu)、測試技巧都有很高的要求。重視這些知識,就會明顯的降低工作壓力。
四. 架構(gòu)設(shè)計
邏輯架構(gòu)
邏輯架構(gòu)主要是為了明確需求而做的設(shè)計。針對需求以及需求變化作為架構(gòu)目標(biāo)。因此邏輯架構(gòu)在架構(gòu)設(shè)計中,是對于提高程序員生存率最至關(guān)重要的一個設(shè)計。采用合理的邏輯架構(gòu),將會大大降低需求變更對開發(fā)的延遲作用。邏輯架構(gòu)最直接指導(dǎo)代碼中互相耦合的情況,仔細(xì)設(shè)計好耦合的規(guī)則,會讓后續(xù)開發(fā)事半功倍。
邏輯架構(gòu)的經(jīng)典模式有《POSA》中指出的幾種,其中以分層和微核模式最為常用。MVC和管道過濾器模式則在特定系統(tǒng)中是最優(yōu)模式。后續(xù)基于分布系統(tǒng)的SoA等架構(gòu)模式,則多是建立在分層的基礎(chǔ)上。分層模式可以按需求關(guān)注點(diǎn)來劃分層次,因此可以安排不同經(jīng)驗水平的程序員分別承擔(dān)。微核模式則直接按具體功能劃分代碼,適合水平相差不大的團(tuán)隊進(jìn)行功能的并行開發(fā),因為可以單獨(dú)測試。
不管何種邏輯架構(gòu),都是把功能-代碼劃分成多個不同的部分。這些部分通過一定的規(guī)則互相耦合。這提供了最好的工作量劃分依據(jù),以及互相之間的接口定義。由于存在接口定義,將來人員流動的時候,也可以根據(jù)接口來理解代碼模塊的邏輯。良好的工作劃分,能極大的降低程序員之間的低效溝通,使得工作能被多個人同時推進(jìn),而工作能被同時推進(jìn),則是軟件項目能利用好人力資源最直接原因。
需要指出的是,很多使用非面向?qū)ο笳Z言的項目,特別是C語言項目,非常蔑視進(jìn)行邏輯架構(gòu)設(shè)計,因為所謂結(jié)構(gòu)化編程其實約束很少,而大家往往直接忽略掉。這是非常大的問題,導(dǎo)致一些復(fù)雜的“過程”最后完全無法維護(hù)。有很多項目到最后不管如何增加人手,都無法提高開發(fā)速度,就是因為實際那些代碼無法利用更多的人力,反而增加了更多的溝通成本,架構(gòu)直接降低了開發(fā)效率——往進(jìn)度落后的項目增加人手,只會讓進(jìn)度更見落后。
運(yùn)行架構(gòu)
運(yùn)行架構(gòu)主要是為了解決運(yùn)行時的質(zhì)量需求,主要分為性能需求和可用性需求。系統(tǒng)的性能需求除了在代碼內(nèi)部通過算法來提高,往往還要采用緩存和并行的方式來擴(kuò)展。這就涉及到程序的運(yùn)行時設(shè)計,如數(shù)據(jù)處理流,多進(jìn)程間通訊,數(shù)據(jù)的多種格式轉(zhuǎn)化。對于可用性,實際上也是通過并行熱備的方法來實現(xiàn),因此運(yùn)行時的各種控制命令、地址、消息數(shù)據(jù)流也是運(yùn)行架構(gòu)需要考慮的。
運(yùn)行架構(gòu)一旦確定,等于大部分的“實現(xiàn)”代碼確定了下來,設(shè)計一個有足夠擴(kuò)展性和可用性的運(yùn)行架構(gòu),可以減少后期為了擴(kuò)展性能或提供可用性做更多的代碼。而且也降低了系統(tǒng)在運(yùn)行期對開發(fā)工作的干擾——正在運(yùn)行系統(tǒng)出了問題,往往是在節(jié)假日或休息時間,都會迫使程序員回公司或者上線維護(hù),極大的增加了開發(fā)人員的疲勞,同樣會影響項目的進(jìn)度。因此一開始就考慮可用性和性能擴(kuò)展問題,并且實際的用代碼去實現(xiàn)好,絕對是一個未雨綢繆的好方法。明智的項目經(jīng)理會愿意在項目前期花多一些資源在這種“非功能性”方面的開發(fā),從而得到一支士氣水平穩(wěn)定的開發(fā)團(tuán)隊。
通常運(yùn)行架構(gòu)需要至少設(shè)計一個可以水平擴(kuò)展的接入層或邏輯層,以便通過增加服務(wù)器來提高性能擴(kuò)展。因此也需要預(yù)先設(shè)計負(fù)載均衡的系統(tǒng),如果是WEB系統(tǒng),用DNS輪訓(xùn)是最簡單方便的,如果是游戲類用戶間交互比較強(qiáng)的,設(shè)計一個“目錄服務(wù)器”用來提供客戶接入地址是最少需要做的。
可用性架構(gòu)中,最少要為邏輯服務(wù)器和數(shù)據(jù)庫(持久層)服務(wù)器設(shè)計至少一個熱備服務(wù)器,在機(jī)器斷電或者機(jī)房斷網(wǎng)的情況下,可以經(jīng)過程序自己的檢測機(jī)制,自動跳轉(zhuǎn)到備份服務(wù)器上處理。一般數(shù)據(jù)庫服務(wù)器mysql采用master-slave用來備用,而邏輯服務(wù)器則可以使用目錄服務(wù)器來指定備份服務(wù)器地址。當(dāng)然了,如果目錄服務(wù)器也需要熱備的話,則需要另外一些代碼支持,如客戶端本身就會去多次嘗試不同的目錄服務(wù)器。
一般有“架構(gòu)設(shè)計”的系統(tǒng)都會有運(yùn)行架構(gòu)的設(shè)計,所以我并不認(rèn)為需要如何強(qiáng)調(diào)其必要性,反而需要強(qiáng)調(diào)的是,系統(tǒng)架構(gòu)設(shè)計,遠(yuǎn)遠(yuǎn)不止是運(yùn)行架構(gòu)的設(shè)計。
開發(fā)架構(gòu)
開發(fā)架構(gòu)一般用于滿足開發(fā)時質(zhì)量需求,和邏輯架構(gòu)有密切的關(guān)系。開發(fā)架構(gòu)定義了源代碼、二進(jìn)制和發(fā)布包的文件、路徑、負(fù)責(zé)人的劃分和依賴關(guān)系。一個按照固定開發(fā)架構(gòu)設(shè)計的系統(tǒng),能方便的開發(fā)出持續(xù)集成的各種工具。
開發(fā)架構(gòu)一般的主要呈現(xiàn)形式為SVN目錄構(gòu)造方式,或者在makefile、IDE的項目設(shè)置文件中。一個軟件通常分成多個不同的“系統(tǒng)”或者“項目”。很多如Eclipse需要每個項目只存在一個執(zhí)行入口main(),所以開發(fā)架構(gòu)在這種情況下同時也收到運(yùn)行時架構(gòu)的進(jìn)程設(shè)計限制。
一般來說功能相對獨(dú)立的代碼會成為一個“模塊”或者“系統(tǒng)”(項目),通過提供程序鏈接接口,如DLL,.a和.h文件,JAR文件,或者SWF文件來提供。這個粒度的劃分有多種標(biāo)準(zhǔn),如按功能的,按開發(fā)者的。但是有一個通用的準(zhǔn)則,就是如果已經(jīng)設(shè)計的不同“模塊”中都有調(diào)用同一個或者類似的代碼塊。這塊代碼就有資格自己成為一個平行的“模塊”,以便日后修BUG可以單獨(dú)升級。
個人比較喜歡按業(yè)務(wù)功能的層次來劃分模塊,這樣有利于劃分任務(wù),減少代碼互相影響,最重要的是比較容易讓人理解。但是就必須經(jīng)常把工具類模塊協(xié)商抽取成為“公共模塊”。
部署架構(gòu)
部署架構(gòu)對于持續(xù)集成,降低程序員的運(yùn)營期壓力,有至關(guān)重要的作用。一個好的部署架構(gòu)可以提高性能和可用性。讓程序員可以按部就班的去解決問題。
運(yùn)行時架構(gòu)在軟件層面提供性能和可用性。而部署架構(gòu)考慮的更多是硬件層面。比如網(wǎng)絡(luò)機(jī)房的分布,服務(wù)器硬件的搭配,監(jiān)控和維護(hù)工具軟件的安裝。開發(fā)測試網(wǎng)絡(luò)和運(yùn)營網(wǎng)絡(luò)的設(shè)置。關(guān)于安全性的配置。
幾個比較明確的經(jīng)驗是:
數(shù)據(jù)架構(gòu)
數(shù)據(jù)架構(gòu)對于任何業(yè)務(wù)都有很重要的影響。對于用戶產(chǎn)生的數(shù)據(jù),架構(gòu)本身需要容易備份和恢復(fù),數(shù)據(jù)就是財富,而數(shù)據(jù)架構(gòu)是存放財富的方案。對于開發(fā)團(tuán)隊產(chǎn)生的數(shù)據(jù),則需要完善和方便的管理工具,便于修改和增加這些數(shù)據(jù)。
數(shù)據(jù)架構(gòu)本身還涉及性能、易用性等多個方面。一般來說分為使用關(guān)系型數(shù)據(jù)庫和不使用關(guān)系型數(shù)據(jù)庫兩種。但是不管那種,對于數(shù)據(jù)的備份(熱備)和恢復(fù)都是最首要應(yīng)該考慮的問題。數(shù)據(jù)的結(jié)構(gòu)過于復(fù)雜其實不利于備份和恢復(fù)。而很多時候大數(shù)據(jù)量又產(chǎn)生“分區(qū)”需求(分庫分表),這是分布數(shù)據(jù)存儲的課題。
對于使用關(guān)系型數(shù)據(jù)的,一般需要依賴數(shù)據(jù)庫服務(wù)器自己的熱備功能和分區(qū)功能,或者自己去實現(xiàn)。然后使用ORM軟件來操作這些數(shù)據(jù)。所以關(guān)系型數(shù)據(jù)不宜做的過于復(fù)雜,太多的“外聯(lián)”表會讓整件事變得很復(fù)雜。
如果不使用關(guān)系型數(shù)據(jù)庫,現(xiàn)在的NoSQL風(fēng)潮提供了很多可選的方案,這些方案最大的特點(diǎn)就是對于結(jié)構(gòu)復(fù)雜的數(shù)據(jù)有良好的擴(kuò)展性,對于大數(shù)據(jù)量也有優(yōu)秀的擴(kuò)展功能——重要的是不用你自己去代碼實現(xiàn)。缺點(diǎn)則是可能無法保證“統(tǒng)一性”。比較實際的觀點(diǎn)是,盡量少使用關(guān)系型數(shù)據(jù)。雖然它的概念已經(jīng)深入人心。
每個模塊都可以做架構(gòu)設(shè)計
上面的幾個架構(gòu),基本包含了整個軟件架構(gòu)應(yīng)該涉及的方面。而我們往往比較重視一些“大項目”的架構(gòu)設(shè)計,而比較忽視一些中小項目的架構(gòu)設(shè)計。實際上大部分項目并非“大項目”,而大型項目本身也很可能劃分成更小一點(diǎn)的項目來外包,所以我們應(yīng)該對于每個項目,都以架構(gòu)設(shè)計的觀點(diǎn)去分析和設(shè)計,只是不需要陷入文檔的案牘之中就好了。
一些好的架構(gòu)設(shè)計,也可以在多個模塊和項目中共用。這種共用的好處非常多,一個是可以節(jié)省開發(fā)時間,另外也可以少走以前的彎路。最重要的是如果積累下這種設(shè)計的文檔和思想,可以讓整個團(tuán)隊的開發(fā)效率都得到提高。
五. 管理激勵
明確目標(biāo)
目標(biāo)管理是現(xiàn)代管理學(xué)的一個重要成果。明確團(tuán)隊的目標(biāo),然后讓所有人都理解并認(rèn)同這個目標(biāo),是管理中最重要的工作。只有每個人明確了目標(biāo),才可能發(fā)揮出他的主觀能動性。而且要有明確的目標(biāo),團(tuán)隊成員之間才可能合作。否則成員之間可能會互相拆臺或者推卸責(zé)任。
目標(biāo)應(yīng)該是整個團(tuán)隊的目標(biāo),而不應(yīng)該是只劃分到個人,因為這樣不利于團(tuán)隊的整合,而會形成嚴(yán)重的個人主義。當(dāng)然我們最常見的是團(tuán)隊中對于目標(biāo)不明確。
目標(biāo)應(yīng)該包括以下內(nèi)容,才稱得上明確。首先是項目要滿足的市場需求,這是項目的愿景。其次是項目怎樣才叫做的好的標(biāo)準(zhǔn),一般是和競爭對手比較的結(jié)果。最后是項目目標(biāo)和個人發(fā)展之間的關(guān)系。三層目標(biāo)必須都讓每個人明確和認(rèn)同,才能真正激發(fā)出團(tuán)隊的動力來。
市場需求如果大家不認(rèn)可,就會覺得項目不值得做,這個時候就需要領(lǐng)導(dǎo)者來用數(shù)據(jù)和事實證明給大家看。
項目優(yōu)秀的標(biāo)準(zhǔn),不可無限拔高或者虛無縹緲,明確的競爭對手?jǐn)?shù)據(jù)是最好的標(biāo)準(zhǔn),雖然這個信息通常很難獲得,但是這個是團(tuán)隊中非常有凝聚力的信息。應(yīng)該盡量的獲取,然后公布給團(tuán)隊。
每個人和項目成敗的關(guān)鍵,則是核心的激勵機(jī)制,雖然很多時候開始很難明確到金錢上的獎勵,但是應(yīng)該起碼提供一個“最好情況下”的許諾。很多項目以收益分紅,或者過程評價來加工資作為明確的激勵。
主要手段
人在集體中能發(fā)揮的作用必然比單個人要大,這是人類作為群居動物的天性所決定的。如果你有一定的工作經(jīng)驗,必定會體會過一個團(tuán)結(jié)的團(tuán)隊所發(fā)揮的良好作用。如何能構(gòu)造起一個真正的高效的團(tuán)隊,我認(rèn)為最重要的方法是“溝通”。這種溝通必須是全方位的,包括團(tuán)隊成員之間的私交,他們互相之間在工作能力、人品性格、興趣愛好方面的了解。在管理者和團(tuán)隊之間,對于項目前景、公司狀況等一切和團(tuán)隊切身利益相關(guān)的方面的信息,都必須有良好的溝通。如果程序員覺得你在隱瞞些東西,你一定就是在某些方面有所保留。這種猜忌會破壞團(tuán)隊的形成。所以對于大量看起來是“保密”的信息上面,對團(tuán)隊盡量多的公開,是能讓團(tuán)隊得到主人翁感覺的重要手段。傳統(tǒng)管理方法中很多時候強(qiáng)調(diào)公司的信息保密,個人對于團(tuán)隊的效忠。而這些在高科技開發(fā)企業(yè)中是行不通的,因為他們就掌握著公司的最大機(jī)密——產(chǎn)品開發(fā)。
管理者除了對“人”做事,直接做事也必不可少,開發(fā)工作有很多方面是在做設(shè)計,所以開發(fā)工作本身并不是所謂的體力活,而是一些精巧的設(shè)計工作。除了自己參與開發(fā)工作,對于團(tuán)隊其他部分的設(shè)計工作,特別是其中的重要決策,管理者也需要盡量多的參與。一方面這種參與可以培訓(xùn)團(tuán)隊成員,另外一方面能加強(qiáng)對于項目控制。在決策的過程中,通過廣泛的討論,也是團(tuán)結(jié)團(tuán)隊的一個手段。當(dāng)然剛愎自用的處理方法就會產(chǎn)生反效果。
因為程序開發(fā)本身是一種高度自律型的工作,所以管理者的“不做”比“做”更重要,而且應(yīng)該提供不受干擾的環(huán)境。在程序員注意高度集中的情況下,工作效率是最高的。試圖不斷的“參與”開發(fā)而打斷程序員的工作,其實是在降低工作效率。好的管理者應(yīng)該能讓程序員沉浸在開發(fā)工作當(dāng)中,完全不去考慮什么進(jìn)度報告,工作匯報之類的事情。
因為程序員對于電腦的熟悉,所以經(jīng)常會把一些別“專業(yè)”的行當(dāng)混合起來交給程序去做。比如寫代碼的同事去處理數(shù)據(jù)庫,由或者讓程序員同事負(fù)責(zé)運(yùn)維服務(wù)器和網(wǎng)絡(luò)……術(shù)業(yè)有專精,如果一個程序員專心的做數(shù)據(jù)庫的工作,他會比同時做其他幾個事情做的更好。更不用說讓程序員去夾網(wǎng)線搬箱子這些了。總體來說,提供資源支持,降低團(tuán)隊的“非專業(yè)”精力消耗。
人力分工
按照專業(yè)領(lǐng)域分工;專業(yè)再細(xì)分分工;軟件開發(fā)團(tuán)隊?wèi)?yīng)該學(xué)習(xí)外科醫(yī)生的團(tuán)隊,采用嚴(yán)格的分工合作,來降低混亂的溝通。每個人只負(fù)責(zé)自己的事情,會做的非常好。因此如果程序能很好的分成5個模塊,就使用5個程序員,然后為他們配上專業(yè)的秘書,數(shù)據(jù)庫管理員,測試人員,項目經(jīng)理,運(yùn)維人員,IT人員,以及其他的資源處理人員,比如美術(shù)資源處理專員。
關(guān)注工作分切點(diǎn)的協(xié)議,因為人力分工是提高效率的重要手段,所以人員之間的切分點(diǎn)——協(xié)議或者流程,就是很關(guān)鍵的東西。客戶端和服務(wù)端程序員之間,通常就是直接的通訊協(xié)議,應(yīng)該把通訊協(xié)議變成一種代碼,然后雙方都使用這種代碼。客戶端程序員和美術(shù)之間通常也應(yīng)該使用某種基于軟件工具的格式文件,比如是UI編輯器的結(jié)果。處理WEB的團(tuán)隊往往由美術(shù)提供圖片,然后由專人切圖變成HTML,而這個HTML文件就是很好的協(xié)議文件。有些數(shù)據(jù)錄入人員使用JSON格式的文件,或者是某種嚴(yán)格定義的EXCEL文件作為協(xié)議文件。
很多團(tuán)隊喜歡“廣播”方式的溝通,任何一個事情都讓所有人在一個QQ群里面看到,或者任何一個事情都抄送郵件給一堆人。實際上這種溝通只會浪費(fèi)別人的時間,所以管理者應(yīng)該降低溝通范圍,減少“噪音”。
在《人件》中,提到了高效團(tuán)隊的形式——膠凍團(tuán)隊。也就是我們所說的非常團(tuán)結(jié)而且互相信任的團(tuán)隊。很多公司會以拓展訓(xùn)練和部門活動的方式去推動形成團(tuán)隊互信,這些都是有用的。但是在工作過程中,更重要的是讓信息共享來打破可能存在的隔膜,給與更大的自由發(fā)揮空間讓團(tuán)隊成員有機(jī)會互動,組織團(tuán)隊成員間一起討論和解決問題。讓團(tuán)隊成員都感覺到受關(guān)注,并且提醒他們互相關(guān)注。多讓大家一起吃午飯。
績效考核
績效考核應(yīng)該考核做了什么事,而不是做的怎么樣;這個和很多按“結(jié)果”管理的老板很不接受。但是如果你只是想把績效考核作為一個發(fā)獎金的機(jī)制的話,單獨(dú)使用獎金考核機(jī)制就可以了。績效考核應(yīng)該是推動別人去做某件事的工具。對于已經(jīng)明確的方法或者子目標(biāo),通過這種細(xì)化的方式去指導(dǎo)下屬工作。因為是需要事后算賬的,而且是量化的,所以下屬會對這個事情很認(rèn)真,同時那些不好量化的事情,管理者也很難執(zhí)行績效考核。所以對于“去做某些事”,是績效考核最好的目標(biāo)。
通過考核結(jié)果提供正式的工作方法意見。績效考核本身有個反饋的過程,這個反饋的過程應(yīng)該提供給下屬針對每個具體事情的建議。這種具體的,單獨(dú)的一對一的指導(dǎo),會提高團(tuán)隊的穩(wěn)定性。而且也讓團(tuán)隊成員獲得“受關(guān)注”的感覺。這種感覺是形成高效團(tuán)隊的重要工具。
考核不能代替目標(biāo),不能阻礙目標(biāo),而應(yīng)該是一個溝通工具。績效考核通常會涉及大量的文檔工作,也會有很多量化的工作,但是這些工作,往往不能完全代表商業(yè)目標(biāo)的完成情況。所以有些時候只是平白的增加了管理工作量。績效考核的設(shè)定首要需要考慮是不能阻礙團(tuán)隊目標(biāo)的實現(xiàn)。很多時候甚至難以覆蓋目標(biāo)。所以績效考核應(yīng)該是成為一種溝通的工具:定時、定量、定人的交換對于工作方法的意見。
目標(biāo)達(dá)成情況作為考核的客觀指標(biāo),但不應(yīng)該是主要績效考核指標(biāo)。最簡單的績效考核指標(biāo)就是收入或者利潤率。但是這種簡單指標(biāo)除了在動機(jī)上提高下屬的工作熱情外,并沒有從方法和經(jīng)驗上幫助團(tuán)隊成員。有效的考核是引導(dǎo)下屬安裝更有經(jīng)驗的方法去實現(xiàn)目標(biāo)。
進(jìn)度掌控
通過測試來了解進(jìn)度;一切軟件的開發(fā),如果無法測試,就是無法了解的。沒有人回去通過讀代碼了解項目的進(jìn)度。所以項目本身必須具備經(jīng)常提供“可測試”的功能。一旦進(jìn)入測試,項目完成的數(shù)量和質(zhì)量都立刻一目了然了。
用提高工作效率和提供資源的方法推進(jìn)進(jìn)度,而不是通過加班。加班是最有效的降低工作效率的方法。只有降低本身進(jìn)度推進(jìn)的損耗——內(nèi)耗,改善工作方法——更好的工具和更多的知識,除此之外很難有別的加快進(jìn)度的手段。但是,你也可以通過增加更多的資源,比如人力或者機(jī)器。如何把資源放在合理的地方,本身是一門學(xué)問,本文在上面很多節(jié)都有提到如何有效的使用資源——人力和金錢。
慶祝每一個進(jìn)度節(jié)點(diǎn)。團(tuán)隊需要鼓勵,才能保持速度。慶祝本身又是凝聚團(tuán)隊的一個契機(jī),讓成員覺得在這群人中間能不斷取得成功,本身就會增加互相合作的意愿。如果無端端搞一些團(tuán)建活動,會讓人覺得厭煩,但是慶祝進(jìn)度節(jié)點(diǎn),則大家都會認(rèn)同,可能只是一起吃個飯,但是也是非常有效的一頓飯。
確保公布進(jìn)度的目標(biāo),并且爭取團(tuán)隊支持。進(jìn)度的目標(biāo)必須能達(dá)成共識,“無理”的目標(biāo)實際上不能成為目標(biāo),團(tuán)隊從此也會陷入最差的狀況——沒有目標(biāo)。所以進(jìn)度目標(biāo)本身需要讓所有人理解并且愿意去努力。通過共同的進(jìn)度目標(biāo),來促進(jìn)團(tuán)隊中所有人的積極性——那些喜歡偷懶的家伙也會不好意思。
在重視質(zhì)量的情況下推進(jìn)進(jìn)度,并且為質(zhì)量犧牲一定的進(jìn)度。項目質(zhì)量是團(tuán)隊和個人為之“自豪”的重要因數(shù)。如果你想擁有具備榮譽(yù)感的團(tuán)隊,就需要為此付出一定代價,可能犧牲一些時間,來獲得更好的產(chǎn)品質(zhì)量,實際上這是個事半功倍的事情。因為產(chǎn)品質(zhì)量在長期來看,還是能提供更好的效益的。進(jìn)度壓力如果造成太多的粗制濫造,會讓后期的團(tuán)隊越來越?jīng)]信心趕上進(jìn)度。最后被迫推倒重來,或者陷入一個“長期的重構(gòu)”工程中。這些都是缺乏遠(yuǎn)見導(dǎo)致的問題。
預(yù)算制訂
放松固定資產(chǎn)的預(yù)算,盡早投入固定資產(chǎn)預(yù)算。項目初期成本中有很大量的固定資產(chǎn)投入。而這些預(yù)算看起來可以用更便宜但是質(zhì)量更差的替代品來替換。但是從長期來看,人力成本才是最重要的大頭。而如果你的固定資產(chǎn)太少,也會難以招聘或者穩(wěn)住最優(yōu)秀的那批員工。優(yōu)質(zhì)的固定資產(chǎn)不但折舊率更低,而且能讓程序員發(fā)揮出更好的功效,直接節(jié)省那些高額的人力成本。
收緊人力資源預(yù)算,重視10倍效率員工的作用。人員的溝通成本,是所有關(guān)于人員的成本中最高昂的。人越少,需要的溝通就越少。很多公司在發(fā)展期喜歡快速擴(kuò)充團(tuán)隊,希望能抓住機(jī)會盡快占領(lǐng)市場。但是請記住,一個母親懷一個孩子需要10個月,100個母親去懷一個孩子,同樣需要10個月。團(tuán)隊和項目的進(jìn)度并非靠人的數(shù)量增加就能加快的。而且更重要的,優(yōu)秀員工的工作效率最大可以比一般員工的效率高10倍以上,你只需要給他們5倍的工資,就能節(jié)省下另外50%的工資,同時還有不止50%的固定資產(chǎn)投入和其他費(fèi)用。少而精的團(tuán)隊在更方面都比龐大良莠不齊的團(tuán)隊更有效率。
針對風(fēng)險,不斷修改預(yù)算,項目進(jìn)度越后期,預(yù)算越準(zhǔn)確。軟件項目開發(fā)和拍電影一樣,具備很高的風(fēng)險。不但成本難以預(yù)料,而且收益也要最后才能知道。因此對于預(yù)算來說,不斷的記錄和回顧預(yù)算執(zhí)行情況,以及其效率,修改現(xiàn)行預(yù)算方案,才能真正適合開發(fā)的進(jìn)度。那種一年都按年度預(yù)算去執(zhí)行的死板方法,是無法適應(yīng)快速變化的軟件開發(fā)項目的。
風(fēng)險防御
留出過冬的口糧,定出必須籠絡(luò)的人員,盡早進(jìn)入資金循環(huán)。軟件項目風(fēng)險之高,難以用其他行業(yè)完全類比。就算最著名的公司如微軟、IBM也頻頻推出失敗的產(chǎn)品。因此在資金上留有盡量大的余地非常重要,很多項目經(jīng)歷過瀕死體驗后,才能實現(xiàn)商業(yè)成功。軟件項目能繼續(xù)高效的開發(fā)下去,核心人員是至關(guān)重要的,讓他們擁有足夠的耐心和薪水,和項目繼續(xù)下去,才有收獲那天的希望。而降低風(fēng)險的最好方法,則是盡快去接觸風(fēng)險,盡快讓產(chǎn)品上市,讓產(chǎn)品開始嘗試賺錢,能讓開發(fā)方向盡快明確到最實際的內(nèi)容上來。團(tuán)隊內(nèi)的爭論和疑惑也會因為實際的財務(wù)數(shù)字而消散,大家的目標(biāo)會更清晰——賺錢。
師徒制度預(yù)備人員流動。人員流動是不可避免的,就算你做到100分,還是會有別的原因?qū)е鲁绦騿T離職。因此除了在代碼上提倡可讀性和良好的結(jié)構(gòu),重視文檔和過程記錄,采用預(yù)備接替人員是很重要的手段。讓資深程序員和一個學(xué)徒程序員一起工作,能盡快提高學(xué)徒程序員的能力,同時也讓代碼能有多一個人熟悉。在師傅離職后,徒弟就可以升職到師傅的地位,也是一種良性的激勵。而徒弟對于這個代碼的感情,是別人所無法比擬的。
盡早進(jìn)入團(tuán)隊和項目估值,尋找合適的買家。項目除了直接到用戶市場上去實現(xiàn)商業(yè)價值外,還應(yīng)該看到,軟件項目因為他的結(jié)構(gòu)性和擴(kuò)展性,往往會在更大的范圍內(nèi)具有價值。一些其他商業(yè)方向的公司或者投資人,可能會看重你的項目的擴(kuò)展價值。而這些擴(kuò)展價值需要一定時間來讓別人認(rèn)識到,因此對于管理者,在清晰的掌握項目的全面價值的情況下,盡早的介紹給潛在的投資人和客戶,能讓項目擁有更廣闊的前景,從而降低其天然的風(fēng)險。
?
轉(zhuǎn)載于:https://www.cnblogs.com/purpleraintear/p/6160716.html
總結(jié)
以上是生活随笔為你收集整理的如何提高程序员的生产率 (2)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何写优雅的代码(5)——远离临界区噩梦
- 下一篇: css实现实心三角箭头,兼容ie