🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

引言

本文是 TRIAL&RetailAI Advent Calendar 2025 第 18 天的文章。

昨天是@zushi_ryota 的「1.26次元的圖形?! ~嘗試計算分形圖形的維度~」這篇文章。文中用 D 語言生成了在雪花中可以見到的分形圖形,真心推薦大家閱讀!


那麼,作為一名工程師已經工作了兩年。

目前,我正在參與每秒有大量數據流入的即時處理系統的開發。這兩年來,經歷了許多失敗後,常常會想「我早該知道這些」。

在本文中,我將分享我親身學到的教訓。

1. 規範變更一定會發生

「這個規範已確定」是謊言。

剛開始的時候,我很自信地按照確定的規範進行「完美的設計」。但現實並不如人願。在發佈前,會突然收到「還想再加這個項目」或「想改變計算邏輯」的請求。

// 對變更敏感的設計:Service 直接依賴 PostgreSQL
class OrderService(
    private val postgresRepository: PostgresOrderRepository
) {
    fun save(order: Order) {
        postgresRepository.insert(order)  // 直接對 PostgreSQL 進行 INSERT
    }
}

當聽到「請改成 Google Cloud 儲存」的那一刻...

  • 不得不修正 Service 類與 Repository
  • 還要搜尋所有使用 PostgresRepository 的地方進行修正...
// 對變更不敏感的設計:抽象化訪問層
interface OrderRepository {
    fun save(order: Order)
}

class OrderService(
    private val repository: OrderRepository  // 依賴於介面
) {
    fun save(order: Order) {
        repository.save(order)  // 不知道保存到哪裡
    }
}

「改成 Google Cloud」→ 只需替換實現類

  • class PostgresOrderRepository : OrderRepository { ... }
  • class GoogleCloudOrderRepository : OrderRepository { ... } // 只需新增這一行

要堅持設計對變更友好

  • 假設「規範會變更」來進行設計
  • 避免硬編碼,留有透過設定變更的空間
  • 意識到要有擴展性結構(介面、策略模式等)

有關設計的更多資訊,參考@kakine_juri
如果只是按功能劃分,是不行的。寫作軟體這塊,還需要學習。」他對於基於變動性進行劃分的設計方法「Righting Software」做了清晰的解釋。

2. 數據一定要進行驗證

奇怪的數據總是會來。

「在規範上不可能出現的數據」,在現實中卻很常見。

實際遭遇的例子:

  • 必填項目為 null、空字串
  • 數值項為負值或超出範圍
  • 相同鍵的數據重複到達
// 不可隨意相信
fun process(data: ExternalData) {
    val amount = data.amount  // 可能為 null、負值,或超過 Int 的最大值
}

// 在入口階段驗證
fun process(data: ExternalData) {
    val amount = requireNotNull(data.amount) { "amount is required" }
    require(amount > 0) { "amount must be positive" }
}

對所有來自外部的數據都要保持懷疑態度

  • 在入口徹底進行驗證
  • 異常數據記錄到日誌並丟棄
  • 「在規範上不可能的」在「現實中是可能的」

3. 測試代碼要寫得好

在處理大量數據的系統中,未涵蓋的情況更容易出現錯誤。

如果只因為「正常情況都能運行」而安心,那麼在生產環境中,你會為只有在特定條件組合下才會發生的錯誤感到懊惱。

// 容易忽略的測試案例
@Test
fun `即使是空列表也能正常運作`() { }

@Test
fun `處理大量數據(10 萬條)不會超時`() { }

@Test
fun `相同鍵的數據連續到達仍然保持一致性`() { }

@Test
fun `處理過程中即使隊列數據中斷也能恢復`() { }

測試是未來自己的一份保障

  • 除了正常情況外,也要寫邊界值、異常情況和大量數據的測試
  • 對於「不可能出現」的情況,越要寫測試

4. Git 要整潔管理

曾經一段時間,每次從 develop 分支切出 feature 分支後,就無止境地進行提交。

結果會如何:

  • 無法追踪到是在哪個提交中出現了 bug
  • 審查方也會苦不堪言(差異過於龐大)
  • 釋出時功能還需要進一步拆分,特別麻煩

Git 是開發的生命線

  • feature 分支要小且壽命短
  • 提交應該注意「每個修改一個提交」
  • 提交信息不僅要寫「做了什麼」,還要說「為什麼這麼做」
  • 定期合併 develop/main 以保持小的差異

關於提交信息,參考@fujithuro 的「讓未來的自己不會哭的提交信息」。我也曾經因為懶惰,做了很多像是 [fix]修正 這類毫無意義的提交,忍不住想揍過去的自己...

5. 預估要長一些

「三天可以完成」→ 實際需要一周。

預估不準確的原因:

  • 只考慮實現,忘記測試、審查和修正時間
  • 以「如果順利的話」的最短路徑來計算
  • 沒有考慮到其他任務的干擾
  • 沒有為調查或驗證的時間進行預估

預估要算 1.5 到 2 倍

  • 給出「現實的」預估,而非「最短的」
  • 對於不確定性高的任務,應該提前告知並新增緩衝時間
  • 記錄預估與實績,以了解自己的準確度

尤其是對於經驗尚淺的工程師,即使預估三倍也不會被罵(多半是這樣)。

6. 數據庫不是萬能的

數據庫也有其極限。

實際遇到的問題:

  • 每條 INSERT 單獨執行 → 大量數據時非常緩慢
  • 索引未優化 → SELECT 要幾十秒
  • 一個事務中塞得太多 → 超時
// 緩慢
items.forEach { repository.save(it) }

// 快速
repository.bulkInsert(items)

了解數據庫的特性並善加利用

  • 大量 INSERT 要用 bulk insert
  • 對於需要搜索的欄位要添加索引
  • 以適當的單位進行提交,避免長時間的事務
  • 養成監控慢查詢日誌的習慣

7. 不要不明就裡地使用

「能動就好!」是最危險的想法。

複製粘貼就能運行的代碼。不經意間添加的註解。完全不理解的庫。這些情況在特定情況下都可能成為災難。

實際經歷過的可怕故事:

  • 不理解 @Transactional 的行為,導致數據不一致
  • 不了解 RabbitMQ 的 ack,造成消息丟失
  • 非同步處理的例外處理漏掉,錯誤消失無蹤

不懂「為什麼會動」的代碼就不要寫

  • 養成閱讀官方文檔的習慣(注意版本)
  • 不要停留在「總之能動」的表面,要確認其行為
  • 如果不懂就問,現在也可以輕鬆地詢問 AI。

8. 日誌要好好記錄

當故障發生時,沒有日誌就無法查明原因。
擔心「日誌輸出過多會讓系統變慢」而有所保留,最終在生產環境中目睹發生了什麼卻一無所知的地獄。

// 不好的例子:什麼都不知道
fun process(data: Data) {
    try {
        service.execute(data)
    } catch (e: Exception) {
        throw e  // 失敗的數據是什麼?
    }
}

// 好的例子:可追蹤
fun process(data: Data) {
    logger.info { "Processing started: id=${data.id}" }
    try {
        service.execute(data)
        logger.info { "Processing completed: id=${data.id}" }
    } catch (e: Exception) {
        logger.error(e) { "Processing failed: id=${data.id}, payload=$data" }
        throw e
    }
}

日誌是未來自己的一封信

  • 處理的開始、結束、失敗一定要記錄在日誌中
  • 包含能特定「哪個數據」和「發生了什麼」的信息
    • 但要對個人資訊和機密信息進行遮蔽
  • 根據日誌級別(INFO / WARN / ERROR)適當區分
  • 使用 @WithSpan 來正確設置分段(opentelemetry)

關於 opentelemetry 的使用,參考@kyojinnaapyon 的「log.debug() 只有看不到的世界,OpenTelemetry 給我們展示」也是不錯的資源。利用 opentelemetry 讓我能夠更快地定位 bug!

結語

用一句話總結我兩年來的學習,
「總之,工程師是真正有趣的工作。」
讓我們朝著不被 AI 淘汰的怪物工程師努力吧。


明天的手作日曆將由@ikeda_takato 為大家帶來「ATT&CK T1059 深入探討:攻擊者為什麼如此熱愛 CLI」。敬請期待!


RetailAI 與 TRIAL 正在招聘工程師。
有興趣的人請隨時聯繫我們!


原文出處:https://qiita.com/ido_shun/items/3529b142ec6849eca24a


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝13   💬9   ❤️5
355
🥈
我愛JS
📝1   💬8   ❤️2
61
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付