想要專精程式必須學會什麼?

原本想把這篇文章命名為「程式設計到底在學什麼?」,結果當它還躺在我的草稿堆時,就看到 Huli 發表的「當我們在學程式時,要學的到底是什麼?」。這篇文章寫得實在太好了,我一定無法寫出這樣的文章,不過好佳在我想寫的內容跟他是完全不同方向,倒也沒什麼衝突。仔細想想,他的內容比我想寫的更貼近「程式設計在學什麼」這個主題,所以我決定把題目改成「想要專精程式必須學會什麼?」。因為我想談論的重點只有兩個:資料結構與演算法。

想寫這篇文章的理由很簡單:在我的認知裡,程式=資料結構+演算法。所以當你看到很多人對於資料結構與演算法不屑一顧時,真心覺得想翻桌!不過其實我也是讀書畢業後才對資料結構演算法有比較深刻的暸解,所以對入門者來說不懂也很正常;資料結構與演算法的課程上完了,還是不知道與我們寫的程式有什麼關連,老師沒講清楚的事只能自己慢慢體會。所以我想在這裡跟大家分享我的體悟,希望對大家的暸解有點幫助。

簡單地說,資料就是指程式變數裡儲存的東西(=數字、字串、布林),當資料儲存的方式有組織性時(=陣列、堆疊、樹、JSON),就是一種由資料組成的結構。而我們撰寫的程式碼,包括判斷式、迴圈等等,是屬於演算法的範疇。程式一定有資料、有演算法,但不一定有結構性的資料。比如說我要印5顆星星在畫面上,「5」和星星就是我的資料,打印的程式碼就是演算法。然而,除非我們寫的程式就這麼簡單,不然通常都需要資料結構來支援。沒有資料結構的程式會很可怕,我曾經有聽過學弟寫了上千行的 IF-ELSE 語句來處理他的程式,老師希望他做一點小修改也完全沒辦法,因為牽一髮就要動全身,不僅工程費時debug困難,也極度缺乏彈性。

我發現新手工程師對於程式步驟的拆解沒什麼概念,所以寫程式不知道要從何著手,他們無法想像寫程式之前要把事情拆開來,再逐步寫成程式後整合起來。所以我想用旅遊計劃來比擬寫程式這件事情,也許比較不那麼抽像。沒有人天生懂得如何準備旅行,所以不懂如何拆解程式步驟也是很正常的,本篇文章名稱就暫時改成:「如何進行完美旅遊計劃」吧,Let’s Go !

最近打算跟朋友去東京旅遊,請問我該做些什麼?首先我準備一本筆記來記錄這次的旅遊計劃,標題就先寫上”目的地:東京”。如果在一個月後我跟朋友討論大阪的旅遊行程,應該會被他揍扁,所以我不能忘記此行是要去東京,而不是其它地方--這是我第一個要記下的。接下來要怎麼做呢?仔細想想,旅遊大致可以分成四件事來處理:交通、飲食、景點、住宿,把這四件事處理好,就可以完成一趟旅遊,所以我將旅遊拆成了這四個部份。對我來說,旅行最重要的是景點,在決定景點之後,才會陸續安排其它東西。不過實際出門的時候,我不可能從家裡瞬間移動至景點,一定是從交通工具開始;也就是說,在計劃階段的順序可能是”景點→住宿→飲食→交通”,可是在執行階段的順序卻可能是”交通→飲食→住宿→景點”,前者按重要程度排列,後者則是按流程排列。為什麼要先決定景點呢?因為根據想去的景點不同,安排的交通住宿也會不同,除非是鐵道之旅之類的,否則我想應該不會有人把交通擺在第一位。

我開始在網路上搜尋東京的熱門與私房景點,將它逐一記錄在筆記上,並且寫上我想去的程度有幾顆星。等到蒐集許多地點後,將它們灑在地圖上,並且根據想去的程度做不同的標記。透過地圖模式,我比較容易知道那些地點是接近的,可以安排在同一天的行程。這時候,我先不急著安排行程,而是先把住宿的旅館決定好,希望是在預算內,又不會離景點太遠。等旅館決定好之後,才會用交通工具將它們串起來。我對吃比較不重視,特別想吃的東西會放在景點區,其餘的就看路過地點是否有店家可以提供伙食,再去搜尋一下該地區的美食就好。我的旅遊計劃已經完成地差不多了。

Photo: Alwyn Ladell

回過頭來看我們的程式。首先,景點很重要,它有名稱、有地址、有我們的喜好程度,還有什麼屬性參數呢?關於景點的特徵,都是「資料」的一部份。當我們把它灑在地圖上,企圖安排行程將它們”串”起來時,它就會形成一個資料結構,因為它是有安排、有順序的,而不是零散地存在於網路上。例如台北、高雄…等等就只是個地名,當我想把台灣地圖存入電腦時,至少要將它們連結順序一併存入,否則電腦無法正確地呈現,總不能說電腦地圖畫出來,結果台北和高雄在隔壁吧?對程式設計師來說不在乎地名是什麼,而是他們之間連結的關係。所以為了讓行程安排順利,景點裡的”交通資訊”是很重要的,它其實不屬於景點的一部份,並且會隨著交通建設的更新而異動。這些可能看不見卻很重要的資料,我把它稱作控制資料。如同交通資訊(控制資料)會影響我們的行程,程式設計師撰寫的演算法就是要配合控制資料來運作。寫程式為什麼抽象就是這樣來的,我們不在意打印出來(看得見)的星星,只在意控制迴圈(看不見)的數字5。同樣都是變數(資料),但裡面儲存的可能是控制用的(交通),也有可能是單純呈現用的(景點),而程式設計師的重點就是在掌握這些控制變數。

如果你想去台北市政府(景點資料),它的交通資訊(控制資料)有台北捷運的藍線,或是各路公車。既然如此,你實際能選擇的交通方式(演算法)就必須配合其中一項。也就是說,必須先決定好資料結構(行程景點),才能決定使用什麼樣的演算法(交通)。好的資料結構(行程安排)可以讓演算法撰寫更簡便(減少交通時間),或是減少出錯的機率(塞車等意外),因此對程式設計來說,資料結構非常地重要。

寫程式應該先從定義資料結構開始。

以前學生時期就聽老師說,魔術方塊是一種資料結構,其實任何東西都是資料結構。當時聽不懂他的意思,等到有些經驗才終於明白,從看得到的實物到看不見的流程,只要你打算把它放進電腦裡,它就「必須」是個資料結構,否則電腦無法完成我們想要的工作。雖然這年頭會接API會接套件/框架就能搞出一些東西,但是對我而言,能夠定義資料結構的軟體工程師才是及格的。API其實就是一種資料結構,不過通常是後端工程師或系統分析師等替我們定義好的,而前端則是要針對UI/UX來定義資料結構。我們不必定義多麼複雜的結構,至少透過數值、布林值、陣列等來控制流程是很基本的,否則能夠做的事情非常非常地有限,勉強寫出來的程式也會面臨缺乏彈性、不好維護等問題。

Photo: TORLEY

從台灣家裡到東京旅館距離很遠,要換好幾種不同的交通工具才能抵達,所以我會先在網路上查看別人是如何搭車的,學習一下經驗再來決定自己要如何前往。這就有點像我們在觀摩別人的演算法一樣,要達成目的,程式的寫法可以有很多種,但你最後只會寫上其中一種。我可能會先搭公車轉火車到機場,搭飛機到日本後再搭他們的地鐵到旅館,這樣就能抵達目標。所以光是”出發”這個行程,就被我拆成四種不同的交通工具,並且有先後順序必須互相配合,這就是程式步驟的拆解。不可否認,拆解是需要經驗的。如果網路上沒有任何人分享過相關的行程,你沒有任何經驗就知道該如何搭這些交通工具嗎?當然,到了現場我們可以臨時反應,只是相對出錯的可能性就會比較大。

資料就像物品一樣只是靜止在那裡的東西,要讓它動起來就是要靠演算法。所以即使我閱讀部落客東京旅遊的遊記(將資料輸入腦袋),也不代表我去過東京旅遊。演算法就是我的旅行計劃,景點、飲食、住宿、交通有各自不同的重點,所以需要不同的演算法,有些可能要處理比較多的資料,有些可能要處理比較多的動作。例如交通就是一種流程控制,每個旅行點(功能)就是用交通串起來的。旅行計劃完成之後,如果將它躺在抽屜裡,我還是沒去過東京。必須要到實際去執行它時,才是真正地獲得東京旅遊的體驗。程式設計師就是那個寫計劃書分享給大家的人,享受遊玩體驗的就是使用者。

旅遊計劃書裡沒有安排景點、沒有計劃,這樣還稱得上旅遊計劃嗎?這就是為什麼我受不了有人說寫程式不需要資料結構、演算法的原因,那我真的不知道這些人寫的是什麼,聽起來很可怕,寫出來的程式一定很恐怖(不過我想多數情況應該是有,只是這些人不知道而已)。無論是定義資料結構,或是拆解程式步驟撰寫演算法等等,這些都需要經驗累積才能很好地執行。開源程式碼提供我們良好的學習管道,多參考別人如何定義資料、如何撰寫程式,等我們自己要使用時,才不會有「書到用時方恨少」的感覺。畢竟這些東西不需要死背,只要多看、看懂就好,耳濡目染就能有一些成果,對程式設計師來說是很好的投資。如果你希望專精程式設計,千萬別忘了跟網路上眾多優秀的工程師學習資料結構與演算法,然後有一天你會對自己撰寫的程式碼感到滿意,就如同寫了一份完美的計劃書那樣。


延伸閱讀