我從1990年就開始編寫PL/SQL代碼。這意味著我已經(jīng)編寫了幾萬行的軟件代碼,但我確信,其中的絕大多數(shù)代碼都非常拙劣,而且難以維護(hù)。
幸運(yùn)地是,我發(fā)現(xiàn)找到并遵循編寫出更好代碼的新方法還為時(shí)不晚。就是在去年,我的代碼質(zhì)量有了顯著改進(jìn);這些改進(jìn)主要是由于制定了一些簡(jiǎn)單的規(guī)則,并像紀(jì)律一樣加以遵守。
本文為PL/SQL新手及有經(jīng)驗(yàn)的開發(fā)人員提出了四條建議;遵守其中任何一條,你的代碼質(zhì)量都會(huì)有提高。這四點(diǎn)建議都采納,你可能會(huì)驚奇地猛然發(fā)現(xiàn):你竟然是一個(gè)非常好的程序員,要遠(yuǎn)遠(yuǎn)超乎你的想象。
所有工作都獨(dú)自完成
我們很少有人是孤立工作的;大多數(shù)PL/SQL開發(fā)工作是在相對(duì)較大的機(jī)構(gòu)中進(jìn)行的。但我們基本上還是在自己的小隔間里用自己的設(shè)備獨(dú)自工作。幾乎沒有PL/SQL開發(fā)小組進(jìn)行正規(guī)的代碼復(fù)查或系統(tǒng)測(cè)試。
我不可能通過這篇文章改變你們開發(fā)小組的基本狀態(tài)。因此,我仔細(xì)地選取出以下幾點(diǎn)建議。實(shí)施其中任何一點(diǎn)并不需征得管理人員同意。不論你的小組是大是小,都不必讓其中的每個(gè)人都贊同這些編碼規(guī)則。你只需按以下建議來改變你的本人的編碼方式:
1. 嚴(yán)格遵循命名約定,好像它們就是你的生命支柱。
2. 戒除編寫SQL的嗜好:編寫的SQL越少越好。
3. 使執(zhí)行部分短小:告別"意大利面條式的代碼"。
4. 找一位伙伴:非常贊同找個(gè)人來監(jiān)督你的工作。
1. 遵循命名約定
如果你建立并嚴(yán)格遵循一套命名約定,特別是對(duì)于應(yīng)用程序組件的,你就可以節(jié)省很多時(shí)間。
當(dāng)然,遵循命名約定的想法并沒有什么新意,你可能已經(jīng)聽煩了。所以我并不提出什么宏偉的命名計(jì)劃,而是給出一些非常具體而明確的約定,然后證明這些約定會(huì)多么有用。
前幾個(gè)月我一直在為PL/SQL開發(fā)人員設(shè)計(jì)、構(gòu)建一種新工具。它名為Swyg(可以在www.swyg.com中找到),可以幫助程序員完成代碼的生成、測(cè)試及重用的工作。它具有幾個(gè)獨(dú)特的組件。我為每個(gè)組件指定了一個(gè)由兩個(gè)字母組成的縮寫名稱,如下所示:
SF-Swyg的基礎(chǔ)部件
SM-Swyg的元數(shù)據(jù)
SG-Swyg的生成程序
SL-Swyg的代碼庫(kù)
ST-Swyg的單元測(cè)試
于是,我便遵循表1中的命名約定,同時(shí)使用這些縮寫。遵循這些約定有什么好處呢?一般來講,如果我要求一致的命名規(guī)則,我就可以更流暢更高效地編寫代碼。
明確地說,這些約定具有可預(yù)測(cè)性,意思是說我編寫的SQL程序能生成有用的腳本。例如,通過使用表1中的約定,可以生成Swyg中所有基礎(chǔ)包的安裝腳本。執(zhí)行這些工作的SQL*Plus腳本如清單1所示。這類腳本非常有用,因?yàn)樗馕吨也槐厥謩?dòng)維護(hù)安裝腳本。當(dāng)我向Swyg方案中增加另一個(gè)表,并生成一組相關(guān)包時(shí),我只要運(yùn)行我的腳本,更新后的安裝腳本便會(huì)跳出來 2. 戒除編寫SQL的嗜好
編寫的SQL越少越好,這似乎與我們的直覺不太一致。對(duì)于PL/SQL開發(fā)人員來說,這是一個(gè)奇特的建議,因?yàn)镻L/SQL的主要優(yōu)點(diǎn)之一就是可以毫不費(fèi)力地在代碼中編寫SQL語句。不過,這種簡(jiǎn)易性也是這種語言的一個(gè)致命的弱點(diǎn)。
可以將純粹的SQL語句直接置于PL/SQL代碼中,而無需JDBC或ODBC之類的中間層。因此,無論何時(shí)何地,PL/SQL開發(fā)人員只要需要SQL語句,他們通常就會(huì)向其應(yīng)用程序代碼中嵌入SQL語句。那么這樣做有什么問題嗎?
在PL/SQL代碼中到處使用SQL語句必然會(huì)導(dǎo)致以下后果:
盡管實(shí)際表現(xiàn)不同,但同一邏輯語句仍會(huì)出現(xiàn)重復(fù),從而導(dǎo)致過多的語法分析,且難于優(yōu)化應(yīng)用程序的性能。
暴露商務(wù)規(guī)則和方案。這直接在SQL語句中包含了執(zhí)行商務(wù)規(guī)則的邏輯。這些規(guī)則總在變化,所以應(yīng)用程序的維護(hù)成本會(huì)急劇增加。
當(dāng)然,你要編寫的每一個(gè)PL/SQL應(yīng)用程序幾乎都是基于基礎(chǔ)表和視圖的。你需要執(zhí)行SQL語句。問題不在于是否執(zhí)行,而是何時(shí)執(zhí)行、如何執(zhí)行。
如果你對(duì)數(shù)據(jù)結(jié)構(gòu)進(jìn)行封裝,或者將它們隱藏于一個(gè)PL/SQL代碼層(通常是一個(gè)代碼包)之后,那么你的應(yīng)用程序?qū)?huì)更健壯,而且你還會(huì)發(fā)現(xiàn)創(chuàng)建和維護(hù)變得更易多了。
我們來看一個(gè)簡(jiǎn)單的例子。 假定我需要編寫一個(gè)處理某員工工作的程序。第一件事是獲取該員工的全名,定義為"姓名逗號(hào)(,)姓";然后我可以進(jìn)行詳細(xì)分析。清單2給出了這種情況下我很可能要編寫的這類代碼的一個(gè)示例。
一切似乎都是這么簡(jiǎn)單和直接;這些代碼可能會(huì)有什么錯(cuò)誤呢?實(shí)際上真是非常糟糕。最主要的是我暴露了一個(gè)商務(wù)規(guī)則:全名的結(jié)構(gòu)。我可能要花費(fèi)數(shù)小時(shí)來對(duì)此代碼及其所基于的應(yīng)用程序進(jìn)行測(cè)試。但就在它剛剛投入使用時(shí),我才知道客戶會(huì)不斷地打電話告訴我,實(shí)際上,他們的全名應(yīng)該表示為"名空格姓"。
現(xiàn)在怎么辦?搜索所有位于引號(hào)內(nèi)的單個(gè)逗號(hào)?
現(xiàn)實(shí)的解決方案是使用隱藏所有細(xì)節(jié)、只提供一組預(yù)定義、預(yù)測(cè)試及預(yù)優(yōu)化并能完成所有任務(wù)的程序包。清單3為基于封裝代碼重新編寫的process_employee過程。hr_employee_tp包提供了用于定義保存姓名的局部變量的類型;hr_employee_rp包含有基于一種商務(wù)規(guī)則而返回全名的函數(shù)。
將顯示PL/SQL語句灌入SQL代碼很容易,同樣,談?wù)摲庋b這些語句是如何重要也不費(fèi)勁。但另一方面,編寫執(zhí)行封裝任務(wù)的代碼卻具有挑戰(zhàn)性;甚至是不現(xiàn)實(shí)的。生成這些包或許更有意義。
幾年前,我曾幫助構(gòu)建這樣一個(gè)生成程序。該程序段為PL/Generator,現(xiàn)在由Quest Software公司擁有,PL/SQL開發(fā)社區(qū)可以免費(fèi)使用。你可以從我的網(wǎng)站www.StevenFeuerstein.com/puter/gencentral.htm下載。要知道,其封裝體系結(jié)構(gòu)與我在前面所概括的約定不同。PL/Generator創(chuàng)建了一個(gè)單獨(dú)的包,它包含了一個(gè)表的類型、查詢和變化邏輯的全部?jī)?nèi)容。
當(dāng)你不再編寫太多的SQL,而是調(diào)用執(zhí)行SQL的程序時(shí),無論你是生成還是編寫自己的定制封裝,你的應(yīng)用程序都會(huì)受益匪淺。
3. 使執(zhí)行部分短小
面對(duì)現(xiàn)實(shí)吧:總是與我們的判斷和最新的一系列新年決議相左,我們必須停止編寫意大利面條式的代碼:龐大而冗長(zhǎng),人們實(shí)際上不可能理解它們,更不用說維護(hù)或升級(jí)了。怎樣才能避免"意大利面條"呢?
實(shí)際上,答案很簡(jiǎn)單:決不允許執(zhí)行部分超過50或60行。這種大小使你能在一頁(yè)紙或一個(gè)屏幕上查看該代碼塊的整個(gè)邏輯結(jié)構(gòu),這也意味著你可以真實(shí)地領(lǐng)會(huì)該程序的意圖,而且完全憑直覺就能理解它。
你可能非常同意上述觀點(diǎn),但同時(shí)又嘲笑我的建議:程序代碼永遠(yuǎn)不超過50行。沒錯(cuò),你應(yīng)當(dāng)嘲笑,因?yàn)檫@當(dāng)然是不可能的。毫無疑問,你需要超過50行的可執(zhí)行代碼;問題是你把這些代碼放在哪,以及你怎樣加以組織。
如果采取以下做法,你的確能夠應(yīng)對(duì)各種復(fù)雜的要求,并把代碼限制在50行以內(nèi):
將所有的商務(wù)規(guī)則和離散邏輯塊置于其自已的程序(通常是函數(shù))中,從而在任何可能的時(shí)候慎重地重用代碼。
盡量使用在程序的聲明部分定義的局部模塊、過程和函數(shù)。
假定我在編制一個(gè)呼叫中心應(yīng)用程序。我需要編寫一個(gè)程序,它要滿足下面的要求:
"對(duì)于特定部門的每個(gè)員工,將其工作量(分派給該員工的呼叫次數(shù))同該部門員工的平均工作量進(jìn)行比較。如果某員工的工作量低于平均工作量,便將下一待處理呼叫分派給此人,并基于這種情況安排約定。"
我從以前的工作中獲悉:我的朋友Claudia已經(jīng)編寫了一個(gè)分析包,它會(huì)返回工作量方面的信息。但是分派待處理呼叫和安排約定都是全新的工作,需求文檔的其余部分對(duì)此進(jìn)行了詳細(xì)說明。
最初我想把這15頁(yè)的內(nèi)容全都看完,但我沒有那樣做。我使用了一種稱為"逐步求精法"或"由頂向下設(shè)計(jì)"的技術(shù),并先編寫了清單4中的代碼來實(shí)現(xiàn)該程序。
下面給出了清單4中最關(guān)鍵代碼行的解釋;由該程序(緊湊的執(zhí)行部分)的最后開始,向上進(jìn)行。這似乎有悖于直覺,但這的確是通讀用逐步求精法編寫的程序的方式。
第22~30行。用一個(gè)游標(biāo)FOR循環(huán)(cursor FOR loop)來對(duì)指定部門的所有員工進(jìn)行迭代處理。在第24~25行,利用分析包中的程序判定當(dāng)前的員工是否工作量不足。在第27~28行,調(diào)用三個(gè)程序:assign_next_open_case、schedule_case和next_appointment。我還不知道怎樣實(shí)現(xiàn)這些程序,但我知道它們通過其名稱和參數(shù)表表達(dá)了需要事先完成的工作。
第10~19行。為第27~28行中的三個(gè)程序創(chuàng)建"stub",也就是占位程序。注意,它們是局部模塊,在assign_workload中進(jìn)行定義,且不能從其他任何程序調(diào)用。
第5~8行。定義一個(gè)游標(biāo),以獲得指定部門的所有員工?,F(xiàn)在可以設(shè)法編譯此代碼。
對(duì)這樣一個(gè)小程序成功完成編譯好像是個(gè)小勝利,也的確如此。完成正確編譯,然后是簡(jiǎn)單測(cè)試,然后增加一點(diǎn)代碼,再進(jìn)行正確編譯,以此類推,諸如此類的小勝利締造出構(gòu)造精良的程序,而且會(huì)非常滿意。
我還可以驗(yàn)證該分析程序是有效的,并且找出了要分派的任務(wù)適當(dāng)雇員。這些工作全部完成后,我將從三個(gè)程序中挑出一個(gè),比如assign_next_open_case,進(jìn)行下一步或下一級(jí)別的精細(xì)設(shè)計(jì)。我要閱讀該任務(wù)的文檔,并在assign_next_open_case里編寫一個(gè)簡(jiǎn)短的執(zhí)行部分,它可反映該任務(wù)的概況。
很快,我的局部過程有了它自己的局部過程和函數(shù),但在該過程的每一步,我的代碼都很短、可讀、易于測(cè)試、可根據(jù)需要進(jìn)行調(diào)整。
4. 找一位好伙伴
計(jì)算機(jī)并不會(huì)編程,人才會(huì)。
有多少次你彎著腰、駝著背坐在計(jì)算機(jī)前,因無法找出代碼中的錯(cuò)誤而感到非常郁悶?先是幾分鐘過去了,接著又過了幾小時(shí)。最后,對(duì)自己都厭煩了,感到非常失敗,你把頭伸出你的小隔間并請(qǐng)朋友過來幫你看一看。
通常會(huì)有下面三種情況之一出現(xiàn):
當(dāng)你的朋友從她的椅子上站起來時(shí),一切都在瞬間變得非常清楚。
你的朋友瞥了一眼屏幕,馬上就指出了問題所在。
你的朋友不負(fù)責(zé)該系統(tǒng)中你所做的部分,所以你必須說明你的程序在干什么。當(dāng)你逐步講解邏輯時(shí),引起錯(cuò)誤的問題所在會(huì)突然暴露在你面前。
事實(shí)就是自己很難調(diào)試自己的代碼,因?yàn)槟阕约簩?duì)它太投入、太專注了。
這個(gè)問題的解決辦法是由開發(fā)經(jīng)理創(chuàng)造這樣一種文化:各種想法是共享的、不懂是可以原諒的并不會(huì)受到處罰、定期進(jìn)行建設(shè)性的代碼評(píng)審。不幸的是,這些文化上的改變是難以實(shí)現(xiàn)的。
與此同時(shí),我建議在幫助改變你所在小組的文化的過程中你應(yīng)起帶頭作用。找到另一位開發(fā)人員,比你經(jīng)驗(yàn)豐富,并建立一種"伙伴"關(guān)系:在出現(xiàn)問題時(shí),他可以充當(dāng)你的參謀,當(dāng)然,你也可以充當(dāng)他的參謀。事前達(dá)成共識(shí):不知道所有問題的答案并沒有什么不對(duì)。
然后為你自己制定一條簡(jiǎn)單的規(guī)則:不要為一個(gè)錯(cuò)誤苦思冥想超過半個(gè)小時(shí)。30分鐘過去后,把你的伙伴叫過來,讓人類心理學(xué)為你服務(wù),而不是跟你作對(duì)。
獲得一種新工作方式的四個(gè)步驟
本文為你提供了可以采取的用于改變你的編程體驗(yàn)四個(gè)步驟,而無須投資新的工具或改變整個(gè)小組的工作流程。這四步甚至可以不全部遵循,只要遵守一步都會(huì)讓你受益。
幸運(yùn)地是,我發(fā)現(xiàn)找到并遵循編寫出更好代碼的新方法還為時(shí)不晚。就是在去年,我的代碼質(zhì)量有了顯著改進(jìn);這些改進(jìn)主要是由于制定了一些簡(jiǎn)單的規(guī)則,并像紀(jì)律一樣加以遵守。
本文為PL/SQL新手及有經(jīng)驗(yàn)的開發(fā)人員提出了四條建議;遵守其中任何一條,你的代碼質(zhì)量都會(huì)有提高。這四點(diǎn)建議都采納,你可能會(huì)驚奇地猛然發(fā)現(xiàn):你竟然是一個(gè)非常好的程序員,要遠(yuǎn)遠(yuǎn)超乎你的想象。
所有工作都獨(dú)自完成
我們很少有人是孤立工作的;大多數(shù)PL/SQL開發(fā)工作是在相對(duì)較大的機(jī)構(gòu)中進(jìn)行的。但我們基本上還是在自己的小隔間里用自己的設(shè)備獨(dú)自工作。幾乎沒有PL/SQL開發(fā)小組進(jìn)行正規(guī)的代碼復(fù)查或系統(tǒng)測(cè)試。
我不可能通過這篇文章改變你們開發(fā)小組的基本狀態(tài)。因此,我仔細(xì)地選取出以下幾點(diǎn)建議。實(shí)施其中任何一點(diǎn)并不需征得管理人員同意。不論你的小組是大是小,都不必讓其中的每個(gè)人都贊同這些編碼規(guī)則。你只需按以下建議來改變你的本人的編碼方式:
1. 嚴(yán)格遵循命名約定,好像它們就是你的生命支柱。
2. 戒除編寫SQL的嗜好:編寫的SQL越少越好。
3. 使執(zhí)行部分短小:告別"意大利面條式的代碼"。
4. 找一位伙伴:非常贊同找個(gè)人來監(jiān)督你的工作。
1. 遵循命名約定
如果你建立并嚴(yán)格遵循一套命名約定,特別是對(duì)于應(yīng)用程序組件的,你就可以節(jié)省很多時(shí)間。
當(dāng)然,遵循命名約定的想法并沒有什么新意,你可能已經(jīng)聽煩了。所以我并不提出什么宏偉的命名計(jì)劃,而是給出一些非常具體而明確的約定,然后證明這些約定會(huì)多么有用。
前幾個(gè)月我一直在為PL/SQL開發(fā)人員設(shè)計(jì)、構(gòu)建一種新工具。它名為Swyg(可以在www.swyg.com中找到),可以幫助程序員完成代碼的生成、測(cè)試及重用的工作。它具有幾個(gè)獨(dú)特的組件。我為每個(gè)組件指定了一個(gè)由兩個(gè)字母組成的縮寫名稱,如下所示:
SF-Swyg的基礎(chǔ)部件
SM-Swyg的元數(shù)據(jù)
SG-Swyg的生成程序
SL-Swyg的代碼庫(kù)
ST-Swyg的單元測(cè)試
于是,我便遵循表1中的命名約定,同時(shí)使用這些縮寫。遵循這些約定有什么好處呢?一般來講,如果我要求一致的命名規(guī)則,我就可以更流暢更高效地編寫代碼。
明確地說,這些約定具有可預(yù)測(cè)性,意思是說我編寫的SQL程序能生成有用的腳本。例如,通過使用表1中的約定,可以生成Swyg中所有基礎(chǔ)包的安裝腳本。執(zhí)行這些工作的SQL*Plus腳本如清單1所示。這類腳本非常有用,因?yàn)樗馕吨也槐厥謩?dòng)維護(hù)安裝腳本。當(dāng)我向Swyg方案中增加另一個(gè)表,并生成一組相關(guān)包時(shí),我只要運(yùn)行我的腳本,更新后的安裝腳本便會(huì)跳出來 2. 戒除編寫SQL的嗜好
編寫的SQL越少越好,這似乎與我們的直覺不太一致。對(duì)于PL/SQL開發(fā)人員來說,這是一個(gè)奇特的建議,因?yàn)镻L/SQL的主要優(yōu)點(diǎn)之一就是可以毫不費(fèi)力地在代碼中編寫SQL語句。不過,這種簡(jiǎn)易性也是這種語言的一個(gè)致命的弱點(diǎn)。
可以將純粹的SQL語句直接置于PL/SQL代碼中,而無需JDBC或ODBC之類的中間層。因此,無論何時(shí)何地,PL/SQL開發(fā)人員只要需要SQL語句,他們通常就會(huì)向其應(yīng)用程序代碼中嵌入SQL語句。那么這樣做有什么問題嗎?
在PL/SQL代碼中到處使用SQL語句必然會(huì)導(dǎo)致以下后果:
盡管實(shí)際表現(xiàn)不同,但同一邏輯語句仍會(huì)出現(xiàn)重復(fù),從而導(dǎo)致過多的語法分析,且難于優(yōu)化應(yīng)用程序的性能。
暴露商務(wù)規(guī)則和方案。這直接在SQL語句中包含了執(zhí)行商務(wù)規(guī)則的邏輯。這些規(guī)則總在變化,所以應(yīng)用程序的維護(hù)成本會(huì)急劇增加。
當(dāng)然,你要編寫的每一個(gè)PL/SQL應(yīng)用程序幾乎都是基于基礎(chǔ)表和視圖的。你需要執(zhí)行SQL語句。問題不在于是否執(zhí)行,而是何時(shí)執(zhí)行、如何執(zhí)行。
如果你對(duì)數(shù)據(jù)結(jié)構(gòu)進(jìn)行封裝,或者將它們隱藏于一個(gè)PL/SQL代碼層(通常是一個(gè)代碼包)之后,那么你的應(yīng)用程序?qū)?huì)更健壯,而且你還會(huì)發(fā)現(xiàn)創(chuàng)建和維護(hù)變得更易多了。
我們來看一個(gè)簡(jiǎn)單的例子。 假定我需要編寫一個(gè)處理某員工工作的程序。第一件事是獲取該員工的全名,定義為"姓名逗號(hào)(,)姓";然后我可以進(jìn)行詳細(xì)分析。清單2給出了這種情況下我很可能要編寫的這類代碼的一個(gè)示例。
一切似乎都是這么簡(jiǎn)單和直接;這些代碼可能會(huì)有什么錯(cuò)誤呢?實(shí)際上真是非常糟糕。最主要的是我暴露了一個(gè)商務(wù)規(guī)則:全名的結(jié)構(gòu)。我可能要花費(fèi)數(shù)小時(shí)來對(duì)此代碼及其所基于的應(yīng)用程序進(jìn)行測(cè)試。但就在它剛剛投入使用時(shí),我才知道客戶會(huì)不斷地打電話告訴我,實(shí)際上,他們的全名應(yīng)該表示為"名空格姓"。
現(xiàn)在怎么辦?搜索所有位于引號(hào)內(nèi)的單個(gè)逗號(hào)?
現(xiàn)實(shí)的解決方案是使用隱藏所有細(xì)節(jié)、只提供一組預(yù)定義、預(yù)測(cè)試及預(yù)優(yōu)化并能完成所有任務(wù)的程序包。清單3為基于封裝代碼重新編寫的process_employee過程。hr_employee_tp包提供了用于定義保存姓名的局部變量的類型;hr_employee_rp包含有基于一種商務(wù)規(guī)則而返回全名的函數(shù)。
將顯示PL/SQL語句灌入SQL代碼很容易,同樣,談?wù)摲庋b這些語句是如何重要也不費(fèi)勁。但另一方面,編寫執(zhí)行封裝任務(wù)的代碼卻具有挑戰(zhàn)性;甚至是不現(xiàn)實(shí)的。生成這些包或許更有意義。
幾年前,我曾幫助構(gòu)建這樣一個(gè)生成程序。該程序段為PL/Generator,現(xiàn)在由Quest Software公司擁有,PL/SQL開發(fā)社區(qū)可以免費(fèi)使用。你可以從我的網(wǎng)站www.StevenFeuerstein.com/puter/gencentral.htm下載。要知道,其封裝體系結(jié)構(gòu)與我在前面所概括的約定不同。PL/Generator創(chuàng)建了一個(gè)單獨(dú)的包,它包含了一個(gè)表的類型、查詢和變化邏輯的全部?jī)?nèi)容。
當(dāng)你不再編寫太多的SQL,而是調(diào)用執(zhí)行SQL的程序時(shí),無論你是生成還是編寫自己的定制封裝,你的應(yīng)用程序都會(huì)受益匪淺。
3. 使執(zhí)行部分短小
面對(duì)現(xiàn)實(shí)吧:總是與我們的判斷和最新的一系列新年決議相左,我們必須停止編寫意大利面條式的代碼:龐大而冗長(zhǎng),人們實(shí)際上不可能理解它們,更不用說維護(hù)或升級(jí)了。怎樣才能避免"意大利面條"呢?
實(shí)際上,答案很簡(jiǎn)單:決不允許執(zhí)行部分超過50或60行。這種大小使你能在一頁(yè)紙或一個(gè)屏幕上查看該代碼塊的整個(gè)邏輯結(jié)構(gòu),這也意味著你可以真實(shí)地領(lǐng)會(huì)該程序的意圖,而且完全憑直覺就能理解它。
你可能非常同意上述觀點(diǎn),但同時(shí)又嘲笑我的建議:程序代碼永遠(yuǎn)不超過50行。沒錯(cuò),你應(yīng)當(dāng)嘲笑,因?yàn)檫@當(dāng)然是不可能的。毫無疑問,你需要超過50行的可執(zhí)行代碼;問題是你把這些代碼放在哪,以及你怎樣加以組織。
如果采取以下做法,你的確能夠應(yīng)對(duì)各種復(fù)雜的要求,并把代碼限制在50行以內(nèi):
將所有的商務(wù)規(guī)則和離散邏輯塊置于其自已的程序(通常是函數(shù))中,從而在任何可能的時(shí)候慎重地重用代碼。
盡量使用在程序的聲明部分定義的局部模塊、過程和函數(shù)。
假定我在編制一個(gè)呼叫中心應(yīng)用程序。我需要編寫一個(gè)程序,它要滿足下面的要求:
"對(duì)于特定部門的每個(gè)員工,將其工作量(分派給該員工的呼叫次數(shù))同該部門員工的平均工作量進(jìn)行比較。如果某員工的工作量低于平均工作量,便將下一待處理呼叫分派給此人,并基于這種情況安排約定。"
我從以前的工作中獲悉:我的朋友Claudia已經(jīng)編寫了一個(gè)分析包,它會(huì)返回工作量方面的信息。但是分派待處理呼叫和安排約定都是全新的工作,需求文檔的其余部分對(duì)此進(jìn)行了詳細(xì)說明。
最初我想把這15頁(yè)的內(nèi)容全都看完,但我沒有那樣做。我使用了一種稱為"逐步求精法"或"由頂向下設(shè)計(jì)"的技術(shù),并先編寫了清單4中的代碼來實(shí)現(xiàn)該程序。
下面給出了清單4中最關(guān)鍵代碼行的解釋;由該程序(緊湊的執(zhí)行部分)的最后開始,向上進(jìn)行。這似乎有悖于直覺,但這的確是通讀用逐步求精法編寫的程序的方式。
第22~30行。用一個(gè)游標(biāo)FOR循環(huán)(cursor FOR loop)來對(duì)指定部門的所有員工進(jìn)行迭代處理。在第24~25行,利用分析包中的程序判定當(dāng)前的員工是否工作量不足。在第27~28行,調(diào)用三個(gè)程序:assign_next_open_case、schedule_case和next_appointment。我還不知道怎樣實(shí)現(xiàn)這些程序,但我知道它們通過其名稱和參數(shù)表表達(dá)了需要事先完成的工作。
第10~19行。為第27~28行中的三個(gè)程序創(chuàng)建"stub",也就是占位程序。注意,它們是局部模塊,在assign_workload中進(jìn)行定義,且不能從其他任何程序調(diào)用。
第5~8行。定義一個(gè)游標(biāo),以獲得指定部門的所有員工?,F(xiàn)在可以設(shè)法編譯此代碼。
對(duì)這樣一個(gè)小程序成功完成編譯好像是個(gè)小勝利,也的確如此。完成正確編譯,然后是簡(jiǎn)單測(cè)試,然后增加一點(diǎn)代碼,再進(jìn)行正確編譯,以此類推,諸如此類的小勝利締造出構(gòu)造精良的程序,而且會(huì)非常滿意。
我還可以驗(yàn)證該分析程序是有效的,并且找出了要分派的任務(wù)適當(dāng)雇員。這些工作全部完成后,我將從三個(gè)程序中挑出一個(gè),比如assign_next_open_case,進(jìn)行下一步或下一級(jí)別的精細(xì)設(shè)計(jì)。我要閱讀該任務(wù)的文檔,并在assign_next_open_case里編寫一個(gè)簡(jiǎn)短的執(zhí)行部分,它可反映該任務(wù)的概況。
很快,我的局部過程有了它自己的局部過程和函數(shù),但在該過程的每一步,我的代碼都很短、可讀、易于測(cè)試、可根據(jù)需要進(jìn)行調(diào)整。
4. 找一位好伙伴
計(jì)算機(jī)并不會(huì)編程,人才會(huì)。
有多少次你彎著腰、駝著背坐在計(jì)算機(jī)前,因無法找出代碼中的錯(cuò)誤而感到非常郁悶?先是幾分鐘過去了,接著又過了幾小時(shí)。最后,對(duì)自己都厭煩了,感到非常失敗,你把頭伸出你的小隔間并請(qǐng)朋友過來幫你看一看。
通常會(huì)有下面三種情況之一出現(xiàn):
當(dāng)你的朋友從她的椅子上站起來時(shí),一切都在瞬間變得非常清楚。
你的朋友瞥了一眼屏幕,馬上就指出了問題所在。
你的朋友不負(fù)責(zé)該系統(tǒng)中你所做的部分,所以你必須說明你的程序在干什么。當(dāng)你逐步講解邏輯時(shí),引起錯(cuò)誤的問題所在會(huì)突然暴露在你面前。
事實(shí)就是自己很難調(diào)試自己的代碼,因?yàn)槟阕约簩?duì)它太投入、太專注了。
這個(gè)問題的解決辦法是由開發(fā)經(jīng)理創(chuàng)造這樣一種文化:各種想法是共享的、不懂是可以原諒的并不會(huì)受到處罰、定期進(jìn)行建設(shè)性的代碼評(píng)審。不幸的是,這些文化上的改變是難以實(shí)現(xiàn)的。
與此同時(shí),我建議在幫助改變你所在小組的文化的過程中你應(yīng)起帶頭作用。找到另一位開發(fā)人員,比你經(jīng)驗(yàn)豐富,并建立一種"伙伴"關(guān)系:在出現(xiàn)問題時(shí),他可以充當(dāng)你的參謀,當(dāng)然,你也可以充當(dāng)他的參謀。事前達(dá)成共識(shí):不知道所有問題的答案并沒有什么不對(duì)。
然后為你自己制定一條簡(jiǎn)單的規(guī)則:不要為一個(gè)錯(cuò)誤苦思冥想超過半個(gè)小時(shí)。30分鐘過去后,把你的伙伴叫過來,讓人類心理學(xué)為你服務(wù),而不是跟你作對(duì)。
獲得一種新工作方式的四個(gè)步驟
本文為你提供了可以采取的用于改變你的編程體驗(yàn)四個(gè)步驟,而無須投資新的工具或改變整個(gè)小組的工作流程。這四步甚至可以不全部遵循,只要遵守一步都會(huì)讓你受益。