奧卡姆剃刀:讓事情回歸簡單

2021-01-17 從碼農到工匠


最近,阿里雲的同學告訴我,COLA作為應用架構,已經被選入阿里雲的Java應用初始化的應用架構選項之一。

This is really something,於是,在這個裡程碑節點上,我開始回過頭來,重新審視COLA一路走來的得與失。

COLA作為一種架構思想無疑是成功的。但是作為框架,個人感覺有點雞肋之嫌。 特別是在簡潔性上做的不好,感覺做了不少畫蛇添足的事情。

試想一下,有些功能我作為作者都很少去使用,我實在想不到,它為什麼還有存在的理由。

基於上面的思考,我做了這一次COLA 2.0 到 COLA 3.0的升級。在本次升級中,我沒有增加任何新的功能,而是儘量多刪減了一些概念和功能。讓COLA可以更加純粹的focus在應用架構上,而不是框架支持和架構約束上。

支持我做這些決策的背後原因只有一個——奧卡姆剃刀原理。

奧卡姆剃刀原理

奧卡姆剃刀原理,是指如無必要,勿增實體(Entities should not be multiplied unnecessarily),即「簡單有效原理」。正如奧卡姆在《箴言書注》2卷15題說「切勿浪費較多東西去做,用較少的東西,同樣可以做好的事情。」

在具體的應用過程中,我們可以遵循以下原則去做事情:「如果同一個現象有n種理論,最簡單的那個便是最正確的。能用n做好事情,那就不要有第n+1個動作。」

比如,《皇帝的新衣》的皇帝到底穿沒穿衣服呢?如果你在現場,你很有可能就是大臣之一。

如果懂得了奧卡姆剃刀原理,可以用邏輯手段,判斷誰是真理。

第一種邏輯如下:假設皇帝是真的穿了衣服→假設愚蠢的人看不見→假設你就是愚蠢的人→所以你沒看見皇帝穿衣服。

第二種邏輯如下:假設皇帝沒穿衣服→所以你沒看見皇帝穿衣服。

同樣看見光身子的皇帝,第二種解釋簡單明了。而第一種解釋,可能正因為它是錯誤的,就需要更多假設來補救漏洞,就像說謊圓謊一樣。

真相不需要偽裝掩飾,簡單明了。

再比如,地心說和日心說,託勒密的地心說模型是一個本輪均輪模型。人們可以按照這個模型,定量計算行星的運動,據此推測行星所在的位置。

到了中世紀後期隨著觀察儀器的不斷改進,人們能夠更加精確地測量出行星的位置和運動,觀測到行星實際位置與這個模型的計算結果存在偏差,一開始還能勉強應付,後來小本輪增加到八十多個,卻仍然不能精確地計算出行星的準確位置


1543年,波蘭天文學家哥白尼在臨終時發表了一部具有歷史意義的著作—《天體運行論》。這個理論體系提出了一個明確的觀點:太陽是宇宙的中心,一切行星都在圍繞太陽旋轉。該理論認為,地球也是行星之一,它一方面像陀螺一樣自轉,一方面又和其他行星一樣圍繞太陽轉動。

哥白尼的計算不僅結構嚴謹,而且計算簡單,與已經加到八十餘個圈的地心說相比,哥白尼的計算與實際觀測資料能更好地吻合。因此,地心說最終被日心說所取代。

設計中的彎彎繞

深入考察一下,我們系統中,類似於「地心說」這樣的彎彎繞的設計,實在是不在少數

從系統架構的角度看,有些彎彎繞是因為系統邊界劃分不合理,導致職責不清,依賴混亂。

從應用架構的角度看,有些彎彎繞是因為過度設計,為了追求所謂的靈活性和可擴展性,使用了不恰當的設計。導致本來可以直觀呈現的代碼邏輯,被各種包裝,各種隱藏,各種轉發.... 無形中極大的阻礙了代碼的可讀性和可理解性,增加了維護成本。

舉個例子,我看過無數的業務系統,喜歡拿業務流程編排說事情。因此,在業務系統中,可以看到各種五花八門的「彎彎繞設計」。

比如,在一個業務系統中,我看到了如下的pipeline設計。這個設計的本質是說把一個複雜的業務操作進行結構化拆解為多個小的處理單元。

拆解是正確的,但是這種處理方式顯然不夠「奧卡姆」(關於更多結構化分解的內容,可以看我的另一篇文章)。作為維護人員,進入「入口函數」後,還要去查資料庫,然後才能知道哪些組件被調用了,太繞了,不夠直觀,也不簡潔。

同樣的邏輯,按照下面的方式寫不香嗎?

public class CreateCSPUExecutor {

@Resource

private InitContextStep initContextStep;


@Resource

private CheckRequiredParamStep checkRequiredParamStep;


@Resource

private CheckUnitStep checkUnitStep;


@Resource

private CheckExpiringDateStep checkExpiringDateStep;


@Resource

private CheckBarCodeStep checkBarCodeStep;


@Resource

private CheckBarCodeImgStep checkBarCodeImgStep;


@Resource

private CheckBrandCategoryStep checkBrandCategoryStep;


@Resource

private CheckProductDetailStep checkProductDetailStep;


@Resource

private CheckSpecImgStep checkSpecImgStep;


@Resource

private CreateCSPUStep createCSPUStep;


@Resource

private CreateCSPULogStep createCSPULogStep;


@Resource

private SendCSPUCreatedEventStep sendCSPUCreatedEventStep;




public Long create(MyCspuSaveParam myCspuSaveParam){



checkRequiredParamStep.check(context);


checkUnitStep.check(context);


checkExpiringDateStep.check(context);


checkBarCodeStep.check(context);


checkBarCodeImgStep.check(context);


checkBrandCategoryStep.check(context);


checkProductDetailStep.check(context);


checkSpecImgStep.check(context);


createCSPUStep.create(context);


createCSPULogStep.log(context);


sendCSPUCreatedEventStep.sendEvent(context);


return context.getCspu().getId();

}

}

這種寫法簡單直觀,易維護,與前一種方式相比,具有同樣的組件復用性。符合奧卡姆剃刀的精神,相比較而言,前面那種彎彎繞設計,雖然看起來有點設計感,帶來了一點點OCP的好處。但是無端增加了理解和認知成本,孰優孰劣,不難分辨。

COLA 3.0 升級

做了這麼長的鋪墊,終於到了批鬥COLA中「彎彎繞設計」的時候了。

去掉Command

在COLA的初始階段,因為受到CQRS的影響,於是想到了使用命令模式來處理用戶請求。設計的初衷是想通過框架,一方面強制約束Command和Query的處理方式,另一方面把Service裡面的邏輯,強制拆分到CommandExecutor中去,防止Service膨脹過快。

和上面介紹過的pipeline設計類似,這種設計有點繞,不夠直觀,如下所示:

public class MetricsServiceImpl implements MetricsServiceI{


@Autowired

private CommandBusI commandBus;


@Override

public Response addATAMetric(ATAMetricAddCmd cmd) {

return commandBus.send(cmd);

}


@Override

public Response addSharingMetric(SharingMetricAddCmd cmd) {

return commandBus.send(cmd);

}


@Override

public Response addPatentMetric(PatentMetricAddCmd cmd) {

return commandBus.send(cmd);

}


@Override

public Response addPaperMetric(PaperMetricAddCmd cmd) {

return commandBus.send(cmd);

}

}

看起來還挺乾淨的,可是ATAMetricAddCmd到底是被哪個Executor處理的呢,不直觀。我還要去理解CommandBus,以及CommandBus是如何註冊Executor的。無形中增加了認知成本,不好。

既然這樣,為何不用奧卡姆剃刀把這個CommandBus剔除呢。如下所示,去除CommandBus之後,代碼是不是直觀了很多,唯一的損失是我們會失去框架層面提供的Interceptor功能,然而,Interceptor正是我下一個要動刀的地方。

public class MetricsServiceImpl implements MetricsServiceI{


@Resource

private ATAMetricAddCmdExe ataMetricAddCmdExe;

@Resource

private SharingMetricAddCmdExe sharingMetricAddCmdExe;

@Resource

private PatentMetricAddCmdExe patentMetricAddCmdExe;

@Resource

private PaperMetricAddCmdExe paperMetricAddCmdExe;


@Override

public Response addATAMetric(ATAMetricAddCmd cmd) {

return ataMetricAddCmdExe.execute(cmd);

}


@Override

public Response addSharingMetric(SharingMetricAddCmd cmd) {

return sharingMetricAddCmdExe.execute(cmd);

}


@Override

public Response addPatentMetric(PatentMetricAddCmd cmd) {

return patentMetricAddCmdExe.execute(cmd);

}


@Override

public Response addPaperMetric(PaperMetricAddCmd cmd) {

return paperMetricAddCmdExe.execute(cmd);

}

}

去掉Interceptor

當時設計Interceptor,是因為有CommandBus作為基礎,為了更好的利用命令模式帶來的好處,便添加了Interceptor功能。其本質是一個AOP處理。

鑑於Spring的AOP功能已經很完善了,這個設計也是有點雞肋。事實證明,大家在使用COLA框架的時候,很少會使用Interceptor,包括我自己也是一樣。既然如此,剔除也罷。

去掉Convertor、Validator、Assembler

關於命名的重要性,這裡就不贅述了。當時想著是否能從框架層面,規範一下一些常用功能的命名。但是在實際使用中,發現這個想法也是有些過於理想化了。

我記得,在團隊實踐COLA的初期,還經常為什麼是Convertor(轉換器),什麼是Assembler(組裝器)的事情,爭論不休。

後面我仔細想了想,命名雖然很重要,但其作用域最多也就是一個團隊規範,你校驗器是叫Validator還是Checker並沒有什麼本質區別,團隊自己定義就好了。嘗試從框架層面去解決團隊約定問題,其效果不會太好,因此也果斷揮刀剔除。

類掃描優化

業務身份和擴展點的思想,是TMF的核心理念,也是阿里業務中臺的進行多業務支持的核心方法論

COLA致力於提供一種輕量級的擴展實現方式,因此該功能得以在奧卡姆的屠刀下得以保存。因為COLA的擴展點設計是借鑑了中臺的TMF,因此在前面的設計中,其類掃描方案是直接照搬TMF的做法。

實際上,TMF的類掃描方案對COLA來說有點多餘。因為COLA本身就是架設在Spring的基礎之上,而Spring又是建立在類掃描的基礎之上。因此,我們完全可以復用Spring的類掃描,沒必要自己寫一套。

在原生的Spring中,至少有3種方式可以獲取到用戶自定義Annotation的Bean,最簡潔的是通過 ListableBeanFactory.getBeansWithAnnotation方法,或者使用 ClassPathScanningCandidateComponentProvider進行掃包。

在這次改版中,我選用的是 getBeansWithAnnotation方法,主要是為了獲取@Extension的Bean,用來實現擴展點功能,廢棄了原來的TMF類掃描實現。

總結

觸發這次升級的動機,主要是因為,自己在實踐COLA的過程中,的確發現有些華而不實的功能。在COLA作為阿里雲的基礎應用架構,其影響力越來越大的時候,我有責任給到大家一個正確的引導——去偽存真,簡潔有效,而不是引入更多的複雜度

實際上,COLA是有兩部分組成的:

一方面COLA是一種架構思想,是整合了洋蔥圈架構、適配器架構、DDD、整潔架構、TMF等架構思想的一種應用架構。

在這次升級中,架構思想部分基本沒有變化,唯一一點是因為去除了Command概念,因此CQRS也成了可選項,而不再是一種強要求。

另一方面COLA也是框架組件,通過這次升級,我使用奧卡姆剃刀砍掉了絕大部分的組件能力,僅僅保留了擴展點功能。其用意是不希望COLA作為框架給到應用開發者太多的約束,這不符合簡單有效的風格。

所以,總結下來,與其說這是一次升級,不如說它是功能「降級」,是在做減法。

但我相信,減法可以讓COLA更加符合奧卡姆精神,幫助COLA輕裝上陣,走的更遠

COLA開源地址:https://github.com/alibaba/COLA

相關焦點

  • 奧卡姆剃刀定律:學會把複雜的事情簡單做
    奧卡姆曾在巴黎大學和牛津大學學習,知識淵博,能言善辯,被人稱為「駁不倒的博士」。他曾提出這樣一個原理:如無必要,勿增實體。其含義是:只承認一個個確實存在的東西,凡幹擾這一具體存在的空洞的普遍性概念都是無用的累贅和廢話,應當一律取消。後來由於反對教皇,奧卡姆和他的名言一起出了名。
  • 奧卡姆剃刀原理(簡單有效原理)
    簡單管理對於處於轉型和成長時期的中國企業具有非凡的意義,但簡單管理本身卻不是簡單。奧卡姆剃刀定律也認為:把事情變複雜很簡單,把事情變簡單很複雜。一些人動輒以「無為而治」、「治大國若烹小鮮」來概括簡單管理,但又有幾人能若庖丁般遊刃有餘?
  • 保持簡單——奧卡姆剃刀原理
    於是他們為了預防生產線再次發生這樣的事情,工程師想盡辦法發明了一臺X光監視器去透視每一臺出貨的肥皂盒。同樣的問題也發生在另一家小公司,他們的解決方法是買一臺強力工業用電扇去吹每個肥皂盒,被吹走的便是沒放肥皂的空盒。這則小故事蘊含著一個重要的原理—奧卡姆剃刀定律(Occam's Razor, Ockham'sRazor)又稱「奧康的剃刀」。
  • 奧卡姆剃刀思維:簡單成就高效
    事實上,簡單的解釋反而最可能是最接近真相的答案,現在也有人認為這些離奇的時間本身就不夠神秘,例如可能是遭遇颶風、船體損壞等緣故,每一起事件都有其合理解釋。前面我們提到了「奧卡姆剃刀」原則,那究竟什麼是「奧卡姆剃刀」呢?
  • 奧卡姆剃刀
    事實上,只有前兩種形式見於他現存的著作中,而第三種形式則由後來的一位學者撰寫。威廉使用這個原理證明了許多結論,包括「通過思辨不能得出上帝存在的結論」。這使他不受羅馬教皇的歡迎。  許多科學家接受或者(獨立的)提出了奧卡姆剃刀原理,例如萊布尼茲的「不可觀測事物的同一性原理」和牛頓提出的一個原則:如果某一原因既真又足以解釋自然事物的特性,則我們不應當接受比這更多的原因。
  • 奧卡姆剃刀定律
    ■管理速遞  在管理學領域,重要的事實是百人法則,即很多國際集團公司的總部不超過100名職員,這種人少高效率的組織結構,不能排除根植於西方文化領域中的奧卡姆剃刀作用。  什麼是 奧卡姆 剃刀?
  • 奧卡姆剃刀原理
    奧卡姆剃刀原理(Occam's Razor, Ockham's Razor)又稱「奧康的剃刀」。
  • 奧卡姆剃刀定律:如無必要,勿增實體
    文|羅輯回歸(專注為大家整理感興趣的內容,如大家喜歡,歡迎個人轉載分享)圖|來源網絡(如有侵權請聯繫刪除)大家好,今天要給大家介紹的是奧卡姆剃刀原理,是14世紀由英格蘭的威廉提出!相比之前給大家介紹的破窗效應、蝴蝶效應等,奧卡姆剃刀原理顯得比較陌生但很重要。奧卡姆剃刀原理又被稱為簡單有效原理,即「如無必要,勿增實體」。
  • 奧卡姆剃刀的效力
    「奧卡姆的剃刀」是一個經常被引用的思維法則,今天好像人人都在揮舞著這把剃刀,不管是物理學家、生物學家還是政策制定者。《劍橋奧卡姆研究指南》,2000年,美國印第安納大學哲學教授保羅·文森特的《奧卡姆的唯名論形上學》文章出自此指南 奧卡姆剃刀是一條經驗法則
  • Laws of UX - 奧卡姆剃刀定律
    之前我們依次聊了費茲定律、席克定律、雅各布定律、米勒定律,以及格式塔理論的三大基礎原則,包括蘊涵律、接近律、相似律;今天來看名字很酷的奧卡姆剃刀定律。新開微內容系列,Laws of UX,用戶體驗(設計)定律,由Lawsofux.com整理,每期一句話簡述相關定律或設計原則,附送漂亮的海報卡片。
  • 奧卡姆剃刀定律:複雜的問題可以簡單化
    奧卡姆剃刀定律:複雜的問題可以簡單化提出者:14世紀歐洲邏輯學家、聖方濟各會修士奧卡姆的威廉。內容精解:如無必要,勿增實體,即「簡單有效原理」。正如他在《箴言書注》2卷15題所說的,「切勿浪費較多東西去做,用較少的東西,同樣可以做好的事情」。應用要訣:不做任何多餘的事。
  • 科學界的名刀-奧卡姆的剃刀
    「奧卡姆的剃刀」在科學界是一個廣為人知,但卻並未得到廣泛認可的一個原理。至於這個原理的提出者,我也是真沒弄明白這哥們到底叫什麼名字,到底是叫威廉還是叫奧卡姆,還是叫個性十足的「奧卡姆的威廉」,今天我就不糾結了,就暫且叫他奧卡姆吧,希望學識淵博的朋友可以為我們指點迷津。
  • 一切理論之母:奧卡姆的剃刀
    奧卡姆剃刀定律(Occam's Razor, Ockham'sRazor)又稱「奧康的剃刀」,它是由14世紀邏輯學家、聖方濟各會修士奧卡姆的威廉(William of Occam,約1285年至1349年)提出。這個原理稱為「如無必要,勿增實體」,即「簡單有效原理」。正如他在《箴言書注》2卷15題說「切勿浪費較多東西去做,用較少的東西,同樣可以做好的事情。」
  • 騙子的剋星:奧卡姆剃刀
    它就是那把小小剃刀,名字叫做奧卡姆。01 奧卡姆剃刀14世紀時,歐洲學者忙於「口遁」,把研究「似是而非」的東西當作智慧象徵。例如:黑色的白傘是否存在?上帝的噴嚏還是哈欠導致了電閃雷鳴?不是張三、也不是李四的人本身是否存在?
  • 奧卡姆剃刀定律(Occam『s Razor, Ockham’s Razor)
    奧卡姆剃刀定律(Occam's Razor, Ockham's Razor)又稱「奧康的剃刀」,它是由14世紀英格蘭的邏輯學家、聖方濟各會修士奧卡姆的威廉(William of Occam,約1285年至1349年)提出。這個原理稱為「如無必要,勿增實體」,即「簡單有效原理」。
  • 【寫作素材】管理中的十大經典定律—奧卡姆剃刀定律
    奧卡姆剃刀定律: 奧卡姆剃刀定律(Occam's Razor,Ockham's Razor)又稱「奧康的剃刀」,是由14世紀邏輯學家、聖方濟各會修士奧卡姆的威廉(William of Occam,約1285年至 1349 年)提出。
  • 奧卡姆剃刀不是「剃鬚刀」
    熟悉科學史的朋友應該都在某種場合聽說過所謂的「奧卡姆剃刀原理」,這是一個由14世紀英格蘭的邏輯學家、聖方濟各會修士奧卡姆的威廉(William of Occam,約1285年至1349年)提出原理,即「如無必要,勿增實體」,或者通俗地說就是簡單直接才最有效。
  • 對奧卡姆剃刀理論和小草的思考
    這就是西方非常著名的奧卡姆剃刀理論。用更通俗點兒的話來說,威廉想表達的意思是:最簡單的,就是最接近真相的,最正確的,最有價值和最有力量的,最高效的,最美的……世界上有很多巨人都對奧卡姆剃刀理論有自己獨到的見解,也因此在實踐中獲得了巨大的成功。奧卡姆剃刀理論是西方哲學的精華之一,是西方社會從本質上理解大自然現象和社會現象的一把利刃。
  • 經濟和生活中非常有效的奧卡姆剃刀
    有些朋友可能不知道,奧卡姆剃刀是什麼意思,我先簡單說一下奧卡姆剃刀的大致意思是,如無必要,勿增實體。就是簡單有效。可以理解為,如果能用較少的東西做好的的事情,不要浪費較多的東西去做同樣的事情。這就是科學界大名鼎鼎的奧卡姆剃刀,比較類似於最小作用量。以上解釋只是樸素,簡單的理解。
  • 奧卡姆剃刀原理:去除無用的東西,讓你更簡潔高效!
    其最重要的成就就是奧卡姆剃刀原理了。那麼到底什麼是奧卡姆剃刀原理呢?切勿浪費較多東西去做,用較少的東西,同樣可以做好的事情。其實簡單的幾個字就可以概括,「如無必要,勿增實體」。所以這個原理也可以成為簡單有限原理。