我是一名DevOps架構師、音樂人及全方位的極客。當我不在工作中寫程式或調整電腦時,我會製作自己的音樂,並在西薩塞克斯的樂團中負責低音部分。
我喜歡做副業專案。像大多數極客一樣,遇到問題時我容易陷入無止盡的探索——只要有一點小不便,我就會樂於花上數週時間打造一個遠比問題本身複雜的解決方案。擁有一個能探索想法和「如果…會怎樣」的遊樂場,是一種樂趣;正如理查德·費曼所說的「發現事物的樂趣」。
當我的翻唱樂團開始難以管理曲目清單和歌曲筆記(「我們重複結尾幾次了?」「為什麼又拒絕這首歌?」)——更別說「下週末誰有空?」——我看到了打造一款應用程式的完美藉口。我們嘗試過從試算表到聊天群組的各種方法,但都無法提供一個無摩擦、能一致記錄筆記和規劃演出的方式。
過去一年多,我利用晚上和空閒時間開發了https://setlist.rocks,對結果相當滿意。它已成為我們和約100個樂團用來管理排練、練習歌曲和規劃演出的全方位工具。但最重要的(也是本文主題)是,我重新發現用傳統方式打造網頁應用的樂趣!我通常偏好復古計算專案,因為近年來對現代開發環境感到失望,但我可以誠實地說,這是我很久以來最享受的開發體驗,而這主要歸功於Rails如今的強大與優秀。
我知道,你會想說Rails?那個老東西?還有人用嗎?但因為這是純粹為了樂趣,我決定放棄日常工作中常用的最新技術棧,回歸我對Ruby的「初戀」。我也覺得這是重新認識這個在2000年代初期掀起革命的框架的好機會。這些年我一直半關注它,但已經很久沒認真使用Rails了。上一次正式使用大概是Rails 3到4時期,約13、14年前。生活變遷,我深入基礎設施和DevOps工作,Rails逐漸淡出我的技術棧。
2025年Stack Overflow開發者調查也反映了類似趨勢。Rails幾乎已不再流行,排名第20,遠落後於前十名的JavaScript和ASP.NET框架。
Ruby本身也不在前十語言之列,甚至排在Lua和組合語言之後!我當然喜歡老派的z80或68k組合語言,但相比之下,JavaScript的使用率高達66%,Python則是57.9%。
但我很固執,如果我喜歡一項技術,尤其是用於不必在意他人使用什麼或最新潮流的專案,我會堅持使用它。所以Ruby從未離開我。我一直熱愛它,選擇時它是我首選的工具。
近年來,基礎設施間的腳本黏合需求減少,因為多數系統成為由YAML或HCL驅動的「黑盒」。但我初次接觸Ruby時,感覺找到了一種符合我思維方式的語言。從Perl(我用它做系統管理腳本,取代多年來範圍越來越大的shell腳本)轉向Ruby,我通讀了《Practical Ruby for System Administration》,發現Ruby是「比Perl更好的Perl」。它同樣富有表達力,卻沒有那些奇怪的巫術。我喜歡方法鏈、yield區塊,甚至複雜邏輯讀起來幾乎像英文。思考與輸入之間的轉換極少。當然,我也能用Python、Go或當季流行語言快速完成,但總覺得在與語言抗爭,而非與它合作。當然,Ruby社群的歡迎感和獨特氛圍也讓我難以割捨,像是Why the Lucky Stiff和他傳奇的《Poignant Guide To Ruby》。
我必須說明,我的興趣(也是本文焦點)一直在開發的「引擎室」——系統管理、DevOps、後端基礎設施領域。這大概也是我選擇貝斯作為樂器的原因。雖然我熟悉前端技術,從90年代末期當「網站管理員」開始,經歷過Fireworks切圖、表格布局、Matt’s Script Archive的各種互動腳本,但現代前端開發——JavaScript框架、建構工具、CSS技巧——從未真正吸引我。我能應付,但更像欣賞爵士樂:技術上令人驚嘆,佩服高手能做出什麼,但不會是我樂於投入的事。它是必要的,不是樂趣所在。
雖然多年沒完整開發或管理Rails專案,但我從未完全離開Rails生態系。即使只是用Sinatra快速搭建API,ActiveSupport等工具也一直陪伴著我。它讓我能輕鬆寫出優雅的程式碼。
但真正坐下來使用Rails 8是另一回事。它依然熟悉——MVC結構、慣例、產生器都在預期位置。以我那塵封的Rails 3經驗,仍能快速找到路並生成基本骨架。但底層和細節已大不相同。
先談談前端代碼處理。作為一個寧願咬玻璃也不願配置Webpack的人,Rails 8採用的「無建構」策略非常合我胃口。我成長於伺服器端生成頁面的時代,經歷Perl CGI.pm、PHP、Java與Struts,喜歡能用現代化方式繼續這種模式,而非將整個應用放在瀏覽器,後端僅處理JSON流。
我想加入拖放排序曲目清單等便利功能,因此很欣賞能用極少JavaScript打造互動應用。Hotwire(HTML Over The Wire)預設堆疊的Stimulus和Turbo提供了足夠的低摩擦功能,讓我不用淹沒在JavaScript中即可完成前端。
Turbo攔截連結點擊和表單提交,替換<body>或頁面片段,帶來類單頁應用的流暢感,卻不必真正建SPA。我還能用小型Stimulus控制器添加彈窗和動態元素。用熟悉的ERB模板和伺服器端渲染內容,快速打造現代感應用令人印象深刻。
Stimulus社群較小,但有許多優質且設計良好的元件庫可直接使用或調整,例如Stimulus Library和Stimulus Components。
這是我第一次接觸Rails 7時引入的簡化JavaScript庫打包工具。它不需JS執行環境、NPM工具或Webpack等打包步驟,JS元件用importmap命令管理。舉例來說,要使用模態對話框元件,只需執行命令下載CDN上的套件,加入vendor目錄並更新config/importmap.rb,然後在HTML模板<head>用javascript_importmap_tags標籤引入即可。
你可以在瀏覽器查看生成頁面原始碼,看到這些標籤如何展開。接著依文件註冊控制器(javascript/controllers/index.js幾行程式碼,開發本地控制器可跳過,因為有自動加載器),即可在視圖模板中立即使用。文件說:「這讓你免去Webpack、Yarn、npm等JavaScript工具鏈的需求,只需Rails內建的資產管線。」
我非常感謝這項改變,也懊惱自己沒早點發現Rails 7就有這功能。坦白說,除了基礎外,我的前端技能有限(很快就會產生「Flexbox怒火」),所以我從各種模板和線上元件生成器取材,並請Claude根據常見畫面和元件的模型生成剩餘部分。然後我透過切割、複製貼上,利用Rails partials打造可重用的「UI工具包」。
我對此感受複雜。一方面,它幫我跳過不喜歡的前端繁瑣部分,專注於有趣的後端;也確實比我獨自設計更快產出更佳體驗。另一方面,我對AI生成內容(音樂、藝術、詩歌,還有LinkedIn上那些讓我反感的東西)深感反感。我的網站內容100%不含AI,因為我認為這些是人類獨有的表達,讓算法代勞令人不安。然而,編碼也是創造性工作,某種程度上可視為藝術。我用AI協助生成UI元件,是偽君子嗎?這和從Bootstrap模板複製或修改UI庫元件有何不同?我想我還得多思考這問題。
稍微說明我的開發流程,或許能說明我為何如此喜愛Rails。它在2000年代初期掀起革命——之前我用過的網頁框架(Struts等)複雜且需大量XML配置。Rails拋棄這些,引入「慣例優於配置」理念,充分利用Ruby的簡潔表達風格。
熟悉Rails的好方法是跟著官方教程,但我用「標籤」系統(樂團可為歌曲、曲目清單加標籤)舉例:我先規劃模型,標籤是什麼,有哪些屬性(文字描述、十六進位顏色)等。接著用Rails產生器創建骨架和遷移檔。
這會自動生成app/models/tag.rb,從資料庫讀取欄位定義,無需額外工作。當然,我們通常會加驗證,例如驗證十六進位顏色格式。
接著設定URL路由。起步可用config/routes.rb中一行程式碼,產生標準RESTful路由。
這些路由支援不同格式請求,如HTML和JSON,方便API設計。
我習慣先用這種方式快速實作應用邏輯,後續再處理呈現。舉例來說,Tags控制器先寫取資料庫紀錄並回傳JSON的程式碼,然後用curl測試API。
一切正常後,再生成標準ERB模板視圖。搭配即時重載等開發便利功能,從想法到可用原型的時間非常短。且Rails生態有豐富套件,幾乎任何需求都有現成解決方案,例如CSV匯入、PDF生成等。
我愛Ruby。
Rails讓你隨著規模擴展啟用元件和模式。可以先用SQLite,流量大時換專用資料庫,再加快取、背景工作等。
問題是這些功能通常需要額外基礎設施。快取要Redis或Memcache,工作隊列也要Redis,再加上Resque或Sidekiq等Ruby庫。工作於GitLab時,我很欣賞Sidekiq,但對小型應用偶爾異步任務來說太重了。
Rails 8引入的Solid*庫(Solid Cache、Solid Queue、Solid Cable)非常棒。Solid Cache用資料庫替代記憶體快取,因為現代儲存速度足夠快,且能快取更多資料,且不需Redis。
你只要用標準Rails快取模式即可。例如我大量用ERB片段快取,整塊HTML快取一段時間或依模型更新自動重建。
快取內容存在SQLite資料庫中,是序列化的Ruby物件,無法輕易在Rails外查看。
Solid Queue同樣用資料庫管理背景工作,不需Redis。開發環境只要設定環境變數即可在Puma內部運行隊列管理器。
排程也用簡單語言設定,非常優雅。
這讓我從一開始就能用這些功能,且只用SQLite資料庫,省去繁複設定。
Solid Cable我用得不多,主要是Action Cable的資料庫適配器,用於即時WebSocket功能。我只用它啟用本地測試的debugbar,方便檢查SQL查詢和HTTP請求,類似PHP框架的除錯工具欄。
我很感激這些功能不需額外基礎設施。
另一個我沒深入研究但有興趣的是Rails 8的新認證產生器。它為小型專案帶來變革,提供簡潔的認證系統骨架,比我慣用的Devise簡單許多。Devise功能豐富,有註冊流程、帳號鎖定、郵件確認等,且有大量教學資源。我想整合Omniauth的Google登入、curl測試的token認證,最後還是用Devise,且很滿意。
不過Devise有點複雜。越看Rails原生認證產生器越喜歡它簡單易懂的哲學。若重新開始,我可能會選擇Rails原生方案,因為更有趣且易於修改。但認證這種事,走穩妥路線很重要。
Rails 8還讓我驚喜的是SQLite的改進。我喜歡PostgreSQL,過去維護Solaris套件並長期用於生產環境,但它是另一個依賴,需要管理、備份和擴展。SQLite簡單得多:單一檔案,無需資料庫伺服器,且效率不錯。過去要用於高效讀取應用,需調整Rails和SQLite設定。
Rails過去用SQLite預設設定偏向安全和相容性,開發環境很好,但生產環境常出現瓶頸和SQLITE_BUSY錯誤。必須調整journal_mode為WAL,synchronous改為NORMAL,還有mmap_size、cache_size等參數。
這些調整繁瑣且脆弱,多數開發者不做,習慣開發用SQLite,生產用其他資料庫。
Rails 8新增database.yml的pragmas區塊,且預設值已調整為適合生產環境,讓SQLite成為中小型Rails應用的可行生產資料庫。搭配Solid*元件,不再只是開發或入門便利。
若有舊Rails專案想用類似方式,有文章介紹如何猴子補丁SQLite適配器,實現pragmas設定。
部署Rails應用一直是弱點。過去我被「幾分鐘打造部落格」的示範震撼,但部署優雅度不及開發。Passenger和Litespeed帶來類似PHP「只要複製程式碼」的部署方式,但我仍記得用Capistrano或Ansible手動部署、遷移和重啟的痛苦,還有各種支援元件。
這也是Heroku和Pivotal Cloud Foundry當年成功原因——提供無痛且有意見的部署方式。只要git push或cf push,神奇地將程式碼打包成容器,連結服務並部署。
如今我偏好自己打造容器。建立OCI映像檔讓我能靈活選擇運行環境,從單一VPS的docker-compose,到Kubernetes集群的Helm chart或operator。Rails新建專案即附Dockerfile,幾乎可直接用於生產。我會稍作調整,採用「元容器」方式,將不常變動的安裝套件等移入基底映像。
你可用任何方式部署容器,但Rails 8預設採用Kamal,使用體驗極佳。
有人不同意,但我本來就為所有東西打造容器,認為這是現代趨勢,且有CI/CD、容器註冊中心、監控等基礎設施。若你沒有這些或不想自己管理伺服器,Kamal不是PaaS,但能讓你接近自架PaaS環境。Heroku已進入維護階段,市場上還有其他PaaS選項,如fly.io(我沒用過)。
Kamal部署設定在deploy.yml,定義伺服器角色:網頁前端、背景工作者等。也可全部指向單一主機,後續再擴展。設定檔可繼承基底,方便區分環境。還有別名方便操作,只需SSH連線即可。
路由由kamal-proxy處理,是輕量反向代理,部署新版本時負責零停機切換:啟動新容器、健康檢查、切換流量、停止舊容器。我用Nginx做TLS終止,但kamal-proxy可直接處理流量並內建Let’s Encrypt SSL。
機密管理也很合理。Kamal從.kamal/secrets讀取機密,指向其他機密來源,部署時注入環境變數,安全管理註冊密碼、Rails主鑰、資料庫憑證等。也可從1Password或AWS SSM拉取機密,範例檔案提供參考。
這一切都由一條命令驅動:kamal deploy。
我用GitLab CI管線觸發,保護分支對應各環境,通常git push或合併請求通過後自動部署。感覺像回到Heroku魔法,但你擁有整個堆疊,清楚知道發生什麼。一次kamal deploy就能建置、推送並滾動更新多台伺服器。這是Rails多年來一直缺乏的工具。
當然沒完美,我覺得用久了總會找到讓人不爽的地方。我傾向用那些讓我不那麼生氣的技術,避開讓我火冒三丈卻沒好處的。Ruby和Rails絕對屬於前者,但這只是我個人看法。
Ruby的「魔法」可能讓你覺得難懂混亂。如果你喜歡表達力強的程式碼,且來自Perl「多種做法」背景,應該會愛它。但我意識到工具選擇(vi、emacs、vscode大戰)很個人,反映思維方式。語言和框架是將想法轉成可執行碼的最底層,選擇很重要。
就品味而言,Ruby符合我對良好系統的美學,但它確實是需要培養的口味。這也是最大缺點。前面調查顯示,Ruby和Rails的吸引力多年來變得更「挑剔」——用Spinal Tap的話說。
它仍被許多不張揚的地方使用(有些你可能意想不到),且Shopify、Soundcloud、Basecamp等大品牌仍用Rails。GitHub也是,但可能不該大肆宣傳……
雖然Stack Overflow調查不一定準確反映開發者意見,但Ruby和Rails排名下滑顯示它近年失寵。很多文件和教學多年未更新,許多套件和插件也如此。警告標語越來越常見。
大多數套件活動趨勢也類似。以Devise為例,發布歷史呈現Rails「黃金時代」的爆發後逐漸維護模式。
除了2016年v4版本有一波活動,之後相當平靜。樂觀者會說這些專案已成熟穩定,功能齊全,運行關鍵高流量網站,沒什麼新功能可加。
反觀Rails本身,自2010年Rails 3大爆發後,發展勢頭持續且穩定,每年都有新版本。它是少數隨著時間成長而非燃燒殆盡的開源專案。是否能吸引新開發者仍是未知,但我很高興還有像我這樣固執的人不願放手這個明顯優秀的工具。我或許能用其他語言或框架差不多速度完成,但不會像現在這麼開心。
如果你看到這裡,恭喜,也謝謝你聽我這場TED演講/長篇大論!我猜你多少被激起好奇心,如果是,強烈建議試試Rails。跟著教程,做點酷東西,最重要是享受過程——因為這才是重點。當然,有更流行的框架能讓你履歷更亮眼,但正如我開頭說的,有時候純粹為了樂趣做事也值得。
我網站上的觀點屬於個人,不代表現任或前任雇主立場。
我記得在祖父過世前不久談起他一生見證的變遷。他生於1911年,說過讓我印象深刻的是,孩童時代人們才剛開始飛行;他60歲前,人類已登月。回望我童年時的8位元微電腦,與我女兒成長的現代世界相比,我不禁感慨……