Educational Products: Month 1

Michael Lynch

教育產品:第一個月

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

一句話總結

我正要回頭重啟我的部落格課程。

重點摘要

重啟《Hit the Front Page》

2020 年,我做了一個關於部落格的影片課程,叫做《Hit the Front Page of Hacker News》。我對課程內容感到自豪,也收到了學生的正面回饋,但總覺得自己從來沒有給予它應有的關注。

當時課程上線時,TinyPilot 正快速成長,我沒有時間行銷課程或反覆打磨教材。

上一篇文章中,我調查了讀者希望接下來看到我做什麼。在表示對我的教學有興趣的人當中,結果如下:

關於接下來想教什麼主題的興趣堆疊長條圖。「幫助開發者提升寫作能力」與「將刻意練習技巧應用於軟體開發」並列第一,各有 32 人感興趣。「為開發者族群寫部落格」以 31 人位居第三。

上一篇文章中讀者問卷的回覆結果

解讀數據的方式有很多,但我的結論是,大家特別希望我教寫作技巧。讓我意外的是,刻意練習也名列前茅,雖然熱度稍微低一點。

我認為,既然現有的課程已經幾乎完成,而且排名第二或第三(取決於怎麼算),我應該把舊教材整理一下,重新推出 2024 年的更新版。

尋找先導計畫的學員

Rob Fitzpatrick 的書Write Useful Books深深影響了我對教育產品的做法。他主張,在推出書籍或影片課程之前,一定要先現場教學一次,因為你需要根據真實學員的回饋來反覆改進。

我和太太也即將在八月底迎來第一個寶寶,到時候我打算消失幾個月專心陪家人。當我在考慮這門課時,距離預產期大約還有 10 週,而課程本身就要上 6 週,所以幾乎沒有什麼緩衝時間。

我寫了一段關於課程的簡介,並寄給部落格的訂閱者,請有興趣的人填寫一份簡短的申請表。有人填表後,我會針對他們在表單中寫的內容親自回覆,並附上付款連結來幫他們保留名額。

結果如下:

  • 有 1,944 位訂閱者收到了關於課程的電子郵件。
  • 有 11 人填寫了問卷表示有興趣。
  • 有 7 人購買了課程。
    • 在填了問卷卻未報名的 4 人中,有 3 人是因為時段衝突。

尋找視訊平台

讓我驚訝的是,視訊通話領域幾乎找不到 Zoom 以外可行的替代方案。自從他們被抓到在安全性上說謊之後,我就一直盡量避用 Zoom,但他們似乎仍是線上課程的唯一選擇。

過去幾年工作會議我都用 Jitsi Meet,體驗大致不錯,但參加 Zoom 會議時畫質明顯比較好。我本來想找 Jitsi Meet 的付費方案,但所有付費選項都標示「聯絡我們」,這通常代表一個月至少要 1,000 美元起跳。

所以,Jitsi 還算堪用,只是有點笨重。它不支援錄影,所以我的變通辦法是:

  1. 在筆電上主持課程的視訊通話。
  2. 再用桌機加入同一通話。
  3. 在桌機上用一般的螢幕錄影軟體錄製通話。
  4. 把影片上傳到PicoShare
  5. 把 PicoShare 連結寄給全班。

這比我想要的複雜,但也有個意外的好處:即使我分享的投影片佔滿整個螢幕,我還是可以在桌機螢幕上看到所有人的臉。

如果你知道比 Jitsi Meet 更好的替代方案,請告訴我

該不該淡化 Hacker News?

大約有一半報名的學員說,他們對 Hacker News 並沒有特別感興趣。他們只是喜歡我的寫作、想多了解我的寫作過程,所以即使課程聚焦在 Hacker News,他們還是報名了。

回頭看問卷數據,大家對廣義的寫作似乎比對部落格本身更有興趣。而且沒有人特別點名想學 Hacker News。

所以我在想,是否該把重心從 Hacker News 轉向更通用的主題。

我擔心一旦轉向,就會失去自己的優勢。教部落格或寫作的人有一大堆,在那個領域我很難脫穎而出。如果我專教 Hacker News,我就是這個領域最厲害的老師,因為根本沒別人在做這件事。

另一個問題是,我大部分部落格成功的證據都跟 Hacker News 有關。在個人部落客中,我在 Hacker News 上算是少見地成功。如果改教更通用的寫作課程,我的資歷就沒那麼亮眼了。我的部落格沒有賺很多錢,也沒有龐大的訂閱數可以拿來炫耀。

同時,我覺得會買我課程的人,多半是先認識我,才找到課程的。他們大概不是去搜尋「世界最強 Hacker News 專家」才找上門的。

或許重點是,我不需要太擔心和其他一大堆人競爭,因為無論如何,找到我課程的路徑大概都是透過我本人或口耳相傳。

這門課用原本聚焦 Hacker News 的形式已經完成了 95%,所以我打算先照原樣推出。結束之後,再把教材調整成更通用的課程。

學習 htmx

過去兩年,htmx 越來越常出現在我的視野中。我的朋友Cory Zue 有在使用 htmx,所以引起了我的興趣。

很長一段時間,最大的障礙就是我完全不懂 htmx 的意義在哪。

htmx 官網首頁的第一句話之一是:「為什麼只有 <a><form> 能發送 HTTP 請求?」我讀到這句時心想:「是啊,讓任何 HTML 元素都能發請求當然不錯,但 JavaScript 本來就能讓任何元素發送任何請求了。為了省幾行 JavaScript,就要採用一整套新方法嗎?」

真正讓我搞懂 htmx 的,是這本書:Hypermedia Systems。它由 htmx 的原作者所寫,解釋了 htmx 的動機,並詳細說明了幾個實際的應用場景。

如果要向四年前的自己推銷 htmx,我會這樣說。

給過去的自己的 htmx 推銷詞

還記得你剛學寫網站時,會這樣寫 HTML 嗎?

<form action="/users" method="POST">
  <input name="first-name" placeholder="First name" />
  <input name="last-name" placeholder="Last name" />
  <input type="submit" value="Add user" />
</form>

現在你不會這樣寫了,因為你想避免使用者送出表單時整個頁面重新載入。整頁重新載入又慢又讓人困惑,尤其如果你只是想顯示一句「使用者新增成功」。而且你也不想在伺服器退回輸入時,把使用者填好的資料全部清空。

所以,你會改用 JavaScript,寫成像這樣:

document.addEventListener("DOMContentLoaded", () => {
  document.querySelector("form").addEventListener("submit", (evt) => {
    evt.preventDefault(); // Block default submit.
    fetch(`/users`, {
      method: "POST",
      credentials: "include",
      headers: {
        Accept: "application/json",
      },
      body: JSON.stringify({
        firstName: document.querySelector("[name='first-name']"),
        lastName: document.querySelector("[name='last-name']"),
      }),
    })
      .then((response) => {
        if (response.ok) {
          return response.json();
        }
        // TODO: Handle errors too.
      })
      .then((result) => {
        // TODO: Handle success.
      });
  });
});

JavaScript 的量不算多,但每次需要表單就得重寫一次。你可以把重複的程式碼重構,但那會讓 UI 邏輯分散在好幾個檔案裡。每一次前端要跟伺服器互動,就得多一道阻礙。

或者你會轉向 React 或 Vue 這類厚重的框架,然後在你的程式碼和瀏覽器實際顯示的內容之間,就隔了無數層 JavaScript 抽象。

htmx 承諾的是回歸你剛學做網頁時的單純。與其寫完 HTML 再把所有邏輯丟給 React 或手寫的事件處理器,不如把 htmx 整合進應用程式,然後把表單寫成這樣:

<form hx-post="/users" hx-target="this">
  <input name="first-name" placeholder="First name" />
  <input name="last-name" placeholder="Last name" />
  <input type="submit" value="Add user" />
</form>

然後 htmx 會讓一切自動運作,完全不需要你寫任何客製化的 JavaScript。

我目前使用 htmx 的心得

為了試用 htmx,我一直在重寫 ScreenJournal 的部分功能。ScreenJournal 是我的開源電影評論 App,就像是電影版的 Goodreads。或者說,它是開源、比較陽春的 Letterboxd。

ScreenJournal 是我的興趣專案,一個用來寫電影評論的網頁 App。

重寫中一個不錯的例子是用 htmx 重新實作通知偏好設定頁面。我有一個頁面讓使用者設定想收到哪些 Email 通知:

ScreenJournal 上用來控制通知的頁面

通知頁面原本需要大量客製化 JavaScript 來處理以下事情:

  • 透過 fetch 送出表單內容,而不是重新載入頁面。
  • 在請求進行中停用表單輸入。
  • 在請求進行中顯示狀態讀取圖示。
  • 如果請求失敗,顯示錯誤訊息。

以下是從原生 JavaScript 轉換到 htmx 的對比:

整體程式碼變少了,尤其是 JavaScript 少了很多。它把邏輯從前端移到後端,這是我比較喜歡的,因為我覺得後端程式碼比 UI 程式碼更容易測試。

以下是目前為止我使用 htmx 的一些心得:

htmx 多了一層抽象,但很直覺

  • 用 Vue 和 Angular 時,我完全搞不懂它是如何把我的程式碼轉換成網頁 App 的。
  • 用 htmx 時,它的行為夠直覺,我大概可以根據看到的運作方式,自己重新實作一套 htmx。

htmx 的錯誤處理不太理想

  • htmx 的模型假設你向伺服器發送請求後,會把伺服器的回應放到頁面上的一個元素裡。
  • 問題是,成功時我想替換掉 HTML 表單,但失敗時我想保留表單原樣,只在表單下方顯示錯誤。
  • htmx 的解法是讓伺服器重新渲染包含使用者輸入的完整 HTML 表單,但我不喜歡這樣,因為那等於重新渲染一個本來就存在的東西,而且會增加 XSS 漏洞的風險。
  • 我可以透過自己寫事件處理器來繞過這個問題,但那樣就感覺有點在跟框架對抗。

htmx 會弱化內容安全政策(CSP)

  • 我喜歡把CSP當作防止跨站腳本攻擊(XSS)的最後一道防線。
  • htmx 大致上與 CSP 相容,但正因為 htmx 能做這麼多事,攻擊者只要能寫入客製化的 HTML,就等同於能寫入任意的 JavaScript。
  • 例如
    • <form action=/delete-account" method="post" onload="this.submit()">
      • CSP 會阻止這段程式碼執行。
    • <form hx-post="/delete-account" hx-trigger="load">
      • CSP 卻會允許這段等效的程式碼執行。
  • 用 htmx 仍然可以寫出安全的應用程式,但它確實會讓 CSP 無法再作為防範 XSS 的可靠最後防線。

出售 Is It Keto

我這週發現 Amazon 在某個時間點改了聯盟行銷連結的做法,導致 Is It Keto 上 90% 的聯盟連結都失效了。網站還是能靠 Google AdSense 賺錢,但我已經沒有時間維護它了。

我正在尋找願意購買這個網站的人,如果是獨立創業者或想創業的人提出不錯的報價,我願意以低於市場行情的價格出售。

總結

完成了什麼?

  • 開始以小班制教授我的部落格課程。
  • 透過把 ScreenJournal 的大量功能移植到 htmx 來學習 htmx。
  • 錄製了課程的第一段加分內容。

學到的教訓

  • 我發現自己並沒有像想像中那樣被 Hacker News 這個角度綁住。
    • 如果有人要上我的課,多半是因為喜歡我的寫作,而不是因為它在 Hacker News 上的表現,所以我應該多想想這樣的客群是什麼樣子。

下個月的目標

  • 錄製四堂課可發布的版本。
  • 開始販售新版課程。

需要協助的地方

視訊通話平台

如果你有符合以下條件的視訊通話平台建議,請告訴我:

  • 必要:支援最多 10 人、90 分鐘的通話。
  • 必要:參與者不需建立新帳號或在裝置上安裝軟體就能加入通話。
  • 必要:費用在每月 80 美元以下。
  • 加分:可錄製視訊通話。

課程平台的使用經驗

如果你曾以講師或學員的身分使用過像 Maven 或 Udacity 這類課程平台,請告訴我。

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

留言