摘要:通過對計(jì)算機(jī)軟件專業(yè)幾門核心課程以及該專業(yè)學(xué)生所必需核心能力的綜合分析,揭示計(jì)算機(jī)軟件專業(yè)以學(xué)生將來的實(shí)戰(zhàn)為教學(xué)目標(biāo),而不是搞以背概念為主的應(yīng)試教育??偨Y(jié)出高效實(shí)用的計(jì)算機(jī)軟件教與學(xué)的方式方法:自下而上的教學(xué)法和自上而下的教學(xué)法。這兩大類方法在教學(xué)實(shí)踐中取得良好的效果。
關(guān)鍵詞:計(jì)算機(jī)軟件;核心課程;軟件開發(fā);綜合構(gòu)思能力;科研;教學(xué)
筆者一直認(rèn)為,計(jì)算機(jī)軟件專業(yè)的核心就是兩個復(fù)雜性和三種能力。兩個復(fù)雜性是復(fù)雜的關(guān)系(包括復(fù)雜的數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)庫及多模塊之間的關(guān)系)和復(fù)雜的思路(包括算法思路和復(fù)雜系統(tǒng)的工作流程思路)。三種能力是編程構(gòu)思能力(算法)、大程序的調(diào)試掌控能力和系統(tǒng)的構(gòu)造能力。其中最根本的能力是編程構(gòu)思能力(算法)。有了這個能力,其他能力都可通過有意識的培訓(xùn)很快得到。計(jì)算機(jī)軟件專業(yè)知識更新快,新知識點(diǎn)層出不窮,但若把握了這個核心,所有新知識均為參考手冊。
與其他專業(yè)不同,計(jì)算機(jī)專業(yè)的幾門主要課程彼此連接非常緊密,孤立地學(xué)習(xí)和理解各門課程肯定達(dá)不到深度要求,但作為初學(xué)者,剛開始又不能不孤立地從最基本的概念學(xué)起。
為此,筆者借鑒計(jì)算機(jī)軟件專業(yè)兩種最基本的軟件開發(fā)方式,提出軟件專業(yè)教學(xué)的兩大方式,即自下而上的教學(xué)法和自上而下的教學(xué)法。前者是從基本概念和基本原理(包括程序語言的基本句型)講起,先孤立地應(yīng)對各門課程,在此基礎(chǔ)上逐步與其他課程關(guān)聯(lián)起來。對此應(yīng)多準(zhǔn)備一些小例子,哪怕深度不夠,能初步說明問題就行。此方法適合于初學(xué)者。后者指的是從綜合構(gòu)思一個較大的系統(tǒng)出發(fā),從各門課程的關(guān)聯(lián)和綜合運(yùn)用出發(fā),自上而下,在關(guān)聯(lián)的層面上,在結(jié)合復(fù)雜構(gòu)思能力的層面上,達(dá)到深入透徹地掌握某門課程具體概念原理之目的。該方法必須始終圍繞構(gòu)思能力來進(jìn)行,適合于高年級學(xué)生。
下面通過幾門課程談?wù)勅绾螒?yīng)用這兩種方法。
1計(jì)算機(jī)語言課
計(jì)算機(jī)專業(yè)有一種錯誤的認(rèn)識,編程是一種低檔次的工作,那是程序員的事,因而學(xué)生不重視語言學(xué)習(xí)和編程。事實(shí)上,一個軟件最終的產(chǎn)品是程序代碼,程序代碼包含了系統(tǒng)的分析設(shè)計(jì)、數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)庫、算法思路、編程技巧等全部信息,可以說,熟練掌控程序代碼的能力再怎么強(qiáng)調(diào)都不過分。只有精通了一門語言,才能運(yùn)用、培訓(xùn)和鍛煉編程構(gòu)思能力和大程序的調(diào)試掌控能力,并最終實(shí)現(xiàn)軟件開發(fā)。通常,C語言是我國高校計(jì)算機(jī)專業(yè)普遍開設(shè)的課程,學(xué)生從大一開始學(xué)習(xí)。學(xué)習(xí)語言課最關(guān)鍵的是領(lǐng)會程序語言的思維方式,各種不同語言的思維方式都是相通的。C語言作為首選是有道理的,因?yàn)樗墓δ軓?qiáng)大,并同時兼有高級語言和低級語言的優(yōu)勢,特別是C語言的句型和語法現(xiàn)象非常豐富,熟練地掌握了C語言,以后學(xué)其他語言就非常容易了[1]。
鑒于C語言是第一門語言課,從低年級開始學(xué),故此課大抵按自下而上的方法教學(xué),以講解句型為主。特別重要的是,要讓學(xué)生領(lǐng)會程序語言的思維方式,必須用心去體會,而不是死記硬背。教師應(yīng)準(zhǔn)備大量的小例子,結(jié)合例子講解句型,并逐步加進(jìn)較復(fù)雜一點(diǎn)的數(shù)據(jù)結(jié)構(gòu)以及算法思路,從句型層面逐步提高到思路層面。愈快地進(jìn)入到思路層面上,結(jié)合思路講解句型的運(yùn)用及其上下文關(guān)聯(lián),教學(xué)效率也就愈高[2]。始終將大量時間拘泥于句型是低效的。
C語言之后還要學(xué)其他語言課,此時的教學(xué)和學(xué)習(xí)方式就應(yīng)與作為第一門語言課的C語言大不相同了。筆者的經(jīng)驗(yàn)是,學(xué)生在熟練掌握C(含C++)語言,尤其是在透徹領(lǐng)會程序語言的思維方式,以及程序語言的幾種句型類別之后,通過直接閱讀專家所寫的大型高質(zhì)量程序源代碼,是學(xué)習(xí)第二門計(jì)算機(jī)語言的最佳方式。當(dāng)然,學(xué)生剛開始可能達(dá)不到這一水準(zhǔn),但以自上而下的教學(xué)方式作為原則是很重要的。下面以Java語言為例說明。
筆者教Java課的理念是:學(xué)生從大一開始學(xué)C語言,由于沒有什么基礎(chǔ),當(dāng)然應(yīng)該從最簡單的概念、語法、句型學(xué)起,而學(xué)Java的學(xué)生往往是大二或大三了,他們此時已掌握了程序的思維方式,具備一定的編程構(gòu)思能力,具有數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)庫、系統(tǒng)構(gòu)造方面的知識技能,再從基本句型學(xué)起就是低效的。而且,作為一個大的開發(fā)平臺,Java擁有的類和函數(shù)的數(shù)目大得驚人,課堂上不可能一一講解。所謂“授人以魚不如授人以漁”,筆者的方法是教學(xué)生如何讀懂別人的程序,通過別人程序的總體功能及上下文來推敲理解Java類及其函數(shù)的功能及正確用法。即從大到小,由整體理解到推敲出小的細(xì)節(jié),而不是相反,這樣不僅小的句型掌握了,而且別人的編程技巧也學(xué)會了,綜合構(gòu)思能力也得到了鍛煉和提高。讓學(xué)生先掌握J(rèn)ava最基本的類和函數(shù),能力具備后,他們就可用此方法自學(xué)掌握其他Java類和函數(shù)。在教學(xué)過程中,教師應(yīng)注意鍛煉和培養(yǎng)學(xué)生較大型程序的調(diào)試能力及讀懂別人程序的能力,這會使學(xué)生在以后的工作中受益無窮。
在教學(xué)中,筆者針對開發(fā)中的重點(diǎn)難點(diǎn)訓(xùn)導(dǎo)學(xué)生,以利于學(xué)生以后的工作實(shí)戰(zhàn)。軟件開發(fā)有三個方面最難突破,首先是綜合調(diào)試大軟件的能力。一個大而復(fù)雜的軟件,由多個小組開發(fā)出各個模塊,每個小組都認(rèn)為自己做得很好,集成調(diào)試時卻問題百出,這時極少有人能掌控整個大軟件,把它調(diào)試順暢。再就是bug問題,有些bug非常難解決。然后是性能問題,主要是速度、內(nèi)存消耗和容量問題。一些高手開發(fā)的成熟軟件,往往在這些方面做得相當(dāng)優(yōu)美,但用戶可能依然對性能不滿意,要求顯著改進(jìn)。
教學(xué)目標(biāo)的高低及正確與否對教學(xué)效率起著決定性作用。筆者希望學(xué)生學(xué)過Java后,對別人寫的數(shù)萬條以上語句的程序,不要任何文檔及注釋行,不作任何介紹,硬讀源代碼,就能將軟件結(jié)構(gòu)、數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)庫、算法思路全部讀通并推出來,而且時間很快,然后想怎么改就怎么改。這就要求學(xué)生在數(shù)據(jù)結(jié)構(gòu)、編程思路方面的功力必須強(qiáng)大。再者,數(shù)據(jù)庫、系統(tǒng)結(jié)構(gòu)及其構(gòu)思運(yùn)用能力必須強(qiáng)大,否則不可能從系統(tǒng)的角度把握整個軟件。另外,學(xué)生必須全面掌握J(rèn)ava本身的結(jié)構(gòu)以及面向?qū)ο缶幊痰乃季S邏輯、各種方法技巧,至于Java的句型細(xì)節(jié),有了上述條件,根本不需花多大功夫,根據(jù)上下文推敲一下就足夠了。
再次強(qiáng)調(diào)讀通別人程序的重要性,它能使你得到一切的一切!
2計(jì)算機(jī)算法
計(jì)算機(jī)算法不同于其他學(xué)科的最大特點(diǎn)是它需要一連串的思維,它們由許多關(guān)鍵點(diǎn)構(gòu)成,這些關(guān)鍵點(diǎn)彼此依序而行,又動態(tài)關(guān)聯(lián)。任何疏忽遺漏或一知半解都會導(dǎo)致整個思路的失敗。這些正是復(fù)雜算法難于理解掌握的根本原因。解決算法問題,最需要的是復(fù)雜思路的構(gòu)思能力,包括思維的多樣性、巧妙性和深入性。其中,多樣性體現(xiàn)的是想象能力,巧妙性是一種創(chuàng)造性思維,是一種天分,而深入性則是深深地沿一條思維脈絡(luò)進(jìn)行下去的能力。這種構(gòu)思能力需要長時間艱辛的培訓(xùn),最有效的方法是在頭腦中一遍又一遍地回味他人的復(fù)雜思路,將他人的復(fù)雜思路印在腦海里,時間一長,自然會功力大增。
因此,算法教學(xué)的關(guān)鍵是首先讓學(xué)生透徹理解和掌握較復(fù)雜的算法,然后才能使其將復(fù)雜的思路印在腦海里反復(fù)回味,以達(dá)到熟能生巧、觸類旁通之效果。因此,教師在講算法課之前,讓學(xué)生先作預(yù)習(xí)是必要的過程。先對要學(xué)的算法有一個初步的理解,并帶著問題聽課,才能有好的效果。其次,抓住關(guān)鍵點(diǎn)實(shí)屬必要。每個復(fù)雜的算法均有幾個關(guān)鍵點(diǎn),攻破了這幾個關(guān)鍵點(diǎn),算法也就迎刃而解了。筆者教學(xué)前先將算法分為易、較難和很難幾個等次,因材施教。告訴學(xué)生要講的算法屬哪個等次,使他們心中有數(shù)。容易的可以較快完成。對難的,教師先逐一講解關(guān)鍵點(diǎn),然后讓學(xué)生依據(jù)講解自己看書,去理解這些關(guān)鍵點(diǎn),然后再讓學(xué)生就不理解的地方提問,教師就學(xué)生的提問作更具針對性的講解。一般來說,經(jīng)過這一過程,學(xué)生基本能理解這些關(guān)鍵點(diǎn)。接著讓學(xué)生自己將這些關(guān)鍵點(diǎn)串起來,形成思路。最后讓學(xué)生反復(fù)回味思路,并給出針對性的問題,讓學(xué)生解答。經(jīng)此過程,學(xué)生大都能很好地掌握要點(diǎn)。
以一般圖搜索算法為例,算法從一個無向圖的初始節(jié)點(diǎn)開始,尋找距該初始節(jié)點(diǎn)路徑最短的目標(biāo)節(jié)點(diǎn)以及最短路徑[3](該算法為經(jīng)典基礎(chǔ)算法,一般算法教科書均可見到,這里不再贅述)。該算法有一定難度,無論是其思路技巧,還是其文字表述,均堪屬經(jīng)典。學(xué)生若能全面掌握此算法,即為進(jìn)一步深入學(xué)習(xí)算法打下良好基礎(chǔ)。
第一步,教師在學(xué)生預(yù)習(xí)的基礎(chǔ)上講一遍整個算法。
第二步,著重強(qiáng)調(diào)關(guān)鍵點(diǎn)。關(guān)鍵點(diǎn)一:對每一節(jié)點(diǎn)建立從父節(jié)點(diǎn)到爺節(jié)點(diǎn)等的祖先鏈,這一祖先鏈?zhǔn)莿討B(tài)變化的。要求學(xué)生理解祖先鏈,理解其為什么和如何動態(tài)變化。關(guān)鍵點(diǎn)二:OPEN節(jié)點(diǎn)和CLOSE節(jié)點(diǎn)的動態(tài)變化過程,必須清晰透徹地理解。OPEN表中已完成展開的節(jié)點(diǎn)放入CLOSE表中,此節(jié)點(diǎn)以后還有可能從CLOSE表中重回OPEN表中繼續(xù)展開,且可能不斷反復(fù),為什么?
第三步,給學(xué)生時間,要求學(xué)生透徹理解關(guān)鍵點(diǎn),并串成清晰的思路。
第四步,要求學(xué)生對還不夠理解的地方提問。有學(xué)生問,既然OPEN表中節(jié)點(diǎn)完成展開后移到CLOSE表,以后又反復(fù)從CLOSE表移到OPEN表重新做展開,那程序何時能結(jié)束?顯然這是沒理解該算法逐步向最優(yōu)解迭代的過程,每重復(fù)一次,到頂點(diǎn)的路徑長度就優(yōu)化一次,而這種優(yōu)化不可能無限進(jìn)行(反問學(xué)生“為什么”),最終OPEN表必然為空,程序終止。
第五步,演算一個較復(fù)雜的例子。
經(jīng)過這五步,學(xué)生大都反映完全掌握了該算法。
對于軟件開發(fā)人員自己學(xué)習(xí)算法,在功力尚不強(qiáng)大且又無老師講解的情況下,在遵循上述步驟原則的基礎(chǔ)上,最好先用幾個小例子或較小規(guī)模的輸入單步跟蹤算法的計(jì)算步驟,反復(fù)回味整個思路,以達(dá)到清晰把握整個思路之目的。即使是功力強(qiáng)大者,這也是攻克復(fù)雜算法思路的有效途徑。
在算法教學(xué)上,筆者注意結(jié)合科研上的難點(diǎn),給學(xué)生以引導(dǎo)激勵,鼓勵學(xué)生大膽思索探討。例如, Hamilton環(huán)為著名的NP難問題[5],讓學(xué)生去解決這樣的問題顯然不切實(shí)際,但可以提到,以激勵學(xué)生。筆者將此問題稍稍改了一下,題目如下。
將具有N個節(jié)點(diǎn)的無向連通圖(最小度數(shù)為2,最大度數(shù)為3)的N個節(jié)點(diǎn)圍成一個圈,我們稱它為虛環(huán),因?yàn)樗赡馨芏鄶帱c(diǎn)。希望用多項(xiàng)式實(shí)踐得到這個虛環(huán)。唯一的要求是:虛環(huán)里不能包含孤立節(jié)點(diǎn)(即某節(jié)點(diǎn)與自己兩側(cè)的節(jié)點(diǎn)都不相連)。
此問題難度不太大,但要完成它也非易事,需要學(xué)生具有較強(qiáng)的復(fù)雜思路的構(gòu)思能力。
3軟件工程課
首先,我們確定軟件工程學(xué)[7]課程的三大教學(xué)目標(biāo):一是掌握軟件開發(fā)的過程、步驟、方法;二是對各學(xué)科知識的綜合運(yùn)用及加深協(xié)作;三是構(gòu)思能力的培訓(xùn)(此點(diǎn)為核心)。
要使學(xué)生不能僅限于對課本概念和原理文字上的理解,而必須時時面臨需要較復(fù)雜思路來解決的問題。因此,必須準(zhǔn)備一些適合于課堂講解的、既短小精悍又能說明問題的例子。
例一,大學(xué)自動排課系統(tǒng)。輸入為:①資源。教室及其容量;每名老師及所能上的課。②每個班。人數(shù)及本學(xué)期上哪幾門課;多少課時。輸出為學(xué)生、教師以及教室管理員均能方便查詢的排課結(jié)果。要求同課可合班,盡量少占教室。此系統(tǒng)看似不大,但相當(dāng)復(fù)雜。若學(xué)生能在課堂上透徹接受此例子,則意味著顯著的收獲:①該例子對數(shù)據(jù)結(jié)構(gòu)和算法知識起運(yùn)用和強(qiáng)化的作用,如怎樣優(yōu)化使教室得到最充分的利用和最大的結(jié)余,做好此算法相當(dāng)有難度。②該例子對數(shù)據(jù)庫知識起運(yùn)用和強(qiáng)化的作用。數(shù)據(jù)庫表設(shè)計(jì):為方便起見,可將上課時間作為一個實(shí)體,每天8節(jié)課,一周5天,共40節(jié)課,編號為1至40,可作主鍵使用。三個方案:①以班級加時間作主鍵,教室老師課程全部作屬性,一個表即能容納排課結(jié)果,另兩個方案為兩個表。讓學(xué)生比較到底誰優(yōu),在什么條件下優(yōu)以及為什么優(yōu)。此外,還有手動調(diào)劑功能,人的權(quán)限與機(jī)器排課權(quán)限之爭的問題、特殊課程和特殊教師的處理問題、教師課程的平衡問題等,都需要考慮。
例二,打手機(jī)的全過程分析設(shè)計(jì)。含市內(nèi)、長途、漫游及交叉等多種情況。每個城市都有一個通信中心,市內(nèi)用戶的所有數(shù)據(jù)均存放在此通信中心,手機(jī)用戶通過分散的基站與通信中心聯(lián)系,各基站只起中轉(zhuǎn)的作用,不存儲數(shù)據(jù),而城市間則通過通信中心互聯(lián)。此例子相當(dāng)能說明問題:①此例子讓學(xué)生明白,系統(tǒng)構(gòu)思與編程構(gòu)思類似,關(guān)鍵是打通思路,而不是背概念、套框框。②使學(xué)生學(xué)會將系統(tǒng)構(gòu)思與數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)庫的構(gòu)思結(jié)合起來。③使學(xué)生明白用戶層面的需求與系統(tǒng)分析員層面的需求有本質(zhì)的不同。本例用戶需求非常簡單,就是打通手機(jī)。而系統(tǒng)分析員的需求分析則要復(fù)雜得多。
總之,軟件工程課應(yīng)運(yùn)用自上而下的教學(xué)方法,準(zhǔn)備幾個像樣的系統(tǒng),從系統(tǒng)構(gòu)思著手,讓學(xué)生通過例子理解掌握軟件工程各個章節(jié)的基本概念,達(dá)到綜合運(yùn)用、融會貫通之目的。
4結(jié)語
針對專業(yè)特點(diǎn),筆者提出計(jì)算機(jī)軟件專業(yè)教學(xué)的兩大方法:自下而上法和自上而下法,并通過幾門主要課程加以說明。在多年實(shí)踐研究的基礎(chǔ)上,給出了一些課教與學(xué)的關(guān)鍵點(diǎn),既可供教學(xué)參考,亦可為軟件開發(fā)人員培訓(xùn)提高功力之借鑒。
參考文獻(xiàn):
[1] 譚浩強(qiáng). C程序設(shè)計(jì)[M]. 北京:清華大學(xué)