開發小結-業務管理類

本篇文章關注於編程實踐中的相關流程設計內容,內容來源本身過去的工做總結。編程

業務流程設計

越複雜流程,越容易出錯。爲了減小出錯的狀況,須要提取而且封裝通用邏輯,用一個易於理解的名字來對外提供服務。在業務不一樣抽象層級上,幹各自職責對應的事情。緩存

先後臺交互的流程越多,須要維護的狀態就越多,出現問題的機率就越大,所以在不影響主要功能的前提下,流程能簡化就儘可能簡化,那些被簡化的路徑,在某些異常場景下,會對業務有必定的影響,具體影響到什麼程序,在上線前,誰也很差說。可經過數據埋點獲得上線後的真實數據,以供權衡。網絡

針對複雜業務時,不能一上手就開始寫,要先設計好框架和總體流程。對於一些需求上面沒有明確的交互細節,通常按照通用交互細節來就能夠。框架

對於具體子功能的實現上,須要細緻考慮,較好的實踐方法是逐條列出來,在每種狀態或狀況下,什麼樣的輸入獲得什麼樣的輸出。函數

在複雜程序執行過程當中,須要維護多個狀態,隨着業務的改變,在處理於狀態關聯的事件時,思惟負擔會愈來愈重重,很容易顧此失彼。
爲了更好的控制複雜度,簡化邏輯,須要對狀態進行分級管理,將每一個級別的狀態和對應處理分層化。對外統一狀態操做接口,每一個模塊中,都經過統一狀態接口來管理狀態。測試

每個常量數字,在業務上都要有依據來源,要麼是經驗值,要麼是業務規則規定的。字體

失敗流程

任何失敗重試類操做,都要考慮對後臺的影響。由於網關只會轉發請求,大量冗餘的請求會給後臺形成巨大壓力,可能會影響正常業務流程。對於失敗重試,必定要設置定時間隔以及重試次數,這裏的失敗要區分類型,若是是業務操做類的失敗,業務層直接提示出錯便可。若是是其餘類型的失敗,底層須要作好重試策略,直到重試策略返回失敗,纔可認爲是失敗,此過程對上層是透明的。優化

針對開發回發的數據,要進行有效性校驗才能繼續往下走,在有些業務場景中,須要對不一樣類型的失敗分配不一樣類的錯誤碼,以便外部處理。好比讀取配置信息這個功能,可能的出錯就有如下幾種狀況:this

  1. 配置文件不存在
  2. 配置文件存在,但文件格式不正確
  3. 配置文件存在,文件格式正確,屬性Key缺失
  4. 配置文件存在,文件格式正確,屬性Key正常,屬性Value缺失
  5. 配置文件存在,文件格式正確,屬性Key正常,屬性Value是異常值(超大的數,或者是負數)

若是由於上述種種緣由,致使讀取配置文件失敗,那要作好默認配置的處理,根據產品要求,對不一樣的異常狀況,作出對應的處理,使用默認配置繼續運行,仍是彈框提示用戶等。設計

在對後臺返回來的格式化數據進行解析時,必定要考慮對應字段不存在的狀況下該如何處理。無論後臺返回什麼類型的錯誤數據,都不能崩潰。

流程優化

仔細分析業務流程,避免沒必要要的依賴和操做,相關的業務邏輯,要聚合到一塊兒。

分析問題的思路要不斷在實踐中打磨,反思,總結。本身第一時間想到的方案,每每還有很大的優化空間,那麼,從什麼角度去思考優化呢?在開發實踐中,逐漸明確兩個大的方向,在此記錄一下

  1. 從底層往上層思考 : 底層是最基礎的數據層,業務流程的數據是否是能夠往下移動到底層,而後調用底層明確性語義接口函數來實現上層業務,而不是把一堆判斷邏輯都交由業務層去作。

  2. 從上層往底層思考 : 在業務層和底層數據之間,要有一個間接層,對上提供較爲高級的功能,對下封裝最底層數據,提供更高層次的接口。

  3. 類似的業務處理採用類似的辦法,不要一堆條件,範圍A-C的用這樣的處理方法,業務範圍D-F的用那樣的處理方法,其餘類型業務用其餘的處理方法。這樣一來,業務和對應的錯誤處理分散在各處,後期維護很容易出錯。

一個類,如需向其餘類得到相關信息,不要依賴於類與類之間的繼承組織關係,嘗試經過this來進行強制轉換來獲取,由於這種層級關係在將來可能會發生變更,而這種層級關係的變更,不會通知使用者,所以在實現相似需求時,須要將對外部的依賴關係儘量的下降,建議採用消息的方式,每層規定好消息的職責,一層一層向上傳遞請求,直到某一層給與響應爲止。

一致性

一致性,指的是對於UI元素和代碼命名的一致性,同一邏輯元素的命名一致性,它在UI層、中間層、網絡層以及後臺接口中的核心詞彙要保持一致,這樣增長代碼的可讀性。

一致性體如今資源管理上,同一份資源,誰申請,誰就負責釋放。誰增長引用記數,誰就負責減小。

在一些通用功能的設置上,保持代碼一致性很重要。好比設置控件字體,原生系統會提供一套接口,自繪部分也會提供一套接口,那麼外部在使用時,就會有疑惑,設置字體是用原生接口仍是自繪接口呢?他們會不會相互影響呢?在前期設計時,同一類功能,只提供一套接口較好。

類似操做可以歸集到一塊兒的,必定要歸集到一塊兒,讓邏輯聚合,而不是處處分散。

修改影響評估

好比,你修改了A函數中的A分支,A函數的B分支沒有改動。外部O1模塊使用了A函數的B分支,O2模塊使用了A函數的A分支,那麼你的本次修改涉及到的影響範圍是哪些呢?O2模塊確定是要測的,O1模塊需不須要提測?答案是須要的,從廣義上來看,任何調用A函數的模塊都要重測一片。即便本次修改沒有涉及到分支,也要去測試。

在嘗試修改後臺程序時,要注意與以前系統的兼容性。

在修改一個涉及範圍比較大的問題時,若是涉及的地方太多了,爲了最終問題的解決和測試方面的平滑過渡,須要將問題分治,按照功能需求模塊來統計彙總,而後,將問題列表按模塊分配給各自負責人,由他們去進一步往下分散進行修改,這樣能夠保證大型問題的平滑過渡,爲開發和測試提供緩衝時間段。

好比本次修改點可分爲如下幾個集合,

集合1:涉及到哪些方面

集合2:涉及到哪些方面

集合3:涉及到哪些方面

邏輯完備性

對於層級調用,資源的申請和釋放,要特別注意一致。這一點,特別容易遺漏。
好比說,先壓入緩存,再發出請求,那麼,清理緩存的時機,應該要覆蓋發出請求後的每一條執行路徑。
7.1 發出請求失敗
7.2 發出請求成功,響應成功
7.3 發出請求成功,響應失敗

一段業務代碼,正確的路徑只有一條,但錯誤的路徑有不少條,怎麼處理在這個過程當中有可能出現的錯誤,就很顯的功力所在了。

若是遇到一些須要特殊處理的地方,優先把大部分狀況放在主幹邏輯上,在額外的分支中處理額外。

凡是涉及到網絡請求的,若是中途關閉了頁面,必定要注意請求資源的清理操做,這樣在從新打開頁面,不會收到上一次無效的響應。

優化前的準備

沒有profile的優化都是瞎扯淡,一旦開始重構,就要指定好優化目標,全部的相關修改都聚焦在目標上,不能跑偏了。優化前要分析現狀、制定方案和可量化的目標,完成優化後,須要提取相關的數據,總結對比可量化的分析優化成果。後臺重構須要配置A/B方案,對於可能會有變化的模塊或者業務,或者A、B方案很差取捨的,可採用後臺配置採用哪一個方案,當重構的版本上線時,先保留舊的模塊,若是有問題,能夠在後臺中配置切回到舊的模塊,這種思想同能夠同灰度發佈一塊兒使用(5W,10W)

在進行組件的重構時,須要遵循最小影響範圍來作,一處重構,儘可能隻影響到這個業務,不影響到其餘業務,保證可控性和可測試性。

維護經驗

對於接手舊項目,裏面用到的第三方庫,若是有新版本的接口庫或者更好的第三方接口庫,該如何抉擇?

  • 若是原有的庫可以知足需求,則不要貿然替換或者升級
  • 若是原有的庫不能知足特定場景下的需求,優先本身封裝在特定場景下的接口,以供使用。若是特定場景下的需求須要的新功能不能經過封裝已有API來提供,而該功能在原有庫的升級版中存在,那麼須要和原有庫維護者商量討論後再進行升級。
  • 用新的三方庫來替換,該方法改動範圍會很大,不到萬不得已,不容許使用。

當老舊代碼中有不少相互交纏的邏輯,須要改動多處才能改好詞Bug,很差評估改動影響的範圍,這個時候,爲了最大限度的兼容老舊代碼,不能繼續在老舊代碼的基礎上繼續填坑、挖坑,若是選取其中一個簡單的界面,用清晰簡單的邏輯去實現,而後在逐步替換老舊模塊,小步慢跑的改進。

當須要在原有功能上面增長新的功能時,要特別注意一點,就是原有功能所使用的指令和流程不能更改。好比查詢A產品的天數信息,原有的指令只支持一種產品的查詢,如今其餘界面有同時查詢多種產品的狀況,而原有指令只實現了查詢單個產品信息, 那麼,下面有兩種解決方法:

優勢                       缺點
方法一:修改原有指令,使其支持多條信息的查詢      增長指令的功能         需修改原有查詢單條產品的頁面,增長了測試成本
方法二:不改動原有指令,新增支持多條信息查詢指令  不會影響已有功能       相似功能有多處實現,查多條包含查一條的功能

由於查詢一條產品信息屬於查詢多條產品信息的特例,爲了可維護性,採用方法一較好。

一個簡答的權限判斷功能設計

有A、B、C三個帳號,有ID1,ID2,ID3,ID4四個功能,每一個帳號容許的功能以下:

A--> ID1, ID3
B--> ID2, ID3
C--> ID4

如今要設計一個權限判斷的函數,給定功能ID和帳號,返回是否容許執行此操做判斷?

一種是從上往下,從入口ID和各個可操做ID段來判斷,優勢是直觀,簡單,缺點是對擴展性很差,將來要增長新的入口時,須要修改多出
方法一: 從上到下,邏輯簡單直接,可擴展性差

bool IsAllow(Account acnt, int nFunId)
{
    if (A == acnt)
    {
        if (nFunId == ID1 || nFunId == ID3)
        {
            return TRUE;
        }
    }
    else if (B == acnt)
    {
        if (nFunId == ID2 || nFunId == ID3)
        {
            return TRUE;
        }
    }
    else if (C == acnt)
    {
        if (nFunId == ID4)
        {
            return TRUE;
        }
    }
    
    return FALSE;
}

另外一種方法是從下往上,將每一個交易ID和可以操做條件集合在一塊兒,這種方式的擴展性和可讀性都很是好,推薦使用。

struct TIDInfo
{
    int nId;
    vector<Account> vAllowAcntType;   //  該ID要求的帳號屬性
    
    bool IsAllow(Account acnt)        // 給定帳號是否存在特定屬性
    {
       return vAllowAcntType.find(acnt) != vAllowAcntType.end();
    }
}

vector<TIDInfo> allIdInfo;            // 全部功能ID集合
bool IsAllow(Account acnt, int nFunId)
{
    for (int i = 0 ; i < allIdInfo.size(); ++i)
    {
        if (allIdInfo[i].nId == nFunId)
        {
            return allIdInfo[i].IsAllow(acnt);
        }
    }
    
    return FALSE;
}
相關文章
相關標籤/搜索