敏捷開發“松結對程式設計”系列之十五:L型代碼結構(編程篇之一)

來源:互聯網
上載者:User

本文是“松結對程式設計”系列的第十五篇。(松結對程式設計欄目目錄)

之前的L型代碼結構的前三篇提到過,L型代碼結構的微觀計劃和估算過程會與一般的編程方法不同,今天正好要編寫一些新代碼,邊寫邊記錄整個過程。如果中間卡殼了,我也會盡量記錄下來。

業務需求這是《火星人》中的一個功能,以往使用者故事是使用故事樹來展示的(就是有父子關係的使用者故事),故事樹隸屬於一個產品Product。但是最近要發版了,感覺一個以前認為暫時用不上的功能,現在變得很急迫,那就是在當前這個版別Edition(比如“線上版”)的目前的版本Version(比如“簡化試用版”)的下一個發布Release(比如“R20120331A”)中,到底有哪些功能?如果某些功能在這個發布中,就要通過自動化測試(某些功能現在有自動化測試案例,但如果運行可能不通過,因為這些功能暫時不發布)和人工測試。看起來功能條目化一下大約如此:1. 先在版別Edition上做與使用者故事的對應2. 然後在版本Version上做(受到版別的約束)3. 然後在發布Release上做(受到版本的約束)一般實現的做法大約包括這些工作:1. 三張資料庫表做對應連結(如果是一張表,則會多一個欄位,表明是版別、版本還是發布),按7或21功能點估算,需要7或21人天(在OA類項目開發中,1功能點大約需要7~9小時,產品研發應該略長)。2. (展示對應關係,加入一個故事,挪出一個故事)×3,按12功能點估算,大約需要4×3=12人天這裡的人天包括了從需求分析到測試、發布(含維護一段時間至穩定)的總工時,實際開發大約佔50%,也就是大約10~15人天左右。L型代碼結構的做法步驟1:找到相似的業務這裡的相似,指商務邏輯相似,比如都是“二叉樹”或都是“查詢”之類的。我們之前做過一個“團隊與產品的對應關係”功能,即安排哪些團隊可以訪問哪些產品(反之亦然)。介面如下(很醜啊呵呵,以後有機會再改,現在整個介面風格都在修改):
這種業務,在火星人的底層稱之為Item to Item Link,所謂Item就是任何以父子關係存在的東西;而Link則是任何這兩種東西之間的連結。圖中也是是部門樹與產品樹的關係;而馬上要建立的,是產品樹(版本等屬於產品樹)與使用者故事之間的關係。步驟2:找到業務代碼團隊在左邊,產品在右邊的(就是,“團隊能訪問哪些產品”):
        public ActionResult LinkTeam2Product(int focusedDepartmentID = 0)        {            ViewBag.ItemTreeViewModel = new ItemTreeViewModel("團隊-產品映射", ProductLine.ProductRootID, SystemItemWhat.Product, whattypes: ItemWhattype.ProductProductline + "_" + ItemWhattype.ProductProduct + "_" + ItemWhattype.ProductEdition);            focusedDepartmentID = focusedDepartmentID == 0 ? Department.DepartmentRootID : focusedDepartmentID;            ViewBag.LinkItem2ItemsViewModel = new LinkItem2ItemsViewModel(ProductLine.ProductRootID, SystemItemWhat.Product, Department.DepartmentRootID, SystemItemWhat.Deaprtment, focusedDepartmentID, whatTypes: ItemWhattype.ProductProductline + "_" + ItemWhattype.ProductProduct + "_" + ItemWhattype.ProductEdition, leftPadWhatTypes: ItemWhattype.DeprtmentProgram + "_" + ItemWhattype.DeprtmentTeam);            return View(ItemTree.ViewPath);        }
ItemTreeViewModel是負責產生右邊的樹的(注意首級目錄是橫向排列的,以便利用好寬屏的空間);LinItem2ItemsViewModel是負責處理連結關係及顯示左邊的樹的。這是另外一個函數,和前面那個差不多,但產品在左邊,團隊在右邊的,“產品能被哪些團隊訪問”,這個好處是左邊不用動了:
        public ActionResult LinkProduct2Team(int focusedProductID = 0)        {            ViewBag.ItemTreeViewModel = new ItemTreeViewModel(                "產品-團隊映射", Department.DepartmentRootID, SystemItemWhat.Deaprtment, ItemWhattype.DeprtmentProgram + "_" + ItemWhattype.DeprtmentTeam);             focusedProductID = focusedProductID == 0? ProductLine.ProductRootID : focusedProductID;            ViewBag.LinkItem2ItemsViewModel = new LinkItem2ItemsViewModel(                Department.DepartmentRootID, SystemItemWhat.Deaprtment, ProductLine.ProductRootID,                 SystemItemWhat.Product, focusedProductID, whatTypes: ItemWhattype.DeprtmentProgram + "_" + ItemWhattype.DeprtmentTeam,                 leftPadWhatTypes: ItemWhattype.ProductProductline + "_" + ItemWhattype.ProductProduct + "_" + ItemWhattype.ProductEdition);            return View(ItemTree.ViewPath);        }

這兩個代碼其實差不多,用後面這個改比較方便。
步驟3:修改出新的業務代碼Controller裡邊就這幾行,二話不說照葫蘆畫瓢改出一個來,只要修改一下參數:

        public ActionResult LinkProduct2Story(int productID, int? focusedItemID)        {            ViewBag.ItemTreeViewModel = new ItemTreeViewModel(                "產品-故事映射", productID, SystemItemWhat.Story);            ViewBag.LinkItem2ItemsViewModel = new LinkItem2ItemsViewModel(                productID, SystemItemWhat.Story, null,                 ProductLine.ProductRootID, SystemItemWhat.Product, null, focusedItemID);            return View(ItemTree.ViewPath);        }

步驟4:必要時,修改底層代碼這個不寫了,原來的new LinkItem2ItemsViewModel中有兩個問題:1. 原來的程式員不會用int?,所以在Action中使用了=0的預設變數改為用int?。2. 處理=0(現在是=null了)的代碼也就是

focusedProductID = focusedProductID == 0? ProductLine.ProductRootID : focusedProductID;

被寫在Action裡邊了,所以每次都要寫一遍。
改為直接傳入new ViewModel,讓裡邊處理。3. 變數順序有交叉,不得不用:把容易看錯的地方標識出來重新調整了順序,變成對稱的了,也就不用寫:了。所以新寫的那個函數比原來兩個(也改了)少了一行,還少兩個:及其變數名。如果在這時候修改了代碼,先測試原來的功能是否正常,再調試新功能。否則兩種錯誤複合在一起,很難定位。L型代碼的一個很大的好處是,每次改進都不是以加法形式存在的,而是乘法。只要有一個人能把一個地方改好,很多人的很多地方都能改好。這樣就能以集體的最高能力作為團隊的整體能力。而在傳統的團隊中,往往是最低能力,決定了產品的最終品質。
步驟5:調試實際上什麼也沒調試,對兩個partial view做了兩次拷貝粘貼外加重新命名,結果出來了:

已經能把“查看所有故事”加入到“最簡版本”這個發布裡邊了。

什麼View也沒寫呢,怎麼就完了呢?下面這句話:
return View(ItemTree.ViewPath);

通向一個可複用的View,它的結構就是左邊一個Pad,右邊一個首級目錄橫置的樹(也可以不是),它會在目前的目錄下尋找一個叫做"_[Action]LeftPad.cshtml"的View來顯示左邊的Pad和"_[Action]TreeNode.cshtml"的檔案來顯示右邊的每一個節點,這是剛才拷貝粘貼和重新命名View的原因。Partial View和函數一樣,都可以視為底層,能複用就複用。總結一些沒講到的地方1. 資料庫表哪去了?因為LinkItem2Items這個表早就有了,所以不用建表。殘留問題不過到此為止,還有點問題:1. 業務需求中,應該是如果一個使用者故事沒有被加入到版本Edition中,就不能加入到下面的發布Release中;或反之,若被加入了發布中Release中,則應該自動被加入到版本Version。這個需求還沒有實現。
這個預計需要10多行代碼。2. 剛才拷貝粘貼重新命名的檔案,沒有經過任何改動居然工作了。這聽起來是個好事,但也說明有兩段代碼是相同的,需要再次複用一次,否則日後的任何改動,都需要改動多處。這個預計需要5行左右的代碼。
L型代碼的好處

1. 代碼減少

這些功能大約有20~30個功能點(取決於建幾個資料庫表),按QTM上的國際資料,C#每個功能點需要59行,所以59×(20~30)=1200~1500行,但如果有L型代碼結構,就只需要20多行代碼。

2. 工作量下降

剛才的工作從13:30開始,到現在16:12,扣除寫部落格實際花費了大約1小時不到,再加上殘留問題修修補補的時間也就1天。所以1天能幹10~15天的活。

這個甚至不需要個人能力,即使是新手,熟悉了這個架構,速度也差不多。

3. 品質上升

每次底層都被多次調用,只要一次失敗就會被發現;而每次底層改動都會協助多個功能最佳化,修改Bug也是如此。

4. 新手上手快

一般“代碼減少”“代碼最佳化”常常面臨的問題就是:新手能看懂和維護嗎?

其實,別看這個體系好像挺複雜的,但新手看這20行代碼的速度,還是比擺弄1200~1500行快多了。

例子中的所有代碼,除了步驟3裡邊的新函數,其他的比如被我重構的LInkItem2ItemViewModel和幾個Action,外加拷貝粘貼重新命名的LeftPad/TreeNode等代碼,其實都是另外一個人編寫的。他在編寫這些代碼的時候編程經驗只有半年(之前作為支援人員工作過4年,大學學過C++,之後從來沒動過代碼),實際編寫的程式碼數估計只有1000行(我們一共只有11000行代碼)。當然,他編寫這些代碼的時候,又是參考了我之前的另外一個“反覆項目計劃”頁面的設計。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.