功能做對了,實作方式也對嗎?

從設計一致性、系統整合與對抗式 review 三個角度,檢查功能不只做對,也用適合既有系統的方式完成。

Day 25 寫到,測試可以把已經確認過的行為留下來,讓後面的修改持續重新面對這些期待。

但即使測試全部通過,我的開發流程還不會停在這裡。

因為測試主要在回答:

已經被寫下來的期待,有沒有成立?

但還有另一個問題:

即使功能真的做對了,這個實作方式也適合這套系統嗎?

這就是我現在還會再做 review 的原因。

第一個要看的是:有沒有照原本的設計做

現在開始 Coding 以前,我通常已經先走過規格和 design 的討論。

這些文件不只描述最後功能要做到什麼,也常會包含:

  • 不同系統部分怎麼分工
  • 資料怎麼流
  • 這次修改預計採什麼方式
  • 哪些既有責任不能被破壞

所以功能完成之後,我會再把實作拿回來和 design 對照。

不是只確認:

最後畫面有沒有動。

而是:

程式最後是不是照著前面確認過的方式做。

因為同一個功能結果,通常不只一種實作方式。

有些做法可以讓測試全部通過,功能也真的正常。

但如果它已經繞過原本設計好的責任分工,或者改成另一套沒有先討論過的方式,這件事情仍然需要被看見。

對我來說,design 不只是 Coding 開始以前的計畫。

它也是 Coding 完成之後,拿來重新確認實作方向的依據。

第二個要看的是:有沒有長進原本的系統裡

我現在還會再看另一個面向:

這次實作,有沒有符合這個專案原本的工程方式。

這和「有沒有照這次 design 做」不完全一樣。

design 比較像是在看這一次修改。

這一層則是把視角拉到整套既有系統。

原本責任怎麼分?

前後端怎麼交換資料?

不同 repo 彼此怎麼配合?

哪些邊界已經被建立?

一個專案做久之後,這些東西會逐漸形成穩定的結構。

如果每一次新增功能,都只想:

這次怎麼最快做出來?

很容易每個地方都長出不同做法。

單看某一個功能可能都可以運作,但整套系統會越來越難理解,也越來越難維持原本的分工。

所以這一層真正問的是:

這個做法放進目前這套系統裡,還合理嗎?

對我來說,更接近:

不是只把功能塞進專案,而是要讓它長進原本的系統裡。

我把這兩個問題放在同一個 review 裡

我目前有一個自訂的雙軸審查方式。

所謂「雙軸」,就是 review 時固定看兩件事:

第一個:

有沒有符合這次 design。

第二個:

有沒有符合既有系統的工程方式。

這兩個面向分開看很重要。

因為一個實作可能:

  • 很符合這次 design,但 design 本身和既有架構不一致。
  • 很符合既有做法,但沒有真正把這次 design 裡的新要求做完整。
  • 功能結果正確,但責任放錯地方。
  • 某一個 repo 自己正常,跨 repo 的修改卻只做了一半。

所以 review 對我來說,不只是再檢查一次「功能有沒有壞」。

而是重新確認:

前面做出的工程判斷,有沒有真的被守住。

對抗式 review,是換一種方式找問題

除了雙軸審查,我現在也會使用 Spectra audit 裡的三角色對抗式 review。

這兩件事不是三個並列的 review 類型。

雙軸比較像是在決定:

我要檢查哪些事情。

對抗式 review 則是在改變:

我要用什麼方式去檢查。

一般實作時,主要問題通常是:

我要怎麼把這個需求做出來?

對抗式 review 會故意站到另一個位置:

我要怎麼找出這個實作可能出問題的地方?

它會主動去挑戰:

  • 有沒有地方偏離 design
  • 有沒有繞過原本的責任邊界
  • 有沒有某條路徑只在正常情況成立
  • 有沒有某個修改只完成其中一部分
  • 有沒有從安全或權限角度看會出現的問題

所以它不是再多加一個 review 面向。

而是用更刻意找問題的方式,重新檢查前面已經定好的那些面向。

測試通過,還不能回答「這樣做適不適合」

到這裡,我會把測試和 review 的差別看得比較清楚。

測試比較像是在問:

那些已經被定義的行為,有沒有成立?

review 則會再問:

即使功能成立,實作本身有沒有偏離前面的設計與系統邊界?

這兩層都需要。

因為如果只看功能結果,很容易變成:

每個功能單獨都能跑。

但整套程式逐漸長成彼此不一致的做法。

前面花時間討論的責任分工、design 和工程決策,也可能在真正實作時被繞掉。

所以我現在不只想知道:

「功能有沒有做對?」

還會再問:

「它是不是用適合這套系統的方式被做出來?」