忍不了,客戶讓我在一個接口里兼容多種業務邏輯
故事
小貓的風波已經過去了,這幾天,小貓在安安心心地擼著系統現狀方案,準備著下次月會的分享。
這天,原本靜謐而又和諧的辦公室卻被開放平臺老六抱怨聲打破了。
“不改,別給我打電話了!說幾遍都沒用。這是一個研發的底線.....”
沒過一會,產品老汪擔心老六對其"對臉開大",孫子似地提著杯咖啡找到了老六。老汪是明事理的產品經理,為人處事兒這方面沒得說。
“這事兒,我也為難,兄弟,幫幫忙,來喝杯咖啡解解乏。我也知道這種客戶很難搞,但是我們是乙方,沒辦法,這年頭大環境擺在這里,賺錢不容易,大家互相體諒一下。”
老六接過老汪的咖啡,氣呼呼地抿了一口。
“上次發布商品的時候讓我把修改商品屬性和新增商品信息放到一個接口也就算了,這次還讓我干脆把上架到貨架直接包到一起?那后面我們這接口還咋維護了?后面是不是把商品添加到活動中也往這一個接口上堆啊?你讓我到后面咋維護么?他們公司的lowb研發懂不懂軟件設計原則啊......”
產品老汪在旁邊連連點頭,"兄弟,消消氣,消消氣"。
“要不這樣吧,咱們拉上對面研發一起聊聊吧,看看雙方是否都可以讓讓步......”。
于是老汪和老六一起來到一間會議室,約客戶開始了在線會議。
單一職責原則
大家有沒有遇到老六一樣的遭遇。由于業務要求,接口或者某個模塊中耦合了太多可能不相干的事情。在這里你們是如何處理的呢?關于這點咱們要引出單一職責原則這樣一個軟件設計原則。
對于單一職責原則,官方術語:單一職責原則,英文縮寫SRP,全稱Single Responsibility Principle。There should never be more than one reason for a class to change。一個類或模塊應該有且只有一個改變的原因。如果一個類擁有多個職責,這些職責之間的耦合會導致系統變得不穩定和難以維護。
在OOP里面,高內聚、低耦合是軟件設計追求的目標,而單一職責原則可以看做是高內聚、低耦合的引申,將職責定義為引起變化的原因,以提高內聚性,以此來減少引起變化的原因。職責過多,可能引起變化的原因就越多,這將是導致職責依賴,相互之間就產生影響,從而極大的損傷其內聚性和耦合度。單一職責通常意味著單一的功能,因此不要為類實現過多的功能點,以保證實體只有一個引起它變化的原因。
可見無論從官方定義,還是對“單一職責”名稱的解釋,都能很好的理解單一職責原則的意義。其實在軟件設計中,要真正用好單一職責原則并不簡單。
老貓覺得如果需要遵循這樣的原則,最關鍵的地方還是在于職責的劃分。不過說到這個職責劃分又是比較偏向于業務性質的,其和產品需求是分不開關系的。咱們就拿老六遇到的這個事情來分析一下。
一個發布商品的例子
說明:下面demo的表現形式,咱們都會用到類圖的方式,關于類圖的相關知識點,大家有興趣可以看這里“類圖知識點”。
第一版
咱們一起看一下這個例子,如下圖:
接口
上面的圖中,我們看到了有一個發布商品的接口類以及實現。在其中,我們看到其中包含了發布商品的基礎信息,發布圖片信息,發布規格信息,將商品加入商品池,將商品加入售貨架,將商品加入某個活動。
我們一起來看一下上述的設計是否存在問題?很多時候其實是有爭議的。
單一職責原則要求一個接口或類只有一個原因引起變化,也就是一個接口或類只有一個職責,它就負責一件事情,原則上來說,單純從客戶角度,如果能保證客戶后續需求不會變更,以商品發布作為顆粒度,那么它是合理的。因為業務上已經約定好,里面有商品屬性信息維護,有商品行為信息維護。如果沒有新的業務概念提出來,頂多后續內部改造的也就是屬性變更以及上下架和商品池維護變更。這種角度來說是合理的。
但是這種不變更的保證誰能擔保呢?另外接口也不是針對這一家客戶開放的,當然考慮通用性。
第二版
這不沒多久業務又接了一家新客戶,他們的要求是發布商品就是商品信息的發布。剩余行為無需做強綁定,上下架行為由對方運營人員選擇性執行,沒必要新品一發就上架。那現在的這套就打又破了之前的單一原則。因為由于業務的要求,咱們要將行為拆分成下面這種模式:
第一次拆分
上面的業務看起來更加清晰一些,咱們把屬性同步設置單獨抽離,針對操作商品的行為也單獨封裝為另外一個行為接口。系統功能可拓展,接口可復用的角度來說,無論是第一個版本還是第二個版本,看起來都比較適用。這么一來,看起來兩個客戶的業務都遵循了單一職責的原則。雖然這種方案會引來第一個客戶的研發的不滿,因為對于他們來說可能會調用兩次(當然我們也可以通過門面模式將其整合,當然這是后話),但是站在系統本身的設計角度來說,是比較合理的。但是這樣的一個抽取方式真的夠了么?
第三版
又來了一家客戶,由于對方公司有自己的運營想法,對方不希望用我們的活動,他們希望有自己的活動,并且需要我們給其單獨定制,那么此時咱們又發現,單一職責的這個設計原則又被打破了,因為我們需要針對活動去做定制,為了遵循職責單一原則,所以這時候需要我們將活動行為單獨剝離。然后就有了下面這樣的情況。
第三次拆分
這次的接口看起來更加靈活,滿足單一模式的同時,滿足了以上所有的業務。但是這就夠了么?
顯然不夠,我們還是會遇到各種業務需求的變動,但是上述的抽取在當前的業務下面看起來是比較適用的。能夠cover住大部分的場景了。對于后續的業務拓展也比較友好。
總結
上述的例子比較極端,老貓其實主要想和大家一件事情,所謂的單一職責的軟件設計模式并不是絕對的,我們會根據業務的需求形態做出動態調整。如何遵循好單一職責的設計原則,其實還是需要我們能夠對業務有一個比較精準的領域劃分。小伙伴們,你們覺得呢?