每個電腦科學專業的學生都應該知道些什麼?
每個電腦科學專業的學生都應該知道什麼?
“每個電腦科學專業的學生都應該知道什麼?”可以把這個問題作為四個問題的結合點來回答:
1.每個學生應該知道什麼才能找到一份好工作?
2.要維持終身就業,每個學生都應該知道些什麼?
3.進入研究生院應該知道什麼?
4.每個學生都應該知道什麼對社會有益?
投資組合與簡歷
從工程和數學畢業後,電腦科學專業採取了以簡歷為基礎的方法來招聘畢業生。簡歷並不能說明程式設計師的能力。每個電腦科學專業的學生都應該建立一個作品集。作品集可以像個人部落格一樣簡單,每個專案或成就都有一個帖子。一個更好的投資組合應該包括每個專案的頁面和可公開瀏覽的程式碼(可能託管在github或谷歌程式碼上)。對開源的貢獻應該被連結和記錄。程式碼組合允許僱主直接判斷能力。gpa和簡歷就不一樣了。教授應該設計課程專案來給作品集留下深刻印象,而學生在每門課程結束時,應該花時間更新它們。
技術交流
電腦科學中的獨狼是一種瀕臨滅絕的物種。現代電腦科學家必須有說服力地、清晰地向非程式設計師傳達他們的想法。在小公司裡,程式設計師是否能把自己的想法傳達給管理層,可能會決定公司的成敗。不幸的是,僅僅增加一門課程並不能解決這個問題(儘管一門紮實的技術交流課程不會有什麼壞處)。更多的課程需要為學生提供機會來展示他們的作品,並通過口頭陳述來捍衛他們的觀點。
具體建議
我建議學生掌握一種演示工具,比如PowerPoint或(我最喜歡的)Keynote。(抱歉,儘管我很喜歡它們,但基於latex的表示工具太靜態了。)在生成漂亮的數學文件方面,LaTeX無與倫比。所有技術課程的書面作業都應以LaTeX提交。
一個工程的核心
電腦科學並不完全是工程學。但是,已經足夠接近了。電腦科學家會發現他們與工程師一起工作。電腦科學家和傳統工程師需要講同一種語言,一種植根於真實分析、線性代數、概率和物理學的語言。電腦科學家應該通過電磁學學習物理學。但是,要做到這一點,他們需要通過多元微積分(和微分方程的良好測量)。在構建聲音模擬時,掌握概率和(通常)線性代數是非常寶貴的。在解釋結果時,沒有什麼可以替代對統計資料的堅實理解。
Unix哲學
電腦科學家應該熟悉並實踐Unix計算哲學。Unix哲學(與Unix本身相反)是一種強調語言抽象和組合以影響計算的哲學。實際上,這意味著要熟悉命令列計算、文字檔案配置和無ide軟體開發的概念。
具體建議
鑑於Unix系統的普及,電腦科學家今天應該精通基本Unix,包括以下能力:導航和操作檔案系統;用管道組成流程;舒適地編輯檔案與emacs和vim;為軟體專案建立、修改和執行Makefile;編寫簡單的shell指令碼。如果學生不理解Unix的強大功能,他們就會拒絕它。因此,最好讓學生完成Unix具有相對優勢的有用任務,例如:在給定的目錄中查詢佔用最多空間的五個資料夾。在計算機上報告mp3的副本(按檔案內容,而不是檔名)。取一個名字和姓氏都是小寫字母的名單,並適當調整其資本結構。找出英語中所有以x為第二個字母,以n為倒數第二個字母的單詞。直接將你的麥克風輸入通過網路傳送到另一臺電腦的揚聲器。為給定的目錄用下劃線替換檔名中的所有空格。報告來自特定IP地址的對web伺服器的最後10次錯誤訪問。
系統管理
一些電腦科學家嘲笑系統管理是一項“IT”任務。人們的想法是,電腦科學家可以自學技術人員能做的任何事情。這是正確的。(在理論上)。然而這種態度是錯誤的:電腦科學家必須能夠勝任並安全地管理他們自己的系統和網路。軟體開發中的許多工無需經過系統管理員就可以高效地執行。
具體建議
每個現代電腦科學家都應該能夠:安裝和管理Linux發行版。配置和編譯Linux核心。故障排除與挖掘、ping和traceroute的連線。編譯和配置web伺服器,比如apache。編譯和配置一個類似於bind的DNS守護程式。使用文字編輯器維護web站點。切斷和捲曲網路電纜。
程式語言
程式語言隨著太陽週期的變化而變化。程式設計師的職業不應該如此。雖然教授與僱主相關的語言很重要,但學生學會如何自學新語言同樣重要。學習如何學習程式語言的最好方法是學習多種程式語言和程式設計範例。學習第n種語言的困難是第n-1種語言困難的一半。然而,要真正理解程式語言,就必須實現一種語言。理想情況下,每個電腦科學專業的學生都應該參加一個編譯班。至少,每個電腦科學專業的學生都應該配備一名口譯員。以下語言提供了範例和實際應用的合理組合:
Racket;
C;
JavaScript;
Squeak;
Java;
Standard ML;
Prolog;
Scala;
Haskell;
C++; and
Assembly.
Racket語言
Racket作為一種功能齊全的Lisp方言,有著非常簡單的語法。對於一小部分學生來說,這種語法是一種障礙。坦率地說,如果這些學生有一個基本的心理障礙來接受一個陌生的語法體系,即使是暫時的,他們缺乏在電腦科學的職業生涯中生存下來的心智靈活性。Racket
強大的巨集系統和用於高階程式設計的裝置徹底消除了資料和程式碼之間的界限。如果教得正確,Lisp會解放。
C語言
C是對矽的簡潔而無情的抽象。在嵌入式系統程式設計方面,C仍然是無可匹敵的。學習能以一種其他語言都無法做到的方式,對馮•諾依曼的主流架構給予深刻的理解。考慮到較差的C程式設計在緩衝區溢位安全漏洞的普遍存在中所起的密切作用,程式設計師學習如何正確地程式設計C是至關重要的。
JavaScript
JavaScript是流行於動態、高階語言(如Python、Ruby和Perl)中的語義模型的良好代表。作為網路的母語,其語用優勢是獨特的。
Squeak
Squeak是Smalltalk的一種現代方言,是最純粹的面嚮物件語言。它賦予了“面向物件”的本質。
Java
Java將繼續流行太久而不能忽視它。
Standard ML
Standard ML是一個乾淨的體現後端-米爾納系統。後端-米爾納式系統是現代計算機領域最偉大(但鮮為人知)的成就之一。雖然複雜程度呈指數級增長,但對人類感興趣的程式來說,後文-米爾納的型別推斷總是很快的。型別系統足夠豐富,可以表達複雜的結構不變數。它是如此豐富,事實上,良好型別的程式通常是沒有bug的。
Prolog
雖然邏輯程式設計在應用中很特殊,但它是計算思維的另一種正規化。對於那些程式設計師可能需要在另一種正規化中模擬它的例項,理解邏輯程式設計是值得的。另一種值得學習的邏輯語言是miniKanren。miniKanren強調純(切不允許)邏輯程式設計。這個約束已經演化出一種被稱為關係程式設計的邏輯程式設計風格,它授予Prolog程式通常不喜歡的屬性。
Scala
Scala是函數語言程式設計語言和麵向物件程式語言的完美融合。Scala就是Java應該有的樣子。它構建在Java虛擬機器之上,與現有的Java程式碼庫相容,因此,它是Java最可能的繼承者。
Haskell
Haskell充分利用了惰性,在任何主要程式語言的純數學中都與程式設計最接近。
C + +
c++是一種必要的邪惡。但是,既然它必須被教授,它就必須被全面地教授。特別是,電腦科學專業的學生應該掌握甚至模板超程式設計。
Assembly
任何組合語言都可以。因為x86很流行,所以最好是這樣。學習編譯器是學習彙編的最好方法,因為它讓電腦科學家直觀地瞭解高階程式碼將如何轉換。
具體建議
電腦科學家應該理解生成程式設計(巨集);詞彙(和動態)範圍;閉包;延續;高階函式;動態排程;子型別化;模組和子;單子作為不同於任何特定句法的語義概念。
離散數學
電腦科學家必須對形式邏輯和證明有紮實的掌握。通過代數操作和自然推演的證明與常規程式設計任務具有相同的推理。歸納法的證明採用了遞迴函式構造的推理方法。電腦科學家必須精通形式數學表示法,嚴格地推理基本的離散結構:集合、元組、序列、函式和冪集。
具體建議
對於電腦科學家來說,很重要的一點是:
樹木;圖;正式的語言;和自動機。學生應該學習足夠多的數字理論來學習和實現常見的密碼協議。
資料結構和演算法
學生當然應該看到常見的(或罕見的但不合理有效的)資料結構和演算法。但是,比了解特定的演算法或資料結構(這通常很容易查詢)更重要的是,電腦科學家必須瞭解如何設計演算法(例如,貪婪的動態策略),以及如何跨越演算法的理想和實現的實質之間的差距。
具體建議
至少,尋求長期穩定就業的電腦科學家應該知道以下幾點:雜湊表;連結串列;樹;二叉搜尋樹;有向圖和無向圖。
電腦科學家應該準備好實現或擴充套件對這些資料結構進行操作的演算法,包括搜尋元素、新增元素和刪除元素的能力。為了完整起見,電腦科學家應該知道每種演算法的強制性版本和功能性版本。
理論
掌握理論知識是研究生學習研究的先決條件。當理論在一個問題上提供了嚴格的界限時(或者當它提供了一種繞過最初看起來是嚴格界限的方法時),它是無價的。計算複雜性可以合法地聲稱是所有計算機“科學”中為數不多的真正預測理論之一。
電腦科學家必須知道可處理性和可計算性的界限在哪裡。忽視這些限制會在最好的情況下招致挫折,在最壞的情況下招致失敗。
具體建議
在本科階段,理論至少應該涵蓋計算模型和計算複雜度。計算模型應該包括有限狀態自動機、正則語言(和正則表示式)、下推自動機、上下文無關語言、形式語法、圖靈機、lambda演算和不可判定性。
在本科階段,學生至少應該學習足夠的複雜性來理解P、NP、NP- hard和NP- complete的區別。為了避免給學生留下錯誤的印象,學生應該通過減少SAT和使用現代SAT求解器來解決NP中的一些大問題。
體系結構
對計算機體系結構的紮實理解是無可替代的。電腦科學家應該從電晶體上理解計算機。
對架構的理解應該包括標準的抽象層次:電晶體、門、加法器、軟線、人字拖、ALUs、控制單元、快取和RAM。在可預見的未來,理解高效能運算的GPU模型將很重要。
具體建議
對快取、匯流排和硬體記憶體管理的良好理解對於在現代系統上獲得良好的效能至關重要。
為了更好地掌握機器架構,學生應該設計和模擬一個小CPU。
作業系統
任何足夠大的程式最終都會成為一個作業系統。因此,電腦科學家應該知道核心如何處理系統呼叫、分頁、排程、上下文切換、檔案系統和內部資源管理。對作業系統的良好理解僅次於對編譯器和實現效能的體系結構的理解。
在編寫沒有執行時系統的嵌入式系統時,理解作業系統(我將大量地將其解釋為包括執行時系統)變得尤為重要。
具體建議
對學生來說,動手操作一個真正的作業系統是很重要的。有了Linux和虛擬化,這比以往任何時候都要容易。為了更好地理解核心,學生可以:在引導過程中列印“hello world”;
設計自己的排程器;修改頁面處理策略;建立自己的檔案系統。
網路
鑑於網路的普遍性,電腦科學家應該對網路中的網路堆疊和路由協議有一個明確的瞭解。在不可靠的傳輸協議(如IP)之上構建高效、可靠的傳輸協議(如TCP)的機制對電腦科學家來說並不神奇。它應該是核心知識。電腦科學家必須瞭解協議設計中涉及的權衡——例如,何時選擇TCP,何時選擇UDP。(程式設計師需要了解大規模使用UDP對擁塞的更大社會影響。)
具體建議
考慮到現代程式設計師接觸網路程式設計的頻率,瞭解現有標準的協議是很有幫助的,例如:
802.3和802.11;IPv4和IPv6;和DNS, SMTP和HTTP。電腦科學家應該理解包衝突解析度的指數迴歸和擁塞控制中的加法-乘法-減法機制。
每個電腦科學家都應該實現以下目標:HTTP客戶端和守護程序;一個DNS解析器和伺服器; 命令列SMTP郵件程式。任何學生都不應該在通過初級網路課程時不嗅探他們導師的谷歌問題。要求所有的學生從頭開始在IP上實現一個可靠的傳輸協議可能有點太過了,但我可以說,對我這樣的學生來說,這是一次個人的變革性體驗。
安全
安全的可悲事實是,大多數安全漏洞來自草率的程式設計。更可悲的事實是,許多學校在培訓程式設計師確保程式碼安全方面做得很差。電腦科學家必須意識到程式被破壞的方法。他們需要培養一種防禦性的程式設計意識——一種思考如何攻擊自己程式碼的意識。安全是一種最好在整個課程中分佈的培訓:每個學科都應該警告學生其固有的弱點。
具體建議
至少,每個電腦科學家都需要了解:社會工程;緩衝區溢位;整數溢位;程式碼注入漏洞;競態條件; 特權的困惑。
一些讀者指出,電腦科學家還需要了解基本的IT安全措施,比如如何選擇合法的好密碼,以及如何使用iptables正確配置防火牆。
密碼學
密碼技術使我們的數字生活成為可能。電腦科學家應該理解並能夠實現以下概念,以及實現這些概念的常見缺陷:對稱金鑰密碼體制;公鑰密碼機制;安全雜湊函式;質詢-響應身份驗證;數字簽名演算法;和閾值密碼。由於這是加密系統實現中的一個常見錯誤,每個電腦科學家都應該知道如何為手頭的任務獲取足夠的隨機數。至少,正如幾乎每一次資料洩露都表明的那樣,電腦科學家需要知道如何對儲存密碼進行加密和雜湊。
具體建議
每一個電腦科學家都應該享受使用手工統計工具破解前現代密碼系統破解密文的樂趣。RSA很容易實現,每個人都應該這麼做。每個學生都應該建立自己的數字證書,並在apache中設定https。(要做到這一點,難度驚人。)學生還應該編寫一個通過SSL連線的控制檯web客戶機。
作為嚴格的實際問題,電腦科學家應該知道如何使用GPG;如何對ssh使用公鑰身份驗證;以及如何加密目錄或硬碟。
軟體測試
軟體測試必須分佈在整個課程中。一門關於軟體工程的課程可以涵蓋測試的基本風格,但沒有什麼可以替代實踐的藝術。學生應該根據他們提交的測試用例來打分。我用學生提交的測試用例與其他所有學生進行對比。學生們似乎不太關心防禦性測試用例的開發,但當涉及到向同學們扔沙袋時,他們就會大發雷霆。
使用者體驗設計
程式設計師經常為其他程式設計師編寫軟體,或者更糟,為他們自己編寫軟體。使用者介面設計(或者更廣泛地說,使用者體驗設計)可能是電腦科學中最不受重視的方面。甚至在教授之間也存在一種誤解,認為使用者體驗是一種無法傳授的“軟”技能。在現實中,現代使用者體驗設計是建立在人類因素、工程設計和工業設計的經驗主義基礎上的。如果沒有別的,電腦科學家應該知道,介面需要使執行任何任務的輕鬆程度與任務的頻率乘以任務的重要性成正比。作為一種實用性,每個程式設計師都應該熟悉用HTML、CSS和JavaScript設計可用的web介面。
視覺化
好的視覺化是將資料以一種人類認為是資訊的方式呈現出來。這不是一件容易的事。
現代世界是資料的海洋,利用人類感知的區域性最大值是理解它的關鍵。
並行性
平行度又回來了,而且比以前更醜。不幸的事實是,利用並行需要對架構有深入的瞭解:多核、快取、匯流排、gpu等等。而且需要實踐和大量的練習。
具體建議
目前還不清楚並行程式設計的“最終”答案是什麼,但已經出現了一些領域特定的解決方案。
目前,學生應該學習CUDA和OpenCL。執行緒對於並行性來說是一個脆弱的抽象,特別是當涉及到快取和快取一致性時。但是,執行緒是流行和棘手的,所以值得學習。Pthreads是一個值得學習的可移植執行緒庫。對於任何對大規模並行性感興趣的人來說,MPI是一個先決條件。
在原則方面,map-reduce似乎是持久的。
軟體工程
軟體工程中的原則變化速度與程式語言一樣快。在團隊軟體構建的實踐中,一個好的實踐課程提供了關於工作中固有缺陷的工作知識。幾位讀者建議學生分成三個小組,由三個不同的專案輪流擔任組長。學習如何攻擊和操縱現有的大量程式碼庫是大多數程式設計師必須掌握的技能,這是在學校而不是在工作中最好的學習方法。
具體建議
所有學生都需要了解像svn這樣的集中版本控制系統和像git這樣的分散式版本控制系統。gdb和valgrind等除錯工具的工作知識在最終會對我們的工作大有幫助。
正式的方法
隨著對安全可靠的軟體需求的增加,正式的方法最終可能成為交付它的唯一手段。
目前,軟體的正式建模和驗證仍然具有挑戰性,但該領域的進展是穩定的:它每年都變得越來越容易。在今天電腦科學專業的學生的一生中,甚至可能會有一天,正式的軟體構建是一種預期技能。每個電腦科學家至少應該適度地使用一個定理證明程式。(我認為哪一個並不重要。)學習使用定理證明程式直接影響編碼風格。
例如,一個人會本能地對寫一個不能涵蓋所有可能性的匹配或切換語句過敏。而且,在編寫遞迴函式時,定理證明程式的使用者強烈希望消除錯誤。
軟體基礎。
圖形和模擬沒有比圖形學更被“聰明”所主導的學科了。這個領域被驅使著,甚至被定義為“足夠好”。因此,沒有比圖形和模擬更好的方法來教聰明的程式設計或對優化工作有紮實的瞭解。我學到的程式設計技巧中有一半以上來自我對圖形學的學習。
具體建議
簡單的射線跟蹤器可以在100行程式碼中構建。線上框圖3D引擎中進行透視3D投影是很好的心理衛生。BSP樹這樣的資料結構和z-buffer呈現這樣的演算法都是聰明設計的好例子。在圖形和模擬中,還有更多。
機器人
機器人技術可能是最吸引人的介紹程式設計的方法之一。此外,隨著機器人技術成本的持續下降,人們正在通過一項門檻,這將引發一場個人機器人技術革命。對於那些會程式設計的人來說,難以想象的個人物理自動化程度即將到來。
人工智慧
如果僅僅因為它對早期計算機歷史的巨大影響,電腦科學家就應該研究人工智慧。
雖然智慧機器最初的夢想似乎還很遙遠,但人工智慧刺激了許多實踐領域,如機器學習、資料探勘和自然語言處理。
機器學習
除了其突出的技術優勢外,“相關性工程師”職位空缺的數量表明每個電腦科學家都應該掌握機器學習的基本知識。機器學習加倍地強調對概率和統計的理解。
具體建議
在本科階段,核心概念應該包括貝葉斯網路、聚類和決策樹學習。
資料庫
資料庫太普通,太有用,不容忽視。理解為資料庫引擎提供動力的基本資料結構和演算法是很有用的,因為程式設計師經常在較大的軟體系統中重新實現資料庫系統。在計算的子圖化模型中,關係代數和關係演算是非常成功的例子。與UML建模不同,ER建模似乎是一種視覺化編碼軟體工件設計和約束的合理機制。
具體建議
一個電腦科學家,可以建立和操作一個燈泡堆疊是一個好主意和很艱苦的工作,而不是經營自己的公司。
歡迎關注我的微信公眾號:AlbertYang
(文章來源http://matt.might.net/articles/what-cs-majors-should-know/)