近日看《許式偉的架構課》中一段關於系統分解的描述全部思考,略記於此。html
原文片斷以下:前端
系統設計,簡單來講就是 「對系統進行分解」 的能力。這個階段核心要乾的事情,就是明確子系統的職責邊界和接口協議,把整個系統的大框架搭起來。nginx
那麼怎麼分解系統?git
首先咱們須要明確的是分解系統優劣的評判標準。也就是說,咱們須要知道什麼樣的系統分解方式是好的,什麼樣的分解方式是糟糕的。程序員
最樸素的評判依據,是這樣兩個核心的點:github
- 功能的使用界面(或者叫接口),應儘量符合業務需求對它的天然預期;
- 功能的實現要高內聚,功能與功能之間的耦合儘量低。
在軟件系統中有多個層次的組織單元:子系統、模塊、類、方法 / 函數。子系統如何分解模塊?模塊如何分解到更具體的類或函數?每一層的分解方式,都遵循相同的套路。也就是分解系統的方法論。web
......後端
一個程序員的系統分解能力強不強,其實一眼就能夠看出來。你都不須要看實現細節,只須要看他定義的模塊、類和函數的使用接口。若是存在大量說不清業務意圖的函數,或者存在大量職責不清的模塊和類,就知道他基本上還處在搬磚階段。websocket
不管是子系統、模塊、類仍是函數,都有本身的業務邊界。它的職責是否足夠單一足夠清晰,使用接口是否足夠簡單明瞭,是否天然體現業務需求(甚至無需配備額外的說明文檔),這些都體現了架構功力。架構
完整原文 https://time.geekbang.org/column/article/117783
佩服做者對系統設計這樣大問題的能簡化到2個樸素的判斷依據,而不是學院式的抽象含糊的說明。
近期因爲工做內容須要,也常思考業務需求對接口的預期是什麼?
對於服務端軟件而言,接口在形式上比有UI交互的前端軟件更加穩定且標準;然而對於業務需求的預期有時會缺乏思考,設計上更傾向於技術的可行便利。
固然這二者並不矛盾,若是業務在接口標準上達成共識,就能取得很好的效果。
對於服務端軟件,軟件配置的組織與設計是一個重要而容易被忽視的接口。
以nginx軟件爲例,我的認爲nginx配置方式的設計對業務需求的表達有時就不夠天然清晰。甚至在某些場景下功能配置的耦合狀況很多。
示例1
# 示例例來源 http://nginx.org/en/docs/http/websocket.html http { map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { ... location /chat/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } } }
上面這段示例的目的是實現WebSocket的代理,但從配置上看不出WebSocket的任何信息,而是依賴於配置人員對WebSocket升級流程與Nginx代理流程十分了解的基礎上才能判斷出這段配置能實現WebSocket代理。
示例2
# 示例例來源 http://nginx.org/en/docs/http/converting_rewrite_rules.html location / { root /var/www/myapp.com/current/public; try_files /system/maintenance.html $uri $uri/index.html $uri.html @mongrel; } location @mongrel { proxy_pass http://mongrel; }
上面這段示例目的是優先嚐試本地文件,不存在再像後端獲取。其中的location @mongrel {}
塊部分是涉及到nginx開發中subrequest的概念。
subrequest的設計在代碼內部很好的處理複雜請求的業務流程,是nginx開發中模塊解耦,下降開發複雜度,並保持高性能的重要利器。
而這樣一個重要特性卻可能會形成配置片斷的隔離性,當這個特性被大量使用時,配置文件看上去就顯得特別複雜。與公司運維童鞋交流過程當中也收到過反饋,說ngxin配置的格式,看着特別像代碼而不是配置項。
關於subrequest更多信息能夠參考http://nginx.org/en/docs/dev/development_guide.html#http_subrequests
然而這個視角的分析太片面。從另外一個視角看,nginx的配置是提供了足夠的靈活性和可擴展性,爲實現各種不一樣的業務提供了可能性。nginx的配置不只是業務需求的展現,並且還能承載業務邏輯,實現靈活擴展的功能。openresty的ngx_http_lua_module就是一個很好的實例。
# 示例來自 https://github.com/openresty/lua-nginx-module/ location = /request_body { client_max_body_size 50k; client_body_buffer_size 50k; content_by_lua_block { ngx.req.read_body() -- explicitly read the req body local data = ngx.req.get_body_data() if data then ngx.say("body data:") ngx.print(data) return end -- body may get buffered in a temp file: local file = ngx.req.get_body_file() if file then ngx.say("body is in file ", file) else ngx.say("no body found") end } }
在配置文件上承載業務邏輯,對於配置的管理與維護就提出了新的挑戰。
孰是孰非,我並無明確的傾向性,在實際項目中還要考慮組織結構、協做流程、歷史數據、現有架構等等因素……才能設計出一個恰如其分的方案。
再看開頭提到徐大牛提出的2個判斷依據。接口知足業務預期;功能高內聚低耦合。用於判斷方案的合理性確實是一個很不錯的標準。