我常常碰到第一次創業團隊的 CTO(技術總監)說:「我要請 Ruby 工程師!」、「我在找 Node 工程師!」、「你知道有誰會寫Python 嗎?」。當我反問公司產品是甚麼,CTO 通常都支支吾吾地說仍在嘗試一個新的點子,Prototype 還沒做出來。選擇程式語言和 Framework 並不是什麼壞事,但是在公司連第一個產品都尚未成形就先以開發語言和架構去篩選員工,無非畫地自限。
說到這,也點出了一個今天科技業的現象:程式設計的宗教化。
所謂宗教化(Becoming more religious),意思就是程式設計派系的對立深化。漸漸地,許多軟體工程師對於程式語言的訴求已經不是各取所長,而是先選定語言,再選擇要解決甚麼問題,說穿了就是跟工程的理念背道而馳。
這種對立現象從程式語言(Programming languges)擴張至程式架構(Programming Framework),最後擴張至軟體設計模式(Design Pattern)。
而程式設計宗教化究竟產生了甚麼樣的影響呢?
樂觀而言,程式設計派系對立,使得個語言、架構和設計模式在劇烈競爭下相繼成熟,使得軟體工程師在工作時有更多的選擇。
程式設計宗教化自然也產生了深遠的影響和迷思,以下容許小弟逐一討論。
程式語言與架構的通用化
通用化,意思就是原本有特殊目的的程式語言或架構逐漸轉變成多用途的程式語言。PHP 與 Javascript 是程式語言通用化的最好典範,PHP 原本是個 HTML 網頁的前置處理器(Preprocessor),作用在於動態產生網頁內容;而 Javascript 則是網景(Netscape)公司開發出的網頁前端語言,用來設計瀏覽器端的互動功能(如檢查表單內容)。如今,PHP 已經發展成為通用Scripting 語言,而 Javascript 也從瀏覽器端延伸到伺服器端。而其他語言如 Ruby,就慢慢衍伸出 CoffeeScript 來將類似 Ruby 的前端語言直接翻譯成為 Javascript。
為什麼許多程式語言開始往通用化發展?主要原因就是程式語言派系對立加劇,讓許多程式設計師寧願使用自己已習慣的語言和架構來取代整合多語言、多架構的開發環境。過去網路應用程式整合 Scripting 語言(如Ruby、Javascript、Python等)和系統語言(如C/C++)的開發模式今日幾乎被 Scripting 語言完全取代。
通用化的好處是大幅減少了學習不同語言的時間,進而節省訓練軟體工程師的成本。
然而這優點帶來了不小的副作用。程式設計語言和架構都很難在簡潔度、效率和多元性之間找到完美的組合,三者則二,必須犧牲一者。現今許多程式語言都是Scripting語言,擁有直譯、動態資料型態、跨作業系統等特性。這也意味著現代程式語言的執行效能很慢,若參考一些網路上的程式語言效能評比,現代的Scripting語言相對於C與C++這類的系統程式語言和C#、Java等虛擬機器語言,執行效率只有後者五分之一。
將執行效率慢的Scripting語言擴大應用,開發出的系統之效能是相當吃虧的。為了解決部分的效能問題,Facebook開發了PHP編譯器HipHop,Facebook因而減少了將近50%的CPU用量。而Twitter從Ruby-on-Rails轉至Java,其搜尋引擎效率成長了三倍。(註:Ruby 當然也發展了自己的編譯器來提升效能)
這麼一說,不代表程式語言通用化是一件壞事;但是在大家圖方便的同時,也要記得軟體工程自身的複雜度,才能判斷程式語言是否適合解決問題,所謂善其事、利其器。
一昧地要求一種語言甚麼東西都要能做,有時反而扼殺了不同程式設計語言社群之間的合作、交流機會,搞到後面許多人都在土法煉鋼。
Design Pattern、方法學綁架程式語言與架構
若你是一位網路軟體工程新鮮人,想必你學的應該是Rails或Django。因為這兩軟體架構的流行,今天MVC(Model-View-Controller)被當作是種預設立場。
當然,世界上不是只有 MVC 而已。所以我們該問清楚,為什麼只有學過MVC的人在沒有比較過其他 Design Pattern 的情況下,會認為 MVC 就是最合宜的選擇呢?
讓我們來看看 MVC 的架構,Controller 就好像是交通警察,當車輛(使用者)駛入,交通警察會將車輛導入正確的道路(View),而在駛入道路時車輛駕駛人可以看到路邊如路名、紅綠燈、招牌等資訊,這些資料就是來自於Model。而開到下個路口,車輛可能又會碰到一位交通警察、再次駛入另一道路,如此反覆直到開到目的地為止。
而這種 Design Pattern 的優點就是把所有的"交通管制"都集中在交通警察(Controller)的手上,不管系統中發生甚麼事情,都聽從 Controller 發號師令。
而 MVC 當然也不是尚方寶劍,他有一個致命的缺點就是若要從車輛(使用者)的角度去整理路線圖,一位使用者使用的功能只是 Controller 的一小部分,但同時又是不同部分串連起來才能完成一工作,其是以管理流程、而不是管理使用者的角度去彙整的。
其實MVC有一位親戚叫做MVP(Model-View-Presenter),其設計理念和MVC一樣是要將介面和程式邏輯分開,但是其結構有明顯不同。
Presenter 相較之下,比較像是一家餐廳的服務生。當你(使用者)走進餐廳(View),你可以跟服務生點餐、詢問廁所在哪裡,或是請服務生幫你加白開水,當服務生(Presenter)知道你的請求後,變會與餐廳的內部人員(Model)互動,然後把你需要的東西交給你。
Presenter 與 Controller 最大的差別在於每個 View 都有個獨立的 Presenter,而這獨立的 Presenter 的角色就是處理一切使用者在該介面上需要完成的工作。因此不難理解,MVP 的優點在於其程式碼是以使用者的角度進行整理,而缺點則是每個 Presenter 都有自己的獨立流程。
說到這邊,有些資深的軟體工程師可能都想開砲了。
沒錯,兩種 Design Pattern 的問題,如果程式碼重構簡化(Refactoring)、程式碼介面化(Code Interfacing)、元件化與模組化(Componentization and Modularization)等技巧,其實問題都能迎刃而解。
重點來了:過去程式語言和程式架構的作用在於寫程式,而至於要用 Design Pattern、程式設計方法(Paradigm)都是軟體工程師針對面臨的問題去量身訂做。這意味著軟體工程師除了會寫程式外還要有規劃的能力。今天,因為簡化工程師的訓練時間,越來越多程式語言和架構被 Design Pattern 和特定設計方法綁架,語言派系對立讓這情況更雪上加霜,變成許多新的軟體工程師只會在一種特定的框架下思考,而不會根據面臨的問題而改變規劃。
小弟一位軟體工程師朋友曾說:「現在越來越多軟體工程師只會用函式庫(Library)寫 Code,而不是真的在做工程。如果你把一位 Ruby-on-Rails 的工程師丟到 J2EE 上去,就寫得一蹋糊塗。這是我們科技業訓練求快卻不求穩造成的失敗。」
同樣地,在程式語言和架構中規範 Design Pattern 並不是甚麼壞事,但我們不要忘記除了 MVC 以外,還有很多不同的 Design Pattern ,如服務型架構(Service-oriented Architecture)、事件導向架構(Event-driven Architecture)、規則導向系統(規則導向系統)、訊息導向系統(Message-Driven Architecture)等不同的系統 Designe Pattern 可以參考,讓我們能夠對症下藥。
動態與靜態資料型態的"省時又省事"迷思
先前有提到,現今的 Scripting 語言多採用動態資料型態,意思就是變數依照「塞」進去的數值可以動態改變型態。典型的動態語言包括 Ruby、PHP、Python、Javascript。
當今許多軟體工程師喜歡動態語言,因為動態語言不必宣告資料型態,可減少寫程式時間。而多數動態語言同時又是直譯語言,直譯的特性讓工程師可以隨時進行軟體更新而無須擔心伺服器記憶體中的版本問題。可謂"省時又省事"。
然而,世界上當然沒有那麼便宜的事情。
之前提到的許多 Scripting 語言執行效率問題,動態資料型態和直譯都是罪魁禍首。動態資料型態的特性代表每次程式執行,直譯器都需要去解析變數的資料型態,自然增加了執行所需的資源;而直譯語言在執行時,必須將所有程式碼即時轉換成為機器語言,自然比已經編譯成為機器碼(或是位元碼)更耗資源。
執行效率除外,動態語言是否能夠減少程式開發時間其實是有爭議的,而小弟個人認為是否定的。
動態語言若發生資料錯誤,都是在執行時(Run time)才知道。反觀編譯語言,若資料型態不符合,程式碼根本完全無法編譯,連跑的機會都沒有。許多編譯時期錯誤(Compile Time Error)在動態語言中都變成了執行時期錯誤(Runtime Error),而軟體工程師都知道,抓執行時期錯誤比編譯時期錯誤更困難、更耗時。因此在使用動態語言開發時,除了寫程式的時間外,Unit Testing 要寫得比使用編譯語言更完整。打字省下的時間,是否有比抓錯和測試增加的時間多,恐有爭議。
而編譯語言在寫程式時雖然需要打更多字,但由於編譯語言的每個函式的標頭(Function Signature)擁有資料型態,在團隊合作時,即使不寫註解也大致上能了解函式要怎麼使用。若以動態語言開發,就可能需要花多點時間和心思在註解上,才能確保團隊溝通良好。
動態與靜態語言各有利弊,個人在此沒有幫任何語言背書的意思,但當今程式設計宗教化現象使許多軟體工程師對於特別語言的加持和罷黜,實際上都與現實有所出入。
工具歸工具,思維才是實力
講到這邊差不多告一段落了。
任何程式語言、架構,最後只是工具而已,在軟體工程的世界中只有「在某個情況下」有相對優勢,而沒有甚麼方法或工具是省時又省事的超級無敵大補帖。
記得工程的理念就是用對的工具去解決問題。因此,希望大家可以共同勉勵,多接觸不同的問題解決思維和方法、多交流,才能在困難時找到最有效(而不是最熟悉、最偷懶)的答案。