工程師與貓
ESC
Content
    ↑↓ navigate open esc close
    Published on

    一個人扛一整個網站時,我學會放掉什麼

    Authors
    • avatar
      Name
      Alex Yu

    前一份工作我帶五個前端,主要的事是分派任務、review、mentor。

    現在我是一整條產品線唯一的前端。一個流量主站、一套自己維護的活動微站框架,加上部署和線上事故——從寫產品功能到管伺服器,全是我一個人扛。

    剛轉過來的時候我還想用帶團隊的標準要求自己——每個 PR 都要完美、每塊 code 都要最佳化。撐了一陣子發現不對。一個人的時間就這麼多,再用「五個人的產能標準」要求一個人,只會把自己榨乾還做不完。

    於是真正要練的能力變成:在「自動化、降標準、不妥協」這三堆之間,快速把每件事分類。

    該自動化的:重複的判斷

    一個人最貴的是判斷力,最不該浪費在重複勞動上。任何「每次都一樣、不需要思考」的事,都該丟給機器。

    最有感的一個是分支清理。我們的流程是一張票會長出好幾條分支——feat/ 開發、candidate/ 待驗、發版時再一條 release/。PR merge 進 main 之後,這些分支就沒用了。

    GitHub 有內建的「merge 後自動刪 head branch」開關,但它只刪 PR 的那一條,同一張票的兄弟分支還留在遠端。一個人開發的時候沒有人會提醒你,幾個月下來遠端就是一長串沒人認得的分支。

    所以自己寫一支,從分支名解析票號,把整組清掉:

    on:
      pull_request:
        types: [closed]
        branches: [main]
     
    jobs:
      delete-branch:
        if: >
          github.event.pull_request.merged == true &&
          (startsWith(github.event.pull_request.head.ref, 'feat/') ||
           startsWith(github.event.pull_request.head.ref, 'hotfix/') ||
           startsWith(github.event.pull_request.head.ref, 'release/'))
        runs-on: ubuntu-latest
        permissions:
          contents: write
        steps:
          - uses: actions/github-script@v8
            with:
              script: |
                const branch = context.payload.pull_request.head.ref
                await deleteBranch(branch)   // 先刪 PR 自己那條
     
                // ← 重點:同一張票的兄弟分支也要一起清
                const ticket = branch.match(/^(?:feat|hotfix)\/(ticket-\d+)/i)?.[1]
                if (ticket) await deleteBranch(`candidate/${ticket}`)

    release/ 的 PR 會一次收掉好幾張票,所以那條路徑改成從 PR 標題把票號全撈出來,逐一清掉。刪之前一律先確認分支存在,404 就跳過——它必須能重複執行而不出錯。)

    這是一次性投入,之後每次 merge 都自動省一個動作。對一人團隊來說,這種 DX 投資的 ROI 最高——它讓我不用再把這件事記在腦子裡。

    當別人的工具每週覆蓋你的 code

    另一個例子更棘手,因為它不只是麻煩,是做錯了不會有人告訴你。

    我手上有個策展活動頁,內容由策展組用視覺化網站工具產出,每週交一包 HTML 給我,當天要上線。流程很單純:把打包檔覆蓋進 repo、上線。

    問題是那包 HTML 是他們的工具產的,不知道我在頁面裡加過東西。每覆蓋一次,我埋的 GA 追蹤腳本就被洗掉一次。還有幾個固定要補的:拿掉會拖慢 INP 的套件、幫 YouTube iframe 補上 enablejsapi=1、把絕對路徑改成相對路徑。

    第一層自動化很直觀,把這些修補寫成腳本,覆蓋完跑一次:

    # pre-deploy-patch.sh — 每次套用打包檔後執行
    #   1. 移除會拖慢 INP 的 script
    #   2. 注入追蹤腳本(</body> 前)
    #   3. YouTube iframe 補 enablejsapi=1
    #   4. 絕對路徑改相對路徑(同 origin 才能用 postMessage)
    #
    # 冪等設計:重複執行不會重複注入   ← 關鍵,不然手滑跑兩次就爆

    更麻煩的是,壞掉的時候沒有人會告訴你

    但腳本注入成功,不代表追蹤真的有效。

    那支追蹤腳本是靠 CSS selector 抓 DOM 的——#PartD-topic 是某個區塊、.nav-link 是導覽按鈕。而策展組在他們的工具裡改版面時,這些 id 和 class 會跟著變。

    於是最糟的情況長這樣:打包檔套用成功、頁面看起來完全正常、上線也沒報錯,但某幾個區塊的 GA 事件從那天起再也沒進來過。 沒有錯誤訊息、沒有紅燈,等到有人問起數據才發現,中間已經漏了兩週。

    所以第二層自動化是把「這些 selector 還在不在」變成可以檢查的東西。selector 全部抽成設定檔:

    {
      "index": {
        "required": [
          { "id": "GA-07", "pattern": "id=\"PartD-topic\"", "description": "專家訪談區塊" },
          { "id": "GA-10", "pattern": "id=\"PartI-video\"", "description": "影音學堂區塊" },
          { "id": "JS-01", "pattern": "exhibition-tracking\\.js", "description": "追蹤腳本有載入" }
        ]
      }
    }

    再配一支驗證腳本,任何一條對不上就 exit 1,然後讓 CI 每個 PR 都跑。原本無聲失效的東西,變成上線前一定會擋下來的紅燈。

    第三層:把整套流程交給 AI

    腳本解決了執行,但每週那套流程還有一堆得記在腦子裡的東西:哪些檔案該 stage、哪個資料夾絕對不能 commit、diff 要怎麼對照策展組的文稿逐項確認。

    這部分我寫成了 Claude Code 的 skill,把整套工作流固化下來:

    ---
    name: exhibition-weekly-update
    description:
      策展頁的接手與維運流程:每週打包檔更新、pre-deploy-patch、
      validate-tracking-selectors、埋點 selector 失效時的修補、常見地雷。
      當使用者提到套用打包檔、tracking selector FAIL 時觸發。
    ---

    這裡有個合理的疑問:前面兩層都寫成腳本了,這層為什麼不繼續寫腳本就好?

    因為剩下的事情,腳本做不了——它們都要先「讀懂當下的東西」才能決定怎麼做:

    • 策展組每週附的更新文稿是白話文(「header 加兩張、學堂多兩支影片、名人區加一位」),我得逐項對照 diff 確認有沒有漏做。腳本沒辦法讀懂一段中文說明,再去跟 DOM 的改動配對。
    • selector 驗證失敗時,腳本只能告訴我「GA-10 這條對不上」。但那個區塊現在改叫什麼、該把設定檔改成哪個新 id,得打開新的 HTML 看過才知道。
    • 每週改動的檔案範圍都不一樣,該 stage 哪些也就不一樣。

    所以分工其實很清楚:確定性的步驟留給腳本(快、可靠、CI 也跑得動),需要讀上下文才能下的判斷交給 AI。而 skill 的角色是把「什麼時候該叫哪支腳本、結果怎麼判讀、哪裡有地雷」這套流程寫下來——它不是取代那些腳本,是指揮它們。

    現在的流程變成:我把打包檔丟給它,它照著跑修補、驗證、精準 stage,再對照文稿列出 diff 摘要,我只做最後確認。

    重點不是 AI 幫我寫了多少 code,而是我把一次想清楚的流程和判準固化下來,之後每次都不用重想——包括三個月後已經忘光的自己。

    判斷哪些該自動化的標準很簡單:這件事需要我的判斷力嗎? 不需要的推給腳本;需要判斷、但每次判準都一樣的,把判準寫下來交給 AI。

    該降標準的:80 分就交的事

    一個人不可能每件事都做到 100 分。重點是刻意決定哪些事 80 分就好,然後不覺得愧疚。

    我的分法大致是這樣:

    • 改動範圍小、又不在核心路徑上的 → 80 分,能動就好
    • 內部工具、自己用的 script → 60 分,醜沒關係
    • 流量大、出錯影響廣的核心頁 → 不在這堆裡,見下一節

    以前帶團隊會覺得「降標準」是種失職。但一個人扛的時候,不分輕重地追求完美,本身才是失職——因為你把時間花在不重要的地方,重要的地方反而沒空顧。

    「不完美但持續做」這句話,當管理者時是拿來鼓勵團隊的;當唯一前端時,是拿來說服自己放手的。

    不能妥協的:核心路徑與不可逆的東西

    降標準有界線。流量最大的核心頁、會白屏的地方、不可逆的破壞性操作——這些不在 80 分那堆裡。

    判準是「出錯的代價」。一個內部 script 出錯,我自己重跑就好。核心文章頁出錯,是當天全站流量的事。代價不對稱,標準就不能對稱。

    破壞性操作也一樣。我可以接受 AI 幫我寫大部分的 code,但真正會刪資料、改 production 設定的動作,一定要人來確認。AI 給建議、人做決策,這一點我很堅持。

    漸進式重構,不做 big bang

    一個人還有一個現實限制:沒有後援。

    帶團隊的時候,可以排一個人花兩週做大重構,其他人扛日常。一個人沒有這種餘裕——你一旦進入 big bang rewrite,日常需求就全部停擺。

    所以我偏好 POC 先行、小步重構。先做一個小範圍驗證可行,再一塊一塊換,每一步都保持系統可運作。

    big bang:停兩週重寫 → 期間零產出 → 上線即大爆炸
    漸進式:每個 sprint 換一塊 → 隨時可上線 → 風險分散

    當年帶團隊把測試覆蓋率從 0% 推到 56%,也不是某次衝刺一次到位,是每個 sprint 多寫一點累積的。一個人做事更要這樣——因為你輸不起一次「全停下來重做」的賭注。

    從帶人到單兵,判斷的優先序變了

    帶五個人的時候,我的槓桿是「設計讓團隊跑得更順的機制」——Git Flow、CI cache、測試文化。我自己寫不寫 code 沒那麼關鍵,把五個人的效率拉起來才是。

    一個人的時候,槓桿變成「決定什麼不做」。產能就這麼多,多做一件 80 分的事,就少做一件該做到 100 分的事。

    技術能力反而不是這個階段的瓶頸。瓶頸是取捨的判斷力——你能不能誠實地承認「這件事我不做」,然後把省下的時間放在真正重要的地方。

    幾個帶走的想法

    • 該自動化的判準:這件事需要我的判斷力嗎?不需要的推給腳本;需要判斷但判準固定的,寫下來交給 AI。
    • 該降標準的判準:出錯的代價多大?代價小的就 80 分。
    • 一個人最該練的不是「做更多」,是「誠實地決定不做什麼」。

    一個人開發的時候,沒辦法事事都追求完美,因為時間就是有限。所以現在對我來說,這份工作比較像是在做資源分配——每天決定哪些事值得花時間,哪些事到此為止。

    延伸閱讀

    參考資料