重構系統的套路-寫有組織的代碼

若是一個項目經歷了快速發展,勢必在業務發展背後留下了一個很無序,結構混亂的代碼,無序而混亂的代碼勢必形成很大的bug修復及擴展成本。數據庫

說到搭建系統都在談論高併發,大數據,而易於維護和可擴展性則被大部分人拋之腦後,增長最基礎的面向對象思想和設計模式幫助咱們組織好易於維護和閱讀的代碼。設計模式

不要好高騖遠看一下高併發,高可用的東西,作好如下這些最基礎的東西,你的系統在可讀性和可維護可擴展方面將會提高一倍的能力,將你們的人效從每次bug產生梳理代碼的過程當中解放出來,創建標準創建原則纔是架構師首先要作的。緩存

  • 進行適當的封裝
  • 開放封閉原則
  • 單一隻能原則
  • 代碼具有隨時刪掉而不影響上下文的能力

命名與註釋

命名須要見名知義,註釋則能夠幫助咱們去了解當時的業務邏輯,否則後期只能經過一行行的日誌去定位問題了。數據結構

考慮到IDE會幫助咱們建立變量名稱,若是名稱類似則存在誤用可能形成很難定位的BUG,入參能夠以Req結尾或者Command結尾,返回值以Resp結尾或者Result結尾。架構

抽離業務骨骼

Web系統的入口層是Controller,基於RPC的服務入口層每每是XxxServiceImpl,入口層應該像一本書的目錄和前言部分,說明了這個方法的主要目的,同時梳理了核心的業務流程,流程不要太細或者太粗,剛恰好知足產品的需求骨骼爲主,能夠簡單的理解爲是產品PRD的信息抽象。併發

創建膠水層代碼

大型系統或者業務系統具備必定的複雜程度,勢必在某些問題場景包含一些必要的大邏輯處理,因而創建一個膠水層代碼,膠水類能夠用入口層的一個方法名稱做爲名稱定義。 膠水層代碼向外暴露的public接口則爲入口層的核心骨骼邏輯,將內部複雜邏輯進行封裝,達到部分方法隨時能夠刪掉,註釋掉,替換掉而不影響核心骨骼邏輯的效果,能夠理解爲TDD,關注入參和返回值就好。 若是經過RPC或者ResultAPI和其餘系統具備必定的依賴,則放到這裏。 其實這層有些上DDD裏面的Domain,可是DDD用很差的話在分佈式微服務場景下會出現很難把控的問題。異步

下層依賴代碼

在入口和業務邏輯之下基本就是Service層代碼和Dao層代碼了,Dao主要是和存儲系統打交道,主要目的是能夠隨時切換到其餘的存儲邏輯中去,而不影響上層業務和代碼。 Service則是進行必定的數據結構組織,數據結構可能來自於底層Dao,可能來自於消息隊列的訂閱,可能來自於Redis緩存或者Hbase等,放在這一層能夠有效分離依賴系統數據和本系統數據。分佈式

示例

輸入圖片說明

入參

public class WmPoiReq { 
    private long userId; 
    private long wmPoiId; 
    private int channel; 
}

返回結果

public class WmPoiResp { 
}

實體

public class Activity { 
    int activityId; 
    Long wmPoiId; 
    int channel; 
    long valida; 
}

服務入口

public class CServiceImpl { 
 
    /** 
     * 發送積分
     * @param req 
     * @return 
     */ 
    public WmPoiResp wmPSendC(WmPoiReq req){ 
        // 入參不合法,及時失敗 
        if(null == req || req.getUserId() < 1l || req.getPId() < 1l || req.getCh() < 0){ 
            throw new IllegalStateException("參數無效"); 
        } 
 
        PSendCHandler handler = new PSendCHandler(); 
        // 1. 獲取可用列表 
        List<Activity> activities = handler.getActivityList(req.getPId(), req.getUserId(), req.getCh()); 
 
        // 2. 知足,進行發操做 
        boolean sendStatus = handler.sendC(req.getPId(), activities); 
 
        // 3. 調用接口服務化發
        // RPC調用服務發送 
 
        WmPoiResp resp = new WmPoiResp(); 
        return resp; 
    } 
}

建立膠水代碼,實現流程細節

public class PSendCHandler { 
 
    /** 
     * 獲取可用活動列表 
     * @param iId  
     * @param userId 用戶id 
     * @param channel 
     * @return 
     */ 
    public List<Activity> getActivityList(long PiId, long userId, int channel){ 
        // 1. 根據PiId, channle獲取活動列表 
        List<Activity> activities = ... // 僞裝從底層數據獲取 
        if(activities.size() == 0) return new ArrayList<>(); 
 
        // 2. 判斷獲取是否已過時 
        boolean expire = activities.size() > 0 ? activities.get(0).getValida() > new Date().getTime() : true; 
        if(expire) return new ArrayList<>(); 
 
        // 3. 判斷是不是新用戶 
        boolean freshMan = ... // 僞裝從底層數據獲取 
 
        if(freshMan){ // 新用戶,驗證是否有適用於新用戶活動 
           Iterator<Activity> iterator = activities.iterator(); 
           while (iterator.hasNext()){ 
               // 檢查每一個activity是否適用於新用戶 
           } 
           // 全部活動不適用於新用戶 
            return new ArrayList<>(); 
        } 
 
        // 返回可用活動列表 
        return activities; 
    } 
 
    /** 
     * 發券 
     * @param PiId 門店id 
     * @param activities 活動集合 
     * @return 
     */ 
    public boolean sendC(long PiId, List<Activity> activities){ 
        // 經過線程池異步發 
        // 同時記錄緩存 
        return true; 
    } 
}

總結

其實總結起來很簡單,增長必要的封裝和抽離,經過入參和返回值把控。 用看書的思惟組織代碼系統的,增長一個業務的可閱讀可理解能力,在一個系統發展必定階段以後,最讓RD同窗苦惱的不是技術問題,每每是一些業務邏輯或者布丁代碼,因此研發同窗要有意識的對業務和技術進行抽離,而不是簡單的將技術和業務糾纏在一塊兒,作好某塊業務邏輯代碼隨時能夠刪掉而不影響系統的能力。 創建適當的代碼命名規則,避免IDE帶來的沒必要要的誤用。 豐富wiki及文檔,涉及到測試用例,數據庫字段文檔,產品PRD等。微服務

相關文章
相關標籤/搜索