Refactoring English: 13개월 차
한 줄 요약
집중에 대해 쓰면서 딴짓하기
처음 방문하셨나요?
안녕하세요, Michael입니다. 소프트웨어 개발자이자 소규모 인디 테크 비즈니스를 운영하고 있습니다. 현재 Refactoring English: Effective Writing for Software Developers라는 책을 집필 중입니다.
매달 이렇게 회고를 발행해 책 작업이 어떻게 진행되고 있는지, 그리고 전반적인 일과 삶은 어떤지 공유하고 있습니다.
하이라이트
- 구매력 평가(PPP)를 기준으로 책에 지역별 가격을 도입했습니다.
- 첫 Flutter 앱을 만들었습니다.
- 첫 크로스 언어 라이브러리를 작성하고 있습니다.
목표 성적표
매달 초에 이루고 싶은 목표를 정합니다. 이번 달 결과는 다음과 같습니다.
Refactoring English 웹사이트로 사람들을 끌어들일 게임 출시하기
- 결과: 대신 “2025년 Hacker News에서 가장 인기 있었던 블로그”를 발행했습니다
- 성적: B
이 글은 도박이었습니다. Hacker News 메인에 올라가야만 새로운 독자에게 도달할 수 있고, 그 기회는 2026년 첫 1~2주뿐이었기 때문입니다.
다행히 글은 Hacker News 1위를 차지했고 거의 22시간 동안 메인에 머물렀습니다. 다른 성공한 테크 작가들을 조명하는 제 전략을 이어간 글인데, 저와 독자, 그리고 소개된 작가 모두에게 이득이 되는 윈윈 전략이라 마음에 듭니다.
Hacker News 예측 게임은 여전히 80% 정도 완성된 상태입니다. 거의 다 만들었지만 재미가 없다고 느껴져 마무리에 동기부여가 되지 않아 어떻게 할지 고민 중입니다. 그래도 끝까지 완성해 사람들의 반응을 보고 싶습니다.
Refactoring English 챕터 2개 발행하기
- 결과: 두 챕터 모두 진전을 이뤘지만 완성하지는 못했습니다
- 성적: D
아이러니하게도 지금 쓰고 있는 챕터 주제가 동기부여와 집중인데, MeshCore 실험 때문에 계속 글쓰기가 밀렸습니다. 새해 들어서는 집중력을 더 잘 유지하고 있으며, 오히려 이런 산만함 덕분에 집중을 회복하는 과정에 대해 쓸 신선한 경험을 얻고 있습니다.
재미로 만드는 가족 사진 공유 앱의 설계 문서 작성하기
- 결과: 설계 문서 초안을 80%까지 작성했습니다
- 성적: C
12월에도 MeshCore 실험에 한눈을 파느라 원하는 만큼 진도를 내지 못했습니다. 설계 문서는 유용하고 좋아하지만 쓰기는 정말 지루해서, 당장 재미있는 일로 미루고 싶은 유혹이 계속됐습니다.
Refactoring English 지표
| 지표 | 2025년 11월 | 2025년 12월 | 변동 |
|---|---|---|---|
| 순 방문자 수 | 7,608 | 2,266 | -5,342 (-70%) |
| 사전 판매 수익 | $1,018.48 | $492.55 | -$525.93 (-52%) |
| 스폰서 수익 | $48.25 | $48.25 | $0.00 (0%) |
| 총수익 | $1,066.73 | $540.80 | -$525.93 (-49%) |
사전 판매가 감소한 이유는 새로운 독자를 끌어들일 새 글이 없었기 때문입니다(Hacker News 글은 1월에 발행했습니다). 그럼에도 ‘패시브 판매’가 꾸준히 증가하고 있다는 점은 긍정적입니다. 12월 사전 판매는 약 500달러였습니다. 방문자 수가 비슷했던 달과 비교하면 5월은 241달러, 8월은 361달러였으니 상승 추세입니다. 책이 더 완성되고 입소문이 퍼질수록 매달 마케팅에 성공하지 않아도 패시브 판매가 계속 늘어나길 기대합니다.
책에 지역별 가격 도입하기
11월 블랙프라이데이 프로모션을 진행했을 때, 한 독자가 메일로 30% 할인된 가격(20달러)도 아르헨티나에서는 여전히 부담스럽다고 알려왔습니다. 지역별 가격을 고려해 달라는 요청이었고, 아르헨티나에서 Steam 게임이 보통 미국보다 50% 저렴하다는 예를 들어주어 좋은 기준점이 되었습니다.
결제는 Stripe로 받고 있는데, 대시보드에서 지역별 가격 옵션을 찾을 수 없었습니다. Stripe 지식베이스에서 “Geographic pricing in practice: Why it matters and how to implement it.”라는 글을 찾아 기대했지만, 끝까지 읽어보니 ‘어떻게 구현하는가’ 부분은 쓰지 않았다는 걸 알게 됐습니다.
결국 Stripe는 지역별 가격을 권장하면서도 정작 기능은 제공하지 않는 셈이었습니다. Stripe가 다른 결제 대행사들을 제외하면 최악의 결제 대행사라는 사실을 다시 한번 일깨워 주었습니다.
그래서 아르헨티나 독자를 위해 일회성으로 할인된 가격의 맞춤 결제 링크를 수동으로 만들어 드렸습니다. 그 과정에서 아르헨티나 페소로 가격을 설정하면 환전 수수료를 아낄 수 있다는 걸 알게 됐습니다. 22,000 ARS(약 15달러)로 설정했고, 독자분은 가격과 결제 경험 모두 만족해하셨습니다.
그 독자는 개발자 수는 많지만 구매력이 상대적으로 낮은 브라질이나 인도 같은 국가에는 공개적으로 지역별 가격을 제공해 보라고 제안했습니다.
Stripe에서 기본 지원하지 않더라도, 수동으로 한 작업을 자동화하는 건 그리 어렵지 않아 보였습니다. Sebastien Castiel이 자신의 강좌에 지역별 가격을 도입한 사례를 읽었고, 거기서 Wes Bos의 글도 알게 됐습니다.
Sebastien은 기술적인 세부 내용을 많이 공유했지만, 그의 솔루션은 React에 대한 의존도가 높았고 제 사이트는 바닐라 HTML과 JavaScript로 되어 있습니다. 또 할인 코드를 사용하는 방식이었는데, 그러면 대다수 고객이 자신은 받지 못하는 특가가 있다는 걸 보게 되어 선호하지 않았습니다.
몇 시간을 들여 적절한 가격을 즉석에서 계산해 Stripe 결제 링크를 동적으로 생성하는 클라우드 함수를 만들었습니다. 그러다 모든 걸 미리 계산해 두면 서버 로직이 필요 없다는 걸 깨닫고, 클라우드 함수를 삭제했습니다.
구현 방식은 다음과 같습니다.
- Stripe가 지원하는 모든 국가/통화 목록을 수동으로 확보합니다.
- 월드뱅크 데이터를 가져와 목록의 각 국가별 구매력 평가(PPP)를 계산하는 스크립트를 작성합니다.
- 미국 대비 구매력을 기준으로 각 국가의 할인율을 계산합니다.
- 예: 브라질의 PPP는 미국보다 54% 낮으므로 54% 할인을 받습니다.
- PPP가 미국과 15% 이내로 차이가 적은 국가는 제외합니다(할인폭이 너무 작아 의미가 없습니다).
- 할인율이 음수가 되는 국가는 제외합니다.
- 그렇지 않으면 룩셈부르크 고객은 두 배를 내야 합니다.
- 할인율은 최대 75%로 제한합니다
- 그렇지 않으면 이집트 가격은 4달러가 되어 수수료를 떼면 3.50달러 정도만 남기 때문입니다.
- 목록에 남은 각 국가별로 Stripe 가격 객체와 결제 링크를 자동으로 생성합니다.
- 모든 국가를 사이트의 HTML 드롭다운에 넣습니다.
사용자는 자신의 국가를 선택하기만 하면 해당 국가용 Stripe 구매 링크가 활성화되고 자국 통화로 결제합니다.
자율에 맡기는 방식으로 운영하므로 IP 지리적 위치 확인이나 VPN 차단은 하지 않습니다. 가장 저렴한 옵션을 고르는 것을 막기 위해 국가별 할인율은 표시하지 않습니다. 또 각국 통화로 가격을 책정하면, 속여서 다른 지역을 선택한 사람은 환전 수수료로 오히려 손해를 보게 되는 효과도 있습니다.
수치가 완전히 정확하게 느껴지지는 않습니다. 엄격한 PPP 기준으로 보면 미국의 30달러는 이집트에서 4달러에 해당하지만, 이집트에서 개발자용 정품 도서를 4달러에 살 수 있을 것 같지는 않습니다.
Wes Bos는 독자들에게 적정 가격을 직접 물어봤다고 해서 저도 같은 방법을 시도해 보려 합니다. 댓글이나 이메일로 여러분 국가에서 개발자용 도서의 일반적인 가격대(현지 통화 기준)를 알려주세요.
첫 Flutter 앱 만들기
12월에 “MeshCore 오프그리드 메시징에 대한 첫인상”을 발행했습니다. 기술 자체에는 기대가 컸지만 클라이언트가 모두 클로즈드 소스라는 사실에 실망했습니다.
그 시점에서 MeshCore 탐구를 잠시 멈추기로 했는데, MeshCore 기여자 Frieder Schrempf가 제 글에 흥미로운 관점으로 댓글을 남겼습니다.
이 주제에 대한 많은 생각에 공감합니다. 개인적으로 MeshCore의 가치는 펌웨어나 앱 같은 소프트웨어 구현보다는 프로토콜 자체에 있다고 봅니다. […] MeshCore가 프로토콜로서 성공해 널리 쓰인다면(현재로선 그렇게 되고 있는 것 같습니다) 제대로 유지보수되는 오픈소스 구현도 뒤따를 것입니다(적어도 그렇게 되길 바랍니다).
Frieder의 의견에 동의했고, ‘내가 직접 오픈소스 MeshCore 앱의 개념 증명(PoC)을 만들어 볼까?’라는 생각이 들었습니다.
사실 이미 개념 증명용 MeshCore 앱이 존재했습니다. 공식 MeshCore 앱 개발자인 Liam Cottle이 공식 버전을 위한 프로토타입으로 MeshCore용 웹 앱을 만든 적이 있습니다. 공식(독점) 앱을 만들면서 프로토타입은 중단됐지만 소스 코드는 여전히 공개되어 있었고, 제가 필요로 하는 기능 대부분을 갖추고 있었습니다.
이 프로토타입을 모바일로 포팅하는 게 얼마나 어려울지 궁금했습니다. MeshCore는 Bluetooth 접근과 오프라인 모드가 필요해 웹 앱으로 쓰기에는 불편합니다. Google의 크로스 플랫폼 모바일 개발 솔루션인 Flutter에 대해 어느 정도 긍정적인 이야기를 들었고, LLM이 제 개입 없이도 웹 프로토타입 코드를 Flutter로 성공적으로 포팅할 수 있을 것이라 예상했습니다.
LLM이 세 단계에 걸쳐 프로토타입을 Flutter로 포팅하도록 계획했습니다.
- Playwright를 이용해 프로토타입 웹 앱의 엔드투엔드 테스트를 작성한다.
- 엔드투엔드 테스트를 그대로 유지해 기능 동등성을 보장하면서 프로토타입 구현을 Flutter 웹 앱으로 포팅한다.
- Flutter 프로젝트에 Android 빌드를 추가한다.
계획은 통했지만 모든 단계가 예상보다 훨씬 더 번거로웠습니다.
- 프로토타입의 엔드투엔드 테스트를 작성하기 전에, 입력 라벨 상당수가 그냥
<div>로 되어 있어 시맨틱 HTML과 ARIA 속성을 사용하도록 변환해야 했습니다. - Flutter는 웹 앱에서 시맨틱 HTML을 생성하지 않기 때문에 Playwright 테스트를 그대로 유지할 수 없었습니다. Flutter는 자체적인 HTML 방언을 만들고 모든 것을 HTML 캔버스에 그립니다. 대부분의 Playwright 엘리먼트 로케이터는 어떻게든 동작했지만, 테스트에 Flutter 전용 수정을 많이 해야 했습니다.
- LLM의 도움을 받아도 Flutter로 Android 패키지를 빌드하는 방법을 알아내는 데 오래 걸렸습니다.
- Android 빌드 시스템인 Gradle은 NixOS에서 버그가 많습니다. 알 수 없는 오류로 계속 빌드가 실패했는데, 알고 보니 홈 디렉터리에 캐시된 오래된 데이터 때문이었습니다.
- Flutter에서는 Bluetooth 통신이 놀랍도록 어렵습니다. 웹(적어도 Chrome)에서는
navigator.bluetooth.requestDevice를 호출하면 기본적으로 바로 쓸 수 있지만, Flutter에서는 독점 서드파티 라이브러리를 사용하고 기기 선택 UI를 직접 만들어야 합니다.
몇 시간 만에 끝낼 수 있는 가벼운 주말 프로젝트라고 생각했습니다. 30시간과 200달러의 LLM 크레딧을 쓴 끝에 겨우 동작하게 만들었습니다.

실제 Android 기기에서 실행 중인 제 MeshCore Flutter 앱
그런데 제 Flutter 구현이 프로토타입과 기능 동등성을 갖추게 된 날, Reddit에 공유하려고 보니 누군가 이미 Flutter로 만든 MeshCore 클라이언트인 meshcore-open을 공유해 놓았습니다. 제가 생각한 것과 같은 아이디어였지만 훨씬 더 잘 만들어져 있었습니다.
누군가 먼저 해내서 아쉬웠지만 한편으로는 안도했습니다. 짧게나마 Flutter를 다루어 보니 가능한 빨리 Flutter에서 벗어나고 싶었습니다. 개념 증명만 만들고 다른 누군가가 이어받길 바랐는데, 이제 기능이 풍부한 오픈소스 MeshCore 클라이언트 구현이 생겨 기쁩니다.
MeshCore에 필요한 건 어쩌면 크로스 언어 라이브러리일지도 모릅니다
MeshCore Flutter 앱을 만들면서 MeshCore 기기-클라이언트 간 메시지를 파싱하는 저수준 로직을 구현해야 했습니다. MeshCore의 P2P 프로토콜을 정의한 공개 스펙이 있긴 하지만 그마저도 꽤 느슨합니다. 그런데 MeshCore 펌웨어가 탑재된 기기가 Bluetooth나 USB를 통해 컴패니언 클라이언트(예: Android 앱)와 통신하는 방식에 대한 또 다른 프로토콜은 문서화조차 되어 있지 않습니다.
사실상의 레퍼런스 구현은 MeshCore 펌웨어인데, P2P 프로토콜 로직과 기기-클라이언트 프로토콜 로직, UI 로직이 뒤섞여 있고 구현이 코드베이스 곳곳에 흩어져 있습니다.
예를 들어 MeshCore 클라이언트는 Bluetooth를 통해 MeshCore 기기에서 연락처 목록을 가져올 수 있지만, 날것의 바이트를 다시 연락처로 역직렬화해야 합니다. 메시지를 디코딩하는 라이브러리가 없어 각 클라이언트와 라이브러리가 각자 구현을 따로 만들고 있습니다.
그 구현들에서 눈에 띄는 점은 다음과 같습니다.
32같은 매직 넘버를 사용해야 하며, 공신력 있는 곳에 정의된 상수를 참조하지 않습니다.- 어느 구현도 파서에 대한 자동화된 테스트가 없습니다.
- 고수준 언어에 불필요한 저수준 작업을 끌고 들어오고 있습니다. 예를 들어 모두가
outPath와outPathLen변수를 저장하는데, 이는 배열이 크기를 알지 못하는 C 구현의 잔재입니다. JavaScript, Python, Dart 같은 언어에서는 배열 크기를 수동으로 추적할 필요가 없습니다. - 데이터를 꼼꼼히 검증하지 않아 음수 경로 길이나 지구 범위를 벗어난 GPS 좌표 같은 쓰레기 데이터를 그대로 전달합니다.
- 모두 flags 필드를 무시합니다. flags는 어떤 필드가 채워져 있는지를 나타내야 하는데, 적어도 P2P 메시지에서는 그래야 합니다. 기기-클라이언트 메시지에서는 의미가 없어 보입니다.
처음에는 protobuf나 Cap’n Proto 같은 프로토콜 라이브러리를 이용해 로직을 다시 작성할까 생각했지만, 현시점에서 서드파티 라이브러리를 하위 호환성을 유지하면서 통합할 방법을 찾지 못했습니다.
그렇다면 MeshCore 기기-클라이언트 프로토콜의 핵심 구현을 C로 작성하면 어떨까 생각했습니다. 언어별 바인딩을 추가하면 Dart, Python, JavaScript 등 어떤 언어로 작성하더라도 별도의 구현을 전부 만들 필요가 없어집니다.
그래서 직접 MeshCore 클라이언트 라이브러리를 만들기 시작했습니다.
이 라이브러리는 아직 개념 증명으로 시연할 단계는 아니지만 거의 다 왔습니다.
MeshCore 메인테이너들이 이 아이디어를 좋아하지 않을 가능성도 크고, 그들의 동의 없이는 사실상 추진이 어렵습니다. 그래도 크로스 언어 라이브러리를 한 번도 만들어 본 적이 없어 흥미로운 경험이 될 것 같아 진행했습니다.
Python에서 C 코드를 호출해 본 마지막 경험은 20년 전이었고, 당시에는 SWIG를 써야 했습니다. 그때는 고통스럽고 꼼수처럼 느껴졌는데, 지금은 80% 정도는 개선된 것 같습니다.
핵심 구현을 C가 아니라 Zig로 하고 싶었지만, 걸림돌이 너무 많았습니다.
- Zig는 아직 대부분의 MeshCore 기기가 사용하는 xtensa 아키텍처로 컴파일되지 않습니다.
- 대부분의 MeshCore 펌웨어 프로젝트가 사용하는 PlatformIO는 Zig를 지원하지 않습니다.
- Dart의 ffigen은 Zig가 C ABI를 지원하므로 어쩌면 동작할 수도 있겠지만, C로도 동작하게 만드는 것조차 어려웠습니다.
- Python의 cffi도 마찬가지입니다.
마무리
무엇을 해냈나요?
- Refactoring English의 새 챕터 두 개를 대부분 작성했습니다.
- 설계 문서 초안을 대부분 작성했습니다.
- “2025년 Hacker News에서 가장 인기 있었던 블로그”를 발행했습니다.
- 첫 Flutter 앱을 만들었습니다.
- 첫 크로스 언어 라이브러리를 만들었습니다.
- MeshCore meshcore.js에 몇 가지 기여를 했습니다.
- 대부분 메인테이너들이 무시하고 있습니다.
배운 점
- 진행 중인 프로젝트 최소화하기
- AI 덕분에 새로운 프로젝트를 시작하는 일은 그 어느 때보다 쉬워졌지만, 그것을 프로덕션 수준으로 만드는 병목은 여전히 저 자신입니다. 그 결과 검토 후 발행하기를 기다리는 진행 중인 프로젝트가 많이 쌓였고, 잦은 컨텍스트 전환과 작업 추적에 정신적 부담이 큽니다.
다음 달 목표
- Refactoring English 챕터 3개 발행하기.
- 2025년 연간 회고(8년 차) 발행하기.
도움이 필요합니다
여러분이 사는 곳에서 개발자 대상 도서가 30달러(USD)라면 비싼 편인가요? 그렇다면 Designing Data-Intensive Applications 같은 프로그래밍 도서에 대해 여러분 국가에서 일반적으로 기대하는 가격을 현지 통화 기준으로 알려주세요.
글을 무작위로 읽기
