今晚我要用筆記,打臉我昨天下午散步時的回憶~😼
昨天(Day23)和今天這兩篇,就僅僅只是拖延了很久的、我個人的使用歷程回顧。
如果你真的想take away什麼,可以滑到底看GenAI的摘要。
優勢 | 陣營 | 腳本語言 | 可能趨勢 |
---|---|---|---|
地端 | Microsoft Excel | Basic(VBA) | TypeScript(Office Scripts) |
雲端 | Google Sheets | JavaScript(GAS環境) | Gemini |
開源且自由 | LibreOffice Calc | Basic(LibreOffice Basic) | Python(UNO環境) |
工作上,其實就是公司有什麼軟體就用哪個。當然,如果能選擇,我現階段會更偏好自己相對熟悉的Google生態系。
個人生活上,雲端我是用Google Sheets,地端則從Excel轉向Calc。[^1]
至於VBA,自Office 2016之後,就幾乎沒有任何新feat,畢竟微軟目前重心放在雲服務市場,主要資源都投入在Office Scripts。
VBA不像LibreOffice是相對自由的生態,既然開發團隊都讓它隨時間凋零了,除非是要待在同一間公司直到退休的讀者,否則我個人是不建議投入時間在學VBA。
這應該是微軟陣營和Google陣營最廣為人知的生態差異。
VBA偏向靜態型別(除了Variant
以外),我必須一開始就宣告型別與大小;GAS/JavaScript則是大家熟悉的動態型別。
這點在Excel與Google Sheets也是一樣,前者每個欄位的型別其實已經被標記好(XML),初始化型別後就會固定;後者則是動態推斷型別(JSON)。
JavaScript就我粗淺的理解,必定是ByValue,但當值本身是物件或函式時,常被新手誤會為ByRef。
VBA則預設是ByRef,使用者可以額外宣告為ByVal;習慣JavaScript的讀者可能要稍微留意這點。
GAS很直覺,就是JavaScript的Date
物件,VBA則是以1900/1/1為序號1,並往後計數的Double
序號。有趣的是,VBA有個bug是它有不存在的1900/2/29,查了一下,完美地被Office Script繼承了哈哈哈。
在VBA,當複製新的表格時,會同時將畫面切換到新的表格,也就是新的表格會自動被設為active:
Sheets(sheetName).Copy After:=Sheets(sheetName)
接著,就可以直接用ActiveSheet
來處理後續的動作:
With ActiveSheet
.Name = newSheetName
.Tab.Color = tabColor
.PivotTables(1).PivotCache.Refresh
End With
這很符合GUI使用者的直覺,等同於用滑鼠拖曳並複製新表。
在GAS,複製新的表格時,不會自動將新的表格設為active[^2];通常會將該表格存入變數裡以進行後續的動作:
const copiedSheet = activeSheet.copyTo(spreadsheet);
copiedSheet.setName(newName);
如果想要改變active sheet,則需要額外宣告:
copiedSheet.activate();
單就複製表格這個動作,VBA可以用更少的語法完成,包含VBA內建ActiveSheet
、自動切換ActiveSheet
,指定複製到哪個位置。
雖然我很討厭VBA,但就這一點,VBA的確對一般使用者更友善。我覺得GUI使用者一直到錄製巨集都還符合直覺,但當開始寫腳本後,要踏入另一種思維模式,會是第一個小門檻。
我昨天瀏覽到的這篇文章,我完全同意VBA腳本就只是公司行政流程內的小道具,並且會使用很多業務術語,所以如果未來有需要寫VBA的話(希望不要),我會盡可能全部用中文,也方便對同仁進行內部行銷。[^3]
雖然公式應該不能算是腳本語言,我覺得它能從小小的公式演變成現在這樣涵蓋樣式、錯誤處理、if判斷等等,真的是挺瘋狂的。所以基於好奇想稍微回窺一點它的歷史。
理想上,公式應該只是簡短地被使用,就跟JavaScript早期其實也只是被設計來處理簡單的文件互動一樣。
隨著應用程式被拓展至更多使用者與場景[^4],公式先天的限制導致可讀性、可維護性極差。
所以就算同樣的需求可以用公式完成,如果可預期它會需要被維護,我就會傾向用VBA或GAS。其次,比較理想的是分成多欄,逐步output結果,也可以方便維護與除錯。[^5]
但是,我們畢竟不是總是能從零開始一份專案/一份例行作業/一組試算表,我們可能是基於各種無奈無法動太多東西,只能在最小限度下改動,這時就會遇到必須在一欄內盡可能塞進所有公式的狀況。
於是我就想,難道Excel和GAS就沒有formatter嗎?(目前我還沒有發現,我覺得formatter真的應該被內建在Excel內。)我目前的作法是,讓GenAI依我習慣的JavaScript formatter風格排版。
這是Excel(轉Calc)的實例:
=IF(
表格5[[#This Row],[狀態]] = "停止訂閱",
0,
IF(
表格5[[#This Row],[週期]] = "年結",
表格5[[#This Row],[每年]] / 12,
IF(
表格5[[#This Row],[貨幣]] = "USD",
表格5[[#This Row],[費用]] * exchange_rate[USD/TWD],
表格5[[#This Row],[費用]]
)
)
)
這個是Google Sheet的實例:[^6]
=IFERROR(
QUERY(
{prodId, channel},
"SELECT Col2
WHERE Col1 = '" & A5 & "'
LIMIT 1",
0
),
""
)
一句話簡介:GoTo
是一種可以讓我們瞬間跳到程式中任何地方的魔法咒語。
一開始發現有GoTo
語法時覺得很酷,被我大量使用;後來則盡可能不使用了,畢竟它破壞線性閱讀,未來重構時會很痛苦。
相對不那麼糟糕的是On Error GoTo HandleError
,Google Sheets則是try
/catch
。儘管後者更工程上可維護,但前者可能更商務使用者友善。
手邊一時找不到單年的版本,如果是JavaScript背景的讀者,這邊是GenAI生成的GoTo
迷宮範例:
Sub ProcessReport()
Dim ws As Worksheet
Dim lastRow As Long
Dim i As Long
Dim total As Double
Set ws = ActiveSheet
GoTo Start
Start:
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
total = 0
If lastRow < 2 Then GoTo NoData
i = 2
LoopStart:
If ws.Cells(i, 1).Value = "" Then GoTo SkipRow
If Not IsNumeric(ws.Cells(i, 2).Value) Then GoTo SkipRow
total = total + ws.Cells(i, 2).Value
SkipRow:
i = i + 1
If i <= lastRow Then GoTo LoopStart
GoTo ShowTotal
NoData:
MsgBox "No data found.", vbExclamation
GoTo CleanUp
RandomLabelThatDoesNothing:
' This label is never used, but it's here to confuse everyone.
GoTo LoopStart
ShowTotal:
ws.Cells(1, 4).Value = "Total"
ws.Cells(1, 5).Value = total
If total = 0 Then GoTo SadEnding
GoTo CleanUp
SadEnding:
MsgBox "The total is zero. Very sad.", vbInformation
GoTo CleanUp
GoTo GoTo:
' This is here just to be evil.
CleanUp:
Set ws = Nothing
MsgBox "Processing complete.", vbOKOnly
End Sub
原則上,能不要隱藏欄位就不要隱藏;就算逼不得已,可以寫一個小腳本,把哪些隱藏的欄位先筆記好,未來要維護時就可以快速展開與再隱藏。
我撰文的此時其實不太能把握VBA到底有沒有內建quick sort,但反正我發現當年我手刻了一個,並跟朋友抱怨為什麼沒有類似JavaScript的Array.prototype.sort()
:
Private Sub QuickSort(arr() As Double, left As Long, right As Long)
Dim i As Long
Dim j As Long
Dim pivot As Double
Dim temp As Double
i = left
j = right
pivot = arr((left + right) \ 2)
Do
While arr(i) < pivot
i = i + 1
Wend
While arr(j) > pivot
j = j - 1
Wend
If i <= j Then
temp = arr(i)
arr(i) = arr(j)
arr(j) = temp
i = i + 1
j = j - 1
End If
Loop While i <= j
If left < j Then
QuickSort arr, left, j
End If
If i < right Then
QuickSort arr, i, right
End If
End Sub
我其實不覺得前GenAI時代的個人歷程有什麼價值,但我想試著從這個歷程裡摘出哪些可以帶往下一階段的什麼。
後設回顧昨天(Day23)散步時的那些簡略回顧,正文的幾點都非常單薄、非常理所當然、非常基本,那顯然我一開始回憶中的VBA之所以那麼痛,是因為有很多被如今的我剝離的無關程式碼的脈絡。
實際上日記也寫了:「下班後真的會逃避現實寫VBA」,所以VBA當然是痛苦的,但相對沒那麼痛苦。又例如日記:「A電腦輸入法超慢/B電腦也是開個VBA就當掉/C電腦連開個Google Sheet歷史紀錄都掛掉」,當時公司設備爛到不行,對比自己個人生活上的設備其實還算不錯,導致每次休假結束後,都要重新調適心態面對巨大的工具落差。
爬梳訊息時,其實還是有跟同溫層的人分享我用VBA時碰到什麼,只是都是一些技術上、實作上的小細節。
可是那時候真正需要交流的,可能是如何在試著[^8]數位轉型的公司,推廣使用風險更小的方案,來減少事後究責的日常。[^9]
這些都不需要什麼技術力,而是需要內部行銷力。實際上,撰文這兩天,才發現其實有很多可以交流的人,除了屬於我的舒適圈的純技術性ニッチ笑話,也有這種基於成功推廣經驗的blog。
總之,我有技術面的同溫層,每個人都比我厲害,但我終歸是處在業務場景的人;如果能提點當時的自己,我會建議他稍微跟這些前輩聊聊彼此的組織文化與應用場景。
一是,明明知道有表格可以一覽各家瀏覽器支援的標準,也明白很多打包工具都幫忙處理好這類相容性問題。
二是,比如某一年想做個基於web的生日電子賀卡,我明明還會先確認對方用的手機品牌與螢幕尺寸,以限縮要實作的規格。
那為什麼反而那一年沒有先確認這些基本事項?
客觀來說,我的確對於Windows系統的權限設置一無所知,相比之下雲服務的IAM可能還更好理解一點。
使用Google Sheets最開心的一點是,每一台裝置跑的版本都是一致的(應該吧),我不用擔心Excel或VBA在其它裝置到底會出現什麼預期外的權限或版本問題。
總之,只能提醒自己以後接觸新的工具和環境之前,先確認權限與版本,而非立即實作。
這是一個常見的掙扎,長期來看,先配置齊全可以省下未來更多時間;短期來說,當下很想趕快改善一堆日常例行事項。
撰文時我還是覺得很難,短期交付成果與長期效益間的權衡。說到權衡,至少我今年逐漸改善過度refactor的壞習慣。
查閱到以前的筆記:「腳本太多個,如何更有效率挑選」,其實最初似乎也不是為了其他使用者,單純自己使用久了,覺得每天要執行那麼多腳本,乾脆寫一個總腳本來自動判斷。
至於,當時參考《如何將巨集程式建立成個人化的快速工具》這篇文章,將VBA腳本綁在更符合一般使用者的GUI上,只是順便做的。[^9]
我這一年很喜歡把自己視為power user,不是開發者,就只是使用瀏覽器與試算表這些應用程式的使用者,然後稍微會一些進階的功能。
我覺得我漸漸不再追逐最新的feat或語法,比較能將就既有的工具或資源。
此外,脫離VBA使用者的角色後,這兩天回顧時,看一些滿懷熱情持續使用VBA的前輩們,就感覺VBA也沒什麼不好。
VBA就只是暫時停在那了,就跟jQuery一樣,可能偶爾會在哪個古老的巷弄裡偶遇他們,一起喝一杯生椰拿鐵。
我們終將move on。
平台 | 腳本語言 | 特點 |
---|---|---|
Excel(地端) | VBA / Office Scripts (TypeScript) | VBA在消亡中,微軟推Office Scripts。 |
Google Sheets | GAS(JavaScript) | 動態型別 + 雲端爽用,不用擔心版本地獄。 |
LibreOffice Calc | LibreOffice Basic / Python(UNO) | 自由但小眾,除非你活在自由軟體夢裡。 |
Double
,從1900/1/1 開始,有個幽靈日 1900/2/29(是 bug)Date
物件ActiveSheet
,可直接用GoTo
是墮落的開始On Error GoTo HandleError
GAS 就像你熟悉的 JS,可以呼吸;VBA 是時間停滯的技術墳場,但你偶爾要下去挖骨頭。
想不到吧,這麼多垃圾資訊我還幫你挑出有用的。你應該感謝我,但我知道你不會,所以沒關係,這段友情我自己扛。🫠
[^1]: 契機是續約Microsoft 365時,沒有注意到有漲價,剛好那兩週正在斷捨離我訂閱的工具與服務,評估後覺得暫時用不到那麼多功能。
[^2]: 撰文時好奇查了一下,Office Scripts在這一點則與GAS一致。
[^3]: 想來這個觀念也不限於VBA,可能其它小腳本也是。或許我很多時候有思維上的錯置?可能由於既有舒適圈是CS背景的老同學,導致將太多不適合的原則,過度套用在小工具/小玩具上。
[^4]: 突然想到,敝人過去在公務單位時,有同仁拿Excel來印海報。
[^5]: GAS還可以自定義公式:Custom Functions。
[^6]: 當年剛用Google Sheet的公式真的感到很爽:不僅不必再將就Excel舊版公式,甚至可以使用SQL-like的語法。
[^7]: 基於日記:「半小時搗不出有效的VBA/不知道為什麼'404
無法匹配到'404
/結果通勤回家路上想通/其實就用函數就可以解了/真的應該先把隱藏欄位取消隱藏/把一切既有邏輯先理清」
[^8]: 包括但不限於:採購了一套新系統,沒有緩衝期,直接強硬上線,完全沒跟不同部門的使用者溝通,甚至連業務主管都沒被教育訓練,導致一再出包。
[^9]: (刪)