iT邦幫忙

DAY 3
7

如何提升系統設計品質 - 技術與工具以.NET為例系列 第 3

[如何提升系統品質-Day3]重構– DRY & Top-Down思考方式(1)

本篇文章接著上一篇的[如何提升系統品質-Day2]重構– UI, Business logic, Data access概念分開,繼續往下重構。

現實是殘酷的,需求不會只有這麼簡單的一個驗證密碼的功能而已,需求就是一直再改變,資訊時代唯一不變的事情就是『改變』。要怎麼樣因應新的需求,擁抱改變,隨著使用者需求改變,讓我們的系統可以逐步逐步的更加穩固,這就是我們希望透過重構達到的目的。

(抱歉,文章內容太長,我只好分兩篇發了...)

[如何提升系統品質]系列文章連結
需求說明
上次我們已經做了『驗證密碼』的功能了,今天User提出一個新的需求是『修改密碼』,這個功能分成三塊:
1.我們得先驗證原本的密碼正確與否。
2.我們得確認User輸入的新密碼有沒輸入錯誤,有沒與確認密碼相同。
3.都OK之後,將新的密碼儲存起來。

通常PM都會說:『這個功能跟上次很像啊,應該很快吧,複製貼上就可以了,不用花這麼多時間吧。』

不要相信這種鬼話啊!!如同7-Eleven之父鈴木敏文所說:『妥協是很簡單的,但一旦妥協了,所有的一切就都結束了。』每次的妥協或貪圖方便,都是在欠下『技術債』,出來跑,總有一天要還的。即使作不到『前人種樹,後人乘涼』,至少也不要當『前人挖坑,後人憎恨』。

重構
如需求所說,基本上按了按鈕就是要做三件事,這邊希望帶出『抽象思考』的方式來設計程式。什麼是抽象思考?以往初學的工程師,總是想到什麼做什麼,做了什麼想什麼,但這樣很容易迷失在自己的邏輯因果循環的叢林中,甚至忘了到底一開始為什麼要設計成這樣。

將需求與思緒整理好,也就是最基本的抽象思考去設計,到底需要什麼樣的功能。我們的抽象化其實很基本,如同上一篇文章重構完看到的樣子,把想要做的事情先列出來,在還沒看到內容之前,先從三萬英尺的高空來構思到底要怎麼設計。

步驟一:
我們先將要做的事情想好,給個方法名字,把『深度1』的邏輯先寫出來,而先不去在意方法裡面的細節,要決定的是該input什麼參數,以及方法該回傳什麼type,讓深度1的邏輯設計可以達成的功能需求。當明白了功能需求,明白了每一個方法很乾淨明確的名稱與意義,明白了input/output的期望值,設計內容細節才有意義。

雖然方法底下長滿了毛毛蟲,但莫急莫慌莫害怕,先來檢視一下這樣的邏輯正不正確,如果正確,透過方便的Visual Studio就可以快樂的進行步驟二。

步驟二:
將滑鼠游標移到長滿紅色毛毛蟲的方法上,可以看到下拉清單,選一下『產生某某class中的某某方法』。另一個方式是用滑鼠右鍵,選『產生』=>『方法Stub』。

接著看到Visual Studio自動產生的內容,貼心的是連parameter的名字都跟一開始抽象化設計的名字一樣,這樣可以讓自動產生的方法也具備對應的可讀性:

接著將原本抽象設計的註解,移至對應的方法中,透過///產生API document的方式來對方法進行說明:

到這邊,步驟二就算結束了。請大家再回顧一下,在產生方法外殼的過程中,我們完全沒動到深度1的抽象設計邏輯,但要做的事,要產生的殼,要建置通過的步驟已經都完成了。

如果您是屬於設計高階邏輯的人,這個時候工作已經做完了,內部的細節可以交給比較junior的programmer進行設計,這樣的抽象程式有點像spec,也有點像虛擬碼。好處是思考與設計不會被細節所迷惑,好處是清楚自己在做什麼,也清楚方法要做到什麼。

步驟三:
這是一步挑戰人性的步驟,當要設計VerifyPassword的時候,PM告知之前已經有個傢伙寫過一模一樣邏輯的程式,請自行『參閱』。您會怎麼做?

請注意,當您打開Validate.aspx.cs,企圖把方法內容選起來,按下複製,想要直接貼到新的這支功能時,相當殘念!您又少了一次成長的機會,您又多了一次技術債留給後人,您又替後面的需求異動多了一層累贅。

DRY=Don't Repeat Yourself,只要兩段程式碼,指的是同一件事,未來需求異動不是看code,而是看domain know-how,在domain中同一件事未來需求變更時,當然都要跟著變。多複製一次,未來就要增加多改一份的成本,就要增加漏改一份的風險。

請不要無腦地複製貼上,讓我們靜下心好好想想,既然這段code在兩個地方用的到,他們是否屬於同一件事?如果是,未來會不會有第三個第四個地方用的到?未來需求異動,要改一份還是兩份,還是很多很多?當判定這樣的驗證密碼邏輯,可能在其他地方還用的到,而且這兩個網頁上這兩個需求的確是指同一件事,那請跟著我這樣做,就能將這個功能的職責分的更清楚與獨立。

先加入App_Code的ASP.NET資料夾,

接著定義VerifyPassword這個行為屬於Authentication的一環,所以增加了Service與DataAccess的folder,並增加了對應的Authentication class在裡面。

接著來看原本v1的程式中,Enum的VerifyStatus是private的,這樣會導致只有該頁面能用。所以就先重構Enum的部分,在App_Code先建立一個Utility的folder,建一個EnumUtility的class,裡面要用來放屬於共用Enum的部分。然後,先將原本的Enum宣告註解掉,這時會發現在VerifyPasswordById的方法,回傳型別出現了紅色毛毛蟲。沒錯,我們要透過IDE來重構與自動產生。在VerifyStatus紅色毛毛蟲上,『產生』=>『產生新的型別』。

接著將visibility設定成『public』,型別選『Enum』,名稱預設就會是剛剛紅色毛毛蟲的型別名字。加入到剛剛建立的class裡面。

然後將註解掉的Enum的項目,填到EnumUtility的項目中即可。

到這邊,我們的邏輯本體還是沒被修改到,但該讓大家共用的Enum宣告,已經放到該放的位置了。

文章內容太長...下篇待續


上一篇
[如何提升系統品質-Day2]重構– UI, Business logic, Data access概念分開
下一篇
[如何提升系統品質-Day4]重構– DRY & Top-Down思考方式(2)
系列文
如何提升系統設計品質 - 技術與工具以.NET為例30

1 則留言

0
kradark
iT邦好手 1 級 ‧ 2011-10-12 23:30:04

高手 除了推 我還能幹嘛?
簽名

我要留言

立即登入留言