1. 程式人生 > >關於軟體複用的思考

關於軟體複用的思考

由於最近接手了一個有關於ActiveX的產品的維護工作,使得我有機會重拾已丟下一年多的COM技術,同時也有機會重新審視技術的變遷歷程,以及蘊含在其中的某些思想,這種感覺就好像回過頭來看自己走過的道路。所不同的是,回首自己的人生路,成敗得失一幕瞭然;而技術的發展雖然依然遵循優勝劣汰的法則,但優劣之間的界限好像並不那麼明顯,反而有些使人迷茫。比如說複用。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

軟體複用一直被視為改善軟體工程的重要手段,人們期望通過複用以前的程式碼或元件,來提高生產率,改善產品的質量。軟體複用一般又分為原始碼級複用和二進位制級複用。對於原始碼級複用,現在已經發展出很多重要的設計正規化(

paradigm)從各個不同的方面提供支援。比如OO通過對資料與處理資料的函式進行封裝來達到class的複用,而GP通過分離資料結構以及處理這些結構的方法與資料的型別之間的聯絡,來使資料結構和方法得到複用。對於二進位制級的複用,目前也有非常成熟的元件模型,比如COMCORBA等。而且,現在也有了一些非常優秀的指導軟體複用的理論,如Design Patterns等。以上這些都說明,軟體複用勿庸置疑是軟體設計中一種非常重要的思想,我們每個人在寫程式碼的時候都應當充分考慮我們的程式碼的複用性,這一直是我遵循的信條之一。但是,現在我有些迷茫了。

還是先說說我最近接手的工作吧。我接手維護的產品是一組寫於數年前的

ActiveX controls(程式碼中最早的註釋可以追溯到公元1997年,看到這行註釋時,我首先想到的竟然是那首叫做“我的1997”的歌曲),由於年代久遠,除了產品的使用手冊之外,沒有任何關於程式碼的文件,我只能靠原始碼和其中零零碎碎的註釋來揣摩前輩們的意圖。我得承認,這些程式碼中雖然夾雜了許多不同的人由於各種原因而做的修改,但程式碼的整體結構還是很好的。

為了從最大程度上滿足複用的要求,這些前輩們從ATL2.1上發展出一套自己的ActiveX control庫(暫且叫做BLib吧),來負責處理control的屬性、介面、事件以及訊息等,這套庫簡化了ATL視窗程式設計的複雜程度,修正了當時存在於

ATL2.1中的某些錯誤,這個庫在當時應該很好用(我只是猜測,因為其中的大部分程式碼我還沒看懂L)。基於BLib庫的產品的邏輯與UI是分開的,大部分的邏輯錯誤並不需要改動庫程式碼。

然而,BLib庫現在維護起來卻好像並不輕鬆(也可能是我的水平有限)。在我看來,現在它具有幾個明顯的不足:

1、由於是基於早期的ATL2.1發展而來,而目前流行的程式設計環境(VC6或者VC.NET)都已經不再支援ATL2.1了,因此BLib庫不得不自己帶上ATL2.1的原始碼,這看起來有些落伍。同時使得基於這個庫的所有產品都無法輕易地遷移到更高版本的ATL上,因此無法直接從ATL的升級中受益。(即使現在已經是ATL7.0了,我還不得不想辦法去搞ATL2.1的幫助文件。)

2、由於要儘量支援複用,BLib庫幾乎對每個ATL中比較重要的部分都做了擴充套件。由於缺乏相應的文件,這使得閱讀、維護這些程式碼成為了一件比較艱難的事情,很多時候那些擴充套件程式碼看起來與ATL中的程式碼只有一些細微的差別,使人很難理解。

3、事實上,BLib庫也並沒有被真正的複用過。這個庫建立的初衷也許就是為了以後的產品都基於這個庫構建吧。但在這組ActiveX control產品建立的過程中,微軟在98年推出了ATL3.0,這一下子使得這個庫顯得有些落伍。而發展出這個庫的前輩們或者離開了公司,或者加入了別的專案,沒有人來進行遷移工作。天長日久下來,後面的專案就都沒有使用BLib庫了。

在閱讀和維護這些程式碼的過程中,我不由的總在想,Joshua Kerievsky說,在設計初期過多的考慮設計模式會引起過度設計。那麼,在設計時過多的考慮複用性會不會引起過度設計呢?或者說,我碰到的這種情況算不算是一種過度設計呢?在我看來,如果不是過多的考慮了複用性,對於這樣一組ActiveX control,完全沒有必要發展一套庫來完成,只需要使用ATL本身就能夠完成了。這樣,向更高版本的ATL遷移就不會成為一個問題。BLib庫的維護成本是很高的(我的個人感受),如果是基於它做了很多產品,那麼花些成本去維護是有意義的。然而只是一套產品,這個代價未免顯得有些太高了。

因此,我有些迷惑了。程式碼的複用一直以來被我個人認為是設計編碼過程中應當著重考慮的一個方面。因此,這些前輩們在開發產品的過程中基於複用的考慮發展一套庫出來也是相當合理的做法,換作是我,我也會選擇寫一個庫作為後續產品的基石的(也許會心有餘而力不足L)。但是,發展一個庫出來必然增加程式碼的維護難度,更何況這個庫還是基於另外一個經常升級的庫。從一個維護者的角度來看,我卻寧願程式碼少一些複用性,而多一些易維護性。畢竟我更關心如何快速理解程式中的邏輯,找出錯誤所在。這是一對矛盾,To be or not to be,我們該如何取捨呢?我們無法確知明天會怎樣,我們今天寫的程式碼,明天是否會被用在其他的地方。那麼我們該如何確定複用對於我們程式碼的重要性呢?Refactoring to Patterns可以減少由Design Patterns引起的過度設計,那麼有沒有Refactoring to Reusable之類的方法,來減少由複用引起的過度設計呢?

上面記錄的是我近期的一些迷思,歡迎討論和拍磚J