Joshua Bloch:訪談關於設計

Joshua Bloch: A conversation about design

與『有效的Java(Effective Java)』一書的作者討論有關API設計、再使用及Java環境的信賴度

Effective Java's author discusses API design, reuse, and trust in Java environments

作者:Bill Venners

"Joshua Block: A conversation about design," by Bill Venners was originally published by JavaWorld (www.javaworld.com), copyright IDG,
January 2002. Translated and reprinted with permission.
http://www.javaworld.com/javaworld/jw-01-2002/jw-0104-bloch.html


『Joshua Bloch:訪談關於設計』由Bill Venners撰稿,原文刊載於JavaWord(www.javaworld.com),版權屬於IDG。
授權翻譯及刊登。
原文位址:http://www.javaworld.com/javaworld/jw-01-2002/jw-0104-bloch.html

翻譯:Areca Chen

摘要

Bill Venners最近訪問位於Santa Clara, Calif.的昇陽(Sun Microsystems)學院的Joshua Bloch(下暱稱Josh),Josh是昇陽Java核心平台群組的建構師(Architect)。在訪談中,Josh說明對於API設計、XP、程式碼品質及再使用、重整(refactoring)、 保護複製(defensive copies)及客戶程式設計師應該被信任的範圍等等有獨到的見解。

在過去幾年間昇陽的建構師Joshua Bloch主要的設計是增強Java API及語言,尤其是Java聚集(Collections)API及java.math包裹。目前他大多領導一個專家委員會,這個委員會定義Java的主張(assert)及效能(preferences facilities)。在他2001年出版的『有效的Java程式語言指引(Effective Java Programming Language Guide)』一書中,Josh粹取出57條有關設計及實作Java程式的指導方針。JavaWorldBill Venners 於本文中與Josh討論許多關於在Java的API上設計的許多觀點。

 

 

為什麼要在API上設計?(Why do API design? )

 

Bill Venners:在您『有效的Java程式語言指引(Effective Java Programming Language Guide)』這書中的序言您提到您比較喜歡以API的方式來設計。我也是這麼做。如果我是管理一個大型的軟體專案,我將會把專案分解(decompose)成次系統並讓其他人為這些次系統設計介面--這些介面就是APIs。

我考慮的問題是;一個API設計的方式如何對照一般的XP方式,及在軟體專案中以API設計作為基準(norm)應該有的範圍為何?
 

Joshua Bloch: 在我的經驗中,有太多龐大的軟體建構。有人說他要設計一個記錄導向檔案系統(record-oriented file system),而且他去確實做了。他開始設計記錄導向檔案系統並且看看會他會被引導到何處,而非依循您所說的分割的方式。分割成次系統是很重要的,但讓每一個次系統成為良好的設計也是很重要的,也就是說次系統必須是獨立的抽象(freestanding abstraction)。這是我最想鼓吹的。

避免把次系統轉化成一個合理(reasonable)元件是比較容易的。尤其是,在你為最初的高階客戶端的使用撰寫低階次系統時;及當你讓關於客戶端的設想(assumption)潛藏於下面(creep downwards),很容易得讓相互關連(reverse dependence)藏入(creep in)。而當程式設計師不是很有經驗的時候,那就不只是設想。你讓變數名稱潛藏於下面,同時你讓最初客戶端的特定的成品藏入宣稱是低階可再使用的元件。當你完成,你並沒有得到可再使用的元件,你只是擁有巨大系統的一小塊。

你想要讓耦合性降低以便次系統可以在原來的背景外面再使用。同時有各種的理由如此做,自我的書中有詳細的說明。你寫一些東西給別人使用,然後發現主要那是可以在其他地方適用。但除非這個次系統是良好的設計否則無法達成,也就是獨立的抽象。

 

 

再使用有多重要?(Reuse: How important is it? )

 

Venners:有一個早期關於物件導向的口號說物件導向促使再使用。但我認為人們發現實務上他們並不常再使用。每一個人所需的東西都與現有的有些不同,因此他們便重頭寫一個新的。或許可能東西並不是以再使用的觀點來設計,但是人們仍然被管理構建軟體。您認為再使用的重要性到甚麼程度?

 

Bloch: 再使用是極端的重要但很難達成。你無法輕易獲得,但那是可達成的。我在昇陽做的專案--Java聚集框架(Java Collections Framework)、Java.math等等--都是可再使用的元件。我想被許多不同的客戶所使用已是相當成功的。

在我最近的工作中構建系統,我發現我寫的75%的程式碼在其他的系統中可重複使用。要達到再使用的水準,我必須針對再使用的目的做設計。我必須耗費大部分的時間分解事物使之成為乾淨的;即獨立的抽象,獨立的除蟲,撰寫單元測試等等事情。

許多開發者並未經過這個步驟。當你被詢問到API設計如何對照XP時你接觸到這個問題,而當你是構建系統的管理者會如何做。XP建議你撰寫可以解決你的問題的最簡單的程式碼。這是一個好的建議,但容易被誤解。

XP的倡議者並未提倡盡你可能的快撰寫某些東西僅僅可以達成目的的程式碼。他們並未建議你忘掉任何設計。他們確實提議省略你不需要的特殊部分及功能並且在隨後真正需要的時候再加入。而且那是極為重要的,因為你可以隨時加入一個功能,但你可以從來不將它取出(take it out)。一旦一個功能存在,你不能說「很抱歉,我們鎖定(screwed up),我們要將它取出因為其他的程式碼現在依賴他。」別人會抗議。因此當懷疑時省略它吧。

XP也強調重整(refactoring)。在重整過程當中,你耗費多數時間在清理元件及APIs,把東西切割成更好的模組。這樣做是很重要的,同時保持你的腳步輕巧--不要隨意凍結APIs。但如果你一開始非常小心設計模組間的邊界你將會有比較輕鬆。

 

Venners: 為什麼?

 

Bloch: 因為大量的重整被證明是困難的,如果你在一個龐大的系統中構建一些東西你會發現到處都是重複的程式碼,而你理所當然的想要做重整,你將會有繁重的工作。相對的,如果你把他寫成元件,但你讓元件的某些邊界有些小錯誤,你可以很容易的修改過來。

我想XP與我所支持以API為基礎的設計程序之間的差距並不如所顯示的那麼大。當你討論到某人像Kent Beck[ Extreme Programming Explained的作者 (Addison-Wesley Pub Co, 1999; ISBN: 0201616416)],我想你會發現他與我所做的有許多相同的本質。

回到你第一個問題,如果你是管理者,你應該在他們跳進去並開始撰寫程式碼之前給你的團隊一個建立好設計的迴旋空間(latitude)。同時,你應該讓他們設計世上所有的特殊功能;你應該確保他們設計將執行這個工作的最小系統。

 

Venners: 因此聽起來XP似乎建議你做可以工作的最簡單的功能組。但不要做最快可以工作的而你可能把他丟掉的東西

 

Bloch: 正確。事實上,人們嘗試「做最快速的而你可能把他扔掉的東西」往往花很長的時間生產一個工作系統而不是小心的設計元件。但確實,如果你考慮整個時間的成本API設計有所幫助。如果你扔下某些東西,而,但願沒有發生這樣的事,這些東西變成永續存在好幾年的公開API,你真的是值得喝一杯。這類APIs長期變成一個巨大的負擔,並導致客戶的不滿意。

 

 

提升程式碼品質(Improve code quality)

 

Venners:你也在你的書中宣稱以APIs思考有助於提升程式碼品質。你可以說明為何如此想。

 

Bloch: 我在此廣泛的討論程式設計。如果你抓住合理大小的問題撰寫高品質的程式碼是相當容易的。如果你把系統適當的分解成元件,你將可以一次集中注意力在一件事情上,同時你將做一個較好的工作。因此廣泛的做好的程式設計(programming in the large)導致在小地方好的程式設計(programming in the small)。

更甚者,模組化分解象徵軟體品質的關鍵元素。如果你有一個緊密耦合的系統,當你修改一個元件,會導致整個系統分解。如果你以API思考,模組間的邊界非常清楚,因此你可以維護並改善一個模組而不會影響其他部分。

 

Venners: 你可以說明『廣泛的程式設計』及『在小地方的程式設計』的意義嗎。

 

Bloch: 『廣泛的程式設計』我的意思是抓住一個大問題--問題太大以致無法坐下來並以一個獨立的小問題來解決;問題太大必須切割成次問題(subproblems)。『廣泛的程式設計』含有從大問題延伸的複雜議題。相對的,『在小地方的程式設計』是問:我如何以最好的方式排序浮點數的陣列。

 

 

API設計及重整(API design and refactoring )

 

Venners: 我們把焦點鎖定在重整程序中API設計對你有甚麼幫助?我相信我聽過你說開發者無須那麼多的重整。

 

Bloch: 那是它的一部份。此外,重整往往是事後的API設計。你看著程式碼說「這裡有幾乎相同的程式碼,這裡,還有這裡。我可以把它拆成一個模組。」然後你小心的設計那個模組的API。因此不管你是在重整的時候或在前置期做這個工作,都是相同的程序。

事實上,你都是在兩者中做一些。撰寫程式是一種反覆的程序。你試著在前置期盡可能的做好,但是除非當你使用它時你無法真正知道你的API是否是正確的。沒有人是在第一次就做正確的,既使他們有多年的經驗。

Doug Lea [Concurrent Programming in Java的作者 (Addison-Wesley Pub Co, 1999; ISBN: 0201310090)] 與常常我討論有關這個議題。我們共同撰寫一些材料,而當我們嘗試的去使用它,往往都不是很成功。回顧過去,很明顯的我們對於API設計有一些誤解。這是否意味著我與Doug都是愚笨的?不是的。正確的預測一個API的需求是不可能的,除非你已嘗試過它。這是為什麼在任何時候你撰寫一個介面或抽象類別,最關鍵的是在交付成為API之前盡可能的多做一些具體的實作。在成為事實以後很難甚至不可能改變的,因此你最好事前就要確認它是好的。

 

 

信任與防禦(Trust versus being defensive )

 

Venners: 現在我想要討論有關信任的問題。 對於客戶程式設計師能夠做正確的事我可以信任到甚麼程度?你在你的書中寫到保護傳到方法及從方法傳回的物件副本。複製的保護是不信任客戶的一個例子。 難道複製的保護沒有一種在強固(robustness)相對執行效率(performance)兩者間的選擇?更切確的說,如果你有相當大的物件,隨時保護複製可能會是昂貴的嗎?

 

Bloch: 很明顯的是有一個選擇。從另一方面而言,我不相信太早攻擊執行效率的問題。如果那不是一個問題,為什麼還要擔心攻擊的問題?而且相關這個問題還有其它的途徑。其中之一;當然;是永遠不變的(immutability)。如果某些東西無法被修改的,那麼你無須複製它。

事實上如果你是在一個安全的環境當中操作(在這個環境中你知道並信任你的客戶端不會做錯事)你比較喜歡的選擇可能是執行效率多於強固並且不要複製一些東西。你確實將發現在多數以C為基礎的程式充滿註釋:「這個方法的客戶端在物件被呼叫後不要修改這個物件是非常重要的」。廢話,這些都是廢話。是的,你可以成功的以這種方式撰寫程式碼,任何人以C或C++撰寫程式已是如此做。從另一方面而言,那是更困難的因為你忘記你不能修改它,或你已另取別名了。你不修改它,但是你已傳遞一個到相同物件的參考到其它的物件而這個其他的物件並不瞭解他不該修改那個物件。

所有的事都是相等的,如果你實際上保護複製或使用永遠不變的機制(immutability)而不是依賴程式設計師撰寫正確的東西;撰寫正確的程式碼是容易的。因此;除非你知道你有一個執行效率需要允許這種錯誤的發生,我想最好簡化而不要允許讓他發生。撰寫程式碼,然後看看程式是否執行的夠快。若否,然後決定是否你要小心的放寬這項限制。

一般的說法,你不應該允許一個不良行為的客戶端摧毀伺服器。你想要把失敗的模組與其他的隔離,以便在一個模組中的失敗不會影響到其他的模組。那是防禦有意的錯誤,比如駭客。而在更普遍的情況;那是防禦草率的程式設計師或爛文件,其中有些模式的使用者不瞭解其責任即是否修改一些資料物件。

 

 

保護複製及合約(Defensive copying and the contract )

 

Venners: 如果我保護一個傳進物件的複製,亦即,一個建構式,我應該註釋保護複製做為合約的一部份嗎?如果我沒有註解,我可以擁有彈性在後面宜除保護複製以提供執行效率。但如果我沒有註釋,客戶程式設計師無法確認建構式將執行一個複製保護。因此他們自己可以在傳遞物件到我的建構式之前執行一個複製保護,此時我們將有兩個保護複製。

 

Bloch: 如果你沒有註解,客戶是否可以允許修改參數?很顯然的,如果你有一個偏執的客戶,他不會修改參數因為那將有損你的模組。實務上,程式設計師不是那麼偏執--他們會修改。所有的事都是相同的,如果文件沒有說你不許這麼做,程式設計師將這麼做。因此,你要簽署(signing on)保護複製不管你是否註解它。而你也可以同時註解因為既使是偏執的客戶也會知道,是的,他有權力以輸入參數做任何他想要做的事。

理想上,你應該註解你執行了一個保護複製。不管如何,如果你回顧我的程式碼,你將飛現我沒有。我防護草率的客戶,但我在文件上並沒有明確的說明。

在撰寫廣泛分散式的原始碼有一個問題就是人們可以回頭看你的程式碼然後說:「啊!但你在此沒有做」。一般的說法,我的回應是:「喔,我學到一些東西因為我寫這些;現在我知道我必須做它。」此時,問題時你在你的文件中有多小心?我可能沒有十分小心,而且的確我想小心一點是值得的。

 

 

信賴合約(Trust contracts )

 

Venners: 我應該信任傳遞的物件正確實作其合約嗎?目前我必須建立一個Set實作其中有一個一系列一致格式介於不同的虛擬機制。我寫了一個類別稱之為ConsistentSet作為你的完善的AbstractSet的次類別,同時我有一個建構式使用Set。在這個建構式中我只是想要從傳遞的Set中複製元素到一個陣列當中以形成新的ConsistentSet的狀態。我把元素放到陣列中以便任何時候ConsistentSet在任何虛擬機制當中是系列的(serialized),這些元素將以相同的順序排列。

因此我撰寫程式碼從傳遞的Set中拉出元素並且複製到陣列中,我懷疑我是否應該信任此傳遞的Set沒有重複?因為如果我做了,我是依賴其他人正確的實作其合約。而如果傳遞的Set因包含重複的元素而違反其合約,這會破壞我的類別。我同時是一個Set及假設不包含重複,因此我可能應該有保護的撰寫程式並且在複製其元素到我的陣列之前檢查傳遞的Set是否有重複的元素。從另一方面而言,難道物件導向程式設計的基礎概念;你區分不同的物件不同的責任,並且讓每一個物件扮演其角色猶如承諾其合約?

 

Bloch: 我想你沒有選擇只能信賴物件實作他們的合約。一旦人們開始違反其合約,整個世界將分崩離散。舉一個簡單的例子:相等(equal)的物件必須有相等的雜湊碼(hash codes)。如果為其建立的型別不是如此,雜湊表(hash tables)及雜湊組(hash set)將無法正確執行。

更一般的狀況,當物件不在遵守其合約,相關的物件將開始分崩離析--他們只有這一條路。我可以瞭解為什麼他們讓你如此不安,但,是的,你必須信賴物件確實實作他們的合約。如果你感到不安,你可以從訊息社區(intelligence community)獲得一個建議並且「信任但持續確認」。最佳去做的方式就是主張(assertions),因為當你對他們不滿時你並未付給他們甚麼。應用主張測試其他的物件是否遵守其合約,同時,如果你的程式開始變得怪怪的,提出主張而你將發現誰該負責。

 

關於作者

About the author

Bill Venners是有14年經驗的專業程式設計師。主要是在矽谷,他提供軟體顧問並在Artima Software提供訓練服務。他是Inside the Java 2 Virtual Machine (McGraw-Hill Professional Publishing, 1999; ISBN: 0071350934 )的作者必建立Artima.com,其中提供Java的資源及Jini的開發者。



 

資源

 

本文獲授權同意翻譯函:

Hi Areca,

Thank you for your interest in Bill's article. You have our permission to
translate and republish the interview on your Website. Please include the
following in the attribution:

"Joshua Block: A conversation about design," by Bill Venners was originally
published by JavaWorld (www.javaworld.com), copyright IDG,
January 2002. Translated and reprinted with permission.
http://www.javaworld.com/javaworld/jw-01-2002/jw-0104-bloch.html

Best regards,
Carolyn

Carolyn Wong
Editor in Chief, JavaWorld
Phone: 415.267.4518
Fax: 415.267.4558
carolyn_wong@javaworld.com

                                                                                                                  
arecagiga@giga.net.tw To:     jweditors@javaworld.com                                           
cc:02/07/2002 10:14

Subject: Feedback: General comments                                        
                      PM                                                                                                  
(Feedback: General comments)
URL Site www.javaworld.com  User agent=Mozilla/4.0
Name Areca Chen  E-mail arecagiga@giga.net.tw

Dear Bill,
I've read the articles " Joshua Bloch: A conversation about design "on the
web site and like it very much.
It will be great if I could translate it into traditional Chinese and
publish on our own site http://www.dotspace.idv.tw) to help those who want
to explore about design. I will, of course, declare the source and
"hyperlink" those to your original documents. I'll be very grateful if you
could give your authorization for me to do this.
Our web site contents about software engineering topics like XP, UML, Rup,
Design Patterns, Framework, those are all in traditional Chinese.
        Regards,
Areca Chen
2002/2/8Author: Bill Venners
ArticleUrl:
http://www.javaworld.com/javaworld/jw-01-2002/jw-0104-bloch_p.html
 PubPerm: No