2016年6月6日 星期一

令人愛恨交織的 javascript, 開發者觀點篇

javascript 令程式設計師又愛又恨。

凡是需要圖形介面的程式, 現在我都用 javascript 來開發, 因為這樣做, 成果可以放在雲端伺服器上, 也可以讓用戶下載離線使用。 用戶不需要安裝任何軟體, 直接拿瀏覽器開啟 .html 檔就可以開始玩。

主要也是因為 js 是我目前唯一會用的 GUI 工具啦。 上一次認真學 GUI 工具, 是十幾年前的 perl-tk。 因為這需要用戶端安裝軟體, 所以我寫的程式根本推不出去。 現在用 js 開發程式, 開發者可以放心你的程式應該可以跟各大廠的瀏覽器活得一樣久 :-) 當然, 有沒有人要用, 那是另一個問題 :-)

此外, 還要感謝 javascript 跟 cordova 聯手 大幅降低手機開發門檻

但是 javascript 的語言設計, 有點令人不敢恭維。 根據 YourLanguageSucks 頁面內容的長短來做一個不太科學的判斷, javascript 可能是數一數二令開發者受不了的語言。 先看一下別人如何批評 js: 1 2 3、 ... 還有 js 函式庫開發者列出了 你不該採用 js 的十大理由 (包含對策, 大推!) 這篇 諷刺文 道出 js 程式設計師面對多變地貌的痛苦心聲, 有 中文翻譯, 不過科技報橘很認真地把它下錯標題了 :-)

接下來換我講一下自己討厭 js 的原因。 我最熟悉的是 C 跟 perl; 也曾經在沒有 google 只能乖乖讀書的年代大量使用 C++ 並且使用 lisp、 prolog 一些時間。 在學習 Object-Oriented Programming 之前, 我的 C 程式就已經寫得有點 OOP 的樣子; 但後來即使是在 C++ 或 perl 裡面, 對於全面 OOP 也並沒有很熱衷。 因為 C 跟 C++, 所以我很能接受有 OOP 或是沒有 OOP; 因為 perl, 所以我很能接受各種標點符號以及一層又一層的括弧; 因為 lisp (還有只讀書沒寫程式的 eiffel), 所以我很能接受 functional programming。 以上三個 「js 備受批評的原因」, 對我而言都不是很大的問題。

第一個討厭的地方: 隨便一件什麼任務 -- 例如讀檔案 -- 都必須採用非同步的方式進行。 「後續處理」 的程式碼如果放錯地方 (應該放在任務的 callback 之內而不是任務之後), 很可能既沒有錯誤訊息也沒有任何效果, 很難除錯。 這比較不算是 js 設計不良, 而是瀏覽器為爭取時間快速顯示頁面的緊張環境給 js 帶來的天生 「原罪」。 現在再究責 「交流道是誰設計的?」 也沒差了, 總之 因為非同步的特性, 所以設計 javascript 程式的門檻一開始就比別的程式語言要更高

再來, perl 跟 js 一樣有很多自動轉換等等便利措施, 但是 perl 的便利措施讓程式變得很簡單 (e.g. 用 hash 開表統計資料時不需要設初始值, 第一次取用的 key 自動加進去、 第一次取用的 value 就當成 0); 反觀 js 的便利措施卻讓程式變得很難除錯 (e.g. "31"+25 vs "31"-25 以及 return 後面自動補上的分號)。 [2019/2/16] 「wtf.js – JavaScript 令人又愛又恨之處」(中文) 舉的例子: 請解釋為什麼 ++[[]][+[]]+[+[]] 得到 "10"。 衍生: 任何 js 程式都可以「翻譯」成6個字母所組成的看不懂版: JSFuck 痛苦搞笑的神人境界!

Perl 發明人 Larry Wall : "Easy things should be easy, and hard things should be possible." 在 js 的世界呢? d3.js 證實了: hard things 有時也可以很 easy; 不過我曾經好幾次 「本以為是 easy things 結果竟然很 hard」, 即使上網搜尋, 都還是不斷撞牆。 讀本地檔案 一事, 讓我有最深刻的體驗。 好幾次搜尋到 stackoverflow 去, 讀完 js 高手們的回答之後, 卻會讓我有莫名奇妙的罪惡感, 以為 js 不該被拿來這樣用。 例如 「js 不該被拿來讀本地的檔案」、 「自己架一個 web server 也很簡單啊」 但是我不想經過 web server, 只是想要從瀏覽器開啟 file:///...html , 然後用 js 讀取同目錄底下的檔案, 這跟安全有屁關係啊!? 詳見 chrome 的禁讀令

這一陣子開始用搜尋 (而不是讀書) 的方式認真寫 js, 得到一個重要心得: 跟原生的陽春 javascript 認真, 你就輸了。 遇到任何問題, 一定要偷懶、 偷懶、 再偷懶, 想辦法搜尋現成的函式庫來幫你躲避那個問題。 要站在巨人的肩膀上, 不要重新發明輪子。 不要被某些高手的否定給嚇到了; 跟你一樣有著簡單需求的人很多。 換個關鍵詞求救。 如果 「javascript + 某功能」 搜尋不到理想的答案, 就改用 「jquery + 某功能」 再試試看。 jQuery 不一定是解決你手上問題的最佳方案, 但至少它在許多 easy things 的面向上, 把 js 拉到跟其他程式語言勉強有相同的立足點。 從 jQuery 的解決方案當中, 你也可以找到更多相關的搜尋關鍵詞。 如果找不到, 歡迎留言, 我來幫你找。 請舉你熟悉的語言作例子, 貼上語言名稱並用它寫出你想要完成某項工作的程式片段範例, 我來幫你搜尋在 js 裡該怎麼做。

以下是我對 javascript 初學者的建議:

  1. 先從用戶觀點認識一下 javascript
  2. js 不適合作為第一個程式語言。 請先學其他語言, 了解 variable scope、 hash table、 shallow copy、 callback、 ... 再來學 js。
  3. 可不可以不要學 js? 有沒有其他替代方案? 我是 因為想玩資料視覺化, 所以才學 d3、 因為想畫地圖, 所以才學 leaflet。 如果是可以在終端機裡面完成的事 (例如處理文字檔) 我絕對用 perl 或 bash 而不是 js。
  4. 如果一定要用 js 程式碼執行, 有沒有可能用其他設計較佳的語言來寫 [12], 然後再把它編譯成 js? 所有的 js 新手都應該先被告知這個替代方案再決定要不要學 js; 但很可惜, 經常都是老手才會發現這些可能性。 我自己也還沒認真研究過。
  5. 如果一定要用 js 原生程式碼來寫, 有沒有可能用 某個 framework 或函式庫 來加速起步? 錯過底層重要的東西? 我才不在意呢。 人生苦短, 沒有時間浪費在繁瑣又沒有成就感的事情上面。 如果不是 jQuery 跟 d3, 我早就放棄 js 了。
  6. 也許其實你並不需要認真學完整的 js, 只需要有能力上網抓現成的 javascript 小工具來就夠了? [ 1234 ]
  7. 不只是著名的 frameworks, 還有其他語言裡面公共函式庫 (C++ 的 STL、 perl 的 CPAN、 python 的 pip、 ...) 可以完成的事 (例如交集差集、 deep copy、 ...) 在 js 的世界裡可能也有類似的函式庫。 用 npm 管理套件庫看來是一條不錯的路; 但我還沒學。
  8. 真的要動手學的時候, 可以考慮透過 「把 javascript 當成計算機來用」 的方式迅速認識基本語法及資料結構。
  9. 真的要開始寫完整的程式的時候, 一定要先學會 console 好用招術 還有 jshint 除錯才比較快。 大推 How to Not Hate JavaScript: Tips from the Frontline

如果說 javascript 初學者像是到了一個陌生的國家, 那麼以下就是一些「地貌簡介」類型的文章, 每一篇都有很豐富的連結; 他們提到的東西, 絕大多數對我而言不是很陌生就是只有「聽說過」的認識。 [如果你是很久以後才讀到我這篇文章, 請注意時效性的問題。]

  1. State of the JavaScript Landscape: A Map for Newcomers
  2. Top JavaScript Frameworks, Libraries and Tools and When to Use Them
  3. Essential Tools & Libraries for Modern JavaScript Developers

我到現在都還沒有興趣跟勇氣認真學 js 的物件導向 「文化」 (因為 高手建議的寫法 好像跟其他 OOP 不太一樣?) 更別談撰寫通用函式庫或欣賞 js 語言設計的精神。 我只想憑著自己在其他程式語言的豐富經驗, 以及精準下搜尋關鍵詞及大量爬(英)文的能力, 來快速上手這個對新手不太友善的程式語言、 很快地寫出簡短而實用的地圖及資料視覺化程式。 所以我的建議跟 保哥穩健紮實的建議 (好文!) 在某些面向可能很不一樣。 本文從這個角度分享我的經驗, 也邀請大家留言分享你的建議。

* * * * *

近期即將錄製一點 js 課程放在 雲端愛上課 上架。 先在這裡表達我對於 javascript 語言的態度, 以免學員有誤上賊船的感覺 :-) 課程內容基本上就是我已張貼還有即將張貼的講義跟部落格文章; 比較大的差別是影片中你將會看見我在 vim 裡面剪貼程式碼、 用 jshint 跟 firebug 除錯的過程, 還可以欣賞我的黑底大綠字終端機 :-)

4 則留言:

  1. 我自己學 html 和 javascript 的動機是為了要能在瀏覽器 瀏覽/打開 本機的檔案 (local files).
    最後變成 html 網頁資訊和硬碟的內容交叉在一起, 這也是我想要的.
    不過由於我懂的太皮毛, 而我又很想趕快建立更完善的系統, 把資料和文件界面穿插在一起, 我現在的觀念開始改變 :
    "不要自己重複發明車輪!". 多少不算小的專案, 最後末落然後死亡? 又多少人想開發新專案來解決沒人解決過的事情?
    "還好我不會寫程式", 不然我就會提早侷限自己的視野, 一頭栽下去了.
    其實最好的方式 (我自己的想法) 就是順應現有的標準走, 因為大部分人都不是天才, 必須站在巨人的肩膀上.

    我覺得目前很重要的 "基礎設施" 等級的個人桌上應用軟體有兩個 :
    1. CMS (content management system) (例如 : Tiki wiki, Mediawiki).
    2. DAM (Digital asset management (system)) (例如 : Resourcespace).

    之所以這 2 類我認為很重要是因為它是所有 資訊/文件 的存取和存放界面, 也掌控所有 資訊/文件 的生死 XD.
    我上面提到的不要重複發明車輪就是指這個, 既然已經有這些軟體寫出來, 那即使他是 "黑箱子", 我無可奈何我還是必須接受,因為自己的青春有限, 我/其他人也是 沒那麼多美國時間自己建一套相同的系統.
    (上面提到的 "黑箱子" 比較精確來說其實應該稱作 "可以打開的黑箱子". 對於不懂資訊的人, 它的運作方式是神秘複雜無法控制的, 此時對 他們/我自己 來說箱子是黑的. 但對於了解資訊的人, 由於是 open source 的關係, 箱子是可以打開的, 觀看或調整箱子裡面的運作對它們來講是很簡單的.)

    回覆刪除
    回覆
    1. 所以看起來你本來是想作一個和 wiki 有點像的系統?
      可以方便地管理 *所有* 的檔案?

      刪除
    2. 嗯 ... 比較精確來說是, 把 CMS (例如 wiki, 因為 wiki 也屬 CMS 的一種), 跟檔案系統 盡量整合在一起, 只要透過瀏覽器 (例如 firefox), 就可以存取 wiki 網頁, 以及檔案.
      我目前自己已經在這樣應用了, 我使用的方式主要利用這 2 個專案 :

      1. Dokuwiki. Dokuwiki 他是適合個人或小團體使用的 wiki, 設計和使用都很簡單, 沒有資料庫 (MySQL), 而是用 純文字 plain text 的方式存在檔案系統上. (對於只有幾萬個 wiki page 時, 效率會比資料庫高). Wiki 最大的特性在於 wiki 語言使用很很方便, 不需要再像寫純 html 那樣 看/讀 那些醜陋的標籤 (tag), 而是用簡單 易讀/易寫 的 wiki 語言寫網頁.

      2. elfinder. elfinder 我比較難解釋, 它是一個 "網頁檔案瀏覽器", 它可以 瀏覽/新增/更名/移動/刪除 一個 有裝 elfinder 的 伺服器/個人電腦 上的檔案, 不過跟 檔案管理器/檔案瀏覽器/File manager 最大的差別是, 透過網頁瀏覽器 (Firefox) 操作.
      建議直接看這個 Demo 就懂了 : http://studio-42.github.io/elFinder/#elf_l1_Lw (或去 google elfinder).

      我透過以上 2 個 open source 專案, 加上自己的一點點 javascript, 目前我已經應用在我自己的個人電腦上, 把 elfinder 的檔案, 穿插到 Dokuwiki wiki 的頁面裡面.


      改進中 :
      elfinder "似乎" 不是走 webDAV 協定的, 我以後會再讓 webDAV 也可以運作. 不過因我自己的電腦同時扮演 server 和 client 的關係, 目前我除了用 elfinder 的方式瀏覽, 我還可以用 檔案管理器 的方式瀏覽 (不過如果要在別台裝置看, 就要走 webDAV).

      優點 :
      1. 實際應用的情況是,我可以用 firefox 進入 Dokuwiki 網站 (local, 還沒公佈到 WAN 網際網路 上去) 的某 wiki 頁面的 影片連結時, 我可以用 elfinder 打開這個影片連結, 這就把檔案和網頁整合在一起了. 當然除了瀏覽以外, 還可以直接 新增/更名/移動/刪除. 簡單來講這個應用就是把網頁瀏覽器和檔案瀏覽器整合在一起.
      2. 這種方法不只可以給個人使用, 如果再把我個人電腦公佈在網路上 (變成 server), 用其他平板或手機連到我這個網站, 也可以有相同的操作.
      3. 網頁和檔案是穿插在一起的, 資訊本身本來就應該用這種方式構成, 也是我為什麼要做這些東西的主要原因.
      4. 傳統的檔案管理方式是用 檔案 + 資料夾 構成的系統, 唯一找到某檔案的方式就是 檔名 + 樹狀結構, 然而檔名有多限制, 且資料的組織方式也不是純樹狀結構, 在管理上問題很多 (比如 網際網路 是樹狀結構嗎?). 由於檔案的連結因為穿插進 wiki 頁面, 所以可以任意寫一些關鍵字然後用這些關鍵字搜尋到.
      5. Dokuwiki (或其他 wiki 都一樣) 有全文搜尋功能, 可以用一個或多個關鍵字搜尋到特定頁面. 也就是說 wiki 除了自由的塑造資料的組織 (頁面之間的超連結網路), 還可以直接存取特定的關鍵字 (搜尋).

      缺點 :
      新增一個檔案的步驟很多, 首先要先寫 wiki 頁面插入一些 html class, 然後在 elfinder 根目錄底下也要新增一個資料夾 (我的概念是資料夾 結構完全平坦化/名稱流水號化), 然後再把檔案經由 elfinder 丟進去.

      我覺的一個笨方法如果經得起時間考驗的話就是好方法, 透過其他 open source 專案加上一個自己了解的間單系統是最安全的 (不會丟失資料或失去技術支援).

      刪除
  2. 真好文!我早該這樣做了!
    另外, 文中 其他設計較佳的語言 的連結,CoffeeScript 的"家族"語言,看一個笑一個!(名字也從咖啡來:可可、冰咖啡、咖啡因 ...)

    回覆刪除

因為垃圾留言太多,現在改為審核後才發佈,請耐心等候一兩天。