一個資工系/所學生畢業該具備甚麼技能?一個資工所畢業的研究生該具備甚麼技能?
除了專業科目所學的知識,我想好好來討論一下資工系所該具備的「基本素養」。

前言

我大學不是念資工,而是研究所才念。在研究所之前,我學程式的路徑是非典型的 (可參考〈對資工的興趣產生〉),我大一時藉由學長提點對寫程式開始有興趣,接著靠自學摸索大部分入門知識,然後有機會去好幾家軟體公司實習,也有貢獻開源社群,一直到大三下、大四上我才真正去修資工系的課,直到研究所才真的成為「本科生」。

因為這種特殊的學習路徑,所以讓我得以觀察同學之中,不少缺乏我覺得很重要的基本素養,我覺得資工系/所學生如果畢業之前沒有養成這些素養的話很可惜。為免遭老王賣瓜之嫌,我承認這些基本素養我也缺乏一些,所以也警惕自己要好好養成。

我所認為的基本素養包含 5 點:

  • 程式開發與除錯技巧
  • 良好的程式開發習慣與風格
  • 閱讀程式碼的能力
  • 程式開發的協作與流程
  • 關於電腦的一切基本知識

除本文外,同時可以參考我的教學影片「拯救資工系學生的基本素養」系列

程式開發與除錯技巧

程式開發我想不用多說,寫程式大家都會,但是要寫得好卻很困難,我覺得既然身為資工系學生,就要把寫程式的能力練好,C++、Python、JavaScipt 等語言盡量熟悉其特性,閒有餘力多參考一些進階的書,像是《C++ Primer》、《Effecitve C++》、《Effective Python》等書,搜尋一下就會有很多大神分享他們獨門書單了。不僅僅如此,程式寫得好還要有各種知識的結合,包含善用標準函式庫 (STD)、資料結構演算法、設計模式 (Design Pattern) 等。

同學之中一定不乏 C++ 高手令人望塵莫及,精熟各種語言特性,甚至可以當別人的 Spec,我想要變成這種「神人」太困難了,不至於需要如此,但據我了解好一點的公司,同事對語言的掌握度都很高,更何況是一輩子用來吃飯的工具,所以要期許自己也可以把語言練得滾瓜爛熟吧!

寫程式一定難免碰到 Bug,這時候你逃都逃不掉,有時候 Debug 好幾天真的想叫人做死。要怎麼去除錯呢?還在用各種 print 嗎?學會用除錯工具,甚至有技巧的使用除錯工具可以讓程式開發更順利,不是一定要學 GDB,現在 IDE 都有很好的除錯工具,反正概念都一樣,只要能達到目標就好。

使用 print 固然方便又簡單,但如果你能用除錯工具下中斷 (Breakpoint),你可以更容易得到你想要的資料,像是從中斷點回朔 (Backtrace) 一層一層的程式片段 (Frame) 去觀察指標和數值傳遞的變化,聽起來效率是不是比較高?怎樣快速判斷哪裡才是 Bug 的來源就是功力所在啦!

最後善用各種開發工具,好的文字編輯器 (我都用 VSCode) 或是整合開發環境 (IDE),搭配好用的各種外掛,像是自動分析、自動排版、語法建議、自動補完等等。可能也要學會在不同平台上各自最適合的工具,因為 Windows、macOS、Linux 都會有機會在上面開發。很建議把 Vim 學會 (Emacs 勿戰🤣),因為就算平時都可以有 IDE,在一些時刻還是需要你直接在 Server 上修改 Code,那用 Nano 可能會有點不方便?!

良好的程式開發習慣與風格

有句話說,沒寫過十萬行程程式碼,不算資工系學生。其實我滿懷疑這句話的,照學校的作業量大概難以達到吧,不過換個角度想,俗話說 10000 小時可以養成一個專家,這個時間大概就是十萬行程式碼了。但千萬不是雜亂無章只求能跑的程式碼,寫好的程式碼才有意義。

良好的程式習慣和風格又可以稱做簡潔程式碼 (Clean Code),你寫的 Code 不見得只有你要看,同時還要讓別人一目了然,也要讓自己在幾年後看不會一臉茫然,漂亮的程式碼可以不用註解卻讓人一看就懂。

程式撰寫方法也關係到好不好寫測試,沒有規劃好的程式碼會非常難做測試,為此甚至還有測試驅動開發 (Test Driven Development, TDD) 的概念出現。不是一定要做 TDD,但隨時去想自己寫的程式碼未來好不好寫測試,容不容易去除錯,如果答案為否,那代表習慣和風格還要改進。

良好的程式寫作習慣的養成,可以透過不斷看高手的程式碼,去不斷思考和自己的差異處,也可以去看像是《Clean Code》之類的書,直接去看錯誤範例的修正方法來學習。

閱讀程式碼的能力

平常作業或是自己的小專案,程式碼大概都不過百行,頂多千行。可是多數知名開源專案都是大專案,程式碼動輒幾十萬幾百萬行,一般的軟體公司開發出來的成熟軟體的規模也是幾百萬行等級,這種時候你要怎辦?

當想要查 Linux 的 pthread 的機制,甚至做系統相關的程式開發,想要改一點 Linux 的原始碼 (Source Code),勢必得先看得懂 Linux 裡面在幹嘛,Linux 本身就有幾百萬行程式碼。Chromium 是知名開源瀏覽器引擎,很多瀏覽器和應用程式採用其核心,那麼去這些用 Chromium 當基礎的公司上班一定也要會看 Chromium 的原始碼。這兩個例子說明,去碰大專案的機率很高,那麼要那麼要如何快速找到跟目標有關的程式碼,看懂程式運作的流程和上下關係,就是要練習的部分。

說明一下厲害的工程師在這方面的比現如何,我之前貢獻 Servo 專案大約是十萬行程式碼的專案,有一個新的貢獻者在第一次貢獻就直接修改一個模組,當我第一次貢獻才改幾行,他已經看懂這不小的專案,掌握如何修改並貢獻了約一千行程式碼。

關於怎樣養成這方面能力,可以從比較小的專案開始練習,慢慢把規模擴大去體會專案規模不同時,程式架構和配置的變化。這篇文章〈在 Linux 理解大型 C/C++ 專案的輔助工具〉也可以參考看看,主要是講那些工具可以幫助你。不過最重要的還是多練習和多觀察。

程式開發的協作與流程

我在進資工所之前,先在好幾間公司實習過,又有參與不少開源專案,所以我對軟體開發流程和共同開發非常熟習。軟體公司中,使用 Git + Github Like 的版本控管開發流程是基本,然後還要搭配寫測試、品質控管、佈署等等。資工系學生最後總是要出去軟體公司上班,也不預期公司會教或培訓,所以還是先學會的好。

版本控管有很多,但主流已經是 Git + Github。學會 Git 有甚麼好處?自己開發的專案可以做版本管理,不小心搞砸了專案可以回到上一版。跟別人一起開發專案時,可以透過 Git 來合併程式碼,共同開發千萬不要再用打包 zip 互相分享啦!

怎樣用 Git 來做 git clonegit commitgit pushgit branchgit checkoutgit merge 都是 Git 基本中的基本。然後至少知道怎樣在 Github 上 fork 專案然後發 Pull Request。因為太多同學 (不管我在台大還是交大) 都不知道怎樣使用這套流程,偏偏又常常要團體開發或是教導助教課學生,所以我之後打算好好寫個教學。

關於寫測試我覺得是好習慣,你怎麼知道你每次改的程式碼都會動?每次改動程式碼都經過測試驗證可以增加你對程式碼的信心度。但也不代表保證你寫的測試就不會有漏掉檢查的 Case,所以測試也要不斷更新。關於測試有太多學問了,單元測試、整合測試、E2E 測試、QA 測試等,請有興趣讀者可以搜尋更多資料來了解。

此外持續整合/持續開發 (CI/CD) 可以說是軟體開發老生常談的關鍵字,大家有興趣也可以去了解一下。

關於電腦系統的一切基本知識

電腦和程式語言就像刀與刃,我們程式既要寫得好 (刃要利),也要懂得電腦各種知識 (刀要軔)。計算機概論、計算機組織、計算機網路、作業系統、演算法、資料結構,只要是資工系學生都學過,這些都是一個資工系所學生該具備最重要的利器,在解決問題時常常要回歸最基本的原理或系統底層架構。

如果能懂其他資工相關知識,自然語言處理、機器學習、電腦圖學、電腦視覺、編譯器原理、異質運算、網路安全等等,還有太多太多了,我想都有機會用上這些知識吧,就算用不上,了解這些科學原理增廣見聞也是一件趣事。

結論

我在本文提了好幾個核心能力,分別是程式開發與除錯技巧、良好的程式開發習慣與風格、閱讀程式碼的能力、程式開發的協作與流程、關於電腦的一切基本知識。我非常欽佩一些知名的電腦科學家、軟體工程師或資工系教授,期許自己也能和他們一樣厲害,我想首先我要把這些基本素養都學好。

我不希望這篇被誤解成我對現狀的批判,我提出這些基本能力都是我實際經歷的痛。我在貢獻開源專案時花了超多時間因為不會用 Git 遭到糾正和退件;我在 C 公司纏著同事不少時間才學會用 GDB,後來我發現以前不會用真的太傻了;我在 S 公司浪費同事許多寶貴時間教導才真的熟練用 Vim,發現很多機會能用 Vim,打 Commit log 也會用到;我在實習了好多家公司之後,發現我因為不是資工系出身,對資工專業知識的認識太低,太多東西不會而有自卑感,同時也對程式語言掌握度太低,寫出來的東西都比別人差很多。

有太多東西是「早知道如此」了,我討厭那種被別人嫌棄覺得你很廢很弱的感覺,相信大家也不想,那何不不再早知道呢?

本篇也用來勉勵各個資工系所的學生,此外讀者也不限於資工學生,任何想要踏進資工領域的人也可以參考我所列述的這幾項能力。希望大家可以一起進步!