교육 상품: 1개월 차
원문은 Michael Lynch님이 에 게재했습니다. 이 블로그 구독하기
한 줄 요약
블로깅 강의를 다시 시작합니다.
하이라이트
- 2020년에 만든 블로깅 강의를 다시 시작합니다.
- htmx는 꽤 괜찮지만 바랐던 모든 것을 충족하지는 못합니다.
- 예전에 운영하던 키토 사이트인 Is It Keto의 구매자를 찾고 있습니다.
Hit the Front Page 다시 시작하기
2020년에 “Hit the Front Page of Hacker News”라는 블로깅 동영상 강의를 만들었습니다. 강의 내용 자체에는 자부심이 있었고 수강생들의 긍정적인 피드백도 들었지만, 정작 강의에 제대로 신경을 쓰지 못했다는 느낌이 들었습니다.
강의를 출시했을 때 TinyPilot이 빠르게 성장하고 있어 강의를 홍보하거나 내용을 개선할 시간이 없었습니다.
지난 블로그 글에서 독자들에게 앞으로 어떤 것을 하면 좋을지 설문했습니다. 무언가를 가르쳐 주는 것에 관심을 보인 분들의 결과는 다음과 같았습니다:

지난 블로그 글의 독자 설문 응답
데이터를 해석하는 방법은 여러 가지가 있겠지만, 제가 내린 결론은 사람들이 제가 글쓰기 기법을 가르쳐 주길 특히 원한다는 것이었습니다. 의도적 수련이 최상위 답변 중 하나였다는 점도 다소 열기는 덜했지만 의외였습니다.
세는 방법에 따라 2~3위를 차지한 만큼 기존 강의가 이미 거의 완성된 상태였기 때문에, 자료를 다시 꺼내 2024년 버전으로 업데이트해 재출시하기로 했습니다.
파일럿 프로그램 수강생 찾기
Rob Fitzpatrick의 책 Write Useful Books는 교육 상품에 대한 제 접근 방식에 큰 영향을 주었습니다. 그는 책이나 동영상 강의를 출시하기 전에 항상 해당 주제를 라이브로 가르쳐 봐야 한다고 주장합니다. 실제 수강생의 피드백을 바탕으로 개선하기 위해서입니다.
아내와 저는 8월 말에 첫 아이를 출산할 예정이라, 아이가 태어나면 몇 달간 가족과 시간을 보내며 자리를 비울 계획이었습니다. 이 일을 고민하던 시점에 출산 예정일까지 약 10주가 남았고 강의는 6주 과정이라 여유가 많지 않았습니다.
강의에 대한 소개 글을 써서 블로그 구독자들에게 이메일로 보내고, 관심 있는 분들에게 간단한 신청서를 작성해 달라고 부탁했습니다. 신청서를 제출한 분들에게는 신청서에 적은 내용을 바탕으로 개별 답장을 보내고, 자리를 확보할 수 있도록 결제 링크를 전달했습니다.
결과는 다음과 같았습니다:
- 강의에 대한 이메일을 받은 구독자 1,944명
- 관심을 표하며 신청서를 작성한 사람 11명
- 강의를 구매한 사람 7명
- 신청 후 등록하지 않은 4명 중 3명은 시간대가 맞지 않아서였습니다.
화상 플랫폼 찾기
화상 통화용으로 Zoom을 대체할 현실적인 대안이 거의 없다는 사실에 놀랐습니다. Zoom이 보안에 대해 거짓말을 한 사실이 드러난 이후로 계속 피해 왔지만, 라이브 강의 분야에서는 사실상 유일한 선택지인 듯합니다.
지난 몇 년간 업무 미팅에 Jitsi Meet을 써 왔고 대체로 만족했지만, Zoom 미팅에 참석할 때 품질이 더 좋다는 걸 느꼈습니다. Jitsi Meet의 유료 플랜을 찾아봤지만, 모든 유료 옵션 가격이 “문의 요망(Contact Us)”으로 되어 있어 아마도 월 최소 1,000달러 이상일 것 같았습니다.
그래서 Jitsi는 다소 투박하긴 해도 쓸 만합니다. 녹화를 지원하지 않아 다음과 같은 편법을 쓰고 있습니다:
- 노트북에서 수업 화상 통화를 호스팅합니다.
- 데스크톱에서 통화에 참여합니다.
- 데스크톱에서 일반 화면 녹화 소프트웨어로 통화를 녹화합니다.
- 영상을 PicoShare에 업로드합니다.
- PicoShare 링크를 수강생들에게 이메일로 보냅니다.
원하는 것보다 복잡하지만, 발표 자료가 노트북 화면을 가득 채우고 있어도 데스크톱 모니터로 모두의 얼굴을 볼 수 있다는 부가적인 장점이 있습니다.
Jitsi Meet보다 더 나은 대안을 아신다면, 알려주세요.
Hacker News에서 방향을 틀어야 할까?
강의에 참여한 학생 중 절반 정도는 Hacker News에 큰 관심이 없다고 말했습니다. 그냥 제 글을 좋아하고 제 작업 과정을 더 알고 싶어서, Hacker News에 초점이 맞춰져 있음에도 불구하고 등록한 것이었습니다.
설문 데이터를 다시 보면, 블로깅 자체보다 일반적인 글쓰기에 대한 관심이 더 많아 보입니다. 그리고 Hacker News를 특정해서 요청한 사람은 아무도 없었습니다.
그래서 Hacker News에서 벗어나 좀 더 일반적인 주제로 방향을 틀어야 할지 고민하고 있습니다.
Hacker News에서 벗어날 때 걱정되는 점은 저만의 강점을 잃게 될 수 있다는 것입니다. 블로깅이나 글쓰기를 가르치는 사람은 셀 수 없이 많아 그 속에서 두드러지기 어렵다고 느낍니다. 반면 Hacker News를 특정해서 가르친다면, 그 분야를 가르치는 사람이 아무도 없으니 제가 세계 최고의 선생님이 됩니다.
Hacker News에서 벗어날 때의 또 다른 문제는 제 블로깅 성공 사례의 대부분이 Hacker News와 관련되어 있다는 점입니다. 개인 블로거 중에서는 Hacker News에서 유난히 좋은 성과를 냈습니다. 더 일반적인 글쓰기 강의를 한다면 내세울 만한 경력이 덜 인상적입니다. 블로그로 돈을 벌고 있지도 않고 자랑할 만한 대규모 구독자 수도 없습니다.
동시에, 제 강의를 구매한 대부분의 사람들은 저를 먼저 알고 나서 강의를 찾은 분들이라고 생각합니다. 아마 세계 최고의 Hacker News 전문가를 검색해서 온 것은 아닐 겁니다.
아마도 얻을 수 있는 교훈은 다른 수많은 사람들과의 경쟁을 너무 걱정하지 않아도 된다는 것일지도 모릅니다. 어쨌든 제 강의로 오는 경로는 결국 저를 통하거나 입소문을 통할 가능성이 높기 때문입니다.
원래 Hacker News 형식의 강의는 95% 정도 완성된 상태라, 이번 강의는 Hacker News에 초점을 맞춰 출시할 예정입니다. 그게 끝나면 자료를 더 일반적인 강의에 맞게 수정할 계획입니다.
htmx 배우기
지난 2년간 htmx가 점점 더 자주 눈에 띄었습니다. 친구인 Cory Zue가 htmx를 사용해서 관심이 생겼습니다.
오랫동안 가장 큰 장애물은 htmx의 요점을 이해하지 못했다는 것이었습니다.
htmx 랜딩 페이지의 첫 문장 중 하나는 “왜 <a>와 <form>만 HTTP 요청을 할 수 있어야 하는가?”입니다. 이 문장을 읽었을 때 저는 “그래, 좋긴 하겠지만 JavaScript로도 어떤 HTML 요소든 원하는 요청을 보낼 수 있는데, 몇 줄의 JavaScript를 피하려고 완전히 새로운 방법론을 도입해야 하나?”라는 생각이 들었습니다.
htmx가 마침내 와닿게 된 계기는 책 Hypermedia Systems였습니다. 이 책은 htmx 저자들이 직접 썼으며, htmx의 동기와 활용할 수 있는 여러 시나리오에 대해 자세히 설명합니다.
4년 전의 나에게 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>요즘은 이렇게 작성하지 않을 겁니다. 사용자가 폼을 제출할 때 페이지 전체를 새로고침하는 걸 피하고 싶기 때문입니다. 전체 페이지를 새로고침하는 건 느리고 사용자를 혼란스럽게 하며, 특히 “User added successfully”라는 메시지만 보여주고 싶을 때는 더욱 그렇습니다. 그리고 서버가 입력을 거부했을 때 사용자의 입력을 모두 날려버리고 싶지도 않을 겁니다.
그래서 대신 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>그러면 별도의 커스텀 JavaScript를 작성하지 않아도 htmx가 모든 것을 알아서 동작하게 해줍니다.
지금까지의 htmx 사용 경험
htmx를 시험해 보기 위해 ScreenJournal의 일부를 htmx로 다시 작성하고 있습니다. ScreenJournal은 제가 만든 오픈소스 영화 리뷰 앱입니다. 영화판 Goodreads라고 할 수 있고, 혹은 오픈소스이면서 못생긴 letterboxd 같은 앱입니다.

ScreenJournal은 영화를 리뷰하기 위해 만든 제 취미 프로젝트 웹 앱입니다.
제 리라이트의 좋은 예는 알림 설정 페이지를 htmx로 다시 구현한 것입니다. 사용자가 받고 싶은 이메일을 지정할 수 있는 페이지가 있습니다:

ScrenJournal의 알림 제어 페이지
알림 페이지는 다음을 위해 많은 커스텀 JavaScript가 필요했습니다:
fetch를 통해 폼 내용을 제출하고 페이지를 새로고침하지 않기- 요청이 진행 중인 동안 폼 입력 비활성화하기
- 요청이 진행 중인 동안 상태 스피너 표시하기
- 요청이 실패하면 오류 메시지 표시하기
그리고 바닐라 JavaScript에서 htmx로의 전환 결과는 다음과 같습니다:
전체 코드 줄 수가 줄었고, 특히 JavaScript 줄 수가 크게 줄었습니다. 로직이 프론트엔드에서 백엔드로 이동했는데, 저는 백엔드 코드가 UI 코드보다 테스트하기 쉽다고 생각해서 이 방식을 선호합니다.
지금까지 htmx를 사용하면서 얻은 몇 가지 소감은 다음과 같습니다:
htmx는 추상화 계층을 추가하지만 직관적이다
- Vue와 Angular에서는 내 코드가 어떻게 웹 앱으로 변환되는지 전혀 감이 잡히지 않았습니다.
- 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 매각
이번 주에 아마존이 어느 시점에 제휴 링크 방식을 변경해서 Is It Keto의 제휴 링크 90%가 깨졌다는 것을 알게 되었습니다. 사이트는 여전히 Google AdSense로 수익을 내고 있지만, 더 이상 유지보수할 시간이 없습니다.
사이트를 인수할 분을 찾고 있습니다. 다른 인디 창업자나 예비 창업자로부터 멋진 제안을 받으면 시세보다 저렴하게 판매할 생각입니다.
마무리
무엇을 했나?
- 소규모 학생 그룹을 대상으로 블로깅 강의를 시작했습니다.
- ScreenJournal의 많은 부분을 htmx로 포팅하면서 htmx를 배웠습니다.
- 강의의 첫 보너스 콘텐츠를 녹화했습니다.
배운 점
- 생각했던 것만큼 제 강의가 Hacker News라는 관점에 얽매여 있지 않습니다.
- 사람들이 제 강의를 듣는다면 Hacker News에서의 성과 때문이 아니라 제가 쓰는 글을 좋아하기 때문일 가능성이 높으므로, 그런 고객이 어떤 사람인지 더 고민해야 합니다.
다음 달 목표
- 강의 중 네 개 수업의 공개 가능한 버전을 녹화하기
- 새 버전 강의 판매 시작하기
도움 요청
화상 통화 플랫폼
다음 기준을 충족하는 화상 통화 플랫폼에 대한 제안이 있다면 알려주세요:
- 필수: 90분 통화에 최대 10명 참여 지원
- 필수: 참가자가 새 계정을 만들거나 기기에 소프트웨어를 설치하지 않고도 통화에 참여할 수 있을 것
- 필수: 월 비용 80달러 이하
- 있으면 좋음: 화상 통화 녹화 가능
강의 플랫폼 경험
Maven이나 Udacity 같은 강의 플랫폼에서 강사나 수강생으로 경험해 보신 적이 있다면 알려주세요.
글을 무작위로 읽기
댓글
로그인하고 댓글 남기기