Table of contents


在開始IDCView專案時,因為底層的模型相對複雜,在用Prototype Balsamiq Mockups^1)^軟體繪製完成後,就用Domain Driven Design的方式對底層的電力設備模型進行分析。模型塑模(modeling)到可開發程度後,就很真覺的寫了一些API去操作這些模型。結果就很順理成章的採用了Bottom-Up(由下至上)的設計開發方式。

整個架構,為了搭配語言及現有的API^2)^特性,並沒有使用Rich Domain而是採POJO的設計方式,採用了4個主要的layers為presentation → application → service → domain object(POJO)

在一段開發時間後,寫了好一堆個人認為應該相當好用的APIs(service layer),就打算套到servlet裡,就在這個時侯才發現,設計出來的API,在他的client (servlet)裡,並沒有那麼好用,總是需要額外的加工,才有辦法使用這些services或者是要好幾個api called才能完成一件事。在發現這個問題後,就改用Top-down的方式開發,事情就順利多了,而且每個設計出來的service也都剛好符合servlet的使用,並不需要太多的加工就可以有合適的service可以用,service的methods數量也大幅的減少。

所以,個人認為Top-down的方式比較能達到K.I.S.S的效果,尤其是對採用TDD開發方式的人來說,因為TDD有一個準備動作,就是列出所有待測的TODOs,然後挑一個最簡單的來實作。這樣,其實很容易造成太多用不到的API,因為,基本上這樣的設計方式,是在在設計一個完整的元件,而不是剛好夠用元件。

整個開發流程是:

  1. 確定網頁大概會傳入/傳出那些參數
  2. 撰寫 servlet test cases
  3. 撰寫 servlet
  4. 決定需要的service API
  5. Mock service API
  6. servlet完成
  7. 撰寫 service test cases
  8. 實作 service interface
  9. 用DBUnit模擬db

確定網頁大概會傳入/傳出那些參數後,即可決定servlet的大致動作,然後就可以撰寫 servlet test casesmock參數的傳入及verify參數的傳出,然後,即可進行撰寫 servlet來滿足servlet test cases,但是servlet需要service來完成 business logic,而且,因為是直接servlet裡決定service的api長相(此時要假設有一個完美的service api可以解決掉你的問題,並為這個api取一個直覺的名字),所以,通常比較能設計出清楚而直接的service api,接著,用mock的方式來mock service api的動作,一方面可以比較快速的得到一個可以動的api,另一方面可以為設計做一個較乾淨的切割。接再讓Servlet的test cases通過測試了。

再來就是service API的實作,如果實作部份跟資料庫有關,就用DBUnit來確定service會正常動作,而不是用mockup的方式了。

改採Top-down最大的收獲是最終的設計比較符合K.I.S.S的原則,但元件的很多不必要很好用功能的功能就不見了,所以,以後,萬一、如果、可能、或許要用到時,就得再加進去了。

本文並是不在說Bottom-Up的設計不可取,而是要看需求,之前在開發Framework或Component base的程式時,反而是Bottom-Up比較適合,因為,你永遠不知道,別人會怎麼來使用你的API

Service Design

在前幾個模組的設計,對於service layer是採用一個模組(或servlet)只有一個service的設計方式,而且每個service只有一個interface(class file),也只有一個相對的實作,一開始的動機為了讓模組間切割的更乾淨,但這樣做,會造成了不少重覆實作的Bad Smell,所以,最後為了去掉這些重覆,就還是改回多個services的架構.

改成一個模組多個services的架構後,service的interface不但簡化了許多,而且更符合SRP,也消除了更多的重覆,更讓整體架構往更佳的方向前進,所以,去除重覆是很多最佳實踐的基石。