前不久“待字閨中”的公眾號,推送了一篇文章《復雜的簡單》,里面講述了復雜的系統往往是由最簡單的組件通過一定的方式組合而成。
一、幾個例子
Tesla高檔豪華時尚的電動汽車,作為核心競爭力和超級秘密的電池,居然是由一顆一顆我們日常生活中常用的鋰電池18650構成的,一輛車就用了將近7000多顆這樣的電池,然后通過電池系統來控制和管理它們。
Google的云計算的基礎設施,沒有采用高性能的大型機和存儲系統,而是創新性的發明了MapReduce模型和HDFS,使用大量的廉價PC實現了具有高性能和高可靠性的復雜系統。
現在流行的深度學習神經元網絡,是有一個一個簡單的神經元組成,每個神經元都很簡單,可是將它們合理組織起來,就能形成威力無窮的人工智能系統,解決語音識別、圖像識別、自然語言處理等領域的問題。
二、軟件設計中的簡單與組合
通過發現具有原子特性的組件,通過組合形成更加復雜的系統,在軟件設計和開發中同樣具有巨大的威力。
這里分別列舉幾個例子進行說明。
1.求三個數字中較大的兩個數字的平方和。
這個問題可以分解為:求三個數中的最大值、求三個數中的次大值,以及計算平方和 3個子問題。分別對應下面函數中的三個函數。
sum of squares of the two larger numbers
(define (f x y z)
(sum-of-squares (biggest-of-three x y z) (medium-of-three x y z))
)
而這三個函數又可以通過更加小的函數來組合而成。這個示例完整的內容可以參考這里:The sum of the squares of the two larger numbers
這里使用了函數式編程語言中的函數;函數具有很好的抽象特性,并且具有很好的復用和組合特性。
2.大整數的四則運算。
編程語言中內置的int類型能表示的范圍是32位或者64位,有時我們需要參與運算的數,可能會遠遠不止32位或64位,一般我們稱這種基本數據類型無法表示的整數為大整數。
實現一個程序,完成大整數的基本運算,如加法、減法、乘法和除法,其中,大整數用字符串來表示。例如:
- "9999999999999999999" + "-9999999999999999999" = "0"
- "1000000000000000000000000" - "1" = "999999999999999999999"
- "12345678" * "54321" = "670629574638"
最終的加、減、乘的C語言實現過程如下所示:
加法:
char * add(const char * left, const char * right)
{
if(is_positive(left) && is_negative(right)) return sub(left, right+1);
if(is_negative(left) && is_positive(right)) return sub(right,left+1);
if(is_negative(left) && is_negative(right)) return negative(add(left+1, right+1));
else return add_internal(left, right);
}
減法:
char * sub(const char *left, const char * right)
{
if(is_positive(left) && is_negative(right)) return add(left, right+1);
if(is_negative(left) && is_positive(right)) return negative( add(left+1, right));
if(is_negative(left) && is_negative(right)) return sub(right+1, left+1);
if(is_positive(left) && is_positive(right))
{
if (less_than_by_abs(left, right)) return negative( subInternal(right,left));
}
return subInternal(left,right);
}
乘法:
char * mul(const char *left, const char * right)
{
if(is_zero(left) || is_zero(right)) return add("0", "0");
if(is_positive(left) && is_negative(right)) return negative( mul(left, right+1));
if(is_negative(left) && is_positive(right)) return negative( mul(left+1, right));
if(is_negative(left) && is_negative(right)) return mul(left+1, right+1);
return mulInternal(left, right);
}
在add
sub
mul
函數中,關注點在于:根據操作數不同的符號組合,執行不同的邏輯。這里的邏輯是業務領域的高層邏輯,不關心算術運算的實現細節。
加法、減法和乘法的實現細節,只體現在addInternal
subInternal
mulInternal
三個函數中,它們是實現過程中的原子;其它高層的業務邏輯均在其基礎上通過組合的方式完成。
完整的示例內容請前往這里:大整數計算器
3.微服務
最近十分火熱的微服務同樣具有簡單、組合的特性。通過將服務劃分為多個、獨立的微服務,消除單體程序中存在的緊耦合;各個相互獨立的微服務可以獨立開發、維護、部署和升級。
關于微服務的具體內容在此不再贅述,已經有很多的資料對此進行解釋。
三、總結
通過簡單和組合的設計思想,可以使得:
- 不同層次、模塊、組件的過程在實現上相互獨立,
- 系統在其中某一個部分的實現被替換的情況下,不需要修改設計仍然能正常工作,
- 通過組合的方式,構建出功能更加強大和復雜的系統。
正如同樂高,使用一個個簡單的顆粒,我們卻可以拼出千變萬化的作品。