Refactoring English: Month 20

Michael Lynch

Refactoring English: 20개월 차

한 줄 요약

스크래퍼 봇과 싸우며 책 판매량 세 배로 늘리기.

처음 방문하셨나요?

안녕하세요, Michael입니다. 소프트웨어 개발자이자 작은 인디 테크 비즈니스를 운영하는 창업자입니다. 현재 Refactoring English: Effective Writing for Software Developers라는 책을 집필하고 있습니다.

매달 이렇게 회고를 발행해 책 작업 현황과 전반적인 근황을 공유하고 있습니다.

하이라이트

  • 7월 책 판매량이 이미 탄탄했던 6월 판매량의 세 배를 기록했습니다.
  • 세상에서 가장 멍청한 스크래퍼 봇과 싸우고 있습니다.
  • AI로 멀티플레이어 브라우저 게임을 만들고 있습니다.

목표 달성 평가

매달 초에 달성하고 싶은 목표를 정합니다. 이번 달에는 목표를 얼마나 달성했는지 정리했습니다.

Refactoring English를 소개하기 위해 팟캐스트 5곳에 섭외 요청하기

  • 결과: 팟캐스트 1곳에만 제안했습니다
  • 평가: D

Talking Postgres에 제안 메일을 보내기 위해 많은 시간을 들였는데, 막상 보니 진행자의 연락처가 LinkedIn 외에는 없었습니다. 그래서 LinkedIn 메시지를 보냈지만 답을 받지 못했습니다. The TMPDIR Podcast에 게스트로 출연하긴 했지만, 제가 제안하기도 전에 먼저 초청을 받은 것이어서 이번 성과로는 셀 수 없습니다.

Refactoring English 웹사이트에 순방문자 3만 명 모으기

  • 결과: 사이트 순방문자 23,800명
  • 평가: B

속으로는 이 목표를 ‘해커 뉴스 첫 페이지에 글 하나 올리기’라고 생각했는데, 실제로 올리고도 순방문자 3만 명에는 도달하지 못했습니다.

얼리 액세스를 마무리하고 책 1.0 정식 출시 선언하기

  • 결과: 아직 1.0 출시에 이르지 못했습니다
  • 평가: D

예상보다 독자 피드백 대응에 시간을 많이 썼습니다. 피드백 앱은 잘 동작하지만, 예측하기 어려운 새로운 작업들을 계속 만들어 냅니다.

Refactoring English 지표

지표2026년 6월2026년 7월변화
순방문자17,52323,817+6,294 (+36%)
사전 예약 수익$1,441.86$3,908.80+$2,466.94 (+171%)

6월은 킥스타터 이후 책 판매량이 두 번째로 높은 달이었는데, 7월 판매량은 6월의 세 배를 기록했습니다.

판매량이 급증한 가장 큰 이유는 얼리 액세스 할인을 종료했기 때문입니다. 7월 13일에 얼리 액세스 가격이 7월 20일에 종료되고 가격이 30달러에서 49달러로 인상된다고 공지했습니다.

7월 20일에 판매량이 급증한 뒤 판매가 둔화된 모습을 보여주는 그래프

할인 마지막 날에 “Why I Stopped ‘Creating Content’”라는 블로그 글을 올렸는데, 이 글이 해커 뉴스 첫 페이지에 올랐습니다. 이어서 해커 뉴스와 비슷하지만 더 인디적이고 기술 중심성이 덜한 사이트인 bubbles.town에서도 그날 가장 인기 있는 글이 되었습니다.

할인 마지막 날 판매량이 크게 급증해, 그날 하루에만 1,000달러가 넘는 매출이 발생했습니다.

가격을 49달러로 올리자 예상대로 판매량은 곧바로 급감했습니다. 책의 공식 1.0 버전을 출시한 뒤에 가격을 더 다양하게 실험해 볼 계획입니다.

세상에서 가장 멍청한 스크래퍼 봇과 싸우는 중입니다

월요일에 블로그 글을 올리고 방문자가 크게 늘었습니다. 그런데 화요일에 또 한 번 방문자가 폭증했습니다.

방문자가 급증한 것을 보고 유명 블로거가 제 글을 링크했나 보다 했는데, 곧 봇이라는 걸 깨달았습니다.

모든 방문자가 Hacker News Popularity Contest로 몰리고 있었습니다. 예전에도 블로거가 대회 순위에 대해 이야기하며 제 도구를 링크해서 방문자가 급증한 적이 있었지만, 이렇게까지 크거나 오래 지속된 적은 없었습니다.

두 번째 급증을 보고 “와, 이번 주는 정말 잘 풀리네!”라고 생각했습니다. 아내에게 이 이야기를 하다가 문득 깨달았습니다.

오늘도 방문자가 5만 명이나 또 늘었어! 어디서 오는지 전혀 모르겠네. 누가 트윗했나 보다고 생각했는데.

음, 사실 누가 트윗했다면 유입 경로에 트위터가 보여야 하는데.

아… 봇이구나.

로그를 확인해 보니 모든 요청이 정확히 동일한 브라우저 유저 에이전트를 사용하고 있었습니다.

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36

Chrome 125는 2년이 넘은 브라우저 버전입니다. 제 블로그를 읽는 실제 사용자 중 이렇게 오래된 브라우저를 쓰는 경우는 거의 없기 때문에, 이 버전 덕분에 봇을 쉽게 식별할 수 있었습니다.

스크래퍼는 루트 콘테스트 페이지를 반복적으로 불러온 뒤 모든 링크를 계속 클릭하는 방식으로 동작하는 것 같았습니다. 그래서 살짝 속임수를 써 보기로 했습니다. Bunny에 유저 에이전트를 확인해 스크래퍼일 경우 가짜 응답을 반환하는 리라이트 스크립트를 넣었습니다. 그러면 3,000개가 넘는 링크가 있는 페이지를 생성하는 대신, 링크가 3개뿐인 페이지를 생성하게 했습니다.

무슨 이유인지 가짜 응답은 효과가 없었습니다. 스크래퍼가 이미 전체 URL 목록을 데이터베이스에 넣어 둔 상태라, 홈페이지에서 링크를 숨겨도 아무 소용이 없었던 것 같습니다.

속도 제한도 시도해 봤지만, Bunny가 지원하는 최소 속도가 1KB/s이고 앱 데이터 대부분이 몇 KB짜리 파일이라 효과가 없었습니다. 스크래퍼는 100개 정도의 서로 다른 IP 대역을 돌아가며 사용하고 있어 IP 기준으로 제한할 수도 없었습니다.

결국 IP 대역으로 차단하기로 했습니다. 바이브 코딩으로 Bunny 로그에서 해당 유저 에이전트를 찾아 공격에 사용된 모든 IP를 수집하는 도구를 만들었습니다. 효과가 있었지만, 일주일 뒤에 새로운 IP와 조금 더 최신인 유저 에이전트로 공격이 다시 시작됐습니다. 그래서 스크립트를 다시 돌려 차단할 IP 목록을 업데이트했고, 지금은 잘 동작하고 있는 것 같습니다.

이번 공격에서 가장 이상한 점은 봇들이 차단되어도 전혀 신경 쓰지 않는다는 것입니다. 그냥 계속 서버를 두드립니다. 보통이라면 “지난 2주 동안 TCP 레벨에서 100% 차단된 요청에 컴퓨팅 자원과 대역폭을 낭비할 필요가 없지”라고 판단할 것 같은데, apparently 신경 쓰지 않는 모양입니다.

공격자의 IP를 차단한 뒤에도 그들은 계속해서 요청을 쏟아붓습니다.

공격이 시작된 날 Netlify 지원팀에 문의했지만 아무 도움이 되지 않았습니다. 답변 하나를 받는 데 일주일씩 기다려야 했습니다. 첫 번째 답변은 존재하지 않는 설정을 바꾸라고 해서 AI가 생성한 것 같았습니다. 두 번째 답변은 좀 더 사람 같았지만, 요지는 “제가 답변하는 데 걸린 2주 동안 고객님이 이미 문제를 해결하신 것 같으니 제가 할 일은 없네요!”였습니다. 다행히 요청한 뒤에는 초과 요금 55달러를 환불받았습니다.

정적 사이트는 어디에 호스팅할 수 있을까?

저는 모든 정적 사이트를 Netlify에 호스팅하고 있는데, 서비스가 점점 나빠지고 있습니다. 특히 스크래퍼 봇 공격에 완전히 무관심한 태도를 보고, 스크래퍼 봇에 더 적극적으로 대응해 주는 업체를 찾아야겠다고 마음먹었습니다.

가장 뻔한 답은 “Cloudflare”지만, 인터넷 인프라가 이미 Cloudflare에 얼마나 집중되어 있는지 보면 우려가 되어 더 집중시키고 싶지 않습니다.

VPS 단독이나 VPS + Bunny CDN 조합도 고려했지만, 제 글이 해커 뉴스 첫 페이지에 오른 날 VPS가 다운되거나 Bunny 캐시를 잘못 설정해서 사이트가 오프라인이 되는 상황은 피하고 싶습니다. 그냥 비용을 지불하고 누군가에게 사이트 운영을 맡기는 솔루션을 원합니다.

  • Surge
    • 장점
      • 정적 호스팅에만 집중한다는 점이 제가 원하는 바와 정확히 일치합니다
      • 대역폭이 무제한이라 스크래퍼 봇 공격 비용을 업체가 부담합니다
    • 단점
      • 아마 1인 운영(으로 보임)이라 장애 위험이 큽니다
      • 모든 관리가 터미널 앱을 통해서만 이루어집니다. 웹 앱이 없습니다
      • 다중 인증을 지원하지 않는 것으로 보입니다. 다만 지원 작업을 진행 중인 것으로 보입니다
      • 업로드 과정에서 변경된 파일만 동기화하는 rsync 방식이 아니라 모든 파일을 무조건 업로드하므로, 조금씩만 변경되는 큰 규모의 사이트를 운영하는 입장에서는 불편합니다
  • statichost
    • 장점
      • 1인 운영이라 고객 지원이 빠르고 꼼꼼합니다
      • 불필요한 복잡함 없이 정적 호스팅에 주로 집중합니다
    • 단점
      • 1인 운영이라 장애 위험이 큽니다
      • 업로드 과정에서 변경된 파일만 동기화하는 rsync 방식이 아니라 모든 파일을 무조건 업로드하므로, 조금씩만 변경되는 큰 규모의 사이트를 운영하는 입장에서는 불편합니다
      • 봇 스크래퍼 보호 기능이 포함되어 있지 않습니다
      • 사이트 빌드와 호스팅을 함께 묶어 제공하지만, 저는 호스팅만 원합니다
      • EU 중심이라는 점이 큰 장점이지만 저는 미국에 있습니다
  • Vercel
    • 장점
      • DDoS/스크래퍼 봇을 막아준다고 합니다
      • rsync 방식의 업로드를 지원하는 것으로 보입니다
    • 단점
      • 거대하고 복잡한 서비스입니다
      • Vercel이 Netlify보다 저를 더 잘 대해줄 거라는 확신이 없습니다
  • Bunny CDN 위에 직접 구축하기
    • 이 방안도 고려했지만, Bunny 위에 증분 업로드와 원자적 배포를 구현하는 것 자체가 꽤 복잡한 프로젝트가 될 것입니다

Mikeville: 미완성 멀티플레이어 브라우저 게임

작은 클라우드 서버로 이것저것 실험하고 있는데, CPU 4코어, RAM 8GB짜리 서버가 대부분 놀고 있습니다. 쓸 만한 서버가 남는 용량을 안고 유휴 상태라면, 친구들을 위해 호스팅하면 재미있을 만한 것은 무엇이 있을까요?

게임은 어떨까 싶었습니다. Valheim이나 ARK 같은 셀프 호스팅 가능한 게임들을 봤지만, 그런 게임들은 다른 플레이어가 동시에 접속해야 재미있는 것 같았습니다.

몇 달에 한 번 겨우 게임을 하는 사람으로서, 다른 사람들이 같이 있을 때 들어가면 즐겁고, 없을 때도 그동안 무슨 일이 있었는지 보는 재미가 있는 무언가를 원합니다. 제가 떠올린 느낌은 친구들과 비치 하우스를 공동 소유해서 가끔 함께 휴가를 보내지만, 따로 방문할 때는 서로에게 쪽지와 선물을 남기는 그런 느낌입니다.

문제는 이 비치 하우스 같은 느낌을 게임의 구체적인 컨셉으로 어떻게 옮길지 떠오르지 않는다는 것입니다.

일단은 바이브 코딩으로 게임을 개발하면 어떤 느낌인지 탐색하면서 무엇이 재미있는지 살펴보고 있습니다. 이 프로토타입을 디자인할 때 염두에 둔 게임은 제가 수백 시간씩 플레이한 Stardew Valley와 Ultima Online 두 가지였습니다.

브라우저에서 직접 플레이해 보실 수 있습니다.

오늘 잠시 접속해 있을 예정이니 들러 보셔도 좋습니다. 소스 코드는 더 나은 git 포지를 찾을 때까지 현재 GitLab에 올려 두었습니다.

인상 깊게 읽은 블로그 글

  • Stripe Just Wants a Number
    • exe.dev 블로그를 즐겨 읽는데, 특히 소규모 소프트웨어 벤더에게 영향을 미치는 소프트웨어 문제를 흥미로운 방식으로 사고합니다. 제게는 이 방식을 적용할 만큼 복잡한 결제 로직은 없지만, 원칙적으로는 멋진 아이디어라고 생각합니다.
  • 99% of My Website Traffic Is Bots
    • 이번 달 스크래퍼 봇 경험 때문에 공감되고 도움이 되었습니다. 직접 그린 일러스트도 마음에 들었습니다.
  • I Regret Migrating to Codeberg
    • 지난 1년간 프로젝트들을 GitHub에서 Codeberg로 옮겼고 유료 회원으로 가입까지 했지만, 이제는 그 플랫폼에 투자한 것을 후회합니다. 장애가 너무 잦고 서버가 과부하에 걸리는 날도 많습니다. 결정타는 Codeberg가 AI를 사용하는 프로젝트를 금지하기로 한 결정이었습니다. 저는 아마 “AI를 너무 많이 썼다”는 자의적인 기준에는 미치지 않을 테지만, 그래도 다른 곳으로 옮길 계획입니다.
  • Super Mario Derivations
    • Nix의 멋진 트릭을 소개한 글로, 작성자가 Nix 속성을 이용해 에뮬레이터에서 Super Mario 3의 플레이 상태를 인코딩했습니다. 예를 들어 nix build '.#level1.rightb.rightb.rightab.rightb'는 레벨 1을 시작해 Right + B(오른쪽으로 달리기)를 두 번, Right + A + B(달리며 점프), 그리고 Right + B를 다시 한 번 누르는 것을 의미합니다. Nix가 모든 게임 상태를 캐시하므로 버튼 입력을 바꾸면 이전 실행과 달라진 부분만 다시 계산하면 됩니다.

마무리

다음 달 목표

  • Refactoring English를 소개하기 위해 팟캐스트 5곳에 섭외 요청하기.
  • Refactoring English 웹사이트에 순방문자 3만 명 모으기.
  • 책 1.0 정식 출시 선언하기.

도움이 필요한 부분

  • 정적 사이트 호스팅에 추천할 만한 서비스가 있다면 알려 주세요.
  • Claire Giordano를 아신다면, 제가 Talking Postgres에 좋은 게스트가 될 수 있다고 전해 주세요(Postgres가 아니라 기술 글쓰기에 대해 이야기하러 나갈 수 있습니다).

원문은 Michael Lynch님이 에 게재했습니다.

이 글은 muse-spark-1.2-contributor 모델을 사용해 번역했습니다.