程式設計是一個複雜的思維活動,從最原始的了解需求,到最終完全可以正常運作的系統,中間需要經歷過好幾個階段。有時,我們聽到了需求,立即寫下了程式碼,但這並不意謂著我們直接略過這些階段,而是可能在極短的時間內完成了這些階段中的工作。

我們常常聽到,也常常在談論「系統分析」、「系統設計」,究竟在實際的編寫程式碼之前,這兩個階段對於我們完成系統,有什麼重要性?事實上,仍然有不少程式設計者認為,這兩個階段,不過只是文書上的紙上作業,對開發來說是額外的負擔。但在能夠真正的編寫程式之前,你終究是要經歷過這兩個階段。

或許問題的規模很小,所以你可以很快在腦中完成它們,但這並不代表你不需要它們。當你嘗試捨棄它們時,它們原先在開發歷程中被賦予的作用,就因此也無法提供了。對於規模大的問題來說,你或許沒法子直接在腦中做快速的處理,很有可能會引發一些負面的結果。

將解決問題的歷程加以分析
基本上,了解需求、分析、設計、編寫程式碼、測試,是一個透過產出程式來解決問題的系統性方法,它將利用程式解決問題的過程拆解,成為不同的階段,並且在這些階段中,定義了分別對應的任務。

總的來說,程式設計就是一個解決問題的方式。我們之所以要設計程式,是因為有一個待解的問題,這個問題會被試著描述成為一組需求,而這組需求就是我們解題的目標,也就是待解的問題本身。有時候系統規模很大,所以,分析系統需求的人,會試著將一個很大的問題拆解成為若干個更小的問題,用分析的語言來描述對系統的需求。所以,我們從什麼時候開始解題呢?其實上,我們從做分析需求的同時,就開始解題了。

不同的分析方法,其實就意謂著不同的解題基本模式了。像在較早之前有許多人使用結構化系統分析(structured system analysis)的方法,而後也有許多人運用物件導向分析(object oriented analysis),採用不同的分析方法,這是代表著使用不同的分析語言(像是ER模型、或是UML中的各種模型)來描述系統。

從理解、描述問題開始著手

解題的第一步,就是試著把問題本身從問題領域(problem domain)轉換到解題領域(solution domain)。

想想我們在小學、中學時期數學考試,時常要解所謂的應用題。應用題的問題本身並不是用數學的語言所描述的,而是用人類的語言,描述一個生活中可能會遭遇到的問題,透過對問題的理解,我們對問題本身進行了分析,並且將其轉換成為若干條的數學式子。能正確的理解應用題本身,就踏出了成功的第一步,而若是能再接著順利的將原始問題轉換成為等價的數學式子,那麼幾乎就大勢底定了,因為剩下的工作,不過就是運用技巧,小心謹慎把數學式子解出。

轉換後的數學式子一樣是個問題,但是和原始的問題不同的是,它已經是將問題從問題領域轉換到解題領域。將原始問題轉換到解題領域的重要意義在於,在解題領域中我們有系統性的方法和工具可以來解決問題。就像,如果可以成功的將原始問題轉換成為數學中的代數式子,那麼許多早就發展好的代數解題技巧,此時就可以拿出來運用,進而解決問題。

以前在研究網路的問題時,許多問題就像是小時候考試時要解的應用題,只不過難度更難。而在解決問題時,卻也是一樣要試著將問題本身轉換到解題領域中,例如我們時常把網路的問題轉換成為數學或演算法上的圖論問題,一旦能夠成功轉換,就能夠獲得在解題領域中已經發展好的方法及工具的支援。

一來,我們對問題的本質就能更了解,就像是解題的時間複雜度、空間複雜度,在過去可能都已經有了長期的研究,一旦可以轉換,就能明白自己的原始問題究竟好解或不好解,解決起來在空間、時間的代價又分別是多少。二來,在演算法領域中已經發展了許多現成的演算法,一旦我們將原始問題轉換成為演算法領域中的問題,那麼自然可以輕易的套用,毋需自行再發展。

所以說,將問題從問題領域轉換到解題領域是很關鍵的動作,少了這個動作,我們就無法解題。當我們用不同的分析方法來對問題進行分析時,往往就是將待解的問題、也就是對系統的需求,轉換到不同的解題領域中去。分析者喜歡用、或想要用的分析方法不同,轉換的解題領域就不同,在這之後解決問題的方法也就會跟著不同。在分析階段使用結構化分析的方法,以及使用物件導向分析的方法,在之後的設計、編寫程式的模式,也都會跟著不同。

設計方法來解決問題

當我們能夠用分析的語言描述,或是建構出問題的模型之後,就可以用設計的語言來描述解決問題的方法。正如之前提過的,什麼是設計?設計就是解決問題的手段。例如,利用物件導向設計方法的人,可能就會利用類別圖、合作圖、循序圖之類的建模方法來描述解決問題的方法。

這個描述的方法通常是比較高階的,因為它常常不涉及低階實作層次的內容。例如,假設你的解題手段裡包括要使用到一個解碼器,在設計的時候,你可能會表示:「在這邊使用一個解碼器,給定此種格式的輸入,能夠產生彼種格式的輸出」,但是,你不會在這個階段就實作解碼器的內容,通常也不會考慮到解碼器內實作的演法為何,你只會關心它的介面。所以在此階段的「解決方法」是高階層次的、是架構層次的,描述系統應該由那些組成所構成、每個組成具備那些能力、它們之間應當如何互動、在什麼時間點互動、……等等。

設計本身就是在解決問題,只不過解決問題的層次不同,關心的重點和面向也不同。而且,設計的時候,除了必須考慮滿足所有的需求之外,也需要考慮到一些額外的因子,像是效率是否足夠、是否有足夠的彈性、是否具備規模可擴充性、是否容易因為需求的變動而調整或擴展、是否容易測試等。或許在需求中包括對這些因子的要求,但通常在需求沒有涉及這些條件的時候,設計者為了利於之後的開發或系統維護,也會自行將它們納入考量。

程式碼的產出,又是再一次用不同的語言及工具來描述解決問題的方法。我們承接著設計階段的產物,將利用設計語言所描述的系統,利用程式語言予以實作,並且增補上更低階的實作細節。

你可以發現,因為從了解需求到產出最後的程式碼之間的思考活動,有時候往往不是那麼直覺,甚至在規模大時,思考更容易無法面面俱到,所以我們才會需要將解決問題的過程畫分成為不同的階段,並且在不同的階段中,利用適合的語言、塑模方法、表述方式,來協助我們完成該階段的工作。而每個階段的工作都是承接著前一個階段的產出,環環相扣,最終將程式碼編寫完成。

了解在每個階段你的工作目的是什麼,就知道如何運用適合的表述工具來輔助你的思考。程式碼是最終的產物,但是這些中間階段的產出,時常也是得到最終產品前所不可或缺的中間產物,因為,你的思考並沒辦法直達終點,所以,你需要它們協助你思考。

 

專欄作者

熱門新聞

Advertisement