iT邦幫忙

2021 iThome 鐵人賽

DAY 1
2
Software Development

From State Machine to XState系列 第 1

Day01 - 緣起:怎麼了?為什麼?如何掌握過於自由的程式碼?

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” – Martin Fowler

程式碼是自由的、彈性的、靈活多變的~

在 JavaScript 的世界尤其是

但隨著商業邏輯、應用場景越來越複雜,程式碼逐漸龐大

除了能運作之外,我們需要考量的東西越來越多,如系統可靠度、信心(意思是不怕壞掉、不怕bug),系統安全性、系統效能等

以整體軟體工程要考量的維度,越來越多。

思考看看以下一些問題

以電商交易舉例

電商的訂單階段,買家提交訂單(給賣家先確認庫存),賣家確認有貨可成立點選同意,訂單進入等待付款,付款完成收帳後進入等待發貨倉儲人員配貨、安排物流,送達目的地後等待取件,取件完成後訂單交易完成

簡單歸納

提交 → 待付款 → 待發貨 → 待取件 → 交易完成

實務考量

上述一系列流程,用文字敘述看似單純,但在程式碼實作的過程中,需要考量的東西很多,最直接可以想到的就是一些簡單的防禦。比如說我們要確保還沒付款時,程式碼沒辦法接觸到等待發貨相關的通知、操作與執行。或賣家還沒確認成立訂單,不能進行扣款等。

以遊戲開發舉例

舉實際應用場景,假設我們今天要設計一個2D RPG遊戲,我們必須撰寫玩家操縱角色的行為

開發角色移動模組

https://img.craftpix.net/2017/10/2D-Game-Police-Character-Free-Sprite-Sheets.gif

規格

  • 按下 ⇦、⇨ 可控制玩家移動
  • 按下 B 是跳躍
  • 長按 ⇩ 是匍匐前進 → 放開 ⇩ 是起身

1.實作跳躍

https://ithelp.ithome.com.tw/upload/images/20210916/20130721V6OathELrO.png

if(input == PRESS_B){
  // 「實作」計算、畫出跳躍的畫面,圖片從站立換成跳躍
}

發現 bug 了嗎(或許對你的遊戲設計不是)?假如角色現在已經是正在跳躍,如果再按一次 B ,就會在空氣中再繼續往上跳

1.1 加入防禦 - 空氣跳躍(連續跳躍)

因此我們勢必要加入一個 flag 來判斷是不是正在 跳躍中 ( isJumping )

if(input == PRESS_B){
  if(!isJumping){
    isJumping = true // 將 flag 跳耀中,轉為 true
    // 跳
  }
}

2. 實作匍匐前進

https://ithelp.ithome.com.tw/upload/images/20210916/20130721BL45s6O4hw.png

長按 ⇩ ,進入匍匐前進

if (input == PRESS_DOWN){
  // 匍匐前進,換成匍匐前進的圖片
}

2.1 加入防禦 - 跳躍不能直接變匍匐前進

接著,因為跳躍中不能匍匐前進

 if (input == PRESS_DOWN){
  if(!isJumping){
    // 匍匐前進,換成匍匐前進的圖片
  }
}

2.2 與前面跳躍整合,這裡從 if 改接 Jump 後的 else if

if(input == PRESS_B){
  // 跳
} else if (input == PRESS_DOWN){
  if(!isJumping){
    // 匍匐前進,換成匍匐前進的圖片
  }
}

2.3 加入判斷 - 匍匐及站立

放開 ⇩ ,為了恢復站立(我們怎麼知道是不是匍匐中),是不是又要加一個flag 匍匐中( isCrawling )

if(input == PRESS_B){
  // 跳
} else if (input == PRESS_DOWN){
  if(!isJumping){
     isCrawling = true
    // 匍匐前進,換成匍匐前進的圖片
  }
} else if (input == RELEASE_DOWN){
  if(isCrawling){
     isCrawling = false
    // 恢復站姿
  }
}

這裡是完整的嗎、正常的嗎?看到這我己經心累了QQ 看得出有 Bug 嗎?

2.4 加入防禦 - 匍匐不能直接變跳躍

假如我們在匍匐前進時,按下 B 跳躍,因為 isCrawling 還是 true ,我們會看到主角是俯臥的樣子飛到空中,所以我們跳躍的logic 判斷勢必又要回去加點預防

if(input == PRESS_B){
  if(!isJumping && !isCrawling){
    isJumping = true // 將 flag 跳耀中,轉為 true
    // 跳
  }
} else if (input == PRESS_DOWN){
  if(!isJumping){
     isCrawling = true
    // 匍匐前進,換成匍匐前進的圖片
  }
} else if (input == RELEASE_DOWN){
  if(isCrawling){
     isCrawling = false
    // 恢復站姿
  }
}

“ Code is like humor. When you have to explain it, it’s bad.” – Cory House

假如有個新人今天要人接手這份程式碼,這種因為商業需求的防護與連貫,不斷在 if/ else 中增添邏輯判斷,需要思考很多東西。

比如 為什麼跳躍的行為還要加入 isCrawling,去判斷這行 if(!isJumping && !isCrawling)

為了交接順利、好維護,我們勢必要增加一些程式碼註解、寫好文件等等。

而且從上述的開發過程中,我們也發現,其實這樣子的開發模式,很容易漏思考一些東西,或者隨著新需求的出現,我們必須回去修改既有的邏輯。

因為我們的程式碼太彈性???程式碼太誠實???程式碼太笨???

下一篇讓我們來思考一下為什麼有這個問題的產生、我們可以怎麼預防?


小結

訂單RPG 角色的移動,這 2 個例子,描述在複雜的軟體應用、系統中,會面臨的挑戰。
以及我們嘗試如何去克服這個困難

  • 透過儲存 boolean flag 進變數,記憶狀態
  • 透過一系列 if / else 判斷狀態、進行防呆)

參考文獻

圖片引用


下一篇
Day02 - 觀察:自由的程式碼?有什麼蛛絲馬跡、現象?
系列文
From State Machine to XState31
1

原來 Ken 大報名 SD 組啊!

Ken Chen iT邦新手 5 級 ‧ 2021-09-16 09:43:35 檢舉

感覺應該報 Web 組XD,但一開始也不知道 FSM / XState 比例會多少,然後就開賽了

0

感謝 Ken 大的分享,最近也在學習 state machine,一直不太會使用這些工具。

Ken Chen iT邦新手 5 級 ‧ 2021-09-16 22:08:08 檢舉

Andy 大大,學習的地圖好廣啊XD 守備範圍很大,看來是位全能選手

不過實務上,如果有必須用這個工具才能解決問題的話,一定很快就學會了~ (就算不懂也會用XDD,這年頭火箭很多,我們好好站穩在巨人的肩膀上就好)。

就跟我的鐵人賽文章一樣,走 DDD (Deadline Driven Developement),23:59 前,再不濟也會湊出300字,等真的要用到就會了/images/emoticon/emoticon01.gif

0
TD
iT邦新手 4 級 ‧ 2021-09-17 09:01:22

期待後續文章!

Ken Chen iT邦新手 5 級 ‧ 2021-09-17 19:46:50 檢舉

一起朝完賽邁進吧XD

/images/emoticon/emoticon69.gif

0
pjchender
iT邦新手 4 級 ‧ 2021-09-18 01:32:46

你的圖好精美

Ken Chen iT邦新手 5 級 ‧ 2021-09-18 01:52:07 檢舉

我畫不出來、但是找很久,感謝有這麼適合的圖出現,也希望不要侵犯到畫家的權益,所以有先特別標注來源

我要留言

立即登入留言