閒談軟體設計:語意的抽象化

更新於 發佈於 閱讀時間約 13 分鐘
唸研究所開始當助教,偶而會有學弟妹問:怎樣寫好程式?老實說,這是個大哉問,連我學開發軟體這麼久,我也只能回答他們:多培養自己釐清問題、拆解問題、解決問題與抽象化的能力。但他們通常只會一臉狐疑看著我,感覺我說的話好抽象。事實上,這也不是我第一個這樣說的,有句軟體工程諺語是這樣說的:
Why is it that some software engineers and computer scientists are able to produce clear, elegant desings and programs, while others cannot? Critical to these questions is the notion of abstraction. (為何有些軟體工程師與電腦科學家能夠產生清楚而且優美的設計與程式,但其他人卻不能?關鍵在於抽象觀念。) — Jeff Kramer CACM 50(4) 2007

釐清問題

釐清問題是讓自己能解決對的問題的第一步,當一開始什麼都不想,根據使用者或顧客一個模糊的需求或是想法就開始埋頭苦寫,即便程式寫好了也不一定解決對方真正的問題,因此有一個說法是找出問題背後的問題,使用者提出一個問題,通常是在現實生活中遇到困難,但在描述時,卻不一定能精確的描述問題 (這當然不能當著顧客的面說),或是把背後的問題給描述出來,所以在理解需求的過程中,是要去幫使用者找出真正的問題。不過,我不打算在這裡說明釐清問題的方法。

拆解問題

當釐清真正的問題後,問題有時很大,有時很小,問題小也許就可以開始找尋解法,但問題很大時,會像毛線球般糾結很難好好處理,所以應該先試著將大問題拆解成小的問題,然後再根據每個小的問題去尋找解法。舉個例子,雖然現在網路就像空氣一樣,幾乎成為生活中不可或缺的一個元素,即便如此,我們還是可以問一個問題:當我們輸入一個網址後,電腦是如何呈現這個網頁?
這樣一個大問題可以被拆解成好幾個小問題:
  • 瀏覽器是怎麼知道一個網址對應到網路上哪一個伺服器?
  • 瀏覽器的請求是如何送到伺服器的?
  • 當伺服器知道某人想看某個網頁時,網頁是以什麼形式回到當初請求的電腦?
  • 當瀏覽器收到伺服器的內容又要如何呈現網頁?
而上述這些問題其實都還很大,還可以再被拆成更多小的問題,在過去許多人的努力下,定義成一個七層的 OSI 網路模型,每一層都提供一個功能(或換個說法解決一個特定問題),例如:
  • 屬於應用層的 HTTP 協定,讓伺服器能知道使用者想要看什麼文件(網頁)並回傳指定的文件
  • 屬於傳輸層的 TCP 協定,建立瀏覽器與伺服器之間一個虛擬連線 [1],並負責確保傳輸資料的完整性
  • 屬於網路層的 IP 協定,為網路上每個節點提供地址,並負責將資料在眾多網路節點中繞送到正確的節點
  • 屬於實體層的 WiFi 協定 [2],負責將電腦的數位訊息能夠在空氣中用電波傳輸,並檢查接收的數位訊號完整性

解決問題

事實上,如何解決問題或是如何邏輯思考?與電腦無關,在沒有電腦之前,我們有數學公式、物理公式、化學公式與機械等,很多的問題其實也都能被解決,只是可能需要很大量的人,或是無法快速的得到想要的結果,因此,當要用電腦解決問題時,需要的是計算思維 (computational thinking),讓解決問題的方法是可以用電腦去計算的,就像前陣子很熱門的Alpha Go圍棋大戰,先要做的是替圍棋找出一個模型讓電腦能夠計算,這其實需要的就是抽象化能力。
當問題能被計算,但可能不夠快,例如下一步棋需要一天或一個小時,這時候需要另一種演算法思維 (algorithmic thinking),透過特殊設計的資料結構,以及找出能讓電腦做更少的計算就能得到結果的演算法,讓電腦能更快的解決問題,類似的例子像是影像壓縮和解壓縮是個抽象概念,可以用更少的網路頻寬傳送更高畫質的影片,而具體的演算法,H.265則可以比H.264有更好的效率與影片品質。

抽象化

說了這麼多,終於又回到抽象化這個詞,抽象化可以用在好幾個不同層面,像剛剛提到的 OSI 網路模型和影片壓縮都是提供抽象概念。但實際寫程式時,抽象化是讓程式容易閱讀的關鍵,畢竟大部分時間讀程式的是人而不是電腦,所以這讓我想起一句話:
Any fool can write code that a computer can understand. Good programmers write code that humans can understand. (隨便找個傻瓜都能寫出電腦能懂的程式碼。好的程式設計師寫人能看得懂的程式碼。) — Martin Fowler
當軟體持續開發,維護程式碼比開發新程式碼要更傷腦筋,如何讓後續的開發者讀程式像是讀文章般容易懂,重要的就是能用問題 domain 中的術詞 (term) 來描述程式。舉個例子,假設有一個 my-book-store 的網路書店,提供若干 REST API 讓客戶端可以使用:
取得Isaac Asimov的科幻類作品
GET http://my-book-store.com/books?category=science-fiction&author=Isaac%20Asimov
在編號19333910書籍新增一筆評論
POST http://my-book-store.com/books/19333910/comments
修改編號13332144書籍的資訊
PUT http://my-book-store.com/books/13332144
刪除編號19333912的第12筆評論
DELETE http://my-book-store.com/books/19333912/comments/12
以 Java 來說,想要使用 REST API,客戶端可以用 Socket 建立連線到 my-book-store 建立連線到 my-book-store,準備好 HTTP 協定相關的標頭與內容,然後傳送給伺服器然後再取得結果,但我想很多人都知道:Socket 是作業系統或 JVM 提供給軟體開發者操作 TCP 的 API,對於我們要做的功能來說太低階了。事實上,Java有提供 HttpURLConnection 讓開發者可以直接建立 HTTP 連線,因此可以用如下的程式呼叫 REST API 取得 Isaac Asimov 的科幻類作品(範例程式中未處理所有可能拋出的例外)。
可以用下面的程式呼叫 RES API 在編號 19333910 書籍新增一筆評論,但寫到這,是否發現有太多與上面重複的程式?而這些程式其實還是在處理很多低階的 IO 處理。也許需要另一層抽象可以跟 REST 伺服器溝通,而不用去處理實作細節。
所以,我們可以觀察一下上述四個 API 不同的地方與相同的地方,可以發現如下,我們的抽象層需要能指定伺服器的位置 (host),API 的路徑 (path),路徑上可能有參數可以設定 (path parameters),額外可以夾帶查詢參數 (query parameters),最後,最重要的是可以指定呼叫的方法 (HTTP Method)。
HTTP Mehotd https://host/path/[{path parameters}][?query parameters]
因此,我們可以根據剛剛的描述設計一個 RestClient,直接來看例子,下面直接以 RestClient 改寫 getBooks(category, author) 和 postComment(bookId, comment) 函式,是否與原先的版本讀起來,在語意上是不是有完全不同的感受?
有了 RestClient,要實作 updateBook(bookId, updates) 跟 deleteComment(bookId, commentId) 是不是也變得很容易,或許,有人覺得只是透過封裝,可以重複使用程式碼,但對我來說,這並不是主要的目的,在看兩個例子,讀起來是否開始有感覺了呢?透過結合 domain 的術語與 Fluent Interface,其實我們已經完成了一個為 REST API設計的Domain Specific Language [3]。
當軟體越開發越大,為軟體進行模組化是絕對必要的,而抽象化也是模組設計所需要的一項很重要的能力,我們可以將剛剛四個函式包裝成一個 MyBookStoreService,因此,使用起來就如下所示,讀起來語意上又提高一個層級,對使用者來說,也已經不知道底層使用的是 REST API。
如同 OSI 網路模型一樣,軟體的開發是透過一層又一層的抽象堆疊完成,解決各種不同層次的問題 (前提是問題已經先被拆解),因此有個說法:
All problems in computer science can be solved by another level of indirection. — David Wheeler
但要怎麼提升抽象化的能力呢?以自己的經驗,首先,先試著讓自己能寫出有條理的文章,因為對現在的我來說,寫程式其實是在寫文章,寫讓其他人看得懂的文章,所以透過寫文章訓練自己的如何思考與如何整理思緒,是非常有幫助的(這真要感謝我的指導教授在我寫碩博士論文時的訓練)。再來,多看別人好的程式碼,瞭解其中使用哪些 design principles、design pattern和 architecture pattern,以及背後使用的意圖,耳濡目染久了,就會有自己對於事物抽象化的想法 (是的,抽象化沒有標準答案的,只有合不合適解決問題與否和是否容易理解的差別)。

結語

語意的抽象化可以說從過去到現在都仍然是進行式,從最早期用打卡機寫程式,到後來可以用組合語言寫程式,到能用 C 寫程序導向的程式,演變到可以用 Java/C# 等語言寫物件導向的程式,甚至最近很流行的用 functional paradigm 的概念寫程式,每次演進都在提高程式語言的抽象程度,到最後每個 domain 都會有自己的 domain specific language,讓原先 domain 的人可以讀懂程式。
其實要開發大型的軟體,不論是在學界或在業界,真正好的軟體開發者要具備的要素還有很多,像是能與同儕溝通、引領思考、軟體工程實務 (開發流程、建構管理等) 的實踐,都會讓一個好的軟體開發者與一個差的軟體開發者在效率上差上好幾倍 (有一說是10倍,但我找不到出處),但就以平日每天在寫程式的層級來看,抽象化能力是最不可缺少的一項能力。寫了這麼多,我想如果再有人問我:怎樣寫好程式?或是怎麼能成為一個好的軟體開發者?這文章是我目前能給的最好說法,希望對想學習軟體開發的人有幫助。
最近寫程式變得很熱門,連歐巴馬總統都在學寫程式,再過幾年,從國中開始,學生也開始要學寫程式,這讓我想起一句在軟體界的幽默諺語:
如果你想毀掉一個人的一天,就給他一個程式; 如果你想毀掉一個人的一生,就教他寫程式。 (If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime.)
如果真是如此,那我們正在進行毀掉全國學生的計畫(笑)?

附註

  1. 實際上瀏覽器的電腦與伺服器之間不可能真的有一條連線,只是透過封包在網路上多個節點轉送達成類似的現象。
  2. 這說法不是很精確,WiFi 事實上包含了實體層與資料鏈結層,但為了方便說明,請體諒一下。
  3. 雖然有人覺得 Objective C 或 Swift 語言寫程式時需要寫出參數名稱很多餘,但設計DSL時,這卻常常能讓程式更像自然語言,例如:client.where("bookId", is: 19333910)。
  4. 文中引用很多諺語主要來自《軟體工程諺語》部落格。

這是從 Medium 搬家到方格子的第三篇文章,個人在 Medium 上有《閒談軟體設計》與《Java Magazine 翻譯系列》兩個大主題,但畢竟翻譯系列不是我原創,當初寫信給官方也是說不會用翻譯營利,就不搬到這裡了,有興趣的就到 Medium 上看吧。接下來應該會是每周一篇的方式陸續將《閒談軟體設計》搬到方格子,至於為什麼不用匯入的方式?因為方格子目前支援 Gist 的方式,無法像圖片那樣加上標題,內文需要搭配對應的修改,稍微麻煩了點。
為什麼會看到廣告
avatar-img
53會員
104內容數
這是從 Medium 開始的一個專題,主要是想用輕鬆閒談的方式,分享這幾年軟體開發的心得,原本比較侷限於軟體架構,但這幾年的文章不僅限於架構,也聊不少流程相關的心得,所以趁換平台,順勢換成閒談軟體設計。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Spirit的沙龍 的其他內容
在履歷中常常看到導入 MVVM,然後問為什麼要導入 MVVM 時,最常聽到的答案是這樣不會有很肥大的 view controller,但如果再問 view controller 是 MVC 的那一個部分,很多人卻回答不出個所以然,所以想聊聊這個很多種說法的 MVC pattern。
為什麼是煮拉麵呢?主題是來自前同事在問我為什麼有人的程式好像常常會歪掉,或是變得難維護,後續的討論中,他用的例子就是拉麵,所以... 今天就用程式來煮拉麵吧!
在履歷中常常看到導入 MVVM,然後問為什麼要導入 MVVM 時,最常聽到的答案是這樣不會有很肥大的 view controller,但如果再問 view controller 是 MVC 的那一個部分,很多人卻回答不出個所以然,所以想聊聊這個很多種說法的 MVC pattern。
為什麼是煮拉麵呢?主題是來自前同事在問我為什麼有人的程式好像常常會歪掉,或是變得難維護,後續的討論中,他用的例子就是拉麵,所以... 今天就用程式來煮拉麵吧!
你可能也想看
Google News 追蹤
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
這篇文章介紹了面試時以及開始工作後可能會遇到的問題,包括物件導向OOP、SOLID 設計原則、測試方式,以及 Cookie、Session 與 Cache 的相似處與不同處。提供了豐富的相關資訊。
計算機組織不難,但東西很多 這個科目也是我比較不熟悉的,在此之前都是自學,所以會寫的更詳細一點 1.計算機組織在學什麼? 想像計算機的架構就像一個蛋糕有好多層,上半是軟體下半則是硬體,對我來說,軟硬體的兩端是電腦的核心(應用程式&半導體),而中間的每一層都是串接兩端的橋樑;那計算機組織就是要探
Thumbnail
系統的分析與規劃 在談到程式設計時,首要的是進行系統的分析與規劃。程式設計的起點通常是系統分析與規劃,這涉及到如何分析和設計系統的大原則和方向。為了達到預期效果,重要的是擁有對產業的清晰邏輯認識和深入了解。 進行深入了解 若要進行系統分析,必須對企業的設計和程式設計的對象進行深入了解,以充分理
在麥肯錫的邏輯裡,分析力是解決問題中最重要的因素,要正確分析問題,才有辦法從根本處置和防止復發。
Thumbnail
解決問題的藝術:從問題的多面向到解決的巧妙之道 最重要的一點就是深入問題的本質。"一個問題研究到精深,就能出師"。 當我們面對一個問題時,往往會急於尋找解決之道,但這並非有效的方式。問題是多面向的,它們存在著無數的可能性,而我們只是看到了其中的一部分。就像是看到了冰山的一角,而忽略了浸沒在水中的巨大
Thumbnail
本文探討了系統思維的重要性,強調理解元素、關係及其背後規律對洞察複雜系統至關重要。書中以商業模式變化為例,展示如何透過系統思維識別時代機遇,提升競爭力。此外,強調系統思維在學習中的應用,促進跨學科理解、批判性思維和解決問題能力,為適應未來變化奠定基礎。
Thumbnail
我們的思維常常呈現網狀結構,涉及大量相關訊息,表達和行動需要線性思維,而網狀思維與線性思維不相匹配,中間隔著關鍵的一步,即讓網狀思維變得有邏輯和組織。 金字塔原理的核心價值就在於找到一套系統方法,建構一個層級清晰、邏輯清晰的樹狀思維。 只有完成這一步,從思考到表達、從思考到行動的道路才算是完整的。
Thumbnail
閱讀分享 書名:底層邏輯 1主題:如何快速洞察本質-解決問題的底層邏輯 重點摘要 1.商業顧問的核心能力就是透過現象看本質的洞察力。 2.洞察力是每個人都可以透過科學的方法練習精進。 3.系統=要素 X 連接關係 系統-一組相互連接的要素 要素-要素可以想成零件,是我們表面看的
Thumbnail
本文探討了普通人和優秀人解決問題的差異,提出了大膽假設、小心求證、得出結論、進行調整的解決問題模式,並強調了不被利益或立場左右的重要性。
Thumbnail
解決電腦上遇到的問題、證明正確性、探討效率 並且很著重溝通,說服別人你做的事是正確且有效率的。 內容: 計算模型、資料結構介紹、演算法介紹、時間複雜度介紹。
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
這篇文章介紹了面試時以及開始工作後可能會遇到的問題,包括物件導向OOP、SOLID 設計原則、測試方式,以及 Cookie、Session 與 Cache 的相似處與不同處。提供了豐富的相關資訊。
計算機組織不難,但東西很多 這個科目也是我比較不熟悉的,在此之前都是自學,所以會寫的更詳細一點 1.計算機組織在學什麼? 想像計算機的架構就像一個蛋糕有好多層,上半是軟體下半則是硬體,對我來說,軟硬體的兩端是電腦的核心(應用程式&半導體),而中間的每一層都是串接兩端的橋樑;那計算機組織就是要探
Thumbnail
系統的分析與規劃 在談到程式設計時,首要的是進行系統的分析與規劃。程式設計的起點通常是系統分析與規劃,這涉及到如何分析和設計系統的大原則和方向。為了達到預期效果,重要的是擁有對產業的清晰邏輯認識和深入了解。 進行深入了解 若要進行系統分析,必須對企業的設計和程式設計的對象進行深入了解,以充分理
在麥肯錫的邏輯裡,分析力是解決問題中最重要的因素,要正確分析問題,才有辦法從根本處置和防止復發。
Thumbnail
解決問題的藝術:從問題的多面向到解決的巧妙之道 最重要的一點就是深入問題的本質。"一個問題研究到精深,就能出師"。 當我們面對一個問題時,往往會急於尋找解決之道,但這並非有效的方式。問題是多面向的,它們存在著無數的可能性,而我們只是看到了其中的一部分。就像是看到了冰山的一角,而忽略了浸沒在水中的巨大
Thumbnail
本文探討了系統思維的重要性,強調理解元素、關係及其背後規律對洞察複雜系統至關重要。書中以商業模式變化為例,展示如何透過系統思維識別時代機遇,提升競爭力。此外,強調系統思維在學習中的應用,促進跨學科理解、批判性思維和解決問題能力,為適應未來變化奠定基礎。
Thumbnail
我們的思維常常呈現網狀結構,涉及大量相關訊息,表達和行動需要線性思維,而網狀思維與線性思維不相匹配,中間隔著關鍵的一步,即讓網狀思維變得有邏輯和組織。 金字塔原理的核心價值就在於找到一套系統方法,建構一個層級清晰、邏輯清晰的樹狀思維。 只有完成這一步,從思考到表達、從思考到行動的道路才算是完整的。
Thumbnail
閱讀分享 書名:底層邏輯 1主題:如何快速洞察本質-解決問題的底層邏輯 重點摘要 1.商業顧問的核心能力就是透過現象看本質的洞察力。 2.洞察力是每個人都可以透過科學的方法練習精進。 3.系統=要素 X 連接關係 系統-一組相互連接的要素 要素-要素可以想成零件,是我們表面看的
Thumbnail
本文探討了普通人和優秀人解決問題的差異,提出了大膽假設、小心求證、得出結論、進行調整的解決問題模式,並強調了不被利益或立場左右的重要性。
Thumbnail
解決電腦上遇到的問題、證明正確性、探討效率 並且很著重溝通,說服別人你做的事是正確且有效率的。 內容: 計算模型、資料結構介紹、演算法介紹、時間複雜度介紹。