《Joel on software》談到所謂抽象漏洞,簡(jiǎn)單來(lái)說(shuō)就是抽象能解決90%的一般情況,而其他10%的情況你仍然需要跟抽象層面下的細(xì)節(jié)打交道,也就是抽象本身只能減少你的工作時(shí)間,而無(wú)法減少你的學(xué)習(xí)時(shí)間。道理簡(jiǎn)單,舉幾個(gè)例子。
以SQL語(yǔ)言為例,SQL是所謂說(shuō)明性的語(yǔ)言,你所寫的語(yǔ)句只是一條what,而how是如何做的無(wú)需關(guān)心,但是真的無(wú)需關(guān)心嗎?事實(shí)上是不行,低效的SQL語(yǔ)句對(duì)數(shù)據(jù)庫(kù)的性能損害非常大,作為程序員你需要知道SQL這個(gè)抽象層次下的部分內(nèi)容,知道數(shù)據(jù)庫(kù)是怎么執(zhí)行這些語(yǔ)句,知道如何去避免一些最差實(shí)踐。再比如分布式調(diào)用希望做到能跟本地調(diào)用一樣的透明,但實(shí)際上還是不行的,網(wǎng)絡(luò)的不確定性讓RPC調(diào)用根本無(wú)法做到的類似本地調(diào)用那樣的透明性。隱藏在RPC這個(gè)抽象層次下的網(wǎng)絡(luò)通信細(xì)節(jié),你不能不去care。抽象能幫你解決大多數(shù)情況,提高你的工作效率,但是剩下的一公里問(wèn)題,仍然需要你花費(fèi)更多時(shí)間和精力去了解并解決。這事實(shí)上也是一個(gè)優(yōu)秀程序員跟普通程序的差別之一,學(xué)習(xí)了java編程,知道了collection集合框架,不代表你無(wú)需再去學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)和算法。
Joel將這個(gè)現(xiàn)象稱為漏洞抽象。事實(shí)上,我并不認(rèn)為這是抽象本身的漏洞,這反而是軟件的本質(zhì)復(fù)雜性在作怪,抽象只能去化簡(jiǎn)偶然復(fù)雜性,例如函數(shù)、類、模塊化等手段去組織代碼,而本質(zhì)的復(fù)雜性是無(wú)法避免的。舉個(gè)不是那么恰當(dāng)?shù)睦樱缥覀冇羞@么個(gè)方法,傳進(jìn)一個(gè)參數(shù)list,我們要遍歷list做一些事情,(我知道用迭代器才是正途,先允許我犯這么個(gè)錯(cuò)誤),你可能這么寫:
public void doSomething(List<String> list){
for(int i=0;i<list.size();i++){
String str=list.get(i);
//do something
}
}
這樣的代碼我估計(jì)在1.5有for語(yǔ)句增強(qiáng)之前不少人都寫過(guò),這樣的代碼有什么問(wèn)題呢?考慮下list是ArrayList和LinkedList這兩種情況,List是鏈表的抽象,但是鏈表的實(shí)現(xiàn)形式卻是可以用數(shù)組或者引用鏈接,鏈表的實(shí)現(xiàn)形式不同,List.get(index)這個(gè)方法的效率會(huì)很成問(wèn)題。我們都知道ArrayList適宜于隨機(jī)訪問(wèn),而LinkedList方便插入添加移除,在這個(gè)doSomething方法中,顯然隨機(jī)訪問(wèn)的訴求大于添加移除。在通常情況下,這樣寫都不會(huì)成為問(wèn)題,但是如果這個(gè)doSomething方法被經(jīng)常調(diào)用,并且list是一個(gè)LinkedList的情況下,這個(gè)方法就很可能成為性能瓶頸。我們寄希望于List這個(gè)接口可以讓我們無(wú)需關(guān)心list的具體實(shí)現(xiàn),然而現(xiàn)實(shí)是你仍然需要知道各種實(shí)現(xiàn)的區(qū)別和原理,這就是所謂漏洞抽象。這并非抽象的無(wú)力,你肯定不會(huì)反對(duì)“針對(duì)接口編程”這條原則,而是抽象本身解決不了本質(zhì)復(fù)雜性,這里的本質(zhì)復(fù)雜性就是鏈表的實(shí)現(xiàn)方法,隨機(jī)訪問(wèn)與添加移除的平衡問(wèn)題。在我們無(wú)法找到更好的鏈表實(shí)現(xiàn)方法來(lái)平衡隨機(jī)訪問(wèn)與添加移除之前,這個(gè)本質(zhì)復(fù)雜性就不是抽象能夠解決的。
同樣的現(xiàn)象出現(xiàn)在String、StringBuffer、StringBuilder的使用上,字符串的實(shí)現(xiàn)方法你仍然需要知道,這是繞不過(guò)去的本質(zhì)復(fù)雜性。這里談到的本質(zhì)復(fù)雜性根本上也是現(xiàn)實(shí)世界的本質(zhì)復(fù)雜性的反映,扯遠(yuǎn)些就更虛了。就現(xiàn)實(shí)的工作情況來(lái)看,不知道其他人有沒(méi)有這樣的經(jīng)驗(yàn),就是在自以為解決某個(gè)難題的時(shí)候,最后卻發(fā)現(xiàn)難題以另一個(gè)面目出現(xiàn),問(wèn)題本身沒(méi)有得到解決,只是以更好的方式被掩蓋了。
無(wú)論是過(guò)程式、OO、函數(shù)式編程,解決的問(wèn)題都是為了更好的抽象,抽象是個(gè)好東西,但是抽象無(wú)法解決那些本質(zhì)性的問(wèn)題,因此《人月神話》斷言沒(méi)有銀彈,我們?nèi)匀恍枰侨俗鲬?zhàn)。