由于業務的複雜多變,我們編寫完的程式,在後期肯定要被修改,而且修改的人很可能不是自己。這種情況我們都遇到過。
而且,看别人的代碼可能會覺得很痛苦:為什麼他要這樣寫相關邏輯?為什麼變量名稱要這樣定義?換用這種方式不是更好嗎?……等等。原因很簡單:我們沒有一個相關的代碼編寫規範。而你所換用的方式可能對其他人不适合。
我們已經做成功了幾個系統。而後期,我們還會編寫或者維護更多的代碼。這樣,編碼的規範性就顯得很重要了。
下面是我遵循的一些規則,以及Steven的幾個建議,歡迎拍磚。
1. 嚴格遵循命名約定,好像它們就是你的生命支柱。
我們可能有自己的命名方法,也許就是v_aab001, i, count, bj, jjzj之類的。你有沒有發現閱讀别人代碼時的那個費勁?怎麼變量命名方式和我的不一樣呢?如果自己維護自己的代碼,那多省事!
我們需要有一個規範,給别人友善,也給自己友善。下面是我定義變量的規範:
* 表字段相關變量的定義規則:<類型名>_<字段名>_<字段注釋>
類型名:varchar2類型為“v”,number類型為“n”,date類型為“d”……
字段名:表中字段的名稱。例如“aab001”、“aac002”……
字段注釋:該字段的注釋
* 普通變量的定義規則:<類型名>_<注釋>
* 記錄類型的定義規則:record_<記錄注釋>
* 記錄變量的定義規則:rec_<記錄注釋>
* 類型的定義規則:type_<類型注釋>
* 類型變量的定義規則:t_<類型注釋>
具體使用什麼規則的變量定義,需要你的項目組内各個成員的讨論。因為最終确定的變量定義規範,是需要大家主動遵守的,而不是被動的。
2. 格式化你的代碼。
内層代碼要空兩格。空兩格的優點是:當層次發生變化時,我可以使用“TAB”鍵或“SHIFT+TAB”組合鍵将選擇的代碼塊前移兩格或後移兩格,來改變代碼塊的層次。
我們看看下面的代碼格式。不用關心這段代碼究竟實作了什麼,注意看的是它内層與外層的邏輯關系是通過空格來直覺表現的。
3. 編寫規範和健壯的sql。
3.1 規範的sql
我們應該知道“綁定變量”的概念。要實作綁定變量,首要的一點是兩個sql的格式統一。我們看看這樣的sql格式是否必要:關鍵字對齊。
3.2 健壯的sql
而且,要知道每個sql都有可能出錯的。是以我們需要使用異常捕獲語句包裹每個sql,并給出恰當的提示。比如某系統前段時間一直有no_data_found的錯誤,程式抛出的異常就是這個。很簡單,這說明我們的程式中有個select語句查詢結果為空,但并沒有捕獲這個異常,是以直接抛出了no_data_found。這個錯誤是無法定位的。
每個編寫的sql應該是類似這樣的:
Begin
<Sql statement>;
Exception
When <錯誤1> then
<錯誤處理>;
When <錯誤2> then
……
When others then
<其他錯誤的捕獲>
End;
這樣,這個sql就在我們的控制之中了,如果提示資訊足夠準确,很容易定位到出錯的位置。
下面是常用的三個sql異常捕獲:
sql類型 | 相關錯誤 | 異常捕獲 |
insert | 主鍵沖突 | dup_val_on_index |
select | 未查詢到資料 | no_data_found |
查詢到多行 | too_many_rows |
我工作兩年多來,還沒遇到過使用其他異常捕獲的情況。除此以外,還有我們不可預期的錯誤,需要最後使用“others”來捕獲。
關于異常的詳細介紹,以及如何手工抛出指定異常,參考《oracle pl/sql programming》第六章。
4. 使執行部分短小:告别"意大利面條式的代碼"。
以我們的過程“prc_p_bj”為例。其所在的包一直報“pls_00123:程式太大”,其實是因為該過程的“意大利面條式的代碼”。該過程有2000多行,嵌套了若幹次。更不幸的是,pl/sql編譯器并不能識别這麼多的嵌套。
詳細介紹可參考:PLS-00123:程式太大
稍微分析一下,就發現這個過程包括三大部分:A、B、C。這是三個互相獨立的業務,可以分成三個子過程來調用。這樣就省去了一層嵌套。
再分析每個子過程,可以發現每個都包括了五個小部分的分别實作。這又可以拆分成五個子過程。又省去了一層嵌套。
拆分後的代碼架構圖見PLS-00123:程式太大。這樣拆分後,消除了“程式太大”的錯誤。更重要的是,它易于代碼的閱讀、定位和維護。我要修改B部分,隻要看原來1/3的代碼;我要修改B的第三個小部分,隻要看原來1/15的代碼!
當然,這樣直接拆分後的過程還不完美,因為它是緊耦合的。我們可以看看第五個建議。
5. 保持松耦合。
緊耦合與松耦合的概念很容易了解:我要修改一段代碼,而且我知道修改這段代碼帶來的影響隻是某個或某幾個過程,這就是松耦合;反之,我發現了這段代碼中的問題,但卻不能确定修改後影響的是那幾個過程,就很可能就是緊耦合了。
對于背景包,我們要力求做到該包中的過程隻被該包中的某個或某幾個過程來調用,來達到松耦合(公共包除外):
* 能定義為包體的局部過程或局部變量的,就不要在包中定義;
* 能在過程内定義的子過程或變量,就不要定義為包體中的局部過程或局部變量;
* 子過程使用的變量,不要在父過程中定義。
6. 定義明确的注釋及注釋層次。
6.1 明确的注釋
我們寫了一個insert語句,并且添加注釋“向表x中插入資料”。這類注釋可以去掉,因為閱讀代碼的人肯定懂insert語句,通過代碼就知道是“向表x中插入資料”。代碼其實也是注釋的一種。
我們的注釋,要注明該插入的前因後果,注明業務上的關系。比如“儲存該人員基本資訊”就比“向表ac01中插入記錄”要明了得多。
6.2 注釋的層次
代碼之間是有層次的,而注釋就要展現這層關系。這樣,通過閱讀注釋,就知道代碼的結構了。下面是一個小例子:
--0.初始化
<代碼>
--1.計算金額A,B,C
--1.1初始化
--1.2計算金額A
-- 1.2.1計算金額A的步驟1
--1.2.2計算金額A的步驟2
--1.2.3計算金額A的步驟3
--1.3計算金額B
--1.4計算金額C
--2.計算金額D
--3.計算金額E
--4.儲存該人員的XX資訊
--5.結束:設定标志,送出等
7. 找一位夥伴:非常贊同找個人來監督你的工作。
這個建議Steven講的很透徹:
計算機并不會程式設計,人才會。
有多少次你彎着腰、駝着背坐在計算機前,因無法找出代碼中的錯誤而感到非常郁悶?先是幾分鐘過去了,接着又過了幾小時。最後,對自己都厭煩了,感到非常失敗,你把頭伸出你的小隔間并請朋友過來幫你看一看。
通常會有下面三種情況之一出現:
* 當你的朋友從她的椅子上站起來時,一切都在瞬間變得非常清楚。
* 你的朋友瞥了一眼螢幕,馬上就指出了問題所在。
* 你的朋友不負責該系統中你所做的部分,是以你必須說明你的程式在幹什麼。當你逐漸講解邏輯時,引起錯誤的問題所在會突然暴露在你面前。
事實就是自己很難調試自己的代碼,因為你自己對它太投入、太專注了。
這個問題最好的解決辦法是由開發經理創造這樣一種文化:各種想法是共享的、不懂是可以原諒的并不會受到處罰、定期進行建設性的代碼評審。不幸的是,這些文化上的改變是難以實作的。
與此同時,我建議在幫助改變你所在小組的文化的過程中你應起帶頭作用。找到另一位開發人員,最好比你經驗豐富,并建立一種"夥伴"關系:在出現問題時,他可以充當你的參謀,當然,你也可以充當他的參謀。事前達成共識:不知道所有問題的答案并沒有什麼不對。
然後為你自己制定一條簡單的規則:不要為一個錯誤苦思冥想超過半個小時。30分鐘過去後,把你的夥伴叫過來,讓人類心理學為你服務,而不是跟你作對