l

2024年9月16日 星期一

重構既有系統,邁向整潔架構 (4):第一回合,分層與移除基本型別依戀

September 16 17:48~18:40;19:49~20:39

▲從下層爬往上層的咪咪 (by 常玉)

 

工商服務

想了解本系列文章完整內容,請參考【重構既有系統:邁向整潔架構實作班】。課程介紹與報名網址在此:https://teddysoft.tw/courses/refactor-to-ca/

***

前言

前三集聊了:
  1. 重構既有系統,邁向整潔架構 (1):為什麼透過重構改善軟體架構很困難
  2. 重構既有系統,邁向整潔架構 (2):逆轉重構流程
  3. 重構既有系統,邁向整潔架構 (3):Task List Kata簡介
這一集終於要動手重構。
***

分層原則

Teddy在第二集提到要採用由上而下的方式來重構,首先套用Clean Architecture,確定架構分為四層,如圖1所示。
 
▲圖1:套用Clean Architecture的分層原則
 
其中Task這支只有不到30行的程式很明顯地屬於Entities Layer,將它移到entity package。150行的TaskList目前還不清楚屬於哪一層,先不移動它。
 
***
 
物件村沒人怎麼辦?
Teddy的重構目標是在架構上採用Clean Architecture,在Entities Layer與Use Cases Layer則是套用DDD(領域驅動設計)的戰略模式語言(Entity, Value Object, Service, Aggregate, Repository等)。現在「物件村(domain model)」只有一個Task,顯得有點孤單,要想辦法增加物件村的人口。
 
物件導向設計,顧名思義就是要透過物件(領域模型)來表達問題領域的業務邏輯。這個Task List Kata重構範例只有兩個物件,這種現象有一個可能性,就是設計者對於「基本型別依戀」,捨不得使用物件,只用了String, Int這些基本型別。因此,接下來Teddy要採用「只管移除基本型別依戀」的方式,來增加物件村的人口。
 
***
 
無腦移除基本型別依戀
請參考圖2,第17行Map<String, List<Task>> tasks,將它「座艙升等」成Tasks物件,如圖3所示。
 
▲圖2:TaskList程式碼片段
 
 
 
▲圖3:移除基本型別依戀,新增Tasks物件
 
***
套用Value Object
圖3中的Map<String, List<Task>> tasks,其中Map的key代表project name,因此將其座艙升等成Value Object,請參考圖4。
 
▲圖4:ProjectName value object,用Java record代表
 
***
 
引入共通語言(Ubiquitous Language)
請參考圖5,此時Tasks類別的第6行變成Map<ProjectName, List<Task>> tasks,這還是一個基本型別依戀。請問一個擁有一組Project Name對應到List<Task>的「概念」要怎麼稱呼它?在此Teddy將其稱為Project。因此我們進一步將Map<ProjectName, List<Task>> tasks重構成List<Project> projects,參考圖6。
 
▲圖5:Tasks類別
 
 
▲圖6:Project類別
 
 
最後,Teddy把Tasks類別改名成ToDoList,現在物件村已經有四個物件,請參考圖7。
 
▲圖7:物件村從1個住戶增加為四個住戶
 
***
 
下集預告
有了物件村的住戶(領域模型),下一集要在領域模型中套用DDD戰略模式,好好了解一下什麼叫做Aggregate, Entity, Value Object。

***

友藏內心獨白:只有一個物件變成全村的希望,這樣壓力太大。

 

2024年9月13日 星期五

重構既有系統,邁向整潔架構 (3):Task List Kata簡介

September 13 20:30~22:07

 

前言

上一集<重構既有系統,邁向整潔架構 (2):逆轉重構流程>Teddy提到只要「大膽假設」不管你是開發什麼系統,就是要套用Clean Architecture就對了。如此一來,便可將重構從「由下而上」的設計方法轉變成「由上而下」的設計過程。

接下來這幾集,Teddy將以Task List Kata為例,說明如何將既有系統的架構重構成Clean Architecture。

***

Task List Kata介紹

Task List Kata是一個公開的重構練習,程式碼可參考:https://kata-log.rocks/task-list-kata。如圖1所示,它有8種不同的語言版本,Teddy使用Java版本。

 

▲圖1:Task List Kata支援的語言

 

如圖2所示,Teddy將Task List Kata複製到自己的repository,並將package name改成tw.teddysoft.tasks。

 

▲圖2:Task List Kata專案目錄

 

Task List Kata原本只有三支程:

  • Task:參考圖3,這是一支只有不到30行的程式,很簡單,好像沒什麼需要重構。
  • TaskList:參考圖4、圖5,這是一支約150行的程式,看起來很亂,感覺是重構的重點。
  • ApplicationTest︰整合測試,當重構進行時可以執行這個測試案例確定沒有感變舊有的程式行為。

 

▲圖3:Task.java程式碼

 

▲圖4:TaskList.java程式碼, 1/2

 

▲圖5:TaskList.java程式碼, 2/2

***

鄉民們怎麼重構

首先,了解需求。Task List Taka的介紹網頁提到 (用ChatGPT翻譯成中文):

 

***

任務清單

這是一個對基元(primitives)過度依賴的程式範例。

基元是任何具有技術性質且與您的業務領域無關的概念。這包括整數、字符、字串和集合(列表、集合、映射等),還有執行緒、讀取器、寫入器、解析器、異常處理等任何純粹專注於技術問題的事物。相比之下,這個專案中的業務概念,如「任務」、「專案」等,應被視為您領域模型的一部分。領域模型是您所運營的業務的語言,將其應用於代碼庫有助於避免使用不同的語言,從而幫助避免誤解。根據我們的經驗,誤解是造成漏洞的最大原因。

練習

嘗試實現以下功能,同時逐步重構以去除基元。在完全重構代碼以移除基元之前,儘量不要實現任何新行為,也就是說,只有在您即將更改的代碼已被重構後,才進行變更。不要重構無關的代碼。

一組判斷基元是否已移除的標準是,只允許基元出現在構造函數的參數列表、本地變量和私有字段中。基元不應該被傳遞給方法或從方法中返回。唯一的例外是基礎設施代碼——與終端、網絡、資料庫等進行通信的代碼。基礎設施需要將數據序列化為基元,但應視為特殊情況處理。您甚至可以將基礎設施視為一個獨立的領域,具有技術性質,其中基元是該領域的核心概念。

您應該嘗試將測試包圍在您正在重構的行為周圍。一開始,這些測試大多是高級系統測試,但隨著進展,您應該會撰寫更多的單元測試。

***

上述說明已經提示了重構方向:「優先考慮去除primitives」,也就是去除重構中提到Primitive Obsession(基本型別依戀)壞味道。但是一般人看到這個練習,直覺的想法是:「把大的拆成小的」。很多人會先把TaskList的private methods像是showaddsetDonehelperror等「座艙升等」,各自變成一個class,並套用Command設計模式,讓execute可以執行不同的命令。

接著,為了產生這些不同的命令,又套了Simple Factory。然後呢…….嗯,就沒有然後了。此時TaskList程式長度剩下原本的1/3,抽離出來的Command也符合單一責任原則,程式碼也很短,感覺好像沒什麼明顯地方需要重構了。

***

 

換你想

在正式談Teddy如何重構Task List Kata之前,請鄉民們也想想看,如果是你,你會如何重構?

***

工商服務

想了解本系列文章完整內容,請參考【重構既有系統:邁向整潔架構實作班】。課程介紹與報名網址在此:https://teddysoft.tw/courses/refactor-to-ca/

***

友藏內心獨白:搞錯順序只會徒然浪費時間。

2024年9月10日 星期二

重構既有系統,邁向整潔架構 (2):逆轉重構流程

September 10 07:38~08:08;11:30~11:49

     

▲圖1:Ada逆練九陰真經

 

前言

上一集<重構既有系統,邁向整潔架構 (1):為什麼透過重構改善軟體架構很困難>Teddy提到重構是一種「由下而上」的設計,而設計本身應該採用「由上而下」的過程,這也是為什麼透過重構改善軟體架構會如此困難的原因。

為了簡化重構軟體架構的難度,要想辦法將重構流程改成「由上而下」。

 

***

怎麼做?

要「逆轉重構流程」,其實很簡單,就是先確定架構目標就可以了。例如,假設鄉民是Uncle Bob的粉絲,不管手邊有什麼軟體,就是要想辦法無條件套用Clean Architecture就對了。如此一來,你就有了軟體架構重構的目標:Clean Architecture。

現在Teddy把架構重構的問題轉換成如何套用Clean Architecture,Teddy用Pattern Language的方式來解釋這個套用的過程,請參考圖1。有五個模式支撐Clean Architecture:

 

▲圖1:Clean Architecture底下有五個模式

 

上述五個模式的套用順序,先從Four Layers開始,將系統分成以下四層(四個不同的packages):

  • entity
  • usecase
  • adapter
  • io
     

有了大方向之後,接下來就是把你的既有系統想辦法塞入Clean Architecture這四層之中,如圖2。

 

     

▲圖2:Clean Architecture的四個階層

***

下一集Teddy將會以Task List Kata為例,說明如何將既有系統的架構重構成Clean Architecture。

***

 

工商服務

想了解本系列文章完整內容,請參考【重構既有系統:邁向整潔架構實作班】。課程介紹與報名網址在此:https://teddysoft.tw/courses/refactor-to-ca/

***

友藏內心獨白:道理很簡單,要做到卻不簡單。

2024年9月5日 星期四

重構既有系統,邁向整潔架構 (1):為什麼透過重構改善軟體架構很困難

September 5 21:02~22:06

▲Ada:我不會逆轉重構但我可以逆轉自己!

 

前言

今年四月Teddy開了一門新課程:【重構既有系統:邁向整潔架構實作班】。以往的開課流程Teddy總是先寫部落格文章,再設計課程,但這門課Teddy卻是直接設計課程而沒寫部落格文章。這系列文章算是「補寫」原本應該出現的文章,第一集先談為什麼軟體架構層級的重構很困難?

***

重構是一種設計

大部分鄉民應該都知道重構是在不改變程式碼外在行為的前提之下,藉由改變它的結構達到增進設計品質的一種方法。既然重構可以「改善設計」,因此可以將重構視為一種設計方法

Teddy將設計方法區分為兩種:

  • 由上而下:先決定設計目標,然後由上而下展開子目標,最後展開到一個可以施工的工作單元。例如,傳統的物件導向分析與設計就是一種由上而下的方法。先確定專案願景,然後展開需求、設計領域模型、軟體架構。
  • 由下而上:不確定最終目標是什麼,先從手邊可接觸到的「東西」著手設計,再慢慢將這些「東西」兜成更大的「東西」,透過這種方法完成設計工作。重構本質上就屬於這種設計方法。

***

 

設計應該是由上而下的過程

根據建築師Christopher Alexander的看法,設計是一種由上而下個過程。這就好比敏捷社群常說「以終為始」是一樣的道理,你希望達到什麼目標,就以這個目標當作設計的出發點。這樣講鄉民們可能還是覺得有點抽象,Teddy舉領域驅動設計中的戰術設計模式語言為例,請參考圖1,Model-Driven Design模式是這個模式語言的「起點」,也是這整個設計最「頂」的模式,也等於這個模式語言的「目標」。

翻成白話文就是:領域驅動設計的戰術設計就是Model-Driven Design。如果看到這模式鄉民們就懂了,就開悟了,底下的其他模式也就無需再看。

 

▲圖1:領域驅動設計的戰術設計模式語言

 

***

再舉一個日常生活的日子,假設你晚上要請朋友吃飯,你要先決定「去那裡吃飯」?例如吃路邊攤、快炒、日式料理、韓式料理或是西餐等。如果是吃快炒,接下來才是決定要點什麼菜、什麼湯和飲料。這就是由上而下的設計思維。

***

由上而下那又怎樣?

重構作為一種由下而上的設計方法,用來達成區域改善是很有效的方法。例如,用Rename重構幫變數、method、class、package取個可以代表它們意圖的好名子。有沒有改善設計,當然有。改善後的設計對軟體架構的影響是什麼?不知道(不明顯)!

同理,用Extract Method把Long Method變短同時又用有意義的method name來代表程式碼的意圖。有沒有改善設計,當然有。改善後的設計對軟體架構的影響是什麼?不知道(不明顯)!

這就是透過重構要達到改善軟體架構很困難的原因。要採用由下而上的方式改善軟體架構並非不可行,但這類似演化的作法,需要一段很長、很長、很長的時間,以至於在一般專案中變得不切實際。因為鄉民們沒有那麼長的時間可以透過演化的方式「長出」一個好架構出來。

***

怎麼辦?

答案就在前文中。其實很簡單,就是要想辦法將重構改成由上而下的設計方法。只要做到這點,透過重構改善軟體架構就變得不再那麼遙不可及。

今天先聊到這個,下一集Teddy再來談如何「逆轉重構」,把它改成由上而下的設計方法。

***

工商服務

【重構既有系統:邁向整潔架構實作班】課程介紹與報名網址:https://teddysoft.tw/courses/refactor-to-ca/,有興趣的鄉民歡迎參考。

***

友藏內心獨白:好久沒出來亮相了。