如何有效學習電腦

Aug 2001 重新整理
(另有 講稿摘要版 內容大致相同, 但有更多圖示。)


我很喜歡玩電腦, 也覺得學電腦是一件很愉快的事。 對於時下主流的電腦補習課程 (甚至是學校的某些電腦操作課程) 的教/學方式, 我有很不一樣的意見。 不論你是不是資訊科系, 如果你喜歡學活的, 長久有用的知識, 不喜歡死記/機械化地操作, 那麼這篇稿子也許可以獲得你的共鳴。 特別是習於解析/建構的理工科系同學, 習於分析文法/造複合句的外語同學系, 如果你採納我的意見, 所培養出來的 「資訊素養」 很可能會超過那些繳了許多電腦學費的朋友, 甚至超過某些只會拉選單的資訊科系學生。

培養組合的力量, 讓新舊知識發揮相乘的效果

經常聽到資訊相關科系的學生抱怨 "長江後浪推前浪, 前浪死在沙灘上": 大一時所學的軟體到了大四就快退流行了; 剛畢業的學弟妹比當完兵回來的學長更符合軟體公司的專長需求。 原因是軟體工具的汰舊換新太快了。 資訊人的「成就階梯」真的必須每兩三年重新歸零一次嗎?

筆者邀請大家想想看我們是如何學國文, 英文, 數學的。 有多少人可以 出一百萬個英文句子呢? 但是看過以下提示後, 有高中英文程度的讀者, 應該都知道如何 出一百萬個英文句子:

四則運算用到多少符號, 又能解決多少類不同的問題? 出售 100 種不同食品的自動販賣機需要用幾個按鈕來操縱? 火車站的自動售票機有幾個按鈕, 又能印出多少種不同的票? 樂高積木有多少種元件, 又能組合出多少種不同的作品? 裝潢師的工具有限, 為什麼卻可以創造出那麼多種不同的室內景觀?

[那一種學習曲線值得長遠投資?]

筆者在學習軟體時, 喜歡挑那些與其他軟體溝通良好, 有很通暢的資訊接駁管道 (姑且稱之為「高組合性」) 的軟體: 這套軟體是否可以在各種不同的軟硬體平臺使用? 是否可正確讀/寫公開檔案格式? 是否全力支援公開通信協定? 所以我兩年前學一套具有 5 個功能的軟體, 一年前再學一套具有 5 個功能的軟體, 今年又學一套具有 5 個功能的軟體, 最後可以解決的問題不是 15 個, 而是 125 個。 另一方面, 有些軟體強調的是花俏, 操作簡單, 多功能聚集於一身, 但卻忽略甚或 刻意阻絕 與其他軟體接駁資訊的管道 -- 我們姑且稱之為「低組合性」的軟體。 我那些學習低組合性軟體的同儕, 或許一開始很快就會覺得有成就感; 但是經年累月下來, 我解決問題的能力卻是隨時間成指數曲線成長, 最後遠遠超過他們! 當然上述情況有點理想化過頭; 但是讀者應該可以了解筆者這個誇張的比喻所要強調的重點: 學習組合軟體, 需要記的東西少; 可以用的場合多

學習高組合性軟體還有另外一個優點。 資訊科技進步迅速, 而資訊市場更是變化驚人, 我們很難預測那些軟硬體未來會有較佳的就業市場。 學一套多功能聚集於一身但與他人溝通不良的「萬能」軟體, 就像是把所有的雞蛋放在同一個籃子裡一樣危險。 反之, 學習一群組合性高的軟體, 當中如果有元件退流行了, 我們只需要重新學習一個元件就好了, 因為這個新元件可以與其他沒有變動的舊元件組合使用。 我們對於環境變化的適應力會強很多。 家庭劇院當中的 LD 要升級成 VCD, 需要把喇叭和電視一起換掉嗎? 舊電燈想改用省電燈泡, 需要把燈體一起換掉嗎? 有人說學 Linux 的人都是高手, 所以把他們丟到 MS Windows 的環境下他們還是 活得下去; 反過來就不一定了。 我認為學 Linux 的人未必真的有多厲害, 但他們習慣選用跨平臺, 高組合性的軟體, 適應力自然比只習慣 Wintel/Office/VB 文化的人來得強。 如果將來出現一個更高強的新作業系統來取代兩者, 猜猜看那一個族群的人會先被淘汰? 文書處理, 程式語言, 資料庫..。 亦是如此。 學習組合軟體, 比較不怕資訊科技快速變化

附帶而來的好處, 就是 學習組合軟體, 知識的壽命長, 經驗可以累積。

[數學組合軟體]

[網路組合軟體]

能夠拿來與其他知識組合運用的知識, 才是投資報酬率高, 生命週期長的知識。 眼光放遠, 慎選所學軟體, 培養組合能力, 讓你的新知識與舊知識發揮相乘的效果, 讓生產力曲線成指數成長! (感謝 GNU 文件的啟發, 本文觀念來自 info -f textutils "Opening the software toolbox" 一節; 也請參考我的 linux 講義當中 「組合的力量」 當中的具體操作實例.)

多用程式, 少寫程式

把組合的觀念用在個人的知識, 我們會將自己的舊知識盡量拿出來重複使用; 同樣的觀念用在人類的集體知識, 我們應該盡量使用既有的程式來解決我們的問題, 也就是要 "站在前人的肩膀上", 而不要一直 "重新發明輪子", 甚或像某些軟體公司一樣, 老是 "踩在前人的腳趾頭上"。

著手寫程式 之前, 你可曾用心地從下列資源當中 尋找可用的程式, 來減輕你的工作份量?

  1. 手邊現成的應用軟體。
    要把 X-Window 上的某個視窗印出來嗎? RedHat 或 CLE 的 CD 上本來就有一個 xwpick 可以用 (轉換檔案格式要配合 libgr-progs 內的工具)。 要限制部分網頁的瀏覽權限? 在 apache 內只要設定數個 Auth* directives 就可以了, 不必寫 cgi 程式。 要把整個目錄下所有的 .php 檔改成 .html 檔? 可以用 find 和 sed 啊! (對不起, 我只舉得出 Linux 上的例子; 不過我相信 MS Windows 下的程式一樣還有許多待人發掘的特異功能; 你知道光是 MS Word 的巨集功能就可以做多少與文書處理不相關的事嗎?)
  2. 網路上現成的應用軟體。
    Linux Software Map 內或許可以找到你要的程式, 甚至已有 現成的 rpm 檔 可以直接拿來使用。 (自己編譯核心或應用程式當然也是一個很好的練習方式; 但初學者為了趕快上手多用編譯好的程式不也是 "站在前人的肩膀上" 嗎?) 要把你的 html 檔案好好地整理乾淨? 有 tidy 可以用。 要作複雜的線性代數, 甚至迴歸分析或統計學的運算? 何不試試 octave 或 rlab 以及 R。 要畫 (離散數學當中的) graph 嗎? dia, xfig 和 angela! 都可以的。
  3. 你所使用的語言內所附的標準程式庫。
    要用 C 語言排序嗎? 在 stdlib 當中有 qsort。 要用 C++ 寫 symbol table 嗎? 在 STL 當中的 map 就是為此而設計的。 要用 perl 寫 CGI 程式嗎? 何不直接 use CGI;
  4. 現成的外掛程式庫。
    要在文字模式下移動遊標, 改變顏色, ...? 不妨試試 ncurses。 要寫漂亮的圖形界面? 只要你選用的語言不是一個 evolutionary deadend, 一定可以與 Tk 連結。 剛才矩陣運算的問題, 如果真的有必要在這麼低階的層次做的話, 可以考慮 libblas, liblapack, ..。 等等。 要把程式目前的狀態存入檔案中嗎? 在 perl 內有 Data::Dumper 可以用。

而且所謂 "可用的程式" 可能遠比我們想像的更要無所不在。 很多時候限制一個軟體使用範圍的, 可能不是程式本身, 而是使用者的想像力與對該軟體的了解。 C 的標準程式庫當中既已提供了 qsort, 實在不需要再自己重寫排序程式; 眾多應用程式都支援 regular expression, 有很多場合實在不需要再用滑鼠辛苦地重複剪貼工作。 尤其像是 perl 這類 scripting language, 乍看之下似乎與我們要解決的問題無關, 但事實上卻經常是最簡單的 "可用程式"。 例如想要分析一天當中, 每個小時上我們網站的人次, 可以下:

        perl -ne 'print "$1\n" if /:(\d+):/' /var/log/httpd/access_log > x
        sort x | uniq -c | perl -pale '$_=join " ", reverse @F' > y
然後進入 gnuplot
        set style data lines
        plot "y"

就完成了。 究竟多花一些時間寫程式比較值得呢? 還是多花一些時間學程式比較值得呢? 學寫完整的程式容易呢? 還是學程式容易呢? (註: 嚴格來說應該只計算讀取成功的部分。 上例中比對字串處應修改如下: ..。 if /:(\d+):.*"(GET|POST).*?"\s+200\s/ ..。 但再怎麼改, 這個 "命令" 的長度還是比相同功能的 java 或 c 程式短很多.)

有人說我們一般人的大腦只使用了十分之一不到; 隨著軟體越來越多, 越來越複雜, 我們對既有軟體的使用程度可能遠在這個數字之下, 甚至不知道找了好久的功能其實就在自己每天隨身攜帶的 CD 當中, 甚至就在自己天天使用的某個軟體之中! (我自己的切身經驗啦 ...) 換句話說, 我們這個社會真正最缺乏的其實並不是專門製作 "全功能應用程式" 設計師, 而是懂得把既有的數個應用程式適當設定, 重新組合, 完成連這些程式作者都沒想像過的工作, 這種會思考的使用者。

目前有許多企業僱主的思考方式依舊是: "花錢買軟體的使用權" 而不是 "花錢僱人幫我善用或小幅修改既有軟體", 所以這種人才的就業市場或許還不是很成熟。 告訴這些僱主 "擁有得多, 不如使用得巧" 正是我未來的工作重點之一。 不論社會大眾何時覺醒, 我們資訊從業人員都應該把眼光放遠, 及早開始做長遠的學習投資, 用有效率的學習方式, 學習可以活用組合的知識。 希望有一天, 社會大眾終於會知道: 僱用一位 會思考/選擇/組合既有程式的使用者, 比買一套具有漂亮使用者介面的 "全功能應用程式" 更能幫助自己解決切身獨特的問題; 希望有一天, 社會大眾終於會知道: 身邊有一位 會思考/選擇/組合既有知識的讀書人, 比擁有一套印刷精美的 "宇宙真理全集" 更能幫助自己解決切身獨特的問題。

當然筆者並非反對寫程式, 只是說寫程式之前要三思 (然後認真找過)。 什麼時候該寫程式呢?

  1. 寫程式不是手段, 而是目的: 例如純粹為了興趣/熱情/狂熱而創作 (就像很多人畫圖, 寫歌, 寫詩, ..。 純粹為了興趣而創作一樣)。 以興趣為動機而創作的人, 是最幸福的人。 不論你寫的程式有沒有用, 不論是否已有現成的程式可以用, 請盡量寫吧! (聽聽看創辦 Apple, NeXT, 與 Pixar 的 Steve Jobs 在 Stanford 對畢業生怎麼說。)
  2. 為了要練習, 為了要了解。 例如寫老師出的作業, 寫課本與參考書上的習題。 就像數學系的學生要不斷地重複證明前人已證過的定理一樣, 練習是學習過程當中很重要的一個環節。
  3. 你需要解決的問題確實沒有人解決過, 而且這是一支「組合性」低的程式: 它只適用於此時此地, 專為滿足這位主管或客戶的要求所設計; 換個應用場合就必須看得懂程式的人再進入加以修改。 例如網頁設計或資訊管理系統等往往是這樣的狀況。 這當然非自己寫不可; 但是其中經常仍有不少地方可以撿現成的程式庫來組合。 (順便一提, 寫這種程式並不是靠版稅賣錢, 而是靠服務賺錢; 與自由軟體的觀念並不衝突.) 通常最適合這種狀況的語言是某種 scripting language
  4. 你需要解決的問題確實沒有人解決過。 而且這是一支「組合性」高的程式: 它的功能介定非常明確, 操作或使用的介面與實作的細節非常獨立, 可以讓很多不了解細節的人在不同的場合使用。 如果你首先寫出來這樣的程式, 不僅可以解決自己眼前的問題, 說不定還可以參與 CLE 計劃 之類的計劃, 把你的成果以 GPL 或 XFree86/FreeBSD 等方式公開授權給大家使用, 成為一位受大家尊敬的駭客。

至於如果寫程式的動機是販售程式使用權, 那恐怕就要三思了。 哺乳動物時代來臨之後, 地球上還是有爬蟲類; 不過那畢竟是少數。 在自由軟體時代來臨之後, 或許還是會有軟體公司能夠持續以版權私有軟體方式生存, 但恐怕也是少數。

有熱情, 才能持久; 持久, 才能真的學好程式設計。

從錯誤訊息當中學習

在 Windows 下, 遇到程式出問題時怎麼辦? 「按 OK」 「重新開機」 「重灌應用軟體」 「重灌作業系統」 這些是最常聽到的答案。

這也是令你永遠受制於電腦, 難有進步的答案。

高手與常人的第一個差別在於 "偵探小說" (注意線索) 的學習法 vs 盲目的 "嘗試錯誤" 學習法。 對於自由軟體豐富的錯誤訊息不但不要抱著害怕的態度, 更要把它當成改正下次行為的珍貴線索。 來自 MS Windows 世界的人經常忽略這些非常重要的學習資訊。 這可以理解: 因為 Windows 和上面的許多 proprietary software 在印錯誤訊息時必須非常小心, 不要把過錯攬到自己身上; 而 Windows 的使用者在習於看到沒有意義的錯誤訊息 ("請與程式設計師聯絡" -- "可是我到那裡去找程式設計師的電話號碼啊? 而且, 就算我查得到...他會理大補帖的使用者嗎?") 之後, 便很自然地養成了忽略錯誤訊息的習慣。 但 Linux 和其上的自由軟體則大不相同, 錯誤訊息的目的在於幫助使用者找出問題所在, 那怕是必須承認程式自己的極限或錯誤也無所謂。

想變成電腦高手, 最重要的就是養成注意錯誤訊息的習慣, 要根據錯誤訊息來找出解決方案。 錯誤訊息可以拿來當做關鍵字, 到文件目錄底下搜尋: grep -i '...' `find /usr/share/doc/... -type f` 也可以拿來上 google 搜尋。

對於 server 類的程式, 往往無法直接看到錯誤訊息, 因此 log 檔也非常重要。

其他有助於學習的方式

  1. 習於略讀 各種文件:
    Linux 上的文件多到不可能讀完。 你有興趣的文件可以細讀; 其他文件都可以略讀或只讀與眼前問題相關的章節。
  2. 加強基本英文閱讀能力, 走出臺灣狹窄的資訊空間:
    閱讀技術性文章不會很困難的, 尤其不需要把術語當做英文來敬畏, 而要把術語當做數字代號或線索來協助我們在相關文件檔當中搜尋 我們要的資訊。 對於不了解觀念的人而言, 「水管」一詞會比「pipe」 更容易記嗎?
  3. 勤作筆記:
    學習新語言的測試程式, 花很多時間才試出來的命令/才解決的安裝問題, 各種設定檔, URL, 同學的經驗, bbs 上看到的小技巧, 高手指導的 e-mail, ..。 以上種種, 都應該小心保存, (何不乾脆用電腦做筆記?) 不要太相信自己的記憶力。 設定檔中自己動手修改過的設定, 也算是筆記; 不用的設定還是要保留 (註解掉就好)。
  4. 珍惜學習成果, 勤作備份:
    我每天備份 1-3 次, 每次存 4 份, 分別放在硬碟, cf 記憶卡, zip 磁碟片, 1.44MB 軟碟片上面, 每一份包含完整版 (最近一年更動過的檔案; 1.44MB 磁碟片放不下) 及更新版 (最近 15 天內更動過的檔案) 已經很多年沒有因為 format 或系統出問題而遺失重要資料的悔恨了。 如果你把備份的工作想成是備份整個分割區, 當然會很懶得做; 但其實重要的資料真的很少, 只要認真整理過一遍, 全部收集在同一個目錄下 (必須放在特定目錄的設定檔等等, 或許可以用 symbolic link / 捷徑 來取悅系統) 再寫一個簡單的 script 或 batch file 並排入每天自動執行的工作, 就可以高枕無憂了。
  5. 善用網路資源: 從前人那裡可以得到的, 不只是程式, 還有很多資訊。 綜合地說, 就是要善用網路上既有的資源。 有一位同學不滿專題指導老師放牛吃草, 於是在專題報告時, 指導老師欄位填上 "google"... 這說明了想要畢業, 搜尋引擎比老師更重要 :-)
  6. 養成良好的使用習慣, 避免使用 root 帳號:
    Linux 再怎麼好, 再怎麼不怕病毒, 一碰上不小心 (或新手) 的 root 使用者, 一切優勢都喪失了。 我的 root 帳號幾乎不 customize, 所以很難用。 我又在 .cshrc 中加了一句:
    set prompt = "%U%{\033[41;37m%}%m:%~%#%{\033[0m%}%u "
    讓 root 的提示符號變得很刺眼。 Bash 的使用者可在 .bashrc 中加上
    PS1="\[\033[4;41;37m\]\h:\w\$\[\033[0m\] "
    (螢幕控制字串請見 「反樸歸真: 文字模式下的程式設計」)。

搜尋的技巧

  1. 想找某一套專屬軟體的自由替代品: 用軟體名稱加上 open source (這個場合用 "free software" 的效果較差, 經常找到免費但並未公開原始碼的軟體。)
  2. 想學一套軟體/工具/技術: 用軟體/工具/技術名稱 (例如 regular expressions, javascript, ...) 加上以下單字其中之一: tutorial, howto, introduction, ...
  3. 如果是學科 (例如 calculus, linear programming, ...) 則改用學科名稱加上 lecture notes 搜尋。 (把 lecture 拿掉, 或許找到更多)
  4. 有些事情/動作, 每個人都在做, 並不是很高深/專門/特別, 但是技巧各有不同。 例如 "搜尋" 本身就是這樣的事。 此時可用 「事情/動作名稱」 加上 technique 或 tips 去搜尋。
  5. 玩軟體遇到困難時, 可拿錯誤訊息當做搜尋關鍵詞組。 這也是為什麼我們喜歡用命令列: 它給的錯誤訊息往往比圖形介面豐富且精確。
  6. 盡量使用有特色的關鍵字 ( 避免太普通的字): 例如要找網頁製作軟體, 用 html authoring 可能會比 write web page 的效果要好。
  7. 如果真的找不到比較有特色的關鍵字, 把很普通, 但卻很少一起出現的字或觀念放在一起, 也有類似的效果。
  8. 決定採用那一套工具開發軟體之前, 記得先上網搜尋替代方案的優劣比較。 例如想用 php 開發一套系統: 當然別從頭開始寫, 最好可撿現成的工具箱。 所以搜尋: php framework comparison
  9. 想要找同一類東西的列表, 比較, 除了用 comparison 這個字之外, 還有一個方法就是將你要的列表裡面最可能會出現的東西並列搜尋, 例如想知道有那些網頁製作軟體可用, 可以用 nvu bluefish 搜尋。

想學更多搜尋技巧嗎? 就搜尋 "搜尋技巧" 或 "search techniques" 吧。 特別推薦以下幾篇:

  1. 善用GOOGLE 從入門到精通
  2. Tips for Searching the Web
  3. Google search basics: Basic search help

具體的學習重點

  1. regular expression: 可以用在: less(1), grep(1), sed(1), vi(1), ..。 等處。 花十分鐘認識 regular expression, 你就會明白為什麼筆者覺得現在的 「人-電腦」關係就像是中國的阿拉丁遇到阿拉伯的神燈精靈一樣令人遺憾。
  2. pipe and xargs(1)/command substitution (back quote) 這是「組合哲學」的基本動作, 就像積木的齒是積木之所以可以組合的關鍵一樣, 這兩者是我們每次將命令拿來組合時, 一定要用到的 "齒"。
  3. 選一種 scripting languages 來學習。
  4. 學會操作 readline user interface, 以後不只在 shell 下, 還有在很多應用程式當中 都可以減少打字的負擔。
  5. gnuplot
  6. 用 find(1) 找到你要處理的檔案, 然後 ..。 (組合哲學: 丟給其他命令處理)
  7. archie(1), lynx(1)
  8. 善用常用環境變數, 一次調整很多應用程式的行為: PAGER, VISUAL, ..。
  9. 下 "info -f fileutils" 命令, 學習 "軟體工具箱哲學" 一文中提到的指令。 (我就是從這裡學到「組合哲學」觀念的)

融入新文化, 拓展新「思界」

  1. 興趣為創作之母:
    為興趣而學習才容易學好, 才容易有真正有價值的創作出現。 如果你不喜歡正在學的東西, 何妨找喜歡的東西來學? 當然也必須要有足夠的耐心渡過學習曲線的「引擎發動區」, 否則永遠找不到喜歡的東西。
  2. 享受千分, 回饋一分:
    把個人的時間精力回饋一點給自由軟體社會, 讓網路把你的貢獻無限放大。 撰寫程式, 製作文件, 參與中文化工作 (CLE), 協助翻譯文件 (CLDP), 利用自由軟體製作 圖案 / 動畫 / 網頁 / 桌面主題 / 音樂, 出點子, 回報程式與文件臭蟲 (順便拜託回報我網頁上的 bugs, 提供相關 URL's, 謝謝! :-), 甚至參與各項計劃的打雜工作, ..。
  3. 貢獻者的法律保障:
    「革奴大眾公有版權」 "自由的範圍以不侵犯他人的自由為限度"
  4. 麵包在那裡?
  5. 不要敵視所有商業行為, 要鼓勵合乎自由軟體理念的商業行為:
    勸說尚未轉型的資訊廠商, 把 Eric Raymond"The Magic Cauldron" 介紹給他們; 開導「需要使用軟體的非資訊廠商」, 把 Linux 的 (1) 商用實例, (3) 給資訊部門主管的建議 等 URL's 介紹給他們; 啟發「與軟體使用幾乎不相關」的紀念品/文具/手機/襯衫/..。 製造商, 把不需要付版稅的 可愛企鵝圖案與 Linux 標語介紹給他們。
  6. 不要迷信 Linux, 不要害怕選擇的自由:
    要尊重他人選擇的自由