熟悉RAD開發工具的同學都知道,看“前人”“遺留”下來的程序是一種痛苦。改這些程序更是一種痛苦。而改程序的過程中,被測出來一些“史前錯誤”是痛苦中的痛苦。扣錢事小,一口氣咽不下,被委屈的滋味不好受。因此,同學們在改程序的時候小心翼翼,全局變量絕對不能動,明明看到原來的一個函數改一下就能滿足要求,但還是自己再寫一個比較保險。誰知道改過的地方會不會造成定時炸彈呢?
於是乎,程序越來越復雜,越來越臃腫。開發組長有對策,每個組員專門負責某幾個模塊,時間長了,自己知根知底,就敢於對自己程序開刀。但人員調動,員工去留是不可避免的事情,一個人負責固定幾個程序難以長久。拋開這些不談,假設某同學在公司就是負責有限的幾個模塊維護,那他有何發展可言呢?
所以,歸根到底,我們要使得程序容易被理解,容易被修改,容易被擴充,才是最終目的。萬事開頭難,先從自己做起。
首先來看一下,別人的程序,到底是什麼妨礙了自己閱讀和修改?
1、全局變量。
全局變量是個討厭的東西。 假設我們現在看到這裡有一句:
mbDisplayInPrice: Boolean; //是否顯示進價
按道理說,風格挺好的,有注釋,有前綴,名字也起的好。但是這個變量它沒有一個“主人”,如果說,它是單據類的屬性: TReceiptInfo.DisplayInPrice,我們能夠理解,如果說它是系統參數類的屬性:TSysParams.DisplayInPrice,我們也好理解,但是現在它是屬於整個程序的,所以我們其實並不知道它確切的作用范圍。
所以,全局變量帶來的問題是它不具備確切的含義而經常被誤解,它不屬於某個對象而在整個程序被隨處可能被修改。
2、程序代碼分布在不同區域。
假設我們現在要檢查程序的修改訂單這樣一個功能的程序代碼。按照我們通常的理解,這是一個很單一的功能,應該這樣實現:
檢查用戶權限
↓
效驗用戶輸入
↓
將用戶輸入作為SQL 的輸入參數
↓
調用SQL
↓
檢查SQL 運行結果
這些程序,如果比較短的話,應該是一個過程完成。如果比較長,就應該分為幾個過程完成,但是由同一個函數來調用,這樣都能夠使我們看得清楚明白。
但是在我們程序裡面,檢查用戶權限是在控件裡面實現的,效驗用戶輸入可能放在Query.BeforePost裡面檢查,SQL 是寫在窗體文件裡面的(天知道哪段程序會對SQL進行過處理,比如加上采購組權限什麼的),ApplyUpdate 是在Query.AfterPost 事件裡面完成的,對某些字段賦初值可能在Query.AfterInsert事件,也可能在 Query.OnNewRecord事件,甚至可能在數據庫觸發器做。
換句話說,我們檢查這一段程序,要到各種不同的地方去看,去改,真是痛苦啊。當然,如果我們有一個叫 UpdateOrder 的函數來統一調用這些過程,那麼多少能幫助理解,但是且慢,這裡面牽涉到事件,事件是控件來調用的,Query1AfterPost就是Query1AfterPost,它不是叫 CommitQuery1 的私有方法,所以它裡面很可能包含了其它的程序代碼(除了ApplyUpdate和CommitUpdate),你改動了它,就可能埋下了定時炸彈。
3、事件陷阱
現在的詳細設計文檔裡面已經基本上見不到流程圖了。因為流程圖無從畫起。事件驅動、界面驅動的RAD方法顛覆了我們的編程方法。
記得在寫DOS程序的時候,程序流程是很簡單的,因為就是一條線嘛,最多有個循環、有個條件轉向語句,因此程序清晰易懂,代碼優化也容易。
然後就是講用戶交互了,也好辦啊,程序跑到中間,需要用戶確認的地方,就在屏幕顯示提示信息,讓用戶按y 或者n,接著往下跑,其實也就是條件轉向語句。
到了Windows時代、RAD時代,情況就完全不同了。假設我們按照DOS程序的思路來設計修改訂單的流程。
用戶按下修改訂單按鈕
↓
提示用戶輸入訂單號
↓
彈出訂單明細表,讓用戶選擇
↓
用戶選中某個明細,系統顯示數量和價格的修改框,用戶修改
↓
彈出訂單明細表,讓用戶選擇(重復)
↓
用戶選擇結束作業
↓
程序提交修改
但是實際上呢,這個流程是沒辦法構造出來的。訂單一開始就在那裡了,不是你按下了修改才出現。查詢條件輸入框也是一直在那裡,不是你選擇了查詢才出現。你可以隨意在DBGrid裡面移動記錄,盡管接下來並不做什麼。你可以輸入查詢條件,然後刪除某個訂單,盡管這兩個動作沒有什麼相關。
通常我們在Qty和Price字段的Onchange事件裡面改寫Amount 的值,現在我們知道,這是造成代碼不清晰的原因之一。因為這個過程的調用,是應該在用戶修改了明細之後進行的,但我們為什麼不放在這裡呢?噢,因為這和Query控件的使用規范不太相稱,對於Query控件來說,在OnChange事件改變其它字段的值是推薦的寫法。看看,我們的程序解決特殊問題,Query 控件解決常規問題。Query 的事件定義不會影響它本身的代碼規范性,但是影響了我們程序的代碼規范性。
(待續)