定義與實作

緣起:最近在公司做的一個專案的內容,是要改善資料庫的效能。原本寫入資料庫的一段程式碼,因為最初寫的時候太暴力,完全套用 ORM 來硬寫,所以造成資料庫很大的負擔。也因此,我們決定要來重構這一部分的程式碼。

重構分成 3 個層面:

  1. SQL 語法的部分
    原本的 SQL 是用 ORM 硬做的,改成活用了 temp table 的語法後,效能就會改善許多。

  2. 移動程式碼到合適的 microservices
    本來週期性寫入資料庫的程式碼是放在 gateway 的模組。因為 gateway 模組需要有很快的反應時間 ,所以在 production 環境中, gateway 的模組有三個 instances ,也因此這段週期性寫入資料庫的程式變成要去考慮「平行寫入」的問題。其實這一段程式碼放錯了「模組」,應該要放在週期性執行的 cron 模組才對。放到全系統唯一的 cron 模組之後,就不需要再考慮「平行寫入」的問題。

  3. 加入合適的抽象層
    我們後來決定,要在再加入一層抽象層: restful API 用來包住資料庫的存取指令 。如此讓程式碼可以依賴於 restful API ,而不是直接依賴於某個特定的資料庫。

這些重構,讓我想清楚了軟體工程中很重要的一個概念:「定義」與「實作」的分離。此處的『定義』,也可以解釋成「企業邏輯」,對應的複雜度可以用 essential complexity 來理解。換言之,定義層次的複雜度、定義層次的語意,是由需求來決定。此處的『實作』,則是指實現企業邏輯的各種可能的方案,對應的複雜度可以用 accidental complexity ,(當然我們一定儘可能去選擇 low accidental complexity 的方式來實現。) 一旦加入了 API 抽象層之後,日後的修改就會變得相對簡單。

比方說,如果是要從 gateway 模組移動 restful API 到 cron 模組,那我們測試的時候,只要確定 gateway 模組與 cron 模組使用 restful API 的方式是等價即可。 API 實現的細節則不會再有任何的改動。

另一種情況,如果需要做的改動是用 temp table 的語法取代舊有的 SQL 語法。這種改動完全藏在資料庫存取的 restful API 裡,所以我們之後驗証的時候,也就只需要對 restful API 做單元測試即可。