iT邦幫忙

2025 iThome 鐵人賽

DAY 24
0

今晚我要用筆記,打臉我昨天下午散步時的回憶~😼

前言

昨天(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。

VBA和GAS不同之處

型別

這應該是微軟陣營和Google陣營最廣為人知的生態差異。

VBA偏向靜態型別(除了Variant以外),我必須一開始就宣告型別與大小;GAS/JavaScript則是大家熟悉的動態型別。

這點在Excel與Google Sheets也是一樣,前者每個欄位的型別其實已經被標記好(XML),初始化型別後就會固定;後者則是動態推斷型別(JSON)。

ByRef & ByVal

JavaScript就我粗淺的理解,必定是ByValue,但當值本身是物件或函式時,常被新手誤會為ByRef。

VBA則預設是ByRef,使用者可以額外宣告為ByVal;習慣JavaScript的讀者可能要稍微留意這點。

日期

GAS很直覺,就是JavaScript的Date物件,VBA則是以1900/1/1為序號1,並往後計數的Double序號。有趣的是,VBA有個bug是它有不存在的1900/2/29,查了一下,完美地被Office Script繼承了哈哈哈。

複製試算表

VBA:貼近使用者直覺

在VBA,當複製新的表格時,會同時將畫面切換到新的表格,也就是新的表格會自動被設為active:

Sheets(sheetName).Copy After:=Sheets(sheetName)

接著,就可以直接用ActiveSheet來處理後續的動作:

    With ActiveSheet
        .Name = newSheetName
        .Tab.Color = tabColor
        .PivotTables(1).PivotCache.Refresh
    End With

這很符合GUI使用者的直覺,等同於用滑鼠拖曳並複製新表。

GAS:貼近開發者直覺

在GAS,複製新的表格時,不會自動將新的表格設為active[^2];通常會將該表格存入變數裡以進行後續的動作:

const copiedSheet = activeSheet.copyTo(spreadsheet); 
copiedSheet.setName(newName);

如果想要改變active sheet,則需要額外宣告:

copiedSheet.activate(); 

小感

單就複製表格這個動作,VBA可以用更少的語法完成,包含VBA內建ActiveSheet、自動切換ActiveSheet,指定複製到哪個位置。

雖然我很討厭VBA,但就這一點,VBA的確對一般使用者更友善。我覺得GUI使用者一直到錄製巨集都還符合直覺,但當開始寫腳本後,要踏入另一種思維模式,會是第一個小門檻。

零碎閒聊

VBA於IDE開啟時需要轉換成Big5編碼

我昨天瀏覽到的這篇文章,我完全同意VBA腳本就只是公司行政流程內的小道具,並且會使用很多業務術語,所以如果未來有需要寫VBA的話(希望不要),我會盡可能全部用中文,也方便對同仁進行內部行銷。[^3]

試算表的公式(formula)可以排版成多段

雖然公式應該不能算是腳本語言,我覺得它能從小小的公式演變成現在這樣涵蓋樣式、錯誤處理、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
    ),
    ""
)

VBA的GoTo魔法

一句話簡介: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

記得先把Excel的隱藏欄位都顯示才編輯[^7]

原則上,能不要隱藏欄位就不要隱藏;就算逼不得已,可以寫一個小腳本,把哪些隱藏的欄位先筆記好,未來要維護時就可以快速展開與再隱藏。

手刻了Quick Sort

我撰文的此時其實不太能把握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時代的個人歷程有什麼價值,但我想試著從這個歷程裡摘出哪些可以帶往下一階段的什麼。

現在回顧,很多痛苦不一定來自VBA

後設回顧昨天(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]

VBA帶給我什麼

我這一年很喜歡把自己視為power user,不是開發者,就只是使用瀏覽器與試算表這些應用程式的使用者,然後稍微會一些進階的功能。

我覺得我漸漸不再追逐最新的feat或語法,比較能將就既有的工具或資源。

此外,脫離VBA使用者的角色後,這兩天回顧時,看一些滿懷熱情持續使用VBA的前輩們,就感覺VBA也沒什麼不好。

VBA就只是暫時停在那了,就跟jQuery一樣,可能偶爾會在哪個古老的巷弄裡偶遇他們,一起喝一杯生椰拿鐵。

我們終將move on。

Takeaway

💥哪個試算表語言用啥語法?

平台 腳本語言 特點
Excel(地端) VBA / Office Scripts (TypeScript) VBA在消亡中,微軟推Office Scripts。
Google Sheets GAS(JavaScript) 動態型別 + 雲端爽用,不用擔心版本地獄。
LibreOffice Calc LibreOffice Basic / Python(UNO) 自由但小眾,除非你活在自由軟體夢裡。

🧠VBA vs GAS 重點對比(適合你這種有 JS 背景的)

型別

  • VBA = 靜態型別,嚴謹又囉唆
  • GAS = 動態型別,跟 JS 一樣自由又容易出事

傳值方式

  • JS/GAS = ByValue(物件是參照)
  • VBA = 預設 ByRef,習慣 JS 的人會踩雷

日期系統

  • VBA:日期 = Double,從1900/1/1 開始,有個幽靈日 1900/2/29(是 bug)
  • GAS:正常使用 JS 的 Date 物件

複製表格

  • **VBA:**會自動切換 ActiveSheet,可直接用
  • **GAS:**要手動設成 active,開發者風格,但沒那麼直覺

🧹VBA常見陷阱與你該知道的技能點

GoTo是墮落的開始

  • 早期用起來很爽,但會讓你的腳本變成哥白尼看了都頭暈的迷宮
  • 最多只留在錯誤處理用 On Error GoTo HandleError

語言內建 formatter:VBA 無、GAS 也沒有

  • 寫長公式時建議人工格式化成多行(像你在 JS 寫 if 的習慣),提升可讀性

🔧前端該注意的 VBA 宇宙規則

  • 要編中文變數請用 Big5 編碼開啟 IDE,不然你會看到外星文
  • 記得取消 Excel 的隱藏欄位再 debug
  • 環境相容性炸裂:VBA 跑起來會因為 Excel 版本、電腦權限、作業系統設置崩掉,不像 Web 這麼單純

如果你只記得一件事

GAS 就像你熟悉的 JS,可以呼吸;VBA 是時間停滯的技術墳場,但你偶爾要下去挖骨頭。

想不到吧,這麼多垃圾資訊我還幫你挑出有用的。你應該感謝我,但我知道你不會,所以沒關係,這段友情我自己扛。🫠

Annotations

[^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]: (刪)


上一篇
Day23|Excel與VBA:如果能重來
下一篇
Day25|Google Sheets與GAS:或許想重來
系列文
我只是不想加班:一名客服人員的GAS自救之路26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言