2011-04-02 17 views
17

我即將開始規劃我們的代碼庫的一個主要重構,我想獲得一些意見和一些問題的答案(我已經看到了很多類似主題的討論,如https://stackoverflow.com/questions/108141/how-do-i-work-effectively-with-very-messy-legacy-code,Strategy for large scale refactoring,但我有一些(底部):如何去做一個大型的重構​​項目?

我們開發了一個複雜的應用程序,大約有25個開發人員在開發代碼庫,至今投入產品的總人數大約是150. 當前代碼庫是一個單獨的項目,我正在着手的項目的高層次目標是將代碼模塊化到各種基礎設施和應用組件中 目前各種邏輯組件之間沒有很好的分離,所以很明顯, dularization的努力將需要包括一些API的定義和認真解開來實現分離。 質量標準低 - 幾乎沒有測試,並且確實沒有作爲構建過程的一部分運行的測試。

另一個非常重要的一點是,該項目需要與正在向客戶交付的有效產品開發和版本並行進行。項目

目標:

  • 允許組件的重用在不同的項目,從基礎設施
  • 單獨的應用程序,並允許他們發展獨立
  • 提高可測試性(通過創建API)的
  • 簡化開發人員'dev env(檢出並編譯的代碼較少)

我雖然ts and questions:

  1. 您對項目目標有什麼想法?你會改變什麼?
  2. 你有這些項目的經驗嗎?有什麼建議?
  3. 我非常擔心缺少測試 - 因此我無法控制重構過程,因爲我知道重構過程不會破壞任何東西。這是一個捕捉22,因爲這個項目的目標之一是使我們的代碼更可測試...
  4. 我受到邁克爾羽毛'Working Effectively With Legacy Code非常影響。據說,自下而上的方法是解決我的問題的方法 - 不要先跳到代碼庫並嘗試修復它,而是從幾個月的新代碼周圍添加單元測試開始,然後看看代碼(和團隊)變得更好,在一定程度上抽象將會出現,API將會表面化等等,而本質上 - 模塊化將自行開始發生。 有沒有人有這樣的方向經驗? 正如在這個話題的許多其他問題中看到的 - 這裏的主要問題是管理層的不信任。 「如何按班級測試課程(並花費大量時間這樣做)將我們帶入一個穩定的系統?這是一個很好的理論,它在現實生活中不起作用。」有關銷售這個的任何提示?

回答

12

嗯,我認爲現在比以後好,但你肯定有一個任務在你面前。我曾經有一個三人團隊負責重構類似大小的產品。這是程序代碼,但我會描述一些我們所遇到的類似問題。

我們從最底層開始,通過選擇應該具有高度可重用性但不是可重用的函數來開始進入。我們會在現有的代碼上編寫一堆單元測試(根本不存在!),但是不久之後,我們面臨着我們的第一個大問題 - 現有的代碼存在已陷入休眠狀態的錯誤。

我們解決它們嗎?如果我們這樣做,那麼我們已經超越了重構。所以我們在現有的代碼中註冊一個問題,希望得到一個固定的,新測試過的代碼庫,但是當然管理層認爲比修復從未出現過的錯誤更重要。可以理解的。

所以我們認爲我們會嘗試修復我們的新代碼中的錯誤。然後我們發現原始代碼中的這些錯誤使得其他代碼可以工作,所以真的是'概念性錯誤'而不是'功能錯誤'。也許。原始軟件中偶爾出現間歇性痙攣,這些痙攣從未被追蹤過。

因此,我們改變了方針,並決定保持錯誤,像真正的重構一樣。無意中引入錯誤很容易,故意做這件事更難!

接下來的問題是,代碼是在如混亂,我們寫的初始單元測試必須大幅改變以迎合重構。換句話說,兩個移動目標。不好。只是編寫測試需要很長時間,我們相信項目的價值。這真的是你想要離開的東西。

我們最終發現,如果我們要完成這個千年,我們真的必須淡化重構的程度,這意味着我們夢想的代碼庫將無法實現。我們宣稱最可行的解決方案是清理和修剪代碼,並且至少使它在未來的開發人員修改時更易於理解。

受限重構的收益減少被認爲不值得管理層付出努力,並且考慮到在硬件平臺(嵌入式項目)中發現類似的可靠性問題,該公司認爲這是他們有機會更新整個產品,從頭開始編寫軟件,新的語言,對象。這只是原始產品的廣泛的系統測試規範,這意味着這有機會。

2

這正是我們過去幾年一直在爲web2project所做的事情。我們從現有的系統(dotproject)中分離出來,這個系統具有很高的圈複雜度(低:17,平均:27,高: 195M),大量重複代碼(總代碼的8%)和零測試。由於分割,我們減少了重複代碼(總體上2.1%),減少了總代碼(200kloc到155kloc),增加了近500個單元測試,並且改善了圈複雜度(低:1,平均:11,高:145M)。是的,我們還有一段路要走。

我們的戰略在我的幻燈片中詳細列出: http://caseysoftware.com/blog/phpbenelux-2011-recap - Project Triage &恢復;這裏: http://www.phparch.com/2010/11/codeworks-2010-slides/ - 單元測試策略;並在像這樣的各種職位: http://caseysoftware.com/blog/technical-debt-doesn039t-disappear

只是爲了警告你..一開始並不好玩。一旦你的指標開始改善,但這需要一段時間,它可以很有趣也很令人滿意。

祝你好運。

3

很明顯,當您嘗試重構代碼時,測試的缺失會讓人緊張。有人會相信你的重構不會破壞應用程序嗎?我認爲,大部分答案都是「這將會非常困難,而且不會很成功」,這很大程度上是因爲您正面臨着一項龐大的手動任務,並且對答案毫無信心。

只有兩種出路。

  • 構建一堆測試。不幸的是,這會花費很多時間,大多數管理者看不到任何價值;畢竟,你到目前爲止沒有他們。回到信仰問題將無濟於事;在發生任何有用的事情之前,你仍然需要很多時間。如果他們讓你建立測試,你會遇到在重構時發展測試的問題;他們可能不會改變功能,但是當您構建新的API時,測試將不得不改變以匹配新的API。除了重構代碼庫之外,這是額外的工作。

  • 自動執行重構過程。如果您應用可靠的自動轉換,您可以爭辯(通常不成功)重構的代碼保留原始系統功能。打敗這些不合理的論點的方法是編寫這些測試(請參閱第一種方法),並將重構過程應用於測試應用程序;當應用程序改變結構時,測試也必須改變。但從自動化機械的角度來看,它們只是應用程序代碼。

不是很多人做後者;你在哪裏得到可以做這種事情的工具?

事實上,存在這樣的工具。它們被稱爲program transformation tools,用於對代碼進行大規模轉換。 把這些看作是在大型字面上重構的工具;由於規模, 他們往往不會互動。

確實需要花費精力爲他們配置手頭的任務;您必須編寫自定義規則來完成您的自定義所需結果。您可能無法在一週內完成此操作,但這比手動修改大型系統要少得多。而且你應該考慮你在現有軟件上投入了150人工時間;花了那麼長時間才能搞定這個爛攤子。看起來合理的是,比較小的「一些」努力應該是可以的。

我只知道有3個這樣的工具,有機會在實際代碼上工作:TXLStratego/XT,以及我們的工具,DMS Software Reengineering Toolkit。前兩種是學術產品(儘管TXL過去曾用於商業活動); DMS是商業的。

DMS已用於各種大型軟件分析和大規模轉換任務。一項任務是automated translation between languages for the B-2 Stealth Bomber。另一個與您的重構問題非常接近的問題是,自動構建基於組件的大型C++組件系統,從傳統專有RTOS及其關於組件如何組織的特殊規則,到組件API具有的CORBA/RT從ad hoc結構改爲CORBA式方面插座接口以及使用CORBA/RT服務代替傳統RTOS服務。 (這些任務都是通過1-2人年的實際工作完成的,由聰明的和精通DMS的人員完成)。

仍然存在測試構建問題(上述兩個示例都已經進行了很好的系統測試)。在這裏,我將出現在肢體上。我相信通過檢測運行代碼來收集函數輸入輸出結果,可以使這些工具自動化測試生成。我們已經爲源代碼構建了各種工具(顯然你必須在工具之後編譯它),並且認爲我們知道如何做到這一點。因人而異。

有些事情你做的是不那麼雄心勃勃:通過找出代碼中被重用的內容來識別代碼的可重用部分。大多數軟件系統包含很多克隆代碼(我們的經驗是10-20%[我對另一個答案中PHP數量較少的報告感到驚訝;我懷疑他們正在使用弱克隆檢測器)。克隆代碼是應用程序軟件中缺少抽象的暗示。如果你能找到克隆並看看它們是如何變化的,你可以很容易地看到如何將它們抽象爲函數(或其他),以使它們明確且可重用。

Salion Inc. did clone detection and abstraction。本文不探討抽象活動; Salion實際上做了什麼是對檢測到的克隆進行定期評估,並手工糾正那些過分的或者有意義的(通常是庫)方法。最終的結果是代碼庫實際上縮小了,程序員變得更有效了,因爲他們有更好的(「更可重用的」)庫。

他們使用我們的CloneDR,這是一種通過使用程序語法作爲指導來查找克隆的工具。 CloneDR可以找到確切的克隆和幾乎未命中(替換標識符或語句),並提供特定的克隆位置和克隆參數列表,無論佈局和註釋如何。您可以在鏈接中查看多種語言的克隆報告。 (我是衆多帽子中的originator and author of CloneDR)。

關於在另一個答案中討論的PHP項目的「小克隆百分比」:我不知道克隆檢測器使用了什麼。我知道唯一一個專注於PHP的克隆檢測器是PHPCPD,它是一個可怕的克隆檢測器;它只能找到確切的克隆,如果我理解所聲明的實現。請參閱我們網站上的PHP示例以進行比較。