在程式開發的世界中,充滿了各種名詞,有些定義清楚,然而也有許多名詞,只是為了簡單描繪提出者想敘述的東西,而被臨時創造出來。

這些名詞通常沒有明確的定義,一開始只是為了溝通方便,而隨著聽聞者各自的領會與轉述,加上時間與歷史的推移,它們的定義會發生岐義而各自發展,最後失去了溝通的意義。

各持己見的名詞之爭

最近網路上有篇MVC是一個巨大誤會引起了許多人的爭論,文章本身的動機在試圖搞清楚,為什麼大家說的MVC都不太一樣?開發者發現正在實作的MVC,為何與某些文件講的MVC不同?因而展開了一場精采的探索之旅。

有幸地,文中也引用了我先前專欄MVC與Model 2的變異與結合作為延伸閱讀,結論是終於搞清楚MVC了,不過,許多網友的回應中卻指出,該文作者在談的MVC好像並不是MVC?

MVC與Model 2的變異與結合中,其實可以看到,MVC這個名詞有著一段歷史發展過程,而在這段過程中,前前後後有人試圖去學習、瞭解MVC,而每個人擷取到的,都是這個歷史發展過程中某個時間對MVC的定義或實作,當兩個開發者用兩個不同時間點的定義或實作嘗試進行溝通時,就會發生隔閡,實際上,這種情況在程式開發的世界中,一直重複不斷地發生著。

舉我先前專欄private繼承之爭來說好了,private成員到底會不會被繼承?在許多討論區中,都曾戰上一回。繼承這名詞,老實說也沒有精確的定義,我試著瞭解每個人的說法,並調查可搜尋到的文件後,發現大家講的其實是兩種不同定義的繼承,也就是「介面繼承」與「實作繼承」,因為沒有去瞭解彼此講的是何種繼承,才會導致兩造各說各話的局面。

如果有人說,函式可以擁有相同的名稱,但參數不同,這個行為是多型,你會予以反駁呢?有人會說這不是多型,而是重載(Overload),如果有人說泛型是一種多型呢?大概不能接受的人也很多。

歷史上,對多型也有不同定義,重載被視為特定(Ad-hoc)多型的一種實現,泛型可被視為一種參數(Parametric)多型的實現,而後者在Haskell是自然且常見的實現,因此都直接稱多型。我先前專欄〈多型的本質〉有三篇文章(請參考:多型的本質(一)多型的本質(二)多型的本質(三)),就討論過這幾個多型,歷史上的多型還不只有這三個,如果硬是要用大家較熟悉的次型態(Subtype)多型,來說重載、泛型不是多型,實在不是使用這些名詞之目的。

某些程度上,在遇到有岐義且引發爭議的名詞時,我還滿愛挖墳考古、探究名詞之起源,因為程式開發界,並不是每個名詞都有精確定義,往往隨著歷史的演變,而有不同的解釋,而我喜歡知道這些解釋是怎麼來的,這樣就可以在有人為某個名詞而爭論時,試著瞭解他在講的可能是歷史上的那種解釋,就算我挖到名詞最初發源的人、事、時、地、物,目的也不在於用這來否定對方的說詞。

舉例來說,同樣是名詞之爭,Java界的Spring框架當初也面臨過,因為它聲稱自己的核心是IoC(Inversion of Control)的實現,在它的文件中指出,這是因為Bean對其相依物件的生成、位置之控制權,反過來被容器(Container)來控制以注入(Inject)的方式實行,不過,有人認為IoC應是指流程的控制權,從開發者手中轉移至框架,而不是指相依物件的控制權被轉移。為此,Martin Fowler建議採用DI(Dependency injection)來取代IoC一詞,以平息對IoC的紛爭。

探索IoC名詞的過程中,我看到Martin Fowler在Inversion of Control Containers and the Dependency Injection patter中有著這樣的說法,最終目的並不是讓我可以指著別人鼻子說:「Spring並不是實現IoC容器,而是DI容器」,而是清楚地知道,當有人說Spring核心是IoC容器,他指的是Bean對相依物件的控制權被轉移這回事,而不是指流程控制權被轉移至框架,我們因此得以繼續用相同觀點溝通,而非摸不清對方在講些什麼。

隨意創造、濫用名詞的世界

程式開發的世界中,名詞的創造經常是隨意的,曾經在Java中爭執不斷的考古題之一是:「Java中有沒有Pass by reference」,就現今來說,大家公認的答案是沒有,Java只有Pass by value,不過還是有人面對Java文件中經常出現reference,而搞不清楚。

說穿了,這個名詞與C++中的reference定義不同,只不過Java最初不知道為什麼,也用了reference一詞,重點也不在搞清楚Pass by value,重點是搞清楚透過參數操作物件時,會有什麼樣的行為。

物件導向的世界更是個名詞王國,實際上物件導向的準確定義與目的也一直存在著不少爭論。

就歷史來看,雛形出現在1960年的Simula語言,它引入了類別的概念,而被視為物件導向語言基礎的Smalltalk,引入了繼承的概念,那麼只有具備類別的語言,才是物件導向嗎?JavaScript也是物件導向語言,即使它沒有類別,但具有物件,也能實現繼承,它不是Class-based OOP,而是Prototype-based OOP。

就我可找到的資料來看,Self也是Prototype-based OOP的語言之一,沿用了Smalltalk中一切都是物件的風格,但取消了類別的概念……想搞清楚這些歷史彼此間的連結,本身就夠混亂了,更別說名詞定義的轉變了。

好吧!確實是有人會在提出一個名詞之前,先為名詞做好定義,Gof(Gang of four)的《Design Pattern》書中,就先為設計模式是什麼而做了定義──一個模式包括了模式名稱(pattern name)、問題(problem)、方案(solution)與結論(consequences)四個部份,不過,有幾個開發者在使用或描述一個模式時,會完整照著這四個部分來思考或溝通?

大多數的情況下,開發者就是對某個模式名詞有個概念,然後試著實作它或拿它來溝通,而常見的溝通不良,像是「這不是XXX模式,你沒有如何如何……」的爭論,就發生了。Gof的書中對模式的第四個部份也說到:「結論是套用模式之後的結果或折衷」因為使用某個模式概念,針對實際處理的問題實作出來的方案,必然會有不同的調整與結果,只是現在常見的是,即使設計模式書中有這四個部分的定義,在發生爭論時,多半也是隨意地取其中一二來各持已見。

放棄令你壁壘分明的名詞

回過頭來看MVC之爭,因為文中延伸閱讀提到了我的專欄文章,看來我的觀點與作者是一致的?不!分清楚MVC與Model2並不是我那篇文章的目的,否則,也不會有「1999年Govind Seshadri在Javaworld發表了Understanding JavaServer Pages Model 2 architecture文章,其影響之一是將Model 2界定為架構模式,第二個影響是確立Model 2為Web應用程式提供了一種MVC架構」這段話,如果我的目的是想分清楚MVC與Model2,那這段話根本就是自打嘴巴!

挖墳考古的目的,不是為了要將找出來的名詞定義奉為圭臬,而是清楚名詞的發展過程,瞭解到彼此溝通時,可能發生了哪些誤會,希望能說出:「我知道你談的XXX是什麼」這樣的話,重點並不在XXX為何,而是因為我探究過這段歷史與這些變異,因而能與對方更好的溝通,而不是吵架。

在《松本行弘的程式設計世界》的〈語彙與共通語言的重要性〉這篇文章中,作者談到,為某個概念決定適當的名詞,目的是在設計時能有共同的語彙,也能讓開發者意識到它們的存在,這才是名詞存在的真正意義。在我看來,如果釐清某些名詞,只是為了壁壘分明,那乾脆就不要這些名詞!

專欄作者

熱門新聞

Advertisement