導讀:Oracle數據庫並不是沒有約束的,Oracle數據庫也是要遵守一定的規則,大家都知道,我們很少有人是孤立工作的;大多數PL/SQL開發工作是在相對較大的機構中進行的。但我們基本上還是在自己的小隔間裡用自己的設備獨自工作。幾乎沒有PL/SQL開發小組進行正規的代碼復查或系統測試。
1. 嚴格遵循命名約定,好像它們就是你的生命支柱。
2. 戒除編寫SQL的嗜好:編寫的SQL越少越好。
3. 使執行部分短小:告別"意大利面條式的代碼"。
4. 找一位伙伴:非常贊同找個人來監督你的工作。
1. 遵循命名約定
如果你建立並嚴格遵循一套命名約定,特別是對於應用程序組件的,你就可以節省很多時間。
當然,遵循命名約定的想法並沒有什麼新意,你可能已經聽煩了。所以我並不提出什麼宏偉的命名計劃,而是給出一些非常具體而明確的約定,然後證明這些約定會多麼有用。
前幾個月我一直在為PL/SQL開發人員設計、構建一種新工具。它名為Swyg(可以在www.swyg.com中找到),可以幫助程序員完成代碼的生成、測試及重用的工作。它具有幾個獨特的組件。我為每個組件指定了一個由兩個字母組成的縮寫名稱,如下所示:
SF-Swyg的基礎部件
SM-Swyg的元數據
SG-Swyg的生成程序
SL-Swyg的代碼庫
ST-Swyg的單元測試
於是,我便遵循表1中的命名約定,同時使用這些縮寫。遵循這些約定有什麼好處呢?一般來講,如果我要求一致的命名規則,我就可以更流暢更高效地編寫代碼。
明確地說,這些約定具有可預測性,意思是說我編寫的SQL程序能生成有用的腳本。例如,通過使用表1中的約定,可以生成Swyg中所有基礎包的安裝腳本。執行這些工作的SQL*Plus腳本如清單1所示。這類腳本非常有用,因為它意味著我不必手動維護安裝腳本。當我向Swyg方案中增加另一個表,並生成一組相關包時,我只要運行我的腳本,更新後的安裝腳本便會跳出來。
2. 戒除編寫SQL的嗜好
編寫的SQL越少越好,這似乎與我們的直覺不太一致。對於PL/SQL開發人員來說,這是一個奇特的建議,因為PL/SQL的主要優點之一就是可以毫不費力地在代碼中編寫SQL語句。不過,這種簡易性也是這種語言的一個致命的弱點。
可以將純粹的SQL語句直接置於PL/SQL代碼中,而無需JDBC或ODBC之類的中間層。因此,無論何時何地,PL/SQL開發人員只要需要SQL語句,他們通常就會向其應用程序代碼中嵌入SQL語句。那麼這樣做有什麼問題嗎?
在PL/SQL代碼中到處使用SQL語句必然會導致以下後果:
盡管實際表現不同,但同一邏輯語句仍會出現重復,從而導致過多的語法分析,且難於優化應用程序的性能。
暴露商務規則和方案。這直接在SQL語句中包含了執行商務規則的邏輯。這些規則總在變化,所以應用程序的維護成本會急劇增加。
當然,你要編寫的每一個PL/SQL應用程序幾乎都是基於基礎表和視圖的。你需要執行SQL語句。問題不在於是否執行,而是何時執行、如何執行。
如果你對數據結構進行封裝,或者將它們隱藏於一個PL/SQL代碼層(通常是一個代碼包)之後,那麼你的應用程序將會更健壯,而且你還會發現創建和維護變得更易多了。
我們來看一個簡單的例子。 假定我需要編寫一個處理某員工工作的程序。第一件事是獲取該員工的全名,定義為"姓名逗號(,)姓";然後我可以進行詳細分析。清單2給出了這種情況下我很可能要編寫的這類代碼的一個示例。
一切似乎都是這麼簡單和直接;這些代碼可能會有什麼錯誤呢?實際上真是非常糟糕。最主要的是我暴露了一個商務規則:全名的結構。我可能要花費數小時來對此代碼及其所基於的應用程序進行測試。但就在它剛剛投入使用時,我才知道客戶會不斷地打電話告訴我,實際上,他們的全名應該表示為"名空格姓"。
現在怎麼辦?搜索所有位於引號內的單個逗號?
現實的解決方案是使用隱藏所有細節、只提供一組預定義、預測試及預優化並能完成所有任務的程序包。清單3為基於封裝代碼重新編寫的process_employee過程。hr_employee_tp包提供了用於定義保存姓名的局部變量的類型;hr_employee_rp包含有基於一種商務規則而返回全名的函數。
將顯示PL/SQL語句灌入SQL代碼很容易,同樣,談論封裝這些語句是如何重要也不費勁。但另一方面,編寫執行封裝任務的代碼卻具有挑戰性;甚至是不現實的。生成這些包或許更有意義。
幾年前,我曾幫助構建這樣一個生成程序。該程序段為PL/Generator,現在由Quest Software公司擁有,PL/SQL開發社區可以免費使用。你可以從我的網站www.StevenFeuerstein.com/puter/gencentral.htm下載。要知道,其封裝體系結構與我在前面所概括的約定不同。PL/Generator創建了一個單獨的包,它包含了一個表的類型、查詢和變化邏輯的全部內容。
當你不再編寫太多的SQL,而是調用執行SQL的程序時,無論你是生成還是編寫自己的定制封裝,你的應用程序都會受益匪淺。
3. 使執行部分短小
面對現實吧:總是與我們的判斷和最新的一系列新年決議相左,我們必須停止編寫意大利面條式的代碼:龐大而冗長,人們實際上不可能理解它們,更不用說維護或升級了。怎樣才能避免"意大利面條"呢?
實際上,答案很簡單:決不允許執行部分超過50或60行。這種大小使你能在一頁紙或一個屏幕上查看該代碼塊的整個邏輯結構,這也意味著你可以真實地領會該程序的意圖,而且完全憑直覺就能理解它。
你可能非常同意上述觀點,但同時又嘲笑我的建議:程序代碼永遠不超過50行。沒錯,你應當嘲笑,因為這當然是不可能的。毫無疑問,你需要超過50行的可執行代碼;問題是你把這些代碼放在哪,以及你怎樣加以組織。
如果采取以下做法,你的確能夠應對各種復雜的要求,並把代碼限制在50行以內:
將所有的商務規則和離散邏輯塊置於其自已的程序(通常是函數)中,從而在任何可能的時候慎重地重用代碼。
盡量使用在程序的聲明部分定義的局部模塊、過程和函數。
假定我在編制一個呼叫中心應用程序。我需要編寫一個程序,它要滿足下面的要求:
"對於特定部門的每個員工,將其工作量(分派給該員工的呼叫次數)同該部門員工的平均工作量進行比較。如果某員工的工作量低於平均工作量,便將下一待處理呼叫分派給此人,並基於這種情況安排約定。"
我從以前的工作中獲悉:我的朋友Claudia已經編寫了一個分析包,它會返回工作量方面的信息。但是分派待處理呼叫和安排約定都是全新的工作,需求文檔的其余部分對此進行了詳細說明。
最初我想把這15頁的內容全都看完,但我沒有那樣做。我使用了一種稱為"逐步求精法"或"由頂向下設計"的技術,並先編寫了清單4中的代碼來實現該程序。
下面給出了清單4中最關鍵代碼行的解釋;由該程序(緊湊的執行部分)的最後開始,向上進行。這似乎有悖於直覺,但這的確是通讀用逐步求精法編寫的程序的最好方式。
第22~30行。用一個游標FOR循環(cursor FOR loop)來對指定部門的所有員工進行迭代處理。在第24~25行,利用分析包中的程序判定當前的員工是否工作量不足。在第27~28行,調用三個程序:assign_next_open_case、schedule_case和next_appointment。我還不知道怎樣實現這些程序,但我知道它們通過其名稱和參數表表達了需要事先完成的工作。
第10~19行。為第27~28行中的三個程序創建"stub",也就是占位程序。注意,它們是局部模塊,在assign_workload中進行定義,且不能從其他任何程序調用。
第5~8行。定義一個游標,以獲得指定部門的所有員工。現在可以設法編譯此代碼。
對這樣一個小程序成功完成編譯好像是個小勝利,也的確如此。完成正確編譯,然後是簡單測試,然後增加一點代碼,再進行正確編譯,以此類推,諸如此類的小勝利締造出構造精良的程序,而且會非常滿意。
我還可以驗證該分析程序是有效的,並且找出了要分派的任務適當雇員。這些工作全部完成後,我將從三個程序中挑出一個,比如assign_next_open_case,進行下一步或下一級別的精細設計。我要閱讀該任務的文檔,並在assign_next_open_case裡編寫一個簡短的執行部分,它可反映該任務的概況。
很快,我的局部過程有了它自己的局部過程和函數,但在該過程的每一步,我的代碼都很短、可讀、易於測試、可根據需要進行調整。
4. 找一位好伙伴
計算機並不會編程,人才會。