iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
0
Software Development

邁向專業軟體工程師必修的英文課系列 第 19

Day 19 - [連接詞一] 想好好討論一下if的用法 - 1

if,一個基本語法,難度極低,但問題爆多的語法。
if在所有的語言的用法都一樣,差別只在有沒有括號跟分號而己:if後面接著一段判斷式,成立的話執行。

if(user.Age > 18)
    Page.Redirect('/jazzdrums');

這麼簡單的語法,但常發生:

判斷式太長

有看過if長到視窗都長出scroll bar那種嗎?從第一個看到最後一個都考慮搭Uber過去那種。

    if(user.Country == Country.Taiwan || user.Country == Country.China || user.Country == Country.USA || user.Country == Country.Japan || user.Country == Country.Singapore || user.Country == Country.Korea)
    return true;

上面的例子還算簡單的,有些還會摻雜呼叫方法,可能還會有其他的邏輯一起進來。
但其實這個判斷式沒有錯,但他有兩個問題:

  1. 難以理解
    這些條件代表的意義是什麼?以上面舉出的例子,在if判斷式裡看到那麼多的國家名稱,它要表達什麼呢?除了當初撰寫這條判斷式的開發人員外,其他人可能都要花一點時間去理解。如果判斷式裡出現了不好或者讓人迷惑的名稱更讓人頭疼。
    過長的判斷式,降低了程式的可讀性,也讓後續的維護需要分心去梳理他的意義。
  2. 難以維護
    邏輯語法其實是有順序性的,它從左到右之外,and和or也有先後之分,因此怎麼擺放判斷式也是學問。那這麼長的判斷式當然就會增加維護的難度,而且不止整到自己,也會整到後續維護的工程師。

比較好的做法是,把判斷式變成方法,並且適度的重構邏輯判斷式:

    if(HasBranch(user.Country)) return true;
    ...
    public bool HasBranch(Country country)
    {
        return Enum.IsDefined(typeof(Country), country);
    }

無限增生的else if

有看過else多到都蓋過一整頁的那種嗎?從第一個看到最後一個都考慮搭電梯下去那種。

if(user.Level == Level.One)
{
}
else if(user.Level == Level.Two)
{
}
else if(user.Level == Level.Three)
{
}
else if(user.Level == Level.Four)
{
}
else if(user.Level == Level.Five)
{
}
else if(user.Level == Level.Six)
{
}

看起來像switch的if-else-if判斷式雖然確實可以改用switch,但並不能改變一個方法裡包含過多分支的情況。換句話說,這個方法並不是專為某個情況而處理。
有什麼問題嗎?問題可大了。

  1. 方法處在不穩定的情況
    以上面的例子來看,如果今天有增加一個新的Level,那表示這個方法又必需要異動,有異動就有可能需要重新測試並確定與其相關的測試案例都必需要通過。一直無法穩定的程式碼絕對是高風險的。
  2. 難以測試及除錯
    如果程式的邏輯不斷的增生,也意即相關的判斷式也有可能變化,每個else都表示不同的可能性,測試案例和除錯都會因此而增加難度。

有比較好的做法嗎?當然有,例如把判斷式分割成不同的方法來呼叫,或者更好的做法:分割成不等分的class,並用factory產生物件,然後統一呼叫一個方法來檢查。
例如,有一個需求,長這個樣子:

The output can be in any format (eg. xml/html/json/csv)

雖然我大可用一個if去判斷需求格式是什麼,但如果透過factory,在Creator裡檢查格式,並回傳輸出格式的介面

    public static IOutput CreateOutput(string outputFormat)
    {
        if(string.IsNullOrEmpty(outputFormat) || outputFormat.Equals("json", StringComparison.InvariantCultureIgnoreCase))
            return new JSONOutput();

        throw new NotImplementedException("Output format not found.");
    }

那原先方法裡的程式碼就變得簡潔多了。

        var output = OutputFactory.CreateOutput(argsDictionary["Output"]);
        Console.WriteLine(output.Output(result));

(未完待續)

感覺有聲音


上一篇
Day 18 - [副詞] Not,你的變數被旋轉了嗎?
下一篇
Day 20 - [連接詞二] 想好好討論一下if的用法 - 2
系列文
邁向專業軟體工程師必修的英文課30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言