Educational Products: Month 2

Michael Lynch

教育產品:第二個月

原文由 Michael Lynch 發布,訂閱此部落格

一句話總結

改善我的影片錄製流程

重點摘要

  • 我學到了幾個技巧,讓錄製課程影片變得更輕鬆。
  • 我決定不需要使用 Merchant of Record 服務。
  • 我已將 htmx 納入我開發網頁應用程式的標準工具組。

目標達成度評分

每個月月初,我都會設定想完成的目標,以下是這個月的達成情況:

錄製四堂可發布的課程

  • 結果:只錄完一堂課的大部分
  • 評分:D

我忘了錄影片要花這麼多時間!而且我也低估了錄影以外的其他工作量。大部分的週我根本沒時間錄影,不過現在我已經慢慢進入狀況了。

我每錄一小時,大約只能得到五到十分鐘可用的片段,錄個 90 到 120 分鐘就會精疲力盡。在比較專注的一週,我完成了一堂 45 分鐘的課,但現在直播課程已經結束,應該可以再加快速度。

開始販售新版課程

  • 結果:改為開放候補名單,而非販售未完成的課程
  • 評分:不適用

我決定暫緩販售新版課程。一開始我想以早鳥優惠的方式提供新版本,在製作期間讓學員先看 2020 年的舊錄影,但後來發現這樣很難包裝得乾淨俐落。

我可能趕不上在太太生產前完成課程,而寶寶出生後我想請幾個月的育嬰假。我不希望在休假期間還覺得欠學員後續的教材,所以決定提供候補名單,而不是預購。

錄製影片的改進

錄製課程影片時,有很多事會中斷錄影,甚至讓我根本無法開始錄。我一直在設法降低錄影的阻力,讓自己能更快進入錄製狀態,也更不容易被打斷。

添購桌上型腳架

錄影時我用的是放在螢幕上方的 Razer Kiyo 視訊攝影機,問題是要把鏡頭調到合適的高度,需要費一番手腳。

我用 Razer Kiyo 視訊攝影機來錄影。

我平常會把桌面螢幕調到中心點大約與視線齊平。但如果螢幕在視線高度,放在螢幕上方的攝影機就會由上往下俯拍我。

為了取得好的拍攝角度,我得調整螢幕支架和桌子高度,讓鏡頭與眼睛齊平。但這樣搬動螢幕讓錄影變得很麻煩,而且每次錄影都無法精準重現相同的鏡頭位置。

我用一個小型的桌上腳架解決了這個問題:SmallRig VT-20

我買了桌上型腳架,這樣就不用為了錄影再去移動桌子或螢幕了。

錄影時我把腳架放在我和螢幕之間,並用油漆膠帶在桌上標記腳架的位置,這樣每次都能放回同樣的地方。

有了腳架,要錄影時只要把腳架和攝影機往桌上一放,位置馬上就對了。這大幅降低了錄影的阻力,而且我可以用平常的桌面配置直接錄,不用在每次錄影前後搬來搬去調整高度。

腳架唯一的缺點是會稍微擋到投影片,但到錄影階段時,我早就已經把內容背熟了。

將視訊攝影機架在螢幕上方(左)與放在螢幕前的桌上型腳架上(右)的比較。放在腳架上讓我更容易直視鏡頭。

讓錄影器材保持連接

以前兩次錄影之間,我會把視訊攝影機收進抽屜,麥克風和支架則放在另一個房間。結果每次錄影的前五分鐘都花在把器材搬出來、架設好。

現在我盡量讓所有器材保持連接、隨時可錄。我把麥克風直接放在桌上接好,視訊攝影機也裝在腳架上,隨時可以放到桌上開始錄。

以章節為單位錄製

為了準備課程,我看了 Aaron Francis 的 screencasting 課程。他的重點雖然是 live-coding,但其中不少內容也能應用在我的課程上,很值得買來參考。

我覺得 Aaron 的課程很有幫助,但最有價值的收穫有些甚至不是他口頭講的,而是觀察他如何包裝課程本身。

我的課程第一版由七堂 30 到 60 分鐘的課組成。Aaron 的課程長度差不多,但他把每堂課再細分成只有幾分鐘的獨立章節。

Aaron Francis 將他的課程拆成短小的章節,每個章節只有幾分鐘。

以學生的角度,我很喜歡這種短章節的做法,可以直接跳到最感興趣的部分。

以課程製作者的角度,我也喜歡短章節,因為錄製和剪輯十支四分鐘的影片,遠比處理一支龐大笨重的 40 分鐘影片容易。而且在製作過程中,完成五個章節的成就感,也勝過一支 40 分鐘影片只剪到一半的感覺。

讓課程不依賴特定順序

2020 年錄製課程時,我的影片開頭都是類似「歡迎來到第二部分:認識 Hacker News」這樣的話,結尾則會說「下一支影片我會談如何挑選寫作主題」。

新版把課程拆成章節,自然會產生更多支影片。如果後期剪輯時要重新排序或刪除某支影片,就得重錄一堆開頭和結尾,才能維持編號和連結的正確性。

看了 Aaron Francis 的課程後,我發現他的影片從不暗示順序。我也決定把影片中的課堂編號拿掉,避免提及先後順序。需要引用另一堂課的內容時,我只會說「我在 Foo 那支影片中有更詳細的說明」,而不是說「在後面的影片中」。

買三件一樣的上衣

Aaron Francis 課程中的一個建議是在所有課程中保持一致的外觀。他在所有影片中都穿著素黑 T 恤,我覺得這個細節很不錯。

我原本準備了一件專門的上衣,每次錄影前換上、錄完再換掉。我想平常穿一件衣服大約 14 小時才會在睡前拿去洗,所以同一件衣服應該可以撐過 14 次一小時的錄影再洗。

結果我對衣服發臭的想像完全錯誤。才錄了三次,衣服就開始覺得噁心了。

所以,我乾脆買了三件一模一樣的衣服:

為了保持影片的連續性,我訂了三件一模一樣的 T 恤。

這是簡單的深藍色 Bonobos T 恤,就是我平常會穿的款式。我想有三件的話,就算有兩件在洗,也至少還有一件可以穿。

直播課程中的神奇時刻

我已經完成部落格課程直播版的六堂課,教得很開心,其中有兩個時刻特別令人印象深刻。

邀請客座講者

在準備課程第一堂講座時,我在 Twitter 上看到 Adam Gordon Bell 宣布被公司裁員。Adam 是我最喜歡的軟體 Podcast 節目之一 CoRecursive 的主持人,他本身也是部落客,並寫出了前東家最受歡迎的幾篇部落格文章

Adam 在 2020 年我開這門課時曾是試點班的學員。看到他突然有空,我便邀請他以特別來賓的身分回來參加問答,他也很慷慨地答應下週加入。

時機巧得不可思議,就在他加入我的課程「登上 Hacker News 首頁」視訊通話的那一刻,Adam 剛好因為他對 PowerShell 首席架構師 Jeffrey Snover 的訪談登上了 Hacker News 第一名。

這場訪談對我來說很有趣,因為我讀過 Adam 很多文章,能一窺幕後、聽他談自己的方法以及這些年來的調整,格外吸引人。

我也感受到學生們的興奮氣氛。熱烈的程度其實讓我有點意外,因為那才第二堂課,並不是那種「終於換個口味」的感覺。我最好的解釋是,班上的學生都認識我,但不是每個人都認識 Adam,所以能聽到另一位有實績的人用自己的觀點來談課程概念,格外有意思。

即時拆解真實文章

課程期間,有學生問我們能不能做個練習,讓大家分享自己的文章並獲得回饋。有三位學生分享了文章或草稿,我們進行了點評,他們也希望能多做一些。

下一堂課我開放自願分享,但沒人準備好要分享的內容。我提議直接上 Hacker News 挑一篇文章,來分析它的優缺點。這樣做很有趣,但我挑的是首頁文章,代表那些文章已經表現不錯了。班上同學建議我挑剛發布、結果還未知的投稿。

當我開始點評新投稿時,課程才真正活了起來。因為回頭看一篇成功的投稿並解釋原因很容易,但要看一篇結果未知的投稿並預測它的表現,挑戰就大多了。而且因為是陌生人的文章,又是在私人小班中分享,我可以暢所欲言,不用擔心得罪作者或過於挑剔。

當我讀那些全新投稿時,班上的回應也更熱烈、更投入。課程中我曾展示過一些負面範例,但我覺得即時觀察一個人如何因為無聊的開頭或糟糕的結構而對文章失去興趣,特別有意思。

如何運用這些神奇時刻?

經歷課堂上的每個神奇時刻後,我都在思考如何加碼,怎樣創造更多類似的時刻並整合到最終的課程中。

像那種現場團體問答,除非我開一個 YouTube 頻道並找八位輪流搭配的夥伴,否則很難重複複製。但一個可行的替代方案是一對一視訊訪談我欣賞的作者,我覺得這更容易實現。

專家訪談恰好也是 Aaron Francis 用來推廣課程的手法:

Aaron Francis 透過發布與 SQLite 領域專家的長篇訪談,來為他即將推出的 SQLite 課程累積關注度。

另一方面,即時拆解則很容易複製。我現在就可以打開攝影機,一邊讀 Hacker News 的投稿一邊錄下我的即時想法。我不確定這樣是否夠有趣,但這是個可以快速嘗試的點子。

Merchant of Record 是騙局嗎?

上週,少數支援 Merchant of Record 的金流處理商之一 LemonSqueezy 宣布已被 Stripe 收購。在 Hacker News 的討論串中,有則留言吸引了我的注意:

我覺得整套 MoR 的說法根本是製造恐慌,要你多付交易手續費

99% 的 SaaS 根本達不到需要 MoR 的 MRR

那 1% 達到七位數 MRR 的,大可直接在內部聘人處理稅務繳納,也不用讓客戶收到印著 MoR 品牌的發票而感到困惑

我詢問了我的會計師,他確認對大多數美國州別而言,數位產品需要繳納銷售稅的門檻大約是每年 10 萬美元或 100 筆交易,依州而異。

像加州或紐約這樣人口眾多的州,門檻是 50 萬美元。如果我真的達到多到讓繳銷售稅變得很麻煩的州數門檻,那時我也已經靠銷售賺了數十萬美元,足以請會計師來處理。

我原本打算在 Gumroad 上販售,很大程度上就是為了它的 Merchant of Record 功能。但 Gumroad 要抽 10% 的佣金,這還不包含金流處理費。

鑑於我在麻薩諸塞州以外的州要達到銷售稅門檻的機率極低,這表示我可以在 Gumroad 之外銷售課程,省下那 10%。

業餘專案

找到我偏好的 htmx 表單寫法

在上一篇回顧中,我提到自己開始使用 htmx 並很喜歡它,但覺得它的錯誤處理有點彆扭。

舉個例子,這是我的電影評論網頁應用程式 ScreenJournal 上的一個表單。

來自 ScreenJournal 網頁應用程式的簡易 HTML 表單。

當使用者送出表單時,只會有兩種結果:

  • 設定成功儲存。
  • 處理請求時發生錯誤。

htmx 慣用的處理方式是,當使用者送出表單時,伺服器回傳整個表單的 HTML,並填入使用者剛送出的值,再加上成功或錯誤訊息。

我覺得 htmx 建議的表單寫法既彆扭又容易出錯。瀏覽器本來就已經正確填好了表單,為什麼伺服器還要把整個表單再丟回來讓瀏覽器重新渲染?唯一的新資訊就是成功或錯誤訊息,為什麼伺服器不能只傳那個就好?

以下是套用在上面 ScreenJournal 表單、讓 htmx 功能更輕量化的微調寫法

<form
  hx-put="/account/notifications"
  hx-clear="#result-success, #result-error"
  hx-disabled-elt="input, .btn"
  hx-target="#result-success"
  hx-target-error="#result-error"
  hx-swap="textContent"
>
  <label for="new-reviews-checkbox">
    Email me when users post reviews
  </label>
 <input
    type="checkbox"
    id="new-reviews-checkbox"
    name="new-reviews"
  />

  <label for="all-comments-checkbox">
    Email me when users add comments
  </label>
  <input
    type="checkbox"
    id="all-comments-checkbox"
    name="all-comments"
  />

  <button value="Save">Save</button>

  <div role="status">
    <span>Loading...</span>
  </div>
</form>
<div id="result-success" role="alert"></div>
<div id="result-error" role="alert"></div>

重點都在 <form> 標籤裡,我來逐一拆解:

hx-put="/account/notifications"

當使用者送出表單時,向伺服器的 /account/notifications 路徑發送 HTTP PUT 請求。

hx-clear="#result-success, #result-error"

當使用者送出表單時,清空 ID 為 result-successresult-error 的元素內容。

這個屬性不是 htmx 內建的,而是我自己寫的擴充功能 clear-before-send。我搭配這個 CSS 規則 .alert:empty { display: none } 使用,讓沒有文字內容、帶有 alert 類別的 <div> 標籤自動隱藏。

hx-disabled-elt="input, .btn"

在 HTTP 請求進行期間,停用所有 <input> 標籤和帶有 .btn 類別的元素,避免使用者重複送出同一個請求。

題外話:htmx 文件暗示 hx-disabled-elt="this" 應該會停用整個表單,但實際上似乎無效。作為變通,我必須用能選到表單內所有輸入欄位的選擇器。

hx-target="#result-success"

如果伺服器回應 200 範圍的狀態碼,就把回應主體放到 ID 為 result-success 的元素中。

hx-target-error="#result-error"

如果伺服器回應非 200 範圍的狀態碼,就把回應主體放到 ID 為 result-error 的元素中。

這個屬性不是 htmx 核心函式庫的一部分,而是來自名為 response-targets 的 htmx 擴充功能。

hx-swap="textContent"

在填入 hx-targethx-target-error 的目標時,htmx 應該替換目標元素的 textContent(而非替換其 innerHTML 或 outerHTML)。

以下是成果。我把開發伺服器調整成延遲兩秒才回應,且每隔一次請求就會回傳錯誤訊息:

ScreenJournal 上的通知管理畫面

值得注意的地方有:

  • 請求進行中時,htmx 會停用表單。
  • 當使用者再次點擊「Save」時,先前的成功/錯誤訊息會立即消失。
  • 成功與錯誤訊息有不同的樣式。

所以,不用為每個表單寫客製化的 JavaScript,就能做到相當多的功能。我多希望 HTML 當初就是這樣演進,而不是得靠第三方函式庫來實現這麼常見的功能,不過很高興 htmx 補上了這個缺口。

總結

完成了什麼?

  • 透過這個部落格以 2,000 美元賣掉了 Is It Keto
  • 完成部落格直播課程的教學。
  • 建立了我的第一個 htmx 擴充功能
  • 打造了 Personal Best,這是一個為課程設計的行銷工具。

經驗收穫

  • 尋找機會,降低錄製影片過程中的阻力。
  • 我可以透過發布與優秀部落客的訪談以及部落格文章的拆解來推廣課程。
  • 在美國,多數獨立創業者大概不需要 Merchant of Record。

下個月的目標

  • 完成課程錄製。
  • 開始販售課程。

本文章由 muse-spark-1.2-contributor 進行翻譯

留言