[實作筆記] Hexo 7 升級的錯誤處理心得

前情提要

最近在對Hexo進行升級至7.0版本的過程中,遇到了一些錯誤與問題。
這篇部落格將記錄下這次升級的過程中所遇到的問題以及解決方法,希望對有需要的讀者有所幫助。

錯誤記錄

Hexo Action 錯誤

升級後,遇到了Hexo Action報錯的問題,錯誤訊息如下:

1
2
3
4
5
6
node:internal/modules/cjs/loader:1051
throw err;
^

Error: Cannot find module 'hexo-util/lib/spawn'
Require stack:

解決方式是查找相應的模組,更新配置文件,在本案中,hexo-util/lib/spawn 路徑不存在,應該改為 hexo-util/dist/spawn。

地端執行 Hexo d 時 Permission Denied

在地端執行Hexo d時,遇到了權限問題,無法提交到GitHub的問題。
暫時解決方式是將repository的協議由ssh改為https,暫時繞過了問題。

1
2
3
4
deploy:
type: git
repository: https://github.com/marsen/marsen.github.io.git
branch: master

後來因 https 需要提供帳號密碼,而這些資訊不適合簽入版本控制,故改回了 ssh,
為了解決相應的 SSH 連線問題,需配置 SSH 連線 .ssh/config
參考:

1
2
3
4
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa

YouTube Tag 無法處理

升級至Hexo 7.0後,發現內建的YouTube標籤無法使用,原因是Hexo 7.0中刪除了這些內建的標籤。
解決方式是引入安裝 hexo-tag-embed package。

Hexo 部署錯誤快取

在部署過程中,遇到了Hexo的快取問題,導致地端和CI都出現異常。
解決方式是清除 Hexo 的快取 hexo clean,完整 SOP 如下:

1
2
3
4
sudo rm -rf .deploy_git
hexo clean
hexo g
hexo d

使用 Docker 偵錯

Hexo Action本身是以容器去運行的,可以在本地端執行測試,不需推版
使用 Docker 進行 Hexo Action 時,進行偵錯的方法:

建置與執行

1
2
docker build -t hexo-action .
docker run -d hexo-action

觀察 logs 與 files 去偵錯,Docker Desktop 是很好的工具。

小結

這次Hexo 7.0的升級過程中,遇到了不少問題,但通過查找相應的解決方案,一一解決了這些問題。
在升級過程中,需要留意Hexo的官方文檔以及相關插件的更新,以確保能夠順利完成升級。

參考

(fin)

[實作筆記] Gitlab CI/CD 與 GCP - 錯誤處理

前情提要

在持續整合/持續交付 (CI/CD) 的過程中,我們常常會遇到一個問題:
當發生錯誤時,系統並不總是會拋出 exit 1 的錯誤碼。
這種情況下,即使發生錯誤,CI/CD 仍然會繼續執行,這可能導致部署了錯誤的版本上線,增加系統的不穩定性。

解決方法

為了解決這個問題,我們可以採取一些措施,確保在發生錯誤時 CI/CD 立即停止,並拋出 exit 1 錯誤碼。

1. 記錄錯誤信息到 output.log

首先,我們可以將所有的執行日誌輸出到一個文件,例如 output.log。這樣一來,
不管是哪個階段出現了問題,我們都能夠查閱這個文件,以便更好地理解錯誤的發生原因。

1
2
3
Copy code
# 在腳本中添加以下命令,將所有輸出寫入 output.log 文件
./your_script.sh > output.log 2>&1

2. 使用 grep 檢查錯誤

其次,我們可以使用 grep 命令來檢查 output.log 文件,查找關鍵字或錯誤模式。
如果發現了任何錯誤,我們可以採取相應的措施。

1
2
3
4
5
6
Copy code
# 使用 grep 查找關鍵字,並在發現錯誤時執行相應的操作
if grep -q "error" output.log; then
echo "Error found in output.log"
exit 1
fi

3. 發現錯誤時丟出 exit 1

最後,在檢查完錯誤後,如果發現了問題,我們應該明確地拋出 exit 1,這會通知 CI/CD 停止進一步的運行,
確保不會將有問題的版本部署上線。

1
2
3
4
5
6
Copy code
# 在發現錯誤時,明確地拋出 exit 1
if [ $? -ne 0 ]; then
echo "Error occurred. Exiting with code 1."
exit 1
fi

透過這些步驟,我們可以更好地管理 CI/CD 中的錯誤,確保系統的穩定性和可靠性。
同時,我們能夠更快速地響應和解決問題,減少部署錯誤版本的風險。

1
2
3
4
5
6
7
8
9
10
11
12
generate-qa:
stage: generate-qa
script:
- npm install
- npm run generate:qa | tee output.log # 可能出錯的命令,將輸出寫到文件
- grep -q "Error.*\[500\]" output.log && echo -e "\e[31m生成異常! Prerendering 發生 500 Error\e[0m" && exit 1
- echo "generated successfully"
artifacts:
paths:
- ./.output/public
rules:
- if: '$CI_COMMIT_BRANCH == "qa"'

小結

這些方法不僅有助於提高系統的穩定性和可靠性,還能夠加速問題的識別和解決過程,減少了部署錯誤版本的風險。
透過這些實踐,我們可以更加信心滿滿地運用 Gitlab CI/CD 與 GCP,確保順暢的開發和部署流程。

參考

(fin)

[工作筆記] 退出 Azure DevOps 的組織

前情提要

Azure DevOps 是一個由微軟開發的服務,提供開發團隊協作和快速交付軟體的解決方案。
它包含了版控、工作追蹤、持續整合/持續部署 (CI/CD) 等功能。
其中,我將重點使用其 Board 功能來進行工作項目的管理和追蹤。
然而,有一天我發現自己被不知名的人邀請進了一個 Azure DevOps 的 Organizations,
所以我開始尋找如何自行退出的方法。

解法

首先進入 dev.azure.com,點擊 user setting icon (這在畫面的右上角,是一個人的右下角有齒輪的圖案)。
點擊 Profile 進到以下頁面,可以看到提示如下:

1
2
You are currently subscribed to other communication regarding Visual Studio and/or Visual Studio Subscriptions.   
Please visit the complete Azure DevOps Profile Page to change those settings.

點擊連結到 Azure DevOps Profile Page

這裡就可以看到你的 Organization 並選擇離開

誤區

my account 也有 Organization 但是不可以隨意離開。
簡單來說,在微軟的 my account 中,Organizations 代表的是你所屬於的 Azure Active Directory (Azure AD) 組織。
這些組織可能是你的工作場所、學校或其他團體,他們使用 Azure AD 來管理員工或成員的身份和訪問權限。
這裡的組織並不等同於 Azure DevOps 中的 Organizations,並且不能隨意離開。

參考

(fin)

[踩雷筆記] 解決 GitHub 帳戶在 VS Code 中的管理問題

前情提要

當我使用 VS Code 時,我需要同時存取多個 GitHub 帳戶,
自已的 Github - 主要存取 VS Code 一些地端的設定值
公司的 Github - 有免費的 Copilot 這很好用。
兩個都我需要,我要作出大人的選擇。

實務上的困境

我可以同時登入兩組帳戶,但是無法達到我要的需求

登入兩組帳戶的方法

  1. 確保安裝了 Github Copilot 與 Github Pull Request and Issues 套件
  2. 如果有其它 Github 帳號已經在登入狀態的,都先登出,並重啟 VS Code
  3. 準備好兩個瀏覽器,分別登入公司與自已的 Github Account
  4. 點擊在左下的頭像 Icon (沒有頭像 Icon 的話在左側欄任一處點右鍵,將帳戶打勾)
  5. 選擇”使用 Github 登入,以使用 Github Copilot”
  6. 選擇登入公司帳戶的瀏覽器,此時會提示要開啟 VS Code,選擇開啟
  7. 回到 VS Code,重複第 4 步
  8. 選擇”使用 Github 登入,以使用 Github 提取要求和問題”
  9. 選擇登入自已帳戶的瀏覽器,此時會提示要開啟 VS Code,選擇開啟

如果你的預設瀏覽器是登入公司 Github 的帳號,就複製網址,貼到登入自已的 Github 帳號瀏覽器,反之亦然。
但是這個作法,實際上沒有什麼幫助,備份與同步設定與 Copilot 會共用同一組帳號
我並不需要 Github Pull Request and Issues 相關功能。

手動組態同步

早期 VSCode 有人寫了組態同步的擴充套件,但是目前內建在 VSCode 內部後不再維護了。
但是我需要的就是自已長期以來的使用的設定,所以可以先登入自已的帳號。
再登出後,登入公司帳號。缺點是需要手動處理。

安裝第二個 VSCode

這個方法也有很多不同的實作方式。
簡單說一個官方直接支援的方式。 VS Code Insider
這算是一個搶先試用版的 VSCode,也有其對應的風險。
但是你就可以在系統上安裝兩個 VSCode,並登入不同的帳戶。

花錢為自已的帳戶買 Copilot

這或許才是最大人的解法。
我們要的是”同步組態設定”與”Copilot”使用權。
根帳號本身其實沒有什麼關係。
資本主義大好,但就失去了一些童趣了。

參考

-https://tutorials.tinkink.net/zh-hant/vscode/copilot-usage-and-shortcut.html
-https://code.visualstudio.com/docs/?dv=osx&build=insiders

(fin)

[工作筆記] 問題,不重要不緊急,就永遠不作了嗎?

問題

最近我在公司引導大家一些敏捷方法的實作,
在這過程中討論了 PBI 排序的原則,價值和風險。
那麼問題來了,這樣有一些事情很小,但價值也不高,又沒有什麼風險,那不就永遠作不到了嗎??

回答的心路歷程

這是一個很好的提問,我反思一下常見的四象限模型,即「重要緊急矩陣」中,
我可以把重要對應到價值,緊急對應到風險,然後 A、B、C、D 四象限,
我們知道要先作 A、B 這樣我們 C、D 的事永遠都不作了嗎 ?

我分享一個故事如下:

有一位教授,他拿著大石頭、小石子、沙子和一個玻璃罐,
先放入大石頭,問學生滿了沒? 再來是小石子,再問學生滿了沒?
最後再倒入沙子,問學生滿了沒? 結果還是沒滿,還可以再放入水

你學到了什麼?
—常見的說法是要先處理重要的事情,順序很關鍵。

我們可以有一些反思,首先當然是重要的事先作(大石頭先放),
再來,你總是還有辦法找到一些空隙。
—時間就像乳溝一樣擠一擠就有了。

這是我當時的回答,
—如果你能守住重要的事,剩下的小事,你是有辦法找到空隙塞進去的。

回答後的反思

我要怎麼知道可不可以塞進去??
這就是透明度的重要性,在 Scrum 或看板方法都有提出。
而我們可以在 Scrum 的每日例會使用看板方法(現行主流的作法),
加上每次迭代所行成的 TimeBox,正好可以對應這個故事中玻璃罐。
有趣的是,我沒想過如果玻璃罐不是透明的話,教授的問題還有意義嗎 ?
正是透過每日例會與看板方法,讓我們可以透明的掌握進度(瓶子剩多少空間/你剩多少時間),
所以你可以判斷是不是可以再塞下石頭或沙、水。

TimeBox

它是一種任務和時間管理的方法,將任務分成小塊,每塊都有一個簡短而固定的時間,以確保高優先級的任務能按時完成。

看板方法

它包括將工作可視化、限制同時進行的工作(WIP)、管理流程、明確陳述流程政策、實施回饋循環以及以協作方式改善。
這些原則和工具都教導我們要優先處理最重要的事情,這是成功的關鍵。

看板方法我還會聯想到限制理論(Toc),但就不過度展開了。

(fin)

[生活筆記] 潛水日誌

20230916

一潛(導潛)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 14:08 |潛水時間:41 |出水時間: 14:49
能見度: 10m |平均水深: 4.8m |最大深度: 10.5m |水溫: 26.4
起始壓力: 200 |結束壓力: 70 |SCR: 3.17 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

時隔半年再次下水
第一潜稍嫌緊張
首次體驗美灩山
無浪無流,嘗試三角、四角導潜
浮力控制不當,未注意深度
未能找到原位

二潛(放呆)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 16:11 |潛水時間: 57 |出水時間: 17:08
能見度:8m |平均水深:5.1m |最大深度:11.5m |水溫: 26.8
起始壓力:200 |結束壓力:100 |SCR: 1.75 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

第二潛是與小夥伴伴潛屬於放呆行程,比較沒有那麼緊張,
算是複習了一下背滾式與跨步式入水,
不過小夥伴的問題有點多,一個是有人被海膽刺到膝蓋,
另兩個小夥伴二級頭跟 BCD 卡住而不自覺,直到教練去救援,
回程有看到黑色相間類似蛇的生物

三潛(導潛)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 17:30 |潛水時間:38 |出水時間: 18:08
能見度: 5m |平均水深: 7.1m |最大深度:11.8m |水溫: 26.5
起始壓力:200 |結束壓力:100 |SCR: 2.63 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

這次練習導潛主要是跟著教練,並繪製海圖,
方向感本來就不好的我,加上水深這個緯度,
其實是個蠻大挑戰,我只知道大概的路徑是一個狹長的 U Turn,
試著認地形,入水後右側是壁,左側是斜坡,前進20米左右會出現沙地,
這裡教練會稍作轉向,然後出現一個更深的地方,大約有到 11 米
之後我就有些迷航了,可能是在附近作了一個四角或三角的繞圈
海圖繪製比例失恆,所幸未來還有好幾次的潛水機會

四潛 (夜潛)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 19:03 |潛水時間: 53 |出水時間: 19:56
能見度: 12m |平均水深: 5m |最大深度: 11.9m |水溫: 26.3
起始壓力:200 |結束壓力:50 |SCR: 2.83 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

最擔心的夜潛反而是最美的一潛,作好安全工作後再下水其實不會有什麼心理壓力,
除了教練外還有一個陪潛的前輩,看到很多生物但是叫不出名字,
過程中有點小意外,前輩以伏地魔之姿突然從下方出現,害我撞向礁石同時被海膽刺了,
所幸以前有被刺過的經驗,知道不會有生命危險,所以我沒有驚慌,但上岸後手上還是多了 4 個黑點,

20230917

一潛(高氧)

1
2
3
4
5
地區: 東北角龍洞四號
入水時間: 9:51 |潛水時間:35 |出水時間: 10:26
能見度: 10m |平均水深:16.2m |最大深度:25.5 |水溫: 25.6
起始壓力:200 |結束壓力:100 |SCR: 2.85 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

突破個人最深的記錄,沒有什麼感覺,下水點的魚群很多,
但深一點的地方就沒有魚了,看到很多三點蟹的空殼,
聽說是漁船上拋下來的,另外撿了一些垃圾

二潛(高氧)

1
2
3
4
5
地區: 東北角龍洞四號
入水時間: 11:07 |潛水時間: 45 |出水時間: 11:52
能見度: 10m |平均水深: 11.8 |最大深度: 25.8 |水溫: 25.7
起始壓力: 200 |結束壓力: 100 |SCR: 2.22 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

再次突破個人最深的記錄到 25.8,浮力的控制還是很差,到深處會揚沙,
突中遇到一團揚沙大隊,簡直是我,
回程時有看到小丑魚

三潛(放呆)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 14:47 |潛水時間: 37 |出水時間: 15:24
能見度: 8m |平均水深: 5.1 |最大深度: 8.6 |水溫: 26.1
起始壓力: 200 |結束壓力: 100 |SCR: 2.70 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

看小夥伴考試,感覺大家很慌張,不過也都通過了,沒有到 11 米處的沙地
覺得有遇到流,但是教練是很清鬆就踢過去了,有種提早回程的感覺

四潛 (夜潛)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 18:54 |潛水時間: 51 |出水時間: 19:45
能見度: 12m |平均水深: 5.1 |最大深度: 11.2 |水溫: 25.9
起始壓力: 200 |結束壓力: 100 |SCR: 1.96 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

看到最多生物的一次,饅頭海星、海蛞蝓跟他的卵、海鰻、河豚、龍蝦
獅子魚、還有鼻子長長的不知什麼魚、黑的紅的、睡覺的、龍蝦等…
微型生物也很多,但是我看不太到,要很靠近峭壁,所以中心浮力控制要很重要。

20230918

一潛(打浮力帶)

1
2
3
4
5
地區: 東北角龍洞四號
入水時間: 09:04 |潛水時間: 53 |出水時間: 09:57
能見度: 8m |平均水深: 6.3 |最大深度: 8.4 |水溫: 25.2
起始壓力: 200 |結束壓力: 50 |SCR: 3.65 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

第一次打差點拉不住,後面就好多了,
不過看了紀錄,發現深度起伏很大,
中心浮力沒有控制好,應該至少有打了10次以上

二潛(打浮力帶)

1
2
3
4
5
地區: 東北角龍洞四號
入水時間: 10:18 |潛水時間: 40 |出水時間: 10:58
能見度: 8m |平均水深: 6.4 |最大深度: 12.2 |水溫: 24.9
起始壓力: 200 |結束壓力: 50 |SCR: 3.75 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

覺得很難控制趴姿,看了錄影,其實還不差,就是一直會停腳,
中心浮力控制不好外,還有旋轉的問題,所以一直忍不住踢腳,
不僅耗氣,看起來也很好笑,打氣只要二級頭向上就好,不用按壓

(fin)

[工作筆記] 採蘋果

前情提要

公司有三台 Macbook pro 2017 年款,普遍都有電池的問題,
為此研究了一下在台灣舊機換新機的策略。

折抵

選擇好你的新機,在「加入購物袋」前,找到「加入換購方案」,依指示輸入郵遞區號、選擇製造商 Apple 後
輸入序號後選擇相關的硬體設備。
就會出現一個換購的金額,再繼續完成你的購物袋即可。

企業商店

企業採購的話可以有累積的金額優惠,如果滿足到累積的金額(一年內 5000 美金),就可以以優惠的方式來做訂購,
需要打電話(見文末參考),使用統編建立企業商店。
其它方式與折抵一樣。
訂單成立後可以刷卡或是匯款,刷卡可以立即看到訂單進度,
而匯款後需要再打電話(0800-020-021)確定訂單進度。

折抵的部份會再出貨後 14 天來回收舊機器,應該有足夠的時間轉移資料。

參考

(fin)

[工作筆記] 軟體工程的檢傷分類

前情提要

回想一下你手頭上的工作,你如何決定你的工作順序?
常見的有緊急/重要四象限法。
另外在一些方法論上,利如 Scrum 交由特定角色排序,
而急診室的檢傷分類如下。

1
2
3
4
5
6
7
8
9
第一級(復甦急救,立即處理-病況危急生命或肢體,需立即處理。如:心跳、呼吸停止、肢體及嘴唇發青、發紫,體溫高於41度或低於32度,無意識或意識混亂、持續抽搐且無意識。

  第二級(危急,可能等候時間10分鐘)-潛在性危及生命、肢體及器官功能,需快速控制與處理。如:急性意識狀態改變、持續胸悶、胸痛且冒冷汗、低血糖(<40mg/dl)、外傷造成之大量出血,頭頸軀幹骨盆部位血流不止、高處墜落、車禍(乘客被拋出車外)、頭部撞擊後曾失去意識等。

  第三級(緊急,可能等候時間30分鐘)-病況可能持續惡化,需急診處置;病人可能伴隨明顯不適症狀,影響日常生活。如:無法控制的腹瀉或嘔吐、外傷後肢體腫脹變形疑似骨折/脫臼、高血壓(收縮壓>200mmHg或舒張壓>110mmHg)且沒有任何症狀等。

  第四級(次緊急,可能等候時間60分鐘)-病況可能為慢性病及急性發作,或某些疾病之合併症相關,需在1至2小時做處置避免惡化。如:局部蜂窩性組織炎、急性咳嗽但沒有發燒、發燒但無其他不適、反覆性疼痛或暈眩等。

  第五級(非緊急,可能等候時間120分鐘)-病況非緊急,需做鑑別性診斷或轉介門診。如:慢性噁心、嘔吐或打嗝、輕微擦傷,瘀青,軟組織受傷、螫傷或咬傷,但無發燒或疼痛不適、輕微腹瀉,無脫水現象等。

我們可以參考。以等級與具體案例作為分析。

個人的經驗是以 3+1 個維度分析,
主要為發生風險、發生頻率、影響範圍和可否重現。

判斷流程

  1. 是否為線上問題:線上問題較可能產生價值的耗損
  2. 發生頻率:高頻的問題如果不處理會帶來大量干擾、下一階段可能會麻痺,甚至讓真正的問題從眼前跑走
  3. 影響範圍:誰會感到痛苦?老闆?客戶?PM ? RD ? 營運?怎麼作可以停止或減輕他們的痛苦。
  4. 風險評估:不作會怎麼樣?作了會怎麼樣?

定義

x 的維度是風險的高低,風險高者需安排修正,風險低小者可以再觀察
y 的維度是影響範圍的大小,範圍大者需優先停損縮小範圍,範圍小者就安排修正
z 的維度是發生的頻率,高頻者需優先停損止傷,低頻者需要觀察,如果發生一次就會形成持續性或永久性的傷害即為高頻
加上可否重現分析如下:

可重現

高風險/高範圍的情況下,頻率已經不重要,重要的不能讓發生 0 次的事情發生 1次,
一但發生只能砍掉重練,具體例子如廣達被勒索病毒攻擊

維度一:高風險/高範圍/高頻率:終止營業、暫停營運的等級
維度二:高風險/高範圍/低頻率:終止營業、暫停營運的等級

應急辦法,止血: 先限縮風險、範圍、頻率至少其中之一。

低風險/高範圍的情況,即使發生了仍有轉還的空間,高頻時處理的重點在縮小範圍與暫時的降噪
一但修正,理應停止降噪的設定,低頻時安排修正計劃即可

維度三:低風險/高範圍/高頻率:部份功能停止運作。應暫時的降噪(暫時停止通止,避免有其它警告被淹沒),安排修正計劃
維度四:低風險/高範圍/低頻率:部份功能停止運作。儘速安排修正計劃。

在高風險的情況,如果有小範圍的異常,都應立即處理,重點在於能不能根除問題,或是緩解發生頻次

維度五:高風險/低範圍/高頻率:根除問題,或是緩解發生頻次
維度六:高風險/低範圍/低頻率:根除問題,或是緩解發生頻次

在低風險/低範圍的情況下,要小心避免讓人習慣這類型的錯誤(麻痺),或是產生過多雜訊影響判斷。
偶一為之但是知道原因的話可以不處理

維度七:低風險/低範圍/高頻率:降噪或是設定提示水位
維度八:低風險/低範圍/低頻率:不處理

不可重現

不知道自已不知道是最可怕的,如果發生時是高風險/高範圍大多也沒救了,
就死前能不能有所收獲

維度一:高風險/高範圍/高頻率:終止營業、暫停營運的等級
維度二:高風險/高範圍/低頻率:終止營業、暫停營運的等級

低風險/高範圍的情況,即使發生了仍有轉還的空間,高頻時處理的重點在縮小範圍與暫時的降噪
一但修正,理應停止降噪的設定,低頻時安排修正計劃即可

維度三:低風險/高範圍/高頻率:暫時的降噪(暫時停止通止,避免有其它告警被淹沒),查明原因,安排修正計劃
維度四:低風險/高範圍/低頻率:查明原因,安排修正計劃

在高風險的情況,如果有小範圍的異常,都應立即處理,重點會在能不能根除問題,或是緩解發生頻次

維度五:高風險/低範圍/高頻率:查明原因,根除問題,或是緩解發生頻次
維度六:高風險/低範圍/低頻率:查明原因,根除問題,或是緩解發生頻次

在低風險/低範圍的情況下,要小心避免讓人習慣這類型的錯誤(麻痺),或是產生過多雜訊影響判斷。
偶一為之但是不知道原因的話要特別小心標記,這很可能是別處發生問題的潛兆

維度七:低風險/低範圍/高頻率:查明原因,降噪或是設定提示水位
維度八:低風險/低範圍/低頻率:查明原因

小結

幾個重點,預防勝於治療,
真的發生時儘可能讓風險降低、範圍縮小、頻率減少,
十萬火急時可以先用暫解去處理,減少傷害。
但是回到正常流程就是要找出根本原因,並用正確的方式治療。

我作了個表以供參考

情境 風險 範圍 頻率 行動
可重現情況(Reproducible)
1 立即處理,確保不再發生。
2 立即處理,確保不再發生。
3 暫時降噪並制定修正計劃。
4 制定修正計劃。
5 根除問題或減少頻率。
6 根除問題或減少頻率。
7 降噪或設定提示水位。
8 不處理。
不可重現情況(Non-Reproducible)
9 查明原因,可能無法挽救。
10 查明原因,可能無法挽救。
11 暫時降噪,查明原因,制定修正計劃。
12 查明原因,制定修正計劃。
13 查明原因,根除問題或減少頻率。
14 查明原因,根除問題或減少頻率。
15 查明原因,降噪或設定提示水位。
16 查明原因,特別小心標記可能是其他問題的潛在預兆。

(fin)

[生活筆記] 一些程式轉職相關的問答

前情提要

一直有在作程式相關的助教、導師相關的工作,有些學生的問題很棒,也是我的盲點。
沒有心思好好整理,至少記錄下來,給未來的自已一絲反芻機會。

問題

Express.js在業界的實用性如何? 優點和缺點是什麼? 有需要再學習第二種語言/框架嗎?,建議的選擇是?

算常見的 Nodejs 的 Web 框架,優點就是夠主流,資源好找。
缺點就太簡單。

語言/框架可以多學,自已判斷。不知道就先跟著公司或社群走。

參考文章10 Best Nodejs Frameworks for App Development in 2023

Google 關鍵字: Nodejs Web Framework 2023

思路:不論什麼樣的程式語言,我的本質是 Web 開發,不同的語言與框架有不同的場景,總不缺乏新的挑戰者,
可以觀望、研究、測試、入坑,沒有一定的正確的答案,能夠快速作出判斷與取捨是重要的,但這需要經驗。

2. 如果想要在自有主機上部署Express.js,比較適合搭配的web伺服器軟體是?

這裡的”web伺服器軟體”是指什麼? Nginx 或 Apache 嗎?
選擇適合的場景就好。目前業界主流是 Nginx,思路參考第一題

3. 樣板引擎在業界的使用度高嗎? 有使用的話會是在什麼情況呢? 有比較主流的選擇嗎? 還是大部分被前端框架取代了?

註:學生這裡指的是 express + handlebars 的開發方式
大部份都前後分離端了,維護舊案可以能會碰到。
樣板引擎主要會發生在 Web Form 這類的舊專案,主流可能是 Php 或 Asp.Net 的某些專案。
或是在 2010 很主流的 MVC 開發方式,這段時間各家語言也有自已的解決方案。  

思路:理解為什麼會有前後端分離的發生,某些情況的小專案,樣板引擎的開發方式會比前後端分離有效率。

4. AC一個練習教案的規模,大概有幾十個到百個檔案要維護。實際業界專案的檔案數量應該更多,檔案間的關係複雜,維護人員要如何弄得清楚呢? 有沒有什麼比較好的管理工具?

檔案是指程式碼的部份嗎?  
學會架構分層,基本就三層式架構、MVC、MVVM、MVP、MV* 等,
使用 OOP 語言的話可能也要依 Pattern 分層,現在比較流行 DDD、六角架構等…
再大一點會是微服務的情況。

思路:想一下檔案間的關係複雜,那你會怎麼作?基本上就是分門別類,
好的分類可以讓錯誤發生時可以快速定位、實作功能時可以職責分離。
舉個生活化的例子,就是像是整理你的房間。

5. 在前後端的協作中,如何決定一項功能應由前端製作或後端製作? 舉例來說,要加上分頁的功能,本質上只是資料的整理重排,這樣的功能應該由前端或後端做呢?

Case by Case, 以我來說跟畫面有關的歸前端、其它歸後端。  
分頁通常會由後端處理、但是有些情況前端也要處理。
Ex: 避免太頻繁的 request 到 Server,一次性回傳大量資料,由前端自行製作分頁。

思路:還是以需求為依歸、預設一個簡單的原則。團隊合作的話,最理想是團隊共識,次之由 Leader 決定,不要發生由某端強勢主導的情況。
舉例說明,欄位檢查,前後端都要作,前端的目的是引導使用者正確操作,後端是真正的防護。

6. 求職網站中許多職缺要求會其他程式語言如: C# or PHP,會建議再去學其他語言嗎? 有推薦的學習平台或課程?

我會想學 TypeScript、Python。
程式在 web 開發上有類似的作法,更多領域其實也需要程式人才,
例如:手機 App 開發、IoT 開發、AI 工程師等…
建議找一個自已可以生存的領域,專研打磨裡面的技術會建議
社群活動可以用來搜集關鍵字,
Udemy 的課程很便宜,YT 也有很多大神的頻道可以學習。

思路:唯一的問題是學不完,怎麼整合應用變現,這個時候就不只是求職了,公司只是某一些技術棧整合的結果,
當你學的更多時,或許可以有別的出路?

7. 建議如何練習LeetCode? 才不會好像只是背答案,而不是懂背後的邏輯。有聽說 NeetCode 平台不錯用?不知道助教是否推薦

就是多刷多累績經驗,看題目、看答案。
兩個重點,把題目看懂、把答案看懂,試著把自已的思路轉化成程式
平台很多:NeetCodeLeetcodeHackerrank

思路:助教用 TDD 刷 LeetCode,實務上蠻常遇到面試造火箭、入職擰螺絲的狀態,
但是仍然不知道要學什麼或作什麼樣的 Side Project 時,刷題是一個好的選擇。

8. Junior工程師除了準備作品集,LeetCode 與程式語言的觀念外,通常面試還會考什麼嗎?

我主要會問架構與流程題,如果能把自已開發的架構與流程說明清楚,就可以同時觀察到技術能力與溝通能力。

思路:常常去面試就會知道現在業界常問什麼了。

10. 職場上在開發專案時,後端工程師的實作範圍會是全部一手包辦還是還會細分工作?或者工作架構會是怎麼分配的?

看公司,建議去有分工的公司,一手包辦很可能會很雷,學到的可能也是一堆大泥球的作法

12. 除了現有AC課程之外,助教建議Junior後端工程師還需要提升哪方面的技術

掌握好版控與協作流程/自動化與容器化技術/實用精實的開發實踐

  • Git、Docker、AWS/Azure/GCP、K8S
  • TDD (BDD、ATDD)/ Refactoring /Design Pattern

13. 目前軟體業有受到景氣影響而減少職缺數嗎或停止招聘

國外有一波大裁員,有影響到,但台灣本身還好
至少我還好

14. 請問助教平常寫程式會如何結合AI加速開發,有建議相關課程嗎

Github Copilot+TDD

15. 網站若有多國語言版本,技術上要怎麼實作呢?

關鍵字i18n

1
2
3
4
5
6
7
8
{
"tw":{
"login":"登入"
},
"en":{
"login":"Login"
}
}

16. 手機版和電腦版的網站要怎麼分割呢?

我知道的兩種作法

結語

部份題目涉及專案內容,所以排除掉。
但是有關從無到有開發一個專案,或是與人合作開發專案,是整個職涯中會很常發生的事。
現在不作,以後也會遇到,可以儘量去嚐試。

(fin)

[實作筆記] Websocket 初體驗

前情提要

tl;dr, websocket 至少是一個 10 年以上的技術了,但是筆者一直沒有機會實作它。
大部份的時候是應用場景不符合,或是簡單 Long Polling 已經足夠,甚至就算用 Polling 這個方法也無法把 Server 打掛。
另一個情況是團隊已經很成熟,有專門負責的部門在統一處理這塊邏輯,
而通常這塊邏輯會與主要的核心功能作切分,所以我也沒有機會接觸到。
這次難得有個小型的專案,有機會實作,故稍作記錄一下。

需求

使用者會停留在某些頁面等待系統的資料狀態更新,大約每 10 秒要作一次 Polling,
而平均資料狀態更新需要 3~10 分鐘不等。在這個情況下要改用 websocket,
(註:我不認為這是一個很好的應用場景,但是牽扯更多未揭露的調整故不展開討論,
EX:Heartbeat、Keep-Alive 等等…機制也未討論到)

WebSocket Server 實作

使用的技術:Typescript + Express + ServerSocket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// import library
import express, { Request, Response } from "express";
import { Server as ServerSocket } from "ws"; // 引用 Server

if (process.env.NODE_ENV !== "production") {
require("dotenv").config();
}
// form env 指定一個 port
const PORT: number = Number(process.env.WS_PORT);
// 設定斷開時間
const CT: number = 1000 * Number(process.env.CONNECTION_TIMEOUT);
const app = express();
const server = app.listen(PORT, () =>
console.log(
`[Server] Listening on http://localhost:${PORT} , timeout is ${CT} ms`
)
);
const wsServer = new ServerSocket({ server });

// Connection opened
wsServer.on("connection", (ws: WebSocket, req: Request) => {
// Connection 建立時發生的邏輯

// Listen for messages from client
ws.on("message", (data: string) => {
try {
// 發送 Message 時發生的邏輯
} catch (error) {
console.error("Invalid JSON format: ", data);
}
// Get clients who has connected
const clients = wsServer.clients;
// Use loop for sending messages to each client
clients.forEach((client) => {
client.send(JSON.stringify(docStatus));
});
});
// 設定 ping 時間間隔,用來讓連線太久的 Client 斷開
const interval = setInterval(() => {
if (ws.alive) {
ws.terminate();
clearInterval(interval);
return;
}

ws.alive = false;
ws.ping("", false, () => {
console.log("[Timeout]", ws.key);
});
}, CT); // 30 秒

// Connection closed
ws.on("close", () => {
// Connection 關閉時發生的邏輯
console.log("[Close connected]", ws.key);
});
});

// 新增一個路由處理器
app.get("/", (req: Request, res: Response) => {
// health and version check
res.send(`WebSocket Running Version ${process.env.WS_VERSION}`);
});

前端實作,收送雙向

使用的技術:JavaScript
以下內容大多參考於神 Q 超人的文章,
作為參考用,實務上會搭配使用的前端框架作修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
var ws;

// 監聽 click 事件
document.querySelector("#connect")?.addEventListener("click", (e) => {
console.log("[click connect]");
connect();
});

document.querySelector("#disconnect")?.addEventListener("click", (e) => {
console.log("[click disconnect]");
disconnect();
});

document.querySelector("#sendBtn")?.addEventListener("click", (e) => {
const msg = document.querySelector("#sendMsg");
sendMessage(msg?.value);
});

function connect() {
// Create WebSocket connection
ws = new WebSocket("wss://localhost:8088");
// 在開啟連線時執行
ws.onopen = () => {
// Listen for messages from Server
ws.onmessage = (event) => {
// 收到訊息的 Logic
console.log(`[Message from server]:\n %c${event.data}`, "color: yellow");
};
};
}

function disconnect() {
ws.close();
// 在關閉連線時執行
ws.onclose = () => console.log("[close connection]");
}

// 監聽 click 事件
document.querySelector("#sendBtn")?.addEventListener("click", (e) => {
const msg = document.querySelector("#sendMsg");
sendMessage(msg?.value);
});

// Listen for messages from Server
function sendMessage(msg) {
// Send messages to Server
ws.send(msg);
console.log("[send message]", msg);
}

後端實作,只送不收

使用技術: php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include "./vendor/autoload.php";

$client = new WebSocket\Client("wss://localhost:8088");

$message = json_encode(array(
"your_property" => "Your Data",
"complex_property" => array(
"no" => 1,
"status" => "Hello word"
)
));

$client->text($message);
$client->close();
?>

後記

實務上在股票看盤即時更新、多人聊天室、多人網頁遊戲上或許十分有用,
但實際上在這此的案例上就有些大材小用了,先當作學習了。
在查找資料的過程有一段話很受用,
我稍作總結如下:
當討論到 WebSocket 時,不應用 Http 的標準去審視它,
更應該關注這些 Connection 會持續連接多久? Connection 之間交互的行為是什麼?  
是運算密集的行為還是讀寫密集的行為?…等等,才是你決策的關鍵。

參考

(fin)

Please enable JavaScript to view the LikeCoin. :P