#工作心得 有些 Bug 不是邏輯錯,而是狀態沒有被初始化
|工程師日記 #1
最近遇到一個蠻離奇的問題。
現場在操作某個「物料位置設定」功能時,原本是要把資料設定到 Port A。
結果設定完成後,資料卻出現在 Port B。
這種問題第一眼看到,其實很容易先往幾個方向想:
是不是現場操作錯?
是不是選錯 Port?
是不是物料編號輸入錯?
但後來查下去才發現,事情沒有那麼單純。
因為這個問題不是每次都發生。
有時候正常,有時候異常。
而且異常發生時,從畫面上看,操作流程也不一定會有很明顯的錯誤。
這種才是最麻煩的。
後來是一路追 LOG,再回頭看操作畫面的 source code,
才發現問題出在一個很不起眼的地方。
不是控制邏輯錯。
也不是資料計算公式錯。
而是畫面上的某個下拉選單,沒有在正確時機重新初始化。
程式裡大概是這種概念:PortNo := ComboBox.ItemIndex + 1;
也就是說,程式會拿畫面目前選到的下拉選單 index,再加 1,轉成實際的 Port No.
例如:
index = 0,代表 Port 1
index = 1,代表 Port 2
index = 2,代表 Port 3
這個寫法本身不一定有問題。
真正的問題是:
如果前一次操作曾經選過其他 Port,而畫面再次開啟時,這個下拉選單沒有被重新設定成預設值,那它就有可能保留前一次的選擇狀態。
這時候如果現場人員沒有特別重新選一次 Port,程式就會直接拿到上一輪殘留的值。
後面又會把 Port No. 跟物料編號組成一個資料,再送到控制端。
概念大概像這樣:setVal := (PortNo * 100) + materialNo;
所以問題就出現了。
畫面上看起來是在設定 Port A,
但程式實際拿到的 Port No.,可能還停在前一次的 Port B。
最後送出去的資料,自然就會跑到錯的 Port。
這種 Bug 很陰,因為單看每一段程式都很合理。
下拉選單 index 加 1,很合理。
Port No. 加上物料編號組成資料,很合理。
按下按鈕後把資料送出去,也很合理。
但整個流程串起來,卻少了一個很重要的前提:
執行這段程式以前,畫面狀態是不是乾淨的?
這次的狀況就是典型的:
前一次操作留下來的狀態,被下一次操作拿去用了。
而且這種問題最麻煩的是,它表面上不像程式錯。
→畫面可以操作
→按鈕可以按
→資料也有送出去
控制端也有收到值。
整個流程看起來都正常。
只是送出去的目標,已經不是你以為的那一個。
這次如果沒有 LOG,其實很容易查到懷疑人生。
因為只看現場現象,會覺得:
「明明是設定到這個 Port,為什麼資料會跑到另一個 Port?」
但從 LOG 反推後才發現:
不是資料在中途被改掉。
而是畫面一開始拿到的狀態就已經錯了。
這也讓我再次覺得,設備軟體裡面有些初始化真的不能省。
尤其是這種跟物料、位置、Port、Slot 有關的功能。
只要下拉選單、暫存值、選擇狀態沒有清乾淨,就可能讓下一次操作吃到前一次的殘值。
這種問題不是邏輯完全寫錯。
而是程式假設:
「畫面現在的狀態一定是正確的。」
但現場最常出事的,往往就是這種假設。
做設備軟體久了會發現:
有些 Bug 不是因為程式不會動。
而是它真的會動。
只是它拿著上一次留下來的狀態,動到錯的地方。


