Hubert Notes

Posts

June 9, 2025

如何用 GitHub Workflow 實現 GitHub Merge Freeze 自動化

當前狀況 公司現行採用 GitHub Flow 進行分支管理。雖然我們大致上每週 Release 新版本,但有時會因 Hotfix 或功能實驗,導致 Release 節奏被打亂,產生以下問題: main branch 可能被提前合併未來要 Release 的功能 若上線後需修正,又要 revert 其他功能或暫時禁止合併 需要人工確認各種狀態,流程繁瑣且易出錯 為了解決這些問題,我們導入了所謂的「GitHub Merge Freeze」機制,也就是在 Release 期間,透過 GitHub Actions 自動凍結 main branch,確保版本穩定。 解決方案:Release PR + Merge Freeze 我們優化後的流程如下: 每次 Release 時建立 Release PR,將本次要上線的功能統一合併,Release 完再 merge 回 main。 Release PR 存在期間,main branch 禁止合併任何新的 PR,僅能合併到 release branch。 這麼做的好處: 所有 Release 內容一目了然,方便查驗和追蹤 自動 freeze main branch,開發者一目瞭然,降低溝通成本,避免誤合併 如何自動 Freeze Main Branch? GitHub 原生僅支援 手動鎖定分支,並無自動 freeze 功能。因此,我們設計兩個 GitHub Workflow 來自動化:
November 10, 2024

與 Hoisting 技術相關的知識

Overview 什麼是提升 (Hoisting) 提升 (Hoisting) 的運作方式 文章中沒解釋的進階知識 什麼是提升 (Hoisting) 變數與函式在程式碼執行之前被『Hoisting』到作用域的頂部,這樣可以確保在執行程式時,所有變數與函式宣告都已經準備好可以使用 Hoisting 的設計主要是為了讓開發者在撰寫程式碼時更有彈性,最常見的是函式之間可以互相呼叫而不會導致錯誤 提升 (Hoisting) 的運作方式 JavaScript 是一個解釋型語言,解釋型語言指的是透過直譯器 (Interpreter) 逐行讀取並執行程式碼的語言,不過現今的 JavaScript 是透過 V8 引擎進行處理,V8 引擎提供『即時編譯(Just-In-Time Compilation, JIT)』,過程並不是逐行解釋程式碼而是先掃描整個程式碼,進行語法解析並生成機器碼(Bytecode),在程式碼執行過程 (runtime) 會監控執行比較頻繁的程式碼將其編譯成機器碼以提升運行效能 現行的框架多數提供『提前編譯 (Ahead-Of-Time Compilation, AOT)』讓程式碼在部署前就提前編譯成機器碼,透過機器碼提升程式碼”啟動”的速度 JIT 側重於運行時的性能提升:因為會在執行過程中動態針對頻繁執行的程式碼進行深度優化,使長時間運行的應用程式 (Node.js Server) 效能更高 AOT 側重於啟動時的速度提升:因為提前將程式碼轉為機器碼,適合在意載入時間的應用程式 (網頁與行動裝置) Hoisting 發生於 JavaScript 編譯階段,而不是執行階段 當 JavaScript 編譯器掃描程式碼時,會將所有變數宣告和函式宣告『Hoisting』至作用域的頂部,這些宣告都會被記錄到記憶體中,此過程即為『Hoisting』,需注意的是,Hoisting 只 Hoisting 變數的宣告不 Hoisting 賦值,因此程式碼執行前 var 宣告的變數會被初始化為 undefined let 和 const 則會因『暫時性死區 (Temporal Dead Zone, TDZ)』的原因,若在宣告前使用該變數,會觸發 ReferenceError 參考以下實際例子的 Hoisting,主要是傳達概念,實際運作會更複雜 使用 var 的變數在宣告前就呼叫 編譯前
October 22, 2023

使用 GitHub Workflow 定期下載新北市實價登錄資料,以及使用 Google Geocoding API 將地址轉換為經緯度

前言 最近想要抓實價登錄的資料來看,但是懶得去找可以免費 setup Server 的服務,但如果沒有一直在跑的 Server 怎麼去跑 Cron Job 來更新資料以及確保資料有被存放呢? 於是就想說試試 GitHub Workflow 能不能達成這件事 XDD 如何設計 GitHub Workflow 基本上設計流程如下 Trigger Workflow by Schedule Run download-data Script Commit and push changes Trigger Workflow by Schedule 我們可以使用官方提供的 events-that-trigger-workflows#schedule ,來達到這個方式,他的時間結構如下 * * * * * ┬ ┬ ┬ ┬ ┬ │ │ │ │ └─ 星期 (0 - 6) │ │ │ └─── 月份 (1 - 12) │ │ └───── 月中的某天 (1 - 31) │ └─────── 小時 (0 - 23) └───────── 分鐘 (0 - 59) 因為實價登錄是每 10 天更新,但我避免誤差,所以設定成每個月的 02 / 12 / 22 號,因此我們的 Workflow 一開始會長這樣
October 17, 2023

整理報表數據時,利用數據回填 Backfilling 來解決程式碼的強耦合

這是關於整理報表時,遇到兩個模組間邏輯會打架的工作雜記,以下除了處理過程相似,其他模組與表格都是虛構 故事脈絡 最近遇到要把以前的報表新增加權分數(weighted_score)的欄位,而報表資料主要是從使用者評分表 Table 撈取出來整理的,加權分數以前是在其他模組計算但沒有被存放到 Table 中,使用者評分表的 Schema 簡化後大概如下 欄位名稱 資料類型 說明 id INT(PK) 主鍵 user_id INT(FK) 外鍵 value INT 新增/扣除的分數 params JSON 放置分數相關的任意資料 confirmed BOOLEAN 已經評分過的資料為 true 範例資料 id value user_id params confirmed 1 122 12 { “type”: 1, “weighted_score”: 456 } 0 2 19 11 { “type”: 2, “weighted_score”: 314 } 1 處理過程 建立共用的模組 由於以前的程式碼在計算加權分數時是直接計算,而加權分數其實會因為不同類型的type而有不同的加權計算方式,為了在報表也能使用這套邏輯,所以我們需要先抽出一個模組 Calculator ,慶幸的是這套邏輯已經有寫測試,所以我們可以省掉寫測試的時間直接重構即可,這邊我是使用工廠模式來處理,後續直接套用模組跑測試無誤就算是完成這個階段,可以到下一個階段進入資料的處理惹。 將計算完的資料放進 Table 中 這邊介紹一下會用到的兩個模組,模組 D 是負責進行使用者扣分的模組,而模組 DeductPoint 是接收到扣分行為時會去使用者評分表把扣分的資料寫入進去,有個需要注意的地方是,扣分會先從確認過(confirmed = 1)的分數先扣不夠再從未確認(confirmed = 0)的分數扣,所以有可能會一次扣分行為但記錄兩筆資料到使用者評分表…
October 7, 2023

Hugo + GitHub + GA4 建置個人部落格

QuickStart 安裝 hugo brew install hugo 創建 hugo 的目錄結構,目錄名稱為 quickstart hugo new site quickstart 切換當前目錄到 quickstart cd quickstart 初始化 git git init Clone Ananke 的 theme 到自己的 theme git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke 設定現在的 theme 是 ananke echo "theme = 'ananke'" >> hugo.toml 啟動 server hugo server 啟動後大概就是長這個樣子 創建第一個頁面 hugo new content posts/my-first-post.md 確認頁面的資料 +++ title: "My First Post" date: 2023-10-07T10:26:52+08:00 draft: true +++ 在底下就可以進行撰寫了,以下是我的文章內容 +++ title = '使用 Hugo 建置 Blog' date = 2023-10-07T10:26:52+08:00 draft = false +++ ## QuickStart --- #### 安裝 hugo brew install hugo #### 創建 hugo 的目錄結構,目錄名稱為 quickstart hugo new site quickstart 雖然剛剛新增了頁面,但其實你現在應該看不到這個頁面,所以要先終止原先的 hugo server 使用 development 模式才可以看到 draft 為 true 的頁面 以下兩個都可以
June 3, 2020

Css系列 - 如何避免邊界重疊 ( Margin Collapsing )

這是以前在 GitHub 寫的文章,現在搬遷過來,所以有一些歷史 XD 邊界重疊 (Margin Collapsing) 當兩個block都有設定邊界,且兩個邊界重疊時,只留下最大值的邊界,這個情況就是邊界重疊 但設有float, position: absolute的元件不會發生上述的事情 有三個情況會造成邊界重疊 同一層相鄰時若設定邊界時,上下邊界會造成重疊 父元素與第一個或最後一個子元素若設定邊界時,上下邊界會造成重疊 兩個元素中間有空的元素時,若這兩個元素有設定邊界,上下邊界會造成重疊 同一層相鄰時若設定邊界時,上下邊界會造成重疊 // .scss .mt-16 { margin-top: 16px; } .mb-16 { margin-bottom: 16px; } <!-- html --> <section> <div class="block mb-16">margin-bottom: 16px</div> <div class="block mt-16">margin-top: 16px</div> </section> 雖然兩個都設定margin,但因為相鄰,所以上下邊界會重疊, 就不是預想的32px而是16px了,以下圖例,綠色為margin的範圍(16px) 父元素與第一個或最後一個子元素若設定邊界時,上下邊界會造成重疊 // .scss .mt-16 { margin-top: 16px; } <!-- html --> <section class="mt-16"> <div class="block mt-16">margin-top: 16px</div> </section> 當父元素有設定margin, 第一個元素也有設定margin, 父元素為block且沒有設定border, padding, overflow時, 就會變成第一個元素與父元素共享同個margin,所以不會分開來,就重疊了, 以下圖例,綠色為margin的範圍(16px) 兩個元素中間有空的元素時,若這兩個元素有設定邊界,上下邊界會造成重疊 // .
© Hubert Notes 2025