閱讀306 返回首頁    go 技術社區[雲棲]


《Microsoft.NET企業級應用架構設計(第2版)》——2.2 軟件項目的機製

本節書摘來自異步社區《Microsoft.NET企業級應用架構設計(第2版)》一書中的第2章,第2.2節,作者: 【意】Dino Esposito(埃斯波西托) , Andrea Saltarello(索爾塔雷羅)著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看

2.2 軟件項目的機製

如果你問:“什麼導致項目失敗?”,你得到的最常見的回答可能會把失敗歸咎到與業務有關的問題,比如說,缺少需求,項目管理不到位,成本估算不正確,缺少溝通,甚至各個團隊的人員相互不配合。你很難看到壞代碼可能導致問題這種情況。

有鑒於此,我們認為未被發現的BBM可以嚴重損害軟件項目,但未能處理的BBM卻可以真的毀了它。

最終,個體以及個體之間的實際互動才能真的決定軟件項目的成功或失敗。但是,組織結構及其整體文化也會影響最終結果。

2.2.1 組織文化
Apple公司的組織看起來很受“一人秀”(One-man-show)創意的啟發,至少在史蒂夫·喬布斯時代是這樣。一個人推動創意和策略,所有團隊支持和實現這個策略。隻要這個創意是偉大的,策略是合適的,成功就會到來。
你可能還記得發生在2008年的一件事,當時Microsoft內部的兩個組出品了兩個幾乎等同的框架—LINQ to SQL和Entity Framework。外界很難理解是什麼原因導致了這樣的情況。

注意:
在Walter Isaacson寫的史蒂夫·喬布斯傳記裏,你可以讀到關於按部門劃分公司的一段非常有趣的見解。史蒂夫·喬布斯分享了他對為什麼是Apple而不是Sony在iPod的創意上取得成功的看法。為了實現創意,Apple首先要構建硬件和軟件,然後就音樂的版權進行談判。Sony這樣的公司在硬件和軟件上擁有的經驗至少與Apple一樣,此外,自家已經擁有音樂和電影的版權。那麼,為什麼Sony沒有建立iPod業務呢?
根據喬布斯的看法,Sony的文化是在公司裏擁有多個分部,每個分部都有自己的盈利/虧損賬戶。或許,從音樂版權獲得盈利的分部認為從MP3播放器賺錢的分部是一個威脅。兩個分部互相打架而不是為了公司的成功共同努力。這本書是Walter Isaacson寫的《Steve Jobs》(Simon & Schuster,2011)。

1.團隊和隊員
有一個笑話是關於一個意大利隊和一個德國隊參加八人劃船比賽的。德國隊隻有一個領隊,其餘都是隊員,他們贏了這場比賽。意大利隊調查輸掉的原因,發現他們的隊隻有一個隊員,其餘都是領隊。

團隊就是讓在技能上互補的人們互相合作。

注意:
劃船隊笑話的後續是討論意大利隊怎樣計劃報複賽,但這可能超出本書的範圍了。不管怎樣,如果你好奇我可以告訴你,意大利隊解雇了隊員,重組隊伍,裏麵有4個領隊、兩個領隊的上司、一個總司令以及一個新的老隊員(因為他更有經驗)。
在軟件項目裏,管理者和開發者都有自己的目標。管理者的做法比大多數開發者的做法更有壓迫感。開發者向管理者回報,這有時會使開發者更傾向於直接接受任何任務和期限。不應該低估大多數開發者想要成為英雄的本能。開發者期望成為超級英雄,來到這個地球就是為了拯救世界。

舉個例子,假設經理打算在星期一早上給一個潛在的客戶做一場演示。他想確保他的演示可以給人留下深刻的印象。所以經理找到開發團隊,要求在星期一準備一個演示。這可能打破當前衝刺(sprint),甚至影響了原來計劃的工作。在公司或者團隊裏處理這種不可避免的利益衝突使用哪種方式最好?以下是幾個可能的場景。

開發團隊可能嚐試適應新的期限,這樣經理就能實現他自己的正當目標了。
開發團隊不接受新的期限,堅持當前安排,這會妨礙經理讓客戶滿意。
開發團隊和經理一起找到合理的目標,既適合雙方的安排,又不會妨礙任何人實現各自的目標。
根據我們的經驗,第一個場景是最常見的,而最後一個則是最令人滿意的。就開發者嚐試適應任何安排改動而言,我們發現Uncle Bob的看法特別有價值。承諾嚐試適應新的期限,開發團隊似乎在暗示自己留了一手,就像在說:“是的,我們可以接受更多工作,但出於某種原因我們一直沒有這樣做;現在是時候用盡我們所有精力了。”但是,如果團隊沒有保留精力,嚐試適應更緊的期限會強迫成員加班,犧牲他們自己的私人時間。這對開發者來說是不公平的,他們也該有自己的生活;同樣對管理層來說也是不公平的,他們聽到了謊言。

我們有過多少次嚐試適應更緊的安排?如果我們做過這樣的事,我們可能是為了避免潛在的不禮貌的對抗。成為一個團隊的好隊員的唯一金科玉律是成為一個好的溝通者,永遠坦誠,永不說謊。

這裏的關鍵字是協商,目的是分享合理的目標,在各自需要和安排之間尋求合理的折中方案。就前麵的例子而言,一個好的折中方案可能是為某些工作創建分支,使用虛構代碼創建一個僅適用於演示的專門構建。這不會從主分支刪除很多內容,不會導致當前衝刺出現明顯延遲,也不需要團隊成員加班或砍掉特性。

2.Scrum救火員
尤其在敏捷環境裏,每個沒有預見的事件都是潛在的危機,都需要恰當地、及時地處理。

在Scrum裏,常見的做法是賦予團隊的一個或多個成員救火員頭銜。

Scrum救火員負責迭代之外保護其他隊員工作所需的任何額外工作。就像現實世界的救火員有時候會空閑一樣,Scrum救火員也會空閑,或者在迭代的過程中,在項目上保持最低活躍度。

因為成為Scrum救火員可能非常無聊,所以這個角色應該讓團隊的所有成員輪流來做。根據我們的經驗,20%的開發精力應該是你騰出來救火的最大值。由此看來,你可能會想,你的生產力將會縮減20%;實際上,你可能會得到更高的產出。

3.領導與老板
我們都知道成本是軟件項目的痛點。成本是實現所有特性所需的時間的函數,包括測試、調試、文檔以及一些其他周邊工作。開發團隊領導會負責這些,他通常向項目經理匯報。

有時候,這兩號人物相互之間缺乏信任:經理認為開發團隊保留精力,開發團隊認為經理隻想付出更少而得到更多。

毋庸置疑,領導藝術是關鍵的技能。

經理腰斬估算然後抱怨項目延遲的情況並不罕見。他們跑到老板那裏指責開發團隊,並要求更多資源。在這種情況下,他們會體驗到Brooks法則的效果,即“向已經延遲的軟件項目增加人手會使之更加延遲。”

領導和老板之間有著巨大區別。

首先,也是最重要的,老板期望團隊為他們服務,而不是他們為團隊服務。老板位於商業等級製度的最高點,可以命令其他人執行他們不願意做或者不會做的任務。相反,領導專注於業務以及帶領開發團隊走出深溝。簡單來說,這個區別就是老板培養跟班,而領導培養其他領導。
2.2.2 幫助團隊更好地寫代碼
我們發現很多開發者似乎認為爛代碼最終並沒有帶來太多傷害。

如果你數一下有記錄在案的因代碼問題而失敗的項目個數,那麼,我們認同這個數字並不會很大。但是,你不必創造真正的災難導致軟件項目損失大量金錢。

作為一名架構師,你可以做什麼來幫助團隊更好地寫代碼呢?

1.爛代碼真的比好代碼更昂貴
我們不清楚你的情況,但我們肯定認為寫爛代碼真的比寫好代碼更加昂貴。至少,我們認為在生命周期比較長,業務影響比較大的項目裏是更加昂貴的。

聽起來可能很簡單,當使用爛代碼(即創建、測試和維護它)的成本超過業務模型可以忍受的代價時,項目才會因它而敗。同樣地,如果公司設法使代碼的成本保持在極低水平,沒有項目會因為代碼問題而失敗。

這就是痛點。

你如何定義最終影響代碼成本的因素?哪些動作組成了“寫代碼”:編碼、構建、調試?你應該把測試當作一個附加的按需的特性嗎?文檔呢?缺陷修複呢?

有時候,管理者隻是投機取巧,通過雇傭廉價開發者或砍掉測試和文檔等縮減開發成本的手段來解決問題。

不幸的是,這些管理者沒有意識到他們隻是縮減了產生可能(但不一定)工作的代碼的成本。產生剛好可以工作的代碼隻是問題的一麵。現在,需求經常改變,複雜性不斷增長,更糟糕的是,複雜性通常僅在行進的過程中才能完全了解。在這種情況下,產生代碼隻是影響總體成本的一個因素。代碼維護和進化才是最大因素。

好的架構師都很清楚,隻有寫得好的代碼,對軟件原則和語言特性有很好的了解,恰當使用模式和實踐,以及注重可測試性才能解決代碼維護的問題。這使得編碼比產生剛好可以工作的代碼更加昂貴,但比維護和進化剛好可以工作的代碼就廉價得多了。

2.使用工具輔助編碼
我們認為成功的項目基於兩個因素:懂得領導藝術的管理層,以及懂得代碼質量的開發團隊。

就編碼而言,不一定有時間讓開發者現在寫代碼,然後在往後的某個時間修複和整理它。每個開發者都會發誓,第二遍處理永遠都不會發生,即使發生,也不會造成很大影響。

如果想在第一次就寫出更好的代碼,最好使用代碼輔助工具。這些工具通常集成在IDE裏,可以簡化常見開發任務,使開發者的工作進展得更快,可以寫出更好的代碼。在最壞的情況下,代碼可以寫得更快,留有一些時間做第二遍處理。

自動完成、慣用設計提示(即根據語言或框架建議的慣用方式寫代碼)、代碼檢查、支持鍵盤輸入的預定義代碼片段,以及支持預定義和自定義模板等服務都是加快開發以及確保一致性和更好、更幹淨代碼的實踐。

代碼輔助工具使開發得以持續發展,隻需兩次點擊就能極大地改善你所寫的代碼的質量。代碼輔助工具可以發現重複和沒用的代碼,使重構體驗變得愉快,簡化導航和檢查,以及強製使用某些模式。

比如說,所有開發者原則上都同意適當的命名規範對於代碼的可讀性和質量來說是很關鍵的。(參見第4章“編寫優質軟件”。)但是,當你意識到你應該重命名一個命名空間或者一個方法時,你就會麵臨至少要在你自己的整個代碼庫裏這樣做的問題。這麼瘋狂的工作原本需要你自己在極短的時間內完成,現在可以由代碼輔助工具代勞了。
但是,你要記住,代碼輔助工具不是魔法,它們所做的隻是讓你付出更低的代價和更少的努力就可以寫出更好和更幹淨的代碼。除此以外,一切仍然取決於你。你在重構過程裏以及在代碼編輯階段操作工具。

3.如何告訴別人他們的代碼很爛
假設你發現你團隊裏有人在寫爛代碼。你會如何跟他們說?

這裏涉及一些心理學方麵的東西。你不想表現得尖銳,你也不想傷害任何人;與此同時,你不想其他人的工作在某一時刻傷害到你。溝通是關鍵,不是嗎?所以你需要找到最佳方式在別人的代碼很爛時告訴他們。

總體而言,我們認為讓人注意到某些代碼的最佳方式是不經意地問為什麼用這種方式來寫。你可能會找到更多背後的動機,不管是信息有誤,態度不好,技能局限,或者你所不知的約束。

在沒有確鑿證據之前,不要斷定你的編碼方式更好。那麼,你隻需對問題代碼背後的真正動機表現出好奇和興趣,並且表達出想了解更多的意願,因為如果換了你會用不同的方式來編碼。

4.使每個人都變成更好的開發者
下麵總結一下讓團隊寫出好代碼的金科玉律:

針對代碼,而不是寫代碼的人。但通過寫代碼的人來嚐試改善代碼。

你可以通過某種方式修複任何一塊爛代碼。但是,當這種情況發生時,你不要責怪寫代碼的人;你可以幫助寫代碼的人改進他做事的方式。如果你可以這樣做,你至少可以得到兩方麵的好處:你的團隊得到一個更好的開發者,你的團隊可能得到一個更快樂更有動力的開發者。你使這個開發者感覺更像英雄,因為他現在有了完成他的工作的最佳方式。

為了改進某些方麵,每個人都需要培訓和實踐。最有效的方式是以敏捷的方式結合培訓和實踐。但是,我們經常看到一些公司購買了培訓服務,讓他們在短短幾天內完成和交付,然後期望人們在接下來的星期一就能投入工作。事情並不是這樣的,至少不會如此有效。

這讓我們想起幾年前非常流行的一個短語:在職培訓。它指的是一邊學習、一邊做實際的工作。這起因於擁有不同技能的人在同一個團隊裏協同工作。

5.在簽入代碼之前檢查一下
你的公司可能會有最好的編碼標準,但你怎樣實施它們?信任開發者是好的,但驗證可能更加有效。結對編程和常規設計審核是檢查代碼庫健康程度的具體方式。在一次典型的設計審核裏,你可以和大家一起開放地討論某些示例代碼。這些代碼可以是來自項目的真實代碼片段,它是某些參與者寫的,或者為了避免牽涉到情緒問題,也可以是為了闡明你想表達的觀點而專門寫的一段代碼。

為了實施編碼標準,你也可以考慮對你的代碼控製係統采用簽入策略,不管是Microsoft Team Foundation Server(TFS)、TeamCity或者其他係統。這個過程可以自動化嗎?

今天,幾乎任何源代碼管理工具都提供針對簽入文件實施控製的方式。比如說,TFS支持封閉簽入(Gated Check-ins)。封閉簽入本質上就是根據規則簽入。換句話說,文件隻有在符合既定規則的時候才會被係統接受。當你選擇創建封閉簽入時,TFS會要求你指定一個現有的構建腳本。隻有在構建成功完成的時候,這個文件才會簽入。

在TFS裏,一個構建隻是有一個MSBuild腳本,它可以使用各種任務來定製。TFS自帶一些可以集成的預定義任務。比如說,你會找到代碼分析(以前的FxCop)任務和一個運行選定測試列表的任務。因為MSBuild任務隻是一個實現了約定接口的注冊組件,所以你可以自己創建新的任務,添加自己的驗證規則。

值得注意的是,JetBrains的ReSharper,前麵提到的其中一個代碼輔助工具,在它的最新版裏提供了一組免費的命令行工具,可以在自定義的MSBuild任務裏檢測重複代碼以及執行常見檢查,包括根據你定義的自定義模板執行自定義檢查。有趣的是,你甚至不需要ReSharper許可證就能使用這個命令行工具。
6.值得欣喜的是,這個項目不需要英雄
開發者傾向於超越自我,至少在他們深藏的夢想裏,希望他們每周可以工作超過80小時來拯救項目,讓客戶滿意,並且成為管理者和開發者同伴眼裏的真英雄。

我們想改編詩人和劇作家Berthold Brecht的一句名言:我們總想活在不需要英雄主義的世界裏。對英雄的需要以及由此而來的高壓力通常源自不足的期限。

有時候,期限從項目一開始就不公平了。在其他情況下,期限是在進展的過程中被證明為 錯的。

當這種情況出現時,情感上容易默許,但對指出不公平的期限的害怕產生對英雄的需要。溝通以及把問題挑明是一種坦誠,也是恢複更多控製以及降低壓力的有效途徑。

在軟件裏,我們可以說,你感到壓力是因為迫在眉睫的最後期限或者缺少所需技能。如果及時溝通,兩種情況都能很好解決。

我們不想要英雄,雖然我們自己也做過幾次英雄(我們猜你們中的大多數也做過),我們認為英雄主義是一種例外情況。在軟件裏,例外通常是要避免的。

7.鼓勵實踐
幾乎任何運動的專業運動員每天都會花上好幾個小時來實踐,到底是為什麼呢?開發者和專業選手之間是否存在某種相似之處?看情況而定。

一種看法是開發者每天在工作中實踐,並且沒有與其他開發者競爭。有鑒於此,有人可能會得出沒有相似之處的結論,因此沒有必要實踐。

另一種看法是選手經常練習基本動作,以便他們可以自動地重複這些動作。定期回顧麵向對象基礎、設計模式、編碼策略以及某些領域的API可以使這些知識記憶得更牢固,回憶得更 快速。

注意:
寫過多本ASP.NET的書,也實踐過驗證和成員係統,時隔多年,Dino最近在使用基於角色的ASP.NET係統時感到問題很大。“老兄”,他最近跟我說,“我上次處理角色是什麼時候?”最終,創建基於角色的UI基礎設施以及相關的成員係統耗費比預期更多的功夫。
8.持續改變是工作的一部分
持續改變是描述現代軟件項目動態的有效方式。軟件項目始於一個想法或者一個相對模煳的業務想法。架構師和領域專家需要收集一些正式的需求,使原來的想法或業務需要更加明顯。

根據我們的經驗,大多數軟件項目就像活動目標,而需求就是把目標到處移動的東西。每次添加一個新的需求,這個環境以及係統的動態(在沒有這個特性的情況下可以正常工作的設計)也會改變。需求的改變是因為問題領域有了更好的了解,問題領域變化很快,或者時間壓力的問題。

需求波動(Requirements Churn)這個術語通常用來表示軟件項目裏的需求變化率(功能性需求、非功能性需求,或者兩者都有)。高需求波動將會為BBM提供理想的藏身之所。

每當處理新的需求都重新審視整個係統的架構是切實避免BBM的唯一辦法。重新審視整個係統的架構確實需要重構,也確實具有較大成本。這裏的重點是找到保持低成本的方法。重構是其中一個很難察覺會為項目帶來價值的東西。未能重構會導致這些價值流失,這很糟糕。

注意:
Twitter在2010年上線,當時的Web前端充滿了客戶端功能。大量功能是通過在動態下載的JSON數據之上即時生成HTML來提供的。在2012年,Twitter重構了整個係統,選擇了服務器端渲染。這是一個架構層麵的重構,毫無疑問是昂貴的。但他們認為這是必要的,並且持續服務數億用戶,不管是對還是錯,反正它能工作。

作為一名架構師,架構和設計重構都是關鍵工具。架構師無法控製曆史以及業務場景和現實世界的發展。架構師需要一直做出調整,避免重新構建。這正是重構派上用場的地方。

最後更新:2017-06-01 16:31:32

  上一篇:go  《Microsoft.NET企業級應用架構設計(第2版)》——2.4 總結
  下一篇:go  JS HTML DOM