閒談軟體設計:Developer eXperience

閱讀時間約 13 分鐘
圖片來源:www.freepik.com

圖片來源:www.freepik.com

最近公司陸陸續續排入了 developer experience 的改進項目,自此,好像這樣,就變成了不再只是關注 UX 也在乎 DX 的好公司,但 DX 的定義是什麼?即便是找到了這段影片

大家真的都認同 DX = (Productivity + Impact + Satisfaction)Collaboration 這個公式嗎?或是認同這句話:

Optimizing DevEx is about creating a collaborative environment where developers can be their most productive, impactful, and satisfied.

但今天我不是要討論 Developer Experience 具體的做法,而是討論 Developer Experience 是否該對標的程式碼有影響?

講古時間

在開始討論我前先來講古一下,多古呢?我寫的第一行程式是在我國中二年級的電腦教室裡 (國小舅舅好像有教過我寫程式,但內容完全忘記了),用 QuickBasic 語言在 386 的電腦上寫簡單的 hello world,然後用以現在標準來看很醜的選單按執行,接著螢幕上就出現了 hello world。現在事後回想,第一次寫程式經驗不算差,因為 QB 在當時就提供了一個還不算差的 IDE,不需要一堆 command line 的指令,就可以完成編譯、連結與執行的動作。

上高中後,語言雖然從 QB 轉成 VisualBasic,但語法沒有太大的改變,但整個畫面變漂亮了,用 GUI 工具拖拉元件到視窗上,對著按鈕點兩下,就可以開始寫程式,當時也不知道那個函式是 MVC 中的 controller,在裡面寫個數十行的程式,程式可以動,做出來的 UI 也很漂亮,但... 那時的程式碼以現在的我來看:爛透了。啊~ 那時還有用 FrontPage/Dreamweaver 寫網頁,但這兩個工具產生出來的 HTML 根本是...,最後工具只是用來預覽。

上大學後,因為是電子工程系,初期寫的程式比較偏硬體,C (用 Turbo C)、組合語言 (用筆記本,真的是筆記本,然後下指令組譯)、HDL (算是有 IDE,但不太好用,加上 PLD 燒錄器不是每人一台,編譯完的檔案要用 3.5 吋磁片,複製到老師的那台電腦上,然後燒錄到 16v8 或 22v10 晶片上,再將晶片插到麵包版上測試),說真的,以現在的 DX 標準,體驗非常差勁,但當時除了組合語言,我其實蠻樂在其中的,看到 LED 燈以期望的方式閃爍,非常開心。

據說,現在電子系已經沒再用燒錄器了,全部都是軟體模擬。

中期寫的程式比較偏應用,寫過 Pascal (用 Delphi) 和 Java (用 JBuilder),那時用 Java applet 寫一個可以在網頁上畫畫的小畫家,和一個工程計算機,我對於我設計的 GUI 非常滿意,當時讓我痛苦的不是 GUI 或 IDE,而是沒有完整的資料結構與演算法知識下,解析輸入的式子,建立 AST (Abstract Syntax Tree) 並用後序的方式計算出結果,或是在小畫家程式裡支援 undo/redo。

後期開始接觸網頁和資料庫應用,用 PHP (用 Dreamweaver) 寫購物車,剛開始覺得很新鮮,Dreamweaver 幫忙做了幾件事:syntax highlight 和FTP 上傳 (佈署),但愈寫到後面愈不喜歡 PHP,因為要到執行時才發現語法錯誤真的是一件很花時間的事。

我先說,我沒有要戰 PHP,畢竟我寫 PHP 時的版本跟現在差太多了,我後續也沒有再研究 PHP,說不定現在 PHP 已經很好寫了,這只是當時的感想。

研究所應該是我工作之前,被要求寫最多程式碼的兩年吧!幾乎每門課都有要寫程式的作業。其中一門課,一個學期分七次作業,用 C++ 搭配 GTK 完成一個 UML Class Diagram Editor,作為助教,帶大學學弟妹用 Visual C++開發遊戲,自己卻是用 Eclipse + CDT 寫作業,那體驗根本是悲劇,再加上 C++ 要自己管理記憶體,寫作業時就是在不斷地處理 segment fault。但是,我很感激這兩年紮實的課程。

聊聊好的體驗

古遠故事說完了,我只是想說,好的體驗其實很簡單:讓學習的循環變快,就會有好的體驗。軟體開發這件事,是工程師在學習如何將 domain know how 轉成軟體的一個過程,學習本質上是不斷試錯,所以,你不會希望三個月後發現整合不起來,你不會希望半年後才知道規格錯了,你當然也不會希望幾分鐘後才知道語法錯了、變數名稱錯了,如果這個循環能愈快,工程師就愈有成就感。

因此就來聊聊幾個,我認為很有感的提升吧!第一個是記憶體管理,對於沒寫過 C/C++ 的人來說應該超級無感,但我當初開始學 Java,發現不用再寫 delete 時,那感動真的是無法形容,終於不用擔心漏掉 delete 會有 memory leak,多一次 delete 都會讓程式 crash 的窘境。

第二個是 incremental build,我忘記第一次體驗到 incremental build 是在哪個 IDE 了,早期的 IDE 是你按下執行,然後 console 會跑出一堆編譯的過程,然後告訴你哪裡錯了,比較差的 IDE 是你要去讀 console 的訊息,好一點的 IDE 會在編輯器上標示錯誤,但你還是得等。有了 incremental build 後,一邊打字 IDE 一邊進行編譯,馬上在錯誤的地方跑出紅色的蚯蚓底線,沒錯就是立即!那體驗真好。

第三個是 code autocomplete 或 code assistant,這裡不是指最近 AI 加持的版本,單純是 IDE 編寫程式時,跳出來的提示,在一個大型的專案中,工程師得將很多事情放入腦袋,小到變數和函式名稱,大到架構設計,所以看到工程師進入流的狀態時,千萬別去打斷他。有了 code assistant,至少可以讓腦袋去處理更有用的東西,而不是記住數十個變數或函式名稱。

第四個是 hot reload,在第一家公司上班時,同時開發後端與前端,即便有當時每修改一小端程式就要把 local 的 server 停掉重新啟動,好載入新版本的程式,同事推薦安裝 JRebel,它會偵測檔案的變動,自動載入變動的部分,省去相當多的時間,後來,Spring boot 也加了類似的功能,以及 React 等前端框架也都有類似的功能。

最後是自動化,同樣在第一家公司,當時 server 是由 IT 管理的 VM,上面裝好 J2EE 的 container server,所以每當要上版,就是要手動將編譯完並打包好的 WAR 檔 (不是 JAR 檔喔) 用 J2EE 的 container server 介面上傳,然後等待重新啟動應用,手動的步驟愈多,就愈容易出錯。後來,第二家公司完全由 Jenkins 完成所有的工作,那種 code 只要 push 上去就會自動佈署的感覺,就是非常好的體驗。

待商榷的體驗

上述我覺得好的體驗,大多不需要 production code 有對應的修改或調整,主要來自工具的優化,像是 IDE、CI/CD 等。但接下來的體驗,須對 production code 進行修改,甚至影響到撰寫,但帶來的體驗我覺得是有待商榷的。

假型別

這幾年都是用 JavaScript 寫後端,弱型別語言在初期可以有非常高的生產力,不用定義類別,變數不用宣告型別,它就是能動 (it works)。但當您的程式規模開始成長,開始進入維運,當團隊裡的人愈來愈多時,弱型別就成了一個包袱,這也是當初 TypeScript 發展的動機之一。

新人開始看不懂程式,為什麼同一個概念,在這裡有某個 property,在另一個地方沒有某個 property,您永遠不知道拿到的物件是完整版、簡化版還是特殊版。於是,奇怪的 bug 開始出現,然後得依賴單元測試或整合測試來確認本來編譯器能幫您檢查的事情。

為了讓新人好上手,於是團隊決定加入 JSDoc,於是花了大量的時間用 JSDoc 定義型別,剛開始是有幫助的,至少 Visual Studio Code 能提示您,您拿到的是某個型別的物件,但事實真的是這樣嗎?JavaScript 不會因為 JSDoc 就突然變成了強型別語言,您還是可能拿到預期外的物件,您還是得依賴測試確認編譯器能檢查的事情。

最後,您還可能得到多個版本的 JSDoc 以及過期的 JSDoc,因為,JSDoc 是文件不是程式。

少寫 Code

Java 這幾年試圖改變「囉嗦」的形象,其中最讓開發者煩躁的是定義一個類別後,您還需要為每個屬性定義 getter 和 setter,並覆寫 equalshashCode 函式,於是我在第一家公司時,同事推薦我使用 Lombok

在一開始確實帶來生產力的提升,因為只需要簡單的幾個 annotation,就會在 bytecode 層級自動生成上述的程式碼。沒錯,bytecode 層級,因此,不只 source code 需要 annotation,連編譯過程都需要 Lombok,非常深的耦合。

但問題是,很少人認真思考,為什麼一定要提供 getter 和 setter?如果一開始就提供 getter 和 setter,直接把屬性宣告為 public 不是更簡單?又或是為什麼一定要覆寫 equalshashCode 函式?一個 Entityequals 是根據 ID 還是屬性的值?那 Value Objectequals 呢?不用管,反正自動生成很快。

在 Java 17 引入 record 後,宣告 Value Object 確實變簡單了,很可惜,Entity 仍然沒有很好的支援 (record 是 immutable 物件)。

自動生成

剛剛的自動生成還是小的程式碼片段,為了少寫程式碼,很多工具還能自動生成整個 server 或是 client。前陣子,團隊試著在不同專案內部溝通上使用 tRPC,有型別支持且能自動生成 client (不用自己串接 API),能提升 DX。對我來說,這不是什麼新鮮事,Java RMI 就是類似的技術。

對了,對我來說,tRPC 產生的不是 RESTful API,不是 HTTP 加上 JSON 就是 RESTful API (參閱 閒談軟體設計:休息時間)。

在第一家公司時 (又是第一家公司,笑),當時用 multi-tier 架構,前端、服務和資料是獨立運行的 server,彼此之間靠 RESTful API 溝通,為了減輕負擔,當時使用了 Apache CXF 自動生成 client,服務提供者與使用者共用一個 interface 定義,使用者就能呼叫使用服務,不需要自己串接 API,相當方便。

那為什麼我覺得有待商榷呢?任何 RPC 的理想是封裝複雜的底層,在本地端提供一個函式可以呼叫遠端的服務,您不需在意也不用在意底層是怎麼實作的。即便如此,仍然會有一個底層的協定,但這個協定不是您能控制的,因此不適合作為公開的 API 使用,有幾個原因:

  • 為了實現序列化與反序列化,通常會和語言高度耦合,僅少數 RPC 技術有提供多語言支援,因此像 Java RMI 兩端都必須是 Java。
  • 即便使用 XML 或 JSON 格式作為中介,減少與特定語言的耦合,仍有一些型別需要特殊處理,例如:JSON 沒有原生的 Date
  • 即便少數 RPC 技術有提供多語言支援,也很不容易做到完全符合標的語言的 coding convention。像是之前串過一個服務商的 API,由於是使用 C# 開發,API 裡的屬性都是用 upper camel case 命名,自定義的抽象層至少可以轉成專案使用的 lower camel case 後再往外丟。
這邊要說一下,Apache CXF 可以用 JAX-RS 完全自訂出 RESTful API,包含 HTTP 動詞、path 變數、query 變數、header 變數等。

也就是說當您在意 API 的形式時,這類 RPC 技術不一定能幫助到您。實際上,除了自動生成 client 外,也有自動生成 server 的技術,但前提是,您的應用只是簡單的 CRUD 應用程式。

取捨

我不是說不能用 xx 技術,而是該怎麼取捨,如果不會影響 production code,問題不大。但如果會影響,那 DX 只是眾多考量的其中一個,對該技術的掌握度、對架構完整性的影響、是否公開等因素,都會是需要考量的,對我來說 DX 的優先度沒其他因素高,可能是我從以前就對自動生成的程式碼不感興趣吧!


後記

寫這篇文章時,突然想起了一個有趣的東西,高中時學長看到很多人都用兩個迴圈寫九九乘法表時,曾問:要不要試試只用一個迴圈寫九九乘法表?不知道有沒有人有興趣試試?

53會員
104內容數
這是從 Medium 開始的一個專題,主要是想用輕鬆閒談的方式,分享這幾年軟體開發的心得,原本比較侷限於軟體架構,但這幾年的文章不僅限於架構,也聊不少流程相關的心得,所以趁換平台,順勢換成閒談軟體設計。
留言0
查看全部
發表第一個留言支持創作者!
Spirit的沙龍 的其他內容
長遠的角度來看,內部函式庫還是值得投資的公司資產,只是它需要時間、人力與管理才能做得好。若有不錯的內部函式庫也可以回饋給open-source社群,畢竟,現在開發軟體已經不太可能沒有用到任何open-source的東西。雖然說是將公司資產以 open-source 釋出,但換取的利益卻不見得是零。
整結來說,受到幾種語言的影響,我個人設計 API 時,除了合乎該語言的 convention、上述的穩定性及一致性外,大致還會注意幾點:語意清楚、相近的顆粒度、簡單的文件、讓程式能像文章般閱讀。
第三方套件用了Promise或是Reactive,導致所有business logic都要做調整,這就違反「只能有對內的相依方向」的原則。business logic大多數情況下與效能優化無關,通常需要優化的是I/O的存取,這些既然都在外層,就應該在外層做優化,外層的優化不該影響核心,這才是好架構。
如果您以為上一篇 已經是所有需要考慮的眉角,那可就錯了,實作 offline first 不是只有 client 要注意,server 也需要下功夫的。
任何語言特性用與不用,其實要看是否提升了生產力?是否提升可讀性?是否提升可維護性?這些都是在三個月甚至半年後回來修改程式時,才能明顯感受到的,而不是寫程式的當下。Java 8 的 CompletableFuture、Stream 和 Optional 都很好,但用的不好反而畫蛇添足又沒提高可讀性。
Offline first 的設計最近有越來越多的感覺,但好的 Offline first 設計要解決蠻多的問題,是否使用 offline first 設計真的需要好好思考,不然可能得不到好處,反而還引起一堆 bug,本篇先探討在 client 端可能會遇到的問題與一些可能的解法。
長遠的角度來看,內部函式庫還是值得投資的公司資產,只是它需要時間、人力與管理才能做得好。若有不錯的內部函式庫也可以回饋給open-source社群,畢竟,現在開發軟體已經不太可能沒有用到任何open-source的東西。雖然說是將公司資產以 open-source 釋出,但換取的利益卻不見得是零。
整結來說,受到幾種語言的影響,我個人設計 API 時,除了合乎該語言的 convention、上述的穩定性及一致性外,大致還會注意幾點:語意清楚、相近的顆粒度、簡單的文件、讓程式能像文章般閱讀。
第三方套件用了Promise或是Reactive,導致所有business logic都要做調整,這就違反「只能有對內的相依方向」的原則。business logic大多數情況下與效能優化無關,通常需要優化的是I/O的存取,這些既然都在外層,就應該在外層做優化,外層的優化不該影響核心,這才是好架構。
如果您以為上一篇 已經是所有需要考慮的眉角,那可就錯了,實作 offline first 不是只有 client 要注意,server 也需要下功夫的。
任何語言特性用與不用,其實要看是否提升了生產力?是否提升可讀性?是否提升可維護性?這些都是在三個月甚至半年後回來修改程式時,才能明顯感受到的,而不是寫程式的當下。Java 8 的 CompletableFuture、Stream 和 Optional 都很好,但用的不好反而畫蛇添足又沒提高可讀性。
Offline first 的設計最近有越來越多的感覺,但好的 Offline first 設計要解決蠻多的問題,是否使用 offline first 設計真的需要好好思考,不然可能得不到好處,反而還引起一堆 bug,本篇先探討在 client 端可能會遇到的問題與一些可能的解法。
你可能也想看
Google News 追蹤
Thumbnail
接下來第二部分我們持續討論美國總統大選如何佈局, 以及選前一週到年底的操作策略建議 分析兩位候選人政策利多/ 利空的板塊和股票
Thumbnail
🤔為什麼團長的能力是死亡筆記本? 🤔為什麼像是死亡筆記本呢? 🤨作者巧思-讓妮翁死亡合理的幾個伏筆
Thumbnail
這篇文章探討了在軟體開發中的技術債可能來自哪些原因,以及如何自動化偵測與修復技術債。作者透過分享不同情境下的技術債選擇,提供了對於技術債的思考與建議,針對開發人員在需要做出無奈的技術決策時,提供了一些建議。此外,還提供了一些在做出技術決策時的方法,如保留抽象層和避免vendor lock-in。
Thumbnail
今天來聊個最近很夯的主題 DDD,但不是 DDD 的本尊 Domain Driven Design,而是無所不在的 Database Driven Design,Database Driven Design 不是不好,只是你的模型容易變成貧血模型,邏輯都集中在 service 層等等。
Thumbnail
有趣的是,Model 其實沒什麼嚴格的定義,所以每個人對 Model 的解讀也不盡相同,有人覺得資料怎麼儲存屬於 Model 的一部份 (受 ORM 工具的影響),有人覺得工作流程 (workflow) 是 Model 的一部份,我個人也有自己的想法,而且隨專案的規模和特性,也不是總是一樣的。
Thumbnail
起源是當時 Facebook 有篇文章討論不少人分不清楚上述二者的差別,當時寫了首部曲《閒談軟體設計:API Naming Style》,接著是《閒談軟體設計:內部函式庫》,但始終沒談到 library 和 framework 的差別,主要是沒有好的例子,這次這例子還蠻不錯的。
Thumbnail
我自己偏好用 Repository 搭配 decorator 來管理 cache,而不是在 controller 層或是到處都有快取的邏輯,如果程式都是透過 Repository 更新資料,Repository 就會是一個不錯的地方更新快取,邏輯也就不會散亂在各處了。
Thumbnail
最近身旁有幾位正在懷孕、或剛生產完的朋友,讓我想起自己在懷孕期間印象最深刻的三件「怪事」,其中又以第三件事最誇張。
Thumbnail
不知道大家在買房之前是不是都會參考親朋好友的意見,或是上網看一些買房注意事項,有時候考慮了這塊就忘了那塊,考慮的那塊又忘了這塊.......
Thumbnail
塔西佗陷阱(Tacitus Trap),一個得名於古羅馬歷史學家塔西佗的政治學理論,意指倘若公權力失去其公信力,無論如何發言或是處事,社會均將給予其負面評價。 當然信著恆信、不信者恆不信,這就是真實的人生。
Thumbnail
關於片名   台灣片名《花漾女子》,原文片名《Promising Young Woman》,台灣譯名將時間定格在悲劇發生前,而原文片名則進一步帶我們看見另一個可能性結果
Thumbnail
前幾年因為身體的關係,當了幾年的律師逃兵,當時開了之前的事務所以後,一時間也沒有特別想要做甚麼事情,所以就邊讀一點書、早晚運動一下,剛好聽到當年同梯朋友進去金融業工作,因此也抱著嘗(ㄊㄠˊ)試(ㄅㄧˋ)的心態,找了份銀行法令遵循的工作
Thumbnail
接下來第二部分我們持續討論美國總統大選如何佈局, 以及選前一週到年底的操作策略建議 分析兩位候選人政策利多/ 利空的板塊和股票
Thumbnail
🤔為什麼團長的能力是死亡筆記本? 🤔為什麼像是死亡筆記本呢? 🤨作者巧思-讓妮翁死亡合理的幾個伏筆
Thumbnail
這篇文章探討了在軟體開發中的技術債可能來自哪些原因,以及如何自動化偵測與修復技術債。作者透過分享不同情境下的技術債選擇,提供了對於技術債的思考與建議,針對開發人員在需要做出無奈的技術決策時,提供了一些建議。此外,還提供了一些在做出技術決策時的方法,如保留抽象層和避免vendor lock-in。
Thumbnail
今天來聊個最近很夯的主題 DDD,但不是 DDD 的本尊 Domain Driven Design,而是無所不在的 Database Driven Design,Database Driven Design 不是不好,只是你的模型容易變成貧血模型,邏輯都集中在 service 層等等。
Thumbnail
有趣的是,Model 其實沒什麼嚴格的定義,所以每個人對 Model 的解讀也不盡相同,有人覺得資料怎麼儲存屬於 Model 的一部份 (受 ORM 工具的影響),有人覺得工作流程 (workflow) 是 Model 的一部份,我個人也有自己的想法,而且隨專案的規模和特性,也不是總是一樣的。
Thumbnail
起源是當時 Facebook 有篇文章討論不少人分不清楚上述二者的差別,當時寫了首部曲《閒談軟體設計:API Naming Style》,接著是《閒談軟體設計:內部函式庫》,但始終沒談到 library 和 framework 的差別,主要是沒有好的例子,這次這例子還蠻不錯的。
Thumbnail
我自己偏好用 Repository 搭配 decorator 來管理 cache,而不是在 controller 層或是到處都有快取的邏輯,如果程式都是透過 Repository 更新資料,Repository 就會是一個不錯的地方更新快取,邏輯也就不會散亂在各處了。
Thumbnail
最近身旁有幾位正在懷孕、或剛生產完的朋友,讓我想起自己在懷孕期間印象最深刻的三件「怪事」,其中又以第三件事最誇張。
Thumbnail
不知道大家在買房之前是不是都會參考親朋好友的意見,或是上網看一些買房注意事項,有時候考慮了這塊就忘了那塊,考慮的那塊又忘了這塊.......
Thumbnail
塔西佗陷阱(Tacitus Trap),一個得名於古羅馬歷史學家塔西佗的政治學理論,意指倘若公權力失去其公信力,無論如何發言或是處事,社會均將給予其負面評價。 當然信著恆信、不信者恆不信,這就是真實的人生。
Thumbnail
關於片名   台灣片名《花漾女子》,原文片名《Promising Young Woman》,台灣譯名將時間定格在悲劇發生前,而原文片名則進一步帶我們看見另一個可能性結果
Thumbnail
前幾年因為身體的關係,當了幾年的律師逃兵,當時開了之前的事務所以後,一時間也沒有特別想要做甚麼事情,所以就邊讀一點書、早晚運動一下,剛好聽到當年同梯朋友進去金融業工作,因此也抱著嘗(ㄊㄠˊ)試(ㄅㄧˋ)的心態,找了份銀行法令遵循的工作