閒談軟體設計:休息時間

閱讀時間約 16 分鐘
看到標題是否覺得很奇怪?休息時間,如果改成 REST time 有沒有一種突然豁然開朗的感覺呢?每次看到 REST 就讓我想起以前念研究所和老師一起想論文題目時,曾提過國外常會玩這種文字遊戲,像是將 Representational State Transfer 變成一個很簡單的單字 REST,但我的東西不管怎麼想,卻想不出什麼有趣的東西 Orz

前言

會想寫 REST,是過去在第一間公司工作時,曾聽到當時的架構師對著團隊說:『不要以為用了 JAX-RS 就是 Restful Web Services,你們 URL 命名根本就亂七八糟』,剛進去的時候,確實只是簡單地看了一下 Wikipedia 的說明,就開始用 JAX-RS 的 annotation 開發後台的 API,也沒多想什麼,所以後來自己在訂 Restful 的 API 總是特別小心,像是複數型的名詞、避免動詞、只使用 HTTP method (GET、POST、PUT 和 DELETE) 等等。
後來換工作,討論 API 時,當只有我特別這麼堅持時,總覺得好像是我比較龜毛似的,但 API 至少還是符合 Restful 風格,後來比較不是前線開發者後,等到 API 會議結束,看結果,幾乎所有的 API 都把動詞放在 URL 上了,曾經詢問了一下原因,但似乎沒引起什麼共鳴,後來想想算了,只要不對外宣稱這是 Restful API 其實也沒什麼不行。
半年後換工作,又從 iOS/Android 工程師變回後端工程師了,由於是我主導整個 API 的設計,在風格上沒什麼問題,但還是得和其他同事解說為什麼 API 是這樣命名的,但說的還是 Wikipedia 上的那一套,直到最近看完《建構微服務》後,才在思考要不要找出原始的論文來讀讀呢?
趁著中秋連假,把《Architectural Styles and the Design of Network-based Software Architectures》抓下來看,老實說,有點震撼到,像是使用 HTTP method 這件事其實根本就沒出現在論文中。

論文導讀

既然看都看了,就簡單和大家分享一下看完這篇論文的心得 (若我理解有誤歡迎更正) 吧!這篇論文用 Chapter 1 整章的篇幅,在說明怎麼描述一個軟體架構,過去在畫架構圖時,總是畫上幾個方塊和線條,然後就開始跟其他人說明,嚴謹一點就用 UML 的部署圖描述,從來也沒去想過要怎麼描述一個軟體架構。
A software architecture is defined by a configuration of architectural elements — components, connectors, and data — constrained in their relationships in order to achieve a desired set of architectural properties.
如上所述,論文倒是很清楚地用三個元素來描述一個軟體架構:
  • A component is an abstract unit of software instructions and internal state that provides a transformation of data via its interface. (也就是平常架構圖上的那些方塊)
  • A connector is an abstract mechanism that mediates communication, coordination, or cooperation among components. (圖上連接方塊的線)
  • A datum is an element of information that is transferred from a component, or received by a component, via a connector. (在元件之間傳遞的資料)
聽完可能有人覺得,啊~ 不就廢話,我平常就這樣描述軟體架構啊,但這一章花了不少篇幅探討這三個元素是否足夠,這倒是我過去不曾想過的。最後,一個軟體架構風格則是一組限制,限制上述元素的角色或功能與關係,任何架構只要符合這些限制就能稱作是某種軟體架構風格,而 REST 是由六個限制所組成的軟體架構風格。
An architectural style is a coordinated set of architectural constraints that restricts the roles/features of architectural elements and the allowed relationships among those elements within any architecture that conforms to that style.
Chapter 2 則是探討網路應用程式 (network-based application) 的架構,我覺得很有價值的是條列了七種網路應用程式架構的 properties:Performance、Scalability、Simplicity、Modifiability、Visibility、Portability 和 Reliability,也就是一般軟體工程書中稱之為 non-functional requirement attributes,並說明為什麼選這七種做為評估架構的依據。並在 Chapter 3 中使用這些 properties 評估了共 20 種 network-based application architectures,合計 7 類的軟體架構風格,值得一看。
Chapter 4 討論設計 Web Architecture 的需求與會遭遇的問題,在繼續之前,可能要想一下為什麼是 WWW 架構,不就是網頁應用程式嗎?如果仔細看 Wikipedia 上對 WWW 的解釋
The World Wide Web (WWW) is an information space where documents and other web resources are identified by URLs, interlinked by hypertext links, and can be accessed via the Internet.
只要任何能以超連結串起來的資訊空間就能稱作是 WWW,沒有一定要用 HTTP 協定,也沒有說一定是 HTML,因此,論文提出一種分散式超媒體系統的軟體架構風格能滿足三個假設,這就不細討論三個假設,這是大多數論文的必備要素,說完一堆人就睡著了,基本上,那個方案就是 REST。
Chapter 5 描述 REST 是如何從無開始對 WWW 加入六種限制所形成的一種軟體架構風格。因為是限制,所有描述會變成:
  • 必須是 Client-Server,用意為 separation of concerns
  • 必須是 Stateless,request 與 request 之間是獨立的,server 不需要記住狀態以處理下個 request
  • 必須是可 Cache 的,但那些內容可以 cache 是由 client 與 server 協調的
  • 必須是 Uniform Interface,這一點很重要
  • 必須是 Layered System,基本上就是用 layer 隱藏實作的細節,client 只需要知道 uniform interface 即可
  • 可以是 Code-On-Demand,這是 optional 的限制,所以我說『可以是』,基本上是可以用這個方式讓 client 用取得程式碼的方式擴充功能。
為了達成 uniform interface,論文對介面設計提出四個限制:
  • identification of resources
  • manipulation of resources through representations
  • self-descriptive messages
  • hypermedia as the engine of application state
剛剛不是說軟體架構可以用 component、connector 和 data 定義嗎?那 REST 風格的軟體架構呢?有的。
首先看 data,所有可被命名的資訊都是 resource,並給予 identifier (滿足 identification of resources),根據 client 的能力與需求 (透過 control data 描述),給予不同的呈現方式 (representations),像是 JSON、XML 等,並透過呈現方式操作資源,而不是直接操作資源,(滿足 manipulation of resources through representations),由於實際的資源與呈現方式可以相同也可以不同,所以 resource identifier 也可以視為資源與呈現方式 mapping (轉換) 的一種識別。resource 可以透過 representation metadata 與 resource metadata 加以描述,讓 client 可以自行決定如何解讀取得的 resources (滿足 self-descriptive messages)。
data 以 connector (client, server, cache, resolver, tunnel) 提供一致的方式存取,透過 identifier 存取不同的 resources (representation) 及轉換,完成目的 (滿足 hypermedia as the engine of application state)。component (origin server, gateway, proxy, user agent) 透過 connector 溝通,實際上,資源源如何儲存和怎麼處理則是隱藏在 component 中,可以直接提供 representation 或再透過 connector 與其他 component 請求 representation,但介面是一致的。
Chapter 6 則是經驗與評估,描述作者在參與 URI 與 HTTP/1.1 制定時,如何用 REST 找出問題並確定這些擴充沒有違反限制,個人認為有幾個重點:
  • 資源的 identifier 應該鮮少變動
  • 資源不是一個儲存物件,而是一種抽象的應對,一個 identifier 對應到一種抽象應對的實作
  • 辨識使用者的資訊不應包含在 representation 裡的 URI 中
  • HTTP 無法完整描述所有 REST 的語意
  • 使用 HTTP 本身的 header 描述 representation 及提供 metadata 與 control data
  • REST 不是 HTTP,HTTP 也不是 RPC
  • 對 resource 的操作,client 和 server 要有一致的認知
Chapter 6 之後便是結論了。

回到 RESTful API

為什麼要花這麼長的篇幅介紹論文的內容呢?主要是,在設計 Restful API 時,有時候會有些猶豫,像是:
  • token 或 session ID 應該放在 query parameter 還是 HTTP header 中?這有點 tricky,雖說 URI 上不該帶有使用者資訊,但若 resource representation 中的 URI 不夾帶使用者資訊,而是在發送當下才夾帶,算是有違反嗎?不過,就安全性來說,query parameter 有時候會在 log 時被記錄下來,所以算是盡量避免的另一個原因。
  • API 版號應該出現在 URI 中還是 HTTP header 中?以 REST API Versioning 的描述兩種皆可,但看完論文後哪種較好呢?
當初在思考這些問題時,在網路上爬了很多文章和討論,但其實不管哪種作法都有,也有各自的擁護者,但等看完這論文後,我覺得我當初的選擇 (都用 HTTP header) 是比較接近論文的原意 (URI 不夾帶使用者資訊,並盡可能保持不變動,由 client 與 server 透過 control data 協調 representation),而自己對 URL 的命名,除了不太使用 controller 之外,也符合一般大多數的最佳實務
至於剛開始說的 URL 中該不該有動詞?以最佳實務來說,可以,用來代表概念性的 controller 資源,但不會用動詞描述 CRUD,因為 HTTP method 本身已經有這個語意了,個人認為 controller 這個概念性資源是對 HTTP 方法的一種擴充 (見論文的 Chapter 6),畢竟,完全用狀態與名詞描述行為確實不容易,以登入與登出這兩個行為來說,若觀察大多數的 API 會發現幾乎都是直接用 login/logout 這兩個動詞放在 URI 上,我當時也是想了很久,才以登入前和登入後狀態的差異,找到一個我覺得合適的名詞,取代用動詞放在 URI 上的做法。但之後是不是堅持不使用 controller 呢?我覺得還是視語意,挑選合適的方法比較重要。最重要的是,是否違反上述的限制,只要不違反就能稱作是 Restful API 了
相較於 SOAP、RPC 或更早的 RMI,Restful API 幾乎是目前最熱門的 API 設計風格,若想知道怎樣朝 Restful API 風格邁進,可以參考 Martin Fowler 在《Richardson Maturity Model — steps toward the glory of REST》文中所提的方式,逐步演進成為 Restful API:
  • level 0 就是什麼規範都沒有,或是把 HTTP 當成 RPC 使用的階段
  • level 1 定義 resource,讓系統能以 resource 描述狀態
  • level 2 善用 HTTP 動詞 (方法:GET、POST、PUT 和 DELETE)
  • level 3 能以超媒體的方式控制流程,或是從 response 中的資訊可以知道接下來可以做什麼
能做到 level 2 我就覺得很好了,想要做到漂亮的 level 3,若使用 XML 作為 resource 的 representation,那已經有一些標準可以遵循,但若是使用 JSON,目前我所知的有 Hypertext Application LanguageJSON API 兩種描述方式,哪種較好,我覺得只要能滿足 REST 的限制,可以依照自己的喜好使用。

結語

所以大家的 API 能到 level 幾呢?其實到 level 3 也不代表 API 設計的好,API 的設計牽涉到很多層面,就如同論文 Chapter 6 中也探討很多要考慮的因素,希望這篇長文,可以讓大家在設計 Restful API 時有更多的想法湧出。最後覆上一個有趣的文章讓大家思考一下,您平常是如何看待 API 的。
為什麼會看到廣告
52會員
102Content count
這是從 Medium 開始的一個專題,主要是想用輕鬆閒談的方式,分享這幾年軟體開發的心得,原本比較侷限於軟體架構,但這幾年的文章不僅限於架構,也聊不少流程相關的心得,所以趁換平台,順勢換成閒談軟體設計。
留言0
查看全部
發表第一個留言支持創作者!
Spirit的沙龍 的其他內容
稍微複雜一點的 query 其實代表著某些商業邏輯,若把這一段程式放到 repository 的實作層,會變成這些商業邏輯被隱藏起來了,如果有個好的描述語言,我倒覺得很好讀,也可以清楚知道背後的商業邏輯是什麼,是很好的一件事。
簡單說,Repository 提供像是 array 或是 dictionary 的容器,對程式來說,就好像記憶體中有所有的物件,不用去想物件其實是從資料庫來的。作法是在 data mapping layer 之上再提供一個 collection 的介面來存取物件,將資料庫的細節從商業邏輯層抽離。
不是在軟體建置之初就決定所有一切的行為,而是執行時根據配置 (configuration) 或執行時的環境 (例如:特定目錄有什麼 plug-in) 決定有哪些行為,話是這麼說,但要實作一個可以載入 plug-in 的軟體 (以下稱作 host application) 倒是有不少事情要考慮。
基本上就是這樣,例外處理是可以在軟體架構設計時就考慮進去,或者說,在軟體架構設計時就該考慮進去,制定方針讓團隊有一個原則可以遵循,透過設計讓例外的處理較容易與一致,最終讓軟體的品質可以更好。
設計時的考量主要有:(1) App 是 Internet App,在考量 UI 體驗和網路頻寬的消耗,多數資料需以某種形式儲存部分資料在行動裝置上;(2) 因此會需要同步伺服器端和行動裝置端之間資料狀態;(3) 但行動裝置網路的穩定性不如一般網路可靠,要有足夠的自動化測試驗證正常的流程與異常的流程。
程式開發有趣的地方,同樣的目標,不同的團隊會因不同的因素做出不同的設計抉擇。而這往往也是為什麼一個資深的工程師在開發速度上不一定比較快的原因之一,一個越是資深的工程師,思考的因素會更多,不過,不是考慮得越多就結果就一定越好,有時還會變成 over design 較糟的結果。
稍微複雜一點的 query 其實代表著某些商業邏輯,若把這一段程式放到 repository 的實作層,會變成這些商業邏輯被隱藏起來了,如果有個好的描述語言,我倒覺得很好讀,也可以清楚知道背後的商業邏輯是什麼,是很好的一件事。
簡單說,Repository 提供像是 array 或是 dictionary 的容器,對程式來說,就好像記憶體中有所有的物件,不用去想物件其實是從資料庫來的。作法是在 data mapping layer 之上再提供一個 collection 的介面來存取物件,將資料庫的細節從商業邏輯層抽離。
不是在軟體建置之初就決定所有一切的行為,而是執行時根據配置 (configuration) 或執行時的環境 (例如:特定目錄有什麼 plug-in) 決定有哪些行為,話是這麼說,但要實作一個可以載入 plug-in 的軟體 (以下稱作 host application) 倒是有不少事情要考慮。
基本上就是這樣,例外處理是可以在軟體架構設計時就考慮進去,或者說,在軟體架構設計時就該考慮進去,制定方針讓團隊有一個原則可以遵循,透過設計讓例外的處理較容易與一致,最終讓軟體的品質可以更好。
設計時的考量主要有:(1) App 是 Internet App,在考量 UI 體驗和網路頻寬的消耗,多數資料需以某種形式儲存部分資料在行動裝置上;(2) 因此會需要同步伺服器端和行動裝置端之間資料狀態;(3) 但行動裝置網路的穩定性不如一般網路可靠,要有足夠的自動化測試驗證正常的流程與異常的流程。
程式開發有趣的地方,同樣的目標,不同的團隊會因不同的因素做出不同的設計抉擇。而這往往也是為什麼一個資深的工程師在開發速度上不一定比較快的原因之一,一個越是資深的工程師,思考的因素會更多,不過,不是考慮得越多就結果就一定越好,有時還會變成 over design 較糟的結果。
你可能也想看
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
最近身旁有幾位正在懷孕、或剛生產完的朋友,讓我想起自己在懷孕期間印象最深刻的三件「怪事」,其中又以第三件事最誇張。
Thumbnail
不知道大家在買房之前是不是都會參考親朋好友的意見,或是上網看一些買房注意事項,有時候考慮了這塊就忘了那塊,考慮的那塊又忘了這塊.......
Thumbnail
塔西佗陷阱(Tacitus Trap),一個得名於古羅馬歷史學家塔西佗的政治學理論,意指倘若公權力失去其公信力,無論如何發言或是處事,社會均將給予其負面評價。 當然信著恆信、不信者恆不信,這就是真實的人生。
Thumbnail
關於片名   台灣片名《花漾女子》,原文片名《Promising Young Woman》,台灣譯名將時間定格在悲劇發生前,而原文片名則進一步帶我們看見另一個可能性結果
Thumbnail
前幾年因為身體的關係,當了幾年的律師逃兵,當時開了之前的事務所以後,一時間也沒有特別想要做甚麼事情,所以就邊讀一點書、早晚運動一下,剛好聽到當年同梯朋友進去金融業工作,因此也抱著嘗(ㄊㄠˊ)試(ㄅㄧˋ)的心態,找了份銀行法令遵循的工作
Thumbnail
那天我問隊友,怎樣才算是一部小說呢?按字數計算嗎? 他說:「故事內起承轉合都有,就算」 所以我大膽地按著他的標準,將自己寫過的故事,粗略整理出一個明細。
纏中說禪,本名李彪,專欄筆名木子,其人是中國股市比較早期的操盤手,所以他比較熟悉a股的市場情況。他以“纏中說禪”為筆名,從2002年開始寫博客,直到2008年癌症病重停更,期間寫下了不少文章。而博客文章中最為著名的就是他的“教你炒股票”系列文章,他在這個系列裡講到的炒股理論和方法被粉絲稱為“纏論
Thumbnail
婚姻是人生大事,對溥儀尤其如此,因為如果皇帝大婚,就代表溥儀可以脫離眾多便宜老媽的束縛而得以親政。 但詭異的是,這個可以讓他脫離便宜老媽掌控的婚姻,卻還是要由便宜老媽進行主導並且居中角力......
Thumbnail
上次我提到:溥儀就是個死小孩。其實這不能全怪溥儀,而要怪詭異的宮廷教育及生活制度......
Thumbnail
近期電影「末代皇帝」重新修復上映。 為了推坑這部經典之作,本人決定以溥儀本身的自傳《我的前半生》為主要基底,和大家談一些電影中礙於篇幅或是藝術改編,而不容易察覺或是沒有呈現的真實歷史。
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
最近身旁有幾位正在懷孕、或剛生產完的朋友,讓我想起自己在懷孕期間印象最深刻的三件「怪事」,其中又以第三件事最誇張。
Thumbnail
不知道大家在買房之前是不是都會參考親朋好友的意見,或是上網看一些買房注意事項,有時候考慮了這塊就忘了那塊,考慮的那塊又忘了這塊.......
Thumbnail
塔西佗陷阱(Tacitus Trap),一個得名於古羅馬歷史學家塔西佗的政治學理論,意指倘若公權力失去其公信力,無論如何發言或是處事,社會均將給予其負面評價。 當然信著恆信、不信者恆不信,這就是真實的人生。
Thumbnail
關於片名   台灣片名《花漾女子》,原文片名《Promising Young Woman》,台灣譯名將時間定格在悲劇發生前,而原文片名則進一步帶我們看見另一個可能性結果
Thumbnail
前幾年因為身體的關係,當了幾年的律師逃兵,當時開了之前的事務所以後,一時間也沒有特別想要做甚麼事情,所以就邊讀一點書、早晚運動一下,剛好聽到當年同梯朋友進去金融業工作,因此也抱著嘗(ㄊㄠˊ)試(ㄅㄧˋ)的心態,找了份銀行法令遵循的工作
Thumbnail
那天我問隊友,怎樣才算是一部小說呢?按字數計算嗎? 他說:「故事內起承轉合都有,就算」 所以我大膽地按著他的標準,將自己寫過的故事,粗略整理出一個明細。
纏中說禪,本名李彪,專欄筆名木子,其人是中國股市比較早期的操盤手,所以他比較熟悉a股的市場情況。他以“纏中說禪”為筆名,從2002年開始寫博客,直到2008年癌症病重停更,期間寫下了不少文章。而博客文章中最為著名的就是他的“教你炒股票”系列文章,他在這個系列裡講到的炒股理論和方法被粉絲稱為“纏論
Thumbnail
婚姻是人生大事,對溥儀尤其如此,因為如果皇帝大婚,就代表溥儀可以脫離眾多便宜老媽的束縛而得以親政。 但詭異的是,這個可以讓他脫離便宜老媽掌控的婚姻,卻還是要由便宜老媽進行主導並且居中角力......
Thumbnail
上次我提到:溥儀就是個死小孩。其實這不能全怪溥儀,而要怪詭異的宮廷教育及生活制度......
Thumbnail
近期電影「末代皇帝」重新修復上映。 為了推坑這部經典之作,本人決定以溥儀本身的自傳《我的前半生》為主要基底,和大家談一些電影中礙於篇幅或是藝術改編,而不容易察覺或是沒有呈現的真實歷史。