• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 重構遺留程序的一次案例學習

    發表于:2013-12-20來源:InfoQ作者:Chen Ping點擊數: 標簽:重構
    重構遺留程序的一次案例學習.遺留代碼經常是腐臭的,每個優秀的開發者都想把它重構。而進行重構的一個理想的先決條件是,它應該包含一組單元測試用例,以避免產生回歸缺陷。但是為遺留代碼編寫單元測試可不是件容易的事,因為它經常是一團糟。要想為遺留代碼編寫有效的

      遺留代碼經常是腐臭的,每個優秀的開發者都想把它重構。而進行重構的一個理想的先決條件是,它應該包含一組單元測試用例,以避免產生回歸缺陷。但是為遺留代碼編寫單元測試可不是件容易的事,因為它經常是一團糟。要想為遺留代碼編寫有效的單元測試,你大概得先把它重構一下。但要重構它,你又需要單元測試來確保你沒有破壞任何功能。這種狀況相當于要回答是先有雞還是先有蛋。這篇文章通過分享一個我曾參與過的真實案例,描述了一種可以安全地重構遺留代碼的方法。

      問題描述

      在這篇文章中,我將用一個真實案例來描述測試與重構遺留系統的有效實踐。這個例子的代碼由Java編寫,不過這個實踐對其它語言也是適用的。我將原始場景稍做了些改動以免誤傷無辜,并稍做簡化以便讓它更容易被理解。這篇文章所介紹的實踐幫助我重構了近期我所參與的一個遺留系統。

      這篇文章并不打算介紹單元測試與重構的基本技巧。你可以通過閱讀相關書籍以學習該主題的更多內容,如Martin Fowler的《重構:改善既有代碼的設計》及Joshua Kerievsky的《重構與模式》。相對而言,這篇文章的內容將描述一些真實場景中的復雜性,我也希望它能夠為解決這些復雜性提供一些有用的實踐。

      在這個案例中我將描述一個虛構的資源管理系統,其中資源指的是可指派給其任務的某個人??梢詾槟硞€資源指派一個HR票據(ticket)或者IT票據,也可以為某個資源指派一個HR請求或IT請求。資源經理可以記錄某個資源處理某項任務的預計時間,而資源本身可以記錄他們在某個票據或請求上工作的實際時間。

      可以用餅圖的方式表示資源的使用情況,圖中同時顯示了預計時間與實際花費的時間。

      相關廠商內容

      BPMS基于RDF/OWL快速元數據倉儲,重用流程開發周期所有資產

      QCon上海2013精彩回顧:GitHub Peter Bell:"首先,殺死所有產品Owner"

      QCon上海2013精彩回顧:Twitter工程VP Raffi:"分解Twitter"

      QCon北京2014大會正式啟動,面向社會征集演講話題

      QCon上海2013精彩回顧:LinkedIn Sam Shah:"如何將數據變為產品"

      相關贊助商

      QCon全球軟件開發大會(北京站)2014,4月25-27日,誠邀蒞臨。

      好像不太復雜嘛?不過,真實的系統能夠為資源分配多種類型的任務,當然從技術上講這也不是多么復雜的設計。但當我初次看到系統的代碼時,我感覺自己似乎看到了一件老古董,從中看得出代碼是如何從開始逐步進化的(或者不如說是退化的)。在一開始,這一系統僅能用來處理請求,之后才加入了處理票據以及其它類型任務的功能。某位工程師開始編寫代碼以處理請求:首先從數據庫中獲取數據,隨后按照餅圖的方式顯示數據。他甚至沒有考慮過要將信息組織為合適的對象:

      class ResourceBreakdownService {

      public Map search (Session context) throws SearchException{

      //omitted twenty or so lines of code to pull search criteria out of context

      and verify them, such as the below:

      if(resourceIds==null || resourceIds.size ()==0){

      throw new SearchException(“Resource list is not provided”);

      }

      if(resourceId!=null || resourceIds.size()>0){

      resourceObjs=resourceDAO.getResourceByIds(resourceIds);

      }

      //get workload for all requests

      Map requestBreakDown=getResourceRequestsLoadBreakdown (resourceObjs,startDate,

      finishDate);

      return requestBreakDown;

      }

      }

      我相信你肯定被這段代碼里的壞味道嚇到了吧?比方說,你大概很快就會發現search并不是一個有意義的名稱,還有應該使用Apache Commons類庫中的CollectionUtils.isEmpty()方法來檢測一個集合,此外你大概也會疑惑該方法返回的Map對象到底包含了些什么?

      別著急,壞味道陸續有來。接下來的一位工程師繼承了先人的衣缽,按照相同的方式對票據進行了處理,以下就是修改后的代碼:

      // get workload for all tickets

      Map ticketBreakdown =getResourceRequestsLoadBreakdown(resourceObjs,startDate,

      finishDate,ticketSeverity);

      Map result=new HashMap();

      for(Iterator i = resourceObjs.iterator(); i.hasNext();) {

      Resource resource=(Resource)i.next();

      Map requestBreakdown2=(Map)requestBreakdown.get(resource);

      List ticketBreakdown2=(List)ticketBreakdown.get(resource);

      Map resourceWorkloadBreakdown=combineRequestAndTicket(requestBreakdown2,

      ticketBreakdown2);

      result.put(resource,resourceWorkloadBreakdown)

      }

      return result;

      先不管那糟糕的命名、失衡的代碼結構以及其它任何代碼美觀度上的問題了。這段代碼中最壞的味道就是它返回的Map對象了,這個Map對象完全是個黑洞,里面塞滿了各種數據,但又不會提示你里面究竟包含的是什么。我只能編寫了一些調試代碼,將Map中的內容循環打印出來后,才看懂了它的數據結構。

      在這個示例中,{} 代表一個Map,=> 代表健值映射,而[] 代表一個集合:

      {resource with id 30000=> [

      SummaryOfActualWorkloadForRequestType,

    原文轉自:http://www.infoq.com/cn/articles/refactoring-legacy-applications

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>