摘要:[獨自murmur]下判斷式時,應找出真正的因
這個題目,是在code review的時候,很常看到的問題。
而且會是致命的問題,但是卻很難說明清楚。
舉個最常聽到的例子來說,
「天雨路滑」,因為下雨,所以地上是濕的。
轉換成程式,大概就是類似:
{RoadState=RoadStateType.Wet;}
else
{RoadState=RoadStateType.Dry;}
上面這例子應該沒啥問題,重點來了,
「天雨+路滑+撐傘」這三個東西搞在一起,就可能有人code寫錯了。
錯誤的例子:
{RoadState=RoadStateType.Wet;}
else
{RoadState=RoadStateType.Dry;}
if(RoadState==RoadStateType.Wet)
{OpenUmbrella();}
這邊為什麼錯?我們用現實的情況來解釋,就看得出為什麼不合理了。
因為下雨,地上就會濕,因為地上濕,所以要撐傘?
不對吧,撐傘的原因,應該是因為下雨,而不是因為地上濕。
地上濕的原因可能會多種,可能有人潑水,地上會濕。可能有人在洗玻璃、洗車,地上會濕。
因此,當你要判斷「是否要撐傘」時,不能拿「下雨」會產生的結果來判斷,而是應該拿「是否下雨」來當作判斷的條件。
很多junior programmer碰到被challenge程式寫法邏輯有問題時,通常都是這種情況。
因為他們會認為,「我的程式跑起來是對的,為什麼你說我錯」,
或是「根本不會因為其他情況導致地上是濕的,所以只要地上是濕的,就代表下雨,就代表要撐傘」。
我再舉個常見的例子,
我曾經看過一段CODE,
是按了存檔的按鈕之後,要把資料存進去DB。但是寫法是下面這個樣子:
{
if (IsPostBack)
{
SaveDB();
}
}
相信寫過程式的人都會覺得這段CODE也太離譜了吧。
沒錯,就是這麼離譜,
因為
存檔button會submit -> submit會postback-> postback會觸發Page_Load() -> IsPostBack會變成true,
所以把SaveDB()寫在Page_Load()用IsPostBack判斷,是合理的。
當你告訴他,其他功能也可能會觸發postback時,他卻跟你說,
「我這隻規格上只有這個button會觸發postback」,真的會想把他的頭扭斷。
如果這例子大家覺得可笑,
那我再舉另外一個例子,
畫面上有兩個Panel擺放著Insert與Edit要用的區塊,分別叫做PanelInsert與PanelEdit好了。
這兩個區塊只固定會顯示其中一個。
Panel外有一個存檔button,固定要顯示,但是當Edit時,要執行Edit的功能,Insert時要執行Insert的功能。
開關panel的code可能是這樣寫:
{
PanelInsert.visible=true;
PanelEdit.visible=false;
}
elseif(Status==StatusType.Edit)
{
PanelInsert.visible=false;
PanelEdit.visible=true;
}
但是問題來了,存檔呢?
相信我,我看過太多的code是寫成這樣:
{InsertDB();}
elseif(PanelEdit.visible)
{EditDB();}
這樣寫的邏輯,跟上述的錯誤例子不是一樣嗎?
正確的寫法應該是:
{InsertDB();}
elseif(Status==StatusType.Edit)
{EditDB();}
請回頭檢查看看自己的code裡面,是否有判斷條件是使用「樣式」來做判斷的,
通常那就是犯了這類型的錯誤,
「樣式」的呈現,通常是某個判斷後產生的結果,而非其他判斷式的「因」。
blog 與課程更新內容,請前往新站位置:http://tdd.best/