AI 時代的軟體分工:為何前端會被併進後端,而不是反過來?
前陣子我接了一個農業 IoT 的外包案。田裡的裝置定時拍照上傳,雲端跑 AI 模型辨識害蟲的種類跟數量,客戶要能在後台看到結果。
我負責的是「軟體這一整塊」。這句話講出來很唬人,實際的意思是:後端沒有第二個人,前端也沒有,App 也沒有。
我是一個寫了十幾年 PHP 跟 Laravel 的後端工程師。那個案子最後我交出了 Laravel + PostgreSQL 的後端(跑在 GCP Cloud Run + Cloud SQL 上)、一個管理後台,還有一支上架 App Store 的 iOS App。
我不覺得這件事值得誇耀。我想講的是另一件事:這條路只有單向通車。
我跨過去了,而且比我以為的省力太多。但這兩年我沒看過一個對稱的反例——沒有哪個純前端工程師,在差不多的時間、差不多沒人帶的條件下,接下一整套牽涉權限、交易與資料一致性的後端,然後平安上線、平安過完接下來的半年。
所以當我看到有些公司開始縮前端的編制、把人併進後端、職稱一律改成 full-stack 的時候,我第一個反應不是驚訝,是「對,而且我大概知道為什麼」。
這篇想講的就是那個「為什麼」。
直覺的答案是錯的
最直覺的解釋是「後端比較難,所以難的吃掉簡單的」。
我不同意。真要比,一個要同時處理複雜 state、side effect、跨裝置相容、動畫效能跟可及性的前端,難度一點都不輸給我平常在做的事。難度不是分水嶺。
我認為真正的分水嶺是另一個東西:驗證成本。
過去兩年變便宜的,是「產生一份看起來合理的程式碼」。沒有跟著變便宜的,是「確認這份程式碼在真實世界是對的」。而這兩件事的落差,在前端跟後端身上差得非常不平均。
AI 在前端跑得快,是因為那個迴圈閉得起來
Agent 能在某些領域跑得飛快,靠的不是它在那個領域比較聰明,是那個領域有一個閉得起來的回饋迴圈。
前端有。改 code、跑起來、開瀏覽器、截圖、點一點、跑 interaction test。錯了會在畫面上——版爆了、按鈕點不到、資料沒帶進去,這些全部都會顯現。Agent 可以自己看、自己改、自己再試一次,不需要我。
這是我做那個管理後台時最直接的體感:那份 CSS 我幾乎沒有「讀懂」過。我只是一直在說「這裡太擠」「這個表格在手機上爆版」「篩選器收起來」,然後看它改、看截圖、再說下一句。迴圈短到我可以只當一個驗收的人。
我甚至沒有為此感到心虛。因為我知道,如果它改壞了,我會在三十秒內看到。
後端的錯誤,多半是沉默的
換到後端,那個迴圈就斷了。不是因為後端比較難,是因為錯誤不會在你面前顯現。
這幾年我修過、或是半夜被叫起來修過的東西,大概長這樣:
- 權限判斷寫錯。 不會拋 exception,API 照樣回 200,只是回了不該給這個人看的資料。測試也會過,因為測試是拿有權限的帳號跑的。
- 交易邊界抓錯。 九成九的時候都對。錯的是那千分之一、兩個請求剛好撞在一起的瞬間,而那個瞬間不會出現在你的本機。
- 少建一個 index。 在你五千筆的測試資料上,那句 query 是 12 毫秒;在客戶三百萬筆的正式資料上,它是四十秒。
- 金額用了 float。 今天對,這個月對,第三個月對帳的時候少了幾毛錢,然後你要花兩天解釋那幾毛錢是怎麼不見的。
- Migration 沒考慮鎖表。 在 staging 兩秒跑完,在 production 把整張表鎖了四分鐘。
- 時區。 所有測試在 UTC+8 通過,然後某個時區的使用者看到的日期差一天。
這些 bug 有一個共同點:它們不會讓任何一個測試變紅。
它們要嘛需要真實的資料量,要嘛需要真實的併發,要嘛需要三個月後的一次對帳,要嘛需要一個剛好不在你時區的使用者。你不能截圖,你不能點兩下就看到,你甚至不能保證它今天會發生。
對 agent 來說,這代表迴圈斷了。它可以寫出那段程式碼,甚至寫得比我快、比我漂亮;但它拿不到「這段是錯的」這個訊號。拿不到訊號,就沒有辦法自我修正。
而只要迴圈需要一個人來閉合,那個人就還在。
把前後端放進同一張圖,差異不在 AI 會不會寫,而在它能不能及時收到「寫錯了」的訊號:
flowchart TD
A["AI 產生一版程式碼"] --> V{"現在能取得可靠的<br/>失敗訊號嗎?"}
V -->|"能:常見於畫面、互動與會報錯的測試"| R["agent 根據訊號修正<br/>當下閉合回饋迴圈"]
V -->|"不能:本機與既有測試可能全部綠燈"| H["等待真實世界條件<br/>資料量、併發、時間<br/>權限組合或不同時區"]
H --> L["沉默錯誤延後在<br/>production 浮現"]
L --> O["需要人補上監控、測試<br/>風險判斷與 ownership"]
前端不是永遠容易驗證,後端也不是永遠無法自動化;真正的界線是右下角那條路徑——錯誤如果要等真實世界給訊號,agent 就無法在當下自行閉合迴圈。
組織不是照能力重組,是照責任重組
有了上面這段,「為什麼是往後端流」就不難理解了。
公司在重畫編制的時候,看的通常不是誰比較厲害,是出事的時候誰要負責。
前端出錯的最壞情況,多半是畫面壞了、按鈕點不到、使用者截圖來罵你。很難看,但通常幾個小時內能修好,而且可以回滾。
後端出錯的最壞情況是資料壞了、權限外洩、帳對不起來。有些能回滾,有些不能——資料一旦寫錯,而且已經被下游讀走、被別的系統寫進別的地方,你能回滾的是程式碼,不是後果。
這對我不是抽象的比喻。我現在的客戶是醫療機構。如果一筆資料串錯了對象,或是某個帳號看到了不該看到的紀錄,那不是「畫面壞了」的等級,那是要寫報告、要通知、可能要面對稽核的等級。
當兩側的責任重量差這麼多,組織自然會把 ownership 留在重的那一側,再把輕的那一側併過去。不是因為輕的那側不重要,是因為併過去的成本比較低——低到只要一輪縮編,就有人會去算這筆帳。
我自己就是被這筆帳算過的人。年初公司裁完一輪之後,後端部門剩下一個,那個人是我。而「順便把後台畫面也做一做」這件事,從來沒有人正式跟我談過,它就是自然而然地變成我的事了。
但 AI 沒有替我做的那一段
這裡我要誠實一點,不然這篇會變成一則太順的故事。
用 agent 生那個管理後台,我大概兩天就有一個能動的版本。但「能動」跟「能用」中間,有一段 AI 完全沒有參與:
- 農夫早上打開後台,第一眼應該先看到什麼?是今天的蟲數,還是有裝置沒回報?
- 一個裝置三天沒上傳,這是告警還是資訊?如果是告警,要吵醒誰?
- 哪些操作該跳出「你確定嗎」把人擋下來,哪些不該——因為擋太多次,使用者就會養成閉著眼睛按確定的習慣。
這些問題,agent 一題都沒有替我回答。它給了我三個都能動的版本,然後我得自己選一個。
所以「前端會被吸收」講的從來不是「畫面自己會長出來」。是把已經想清楚的設計決策翻譯成畫面這一段實作變得非常便宜;而想清楚的那一段,一點都沒有變便宜。
我不覺得前端會消失
「XX 已死」這種標題我一向不太信,所以這裡要把但書寫清楚。
會被壓縮的是三樣東西:獨立的前端部門編制、獨立的職稱,以及中位數的那些 UI implementation 工作。
不會消失的第一樣,是人跟系統怎麼溝通這件事。它反而在 agent 時代更重要:當使用者可以直接對系統下指令、讓它一次做完十步,介面的問題就從「按鈕放哪」變成「什麼時候該讓人確認」「怎麼預覽一個還沒發生的動作」「做錯了要怎麼回復」。這幾題比排版難得多,而且答錯的代價高得多。
不會消失的第二樣,是前端的深水區——design system、可及性、動畫與渲染效能、跨裝置行為。有意思的是,這些東西照我自己的邏輯推下去,恰好也是驗證迴圈斷掉的那一類:可及性做壞了不會讓測試變紅,效能劣化在你那台高階筆電上看不出來,某個特定機型的 WebView 行為要有那台實機才會發現。
換句話說,前端裡最不容易被吸收的部分,剛好就是最不容易被自動驗證的部分。我覺得這個推論反過來也支持了前面那個框架:真正決定誰被誰吸收的,從頭到尾都是驗證成本,不是技術棧的名字。
後端也不要太得意
同一把尺,也要照回自己身上。
後端裡驗證迴圈完整的部分,一樣已經便宜了。CRUD、標準的 REST endpoint、把規格翻成 service class、補單元測試——這些我現在幾乎不自己寫第一版了。它們能跑、能測、錯了會紅,完全符合「agent 擅長」的條件。
真正還撐住我的,不是「我會寫 API」。是我知道這個功能上線之後最壞會怎麼壞、以及什麼時候該把一個看起來沒問題的需求擋下來。
那實務上該做什麼
不灌雞湯,就講兩件我自己在做的事。
如果你是後端: 既然你的價值在「沉默的錯誤」那一側,那最划算的投資就是讓錯誤不再沉默。監控與告警、一個資料量接近真實的測試環境、把權限規則寫成會失敗的測試而不是寫成註解、把對帳做成排程而不是等客戶問。你每把一個沉默的錯誤變成一個會叫的訊號,就多一段工作可以放心交給 agent,同時多一分晚上睡得著的機會。
另外,順手把前端撿起來。成本比你以為的低很多,而且它會改變別人怎麼定義你——在一輪縮編裡,這件事的價值遠比它的技術含量高。
如果你是前端: 我不是要你去背 SQL 語法,那沒用。是往驗證迴圈斷掉的地方移動:這份資料的真相來源在哪裡、兩個人同時按下去會發生什麼、這一步失敗了下游會怎樣、出事之後要怎麼收拾。你不需要變成 DBA,你需要的是在一個功能上線前,講得出它最壞會怎麼壞。能講出這句話的人,不管掛什麼職稱,都不會是先被併掉的那一個。
寫在最後
我真正相信的版本比較無聊,沒什麼標題張力:分工的邊界,會沿著「哪裡的錯誤看得見」重新畫一次。看得見的那一側會被壓縮、被自動化、被併進去;看不見的那一側會留下 ownership,也會留下人。
我剛好站在看不見的那一側。這不是因為我比較聰明,比較像是入行的時候隨手選了一條路,而那條路後來剛好比較難被自動化。
所以我不打算把它當成護城河。我打算把它當成一份提醒:現在還保住我的,從來不是我寫出來的那些 code——是我對「它會怎麼壞」的理解。而這件事,是要一次一次被叫起來修,才會慢慢長出來的。