천천히 둘러봐도 괜찮아요. 먼저 하고 싶은 이야기부터 골라 보세요.
반갑습니다. 7년째 만들고 고치는 중입니다.
필요한 건 직접 만드는 개발자, 박상욱입니다.
프론트엔드로 시작했는데, 하다 보니 서버도 보고 배포도 하고 AI도 붙이고 있었습니다. 문제가 생기면 제 담당인지부터 따지기보다 어디서 꼬였는지부터 찾아갑니다.만든 것들은 바로 아래 있습니다.
- 14개 언어
- 앱 설치 없이 바로 쓰는 이용자용 웹
- 백오피스 도메인별 화면
- 공통 구조를 만들고 직접 구현했습니다
- 9개월
- 그 웹을 혼자 만들고 운영한 기간
- 10회 연속 성공
- 가끔 실패하던 결제 테스트
대표 작업 세 장을 먼저 보면 제가 어떤 문제를 좋아하는지 금방 보여요.
요즘엔 이런 걸 했어요
그래서 뭘 만들었냐고요?
사용자는 앱을 깔기 싫고, 운영자는 복잡한 화면이 싫고, 서버는 가끔 예고 없이 아픕니다. 서로 다른 세 문제를 한 서비스 안에서 함께 풀었습니다.
- 01이용자용 웹앱부터 깔라고요? 웹에서 바로 시작하죠.검색하고, QR을 찍고, 결제하는 길을 하나로 이었습니다.14개 언어 · 처음부터 제작 · 9개월 운영
- 02운영자 화면규칙을 사람이 아니라 도구가 지키게 했습니다.메뉴와 버튼, 오류 안내가 제각각 놀지 않게 바탕을 맞췄습니다.백오피스 도메인별 화면 · 공통 구조 · 주요 기능 직접 구현
- 03서버한 곳이 삐끗해도 다 같이 넘어지지 않게.문제가 생긴 곳만 잠시 멈추고, 나머지는 계속 움직이게 했습니다.외부 연동 43곳 · 쿠폰 상황 101가지
마음 가는 카드부터 눌러 보세요. 순서대로 보지 않아도 괜찮습니다.
앱 설치 없이 바로 쓰는 길을 함께 살펴봐요.
요즘 한 일 01 · 이용자용 웹
1앱을 깔아야 시작되는 서비스는 만들고 싶지 않았습니다
여행 중 병원을 찾는데 앱부터 깔라고 하면 귀찮습니다. 처음 온 사람이 아무것도 미리 준비하지 않아도 검색부터 결제까지 끝낼 수 있게 만들었습니다.
- 어디가 불편했나
- 검색으로 들어온 해외 사용자가 앱 설치 안내에서 돌아서곤 했습니다.
- 그래서 이렇게
- 검색 → 장소 확인 → QR → 주문 → 결제를 웹 하나로 이었습니다.
- 결국
- 14개 언어의 웹을 처음부터 만들고 9개월 동안 실제로 운영했습니다.
- 1
14개 언어, 번역만 붙이면 끝일 줄 알았습니다
주소가 하나뿐이면 검색엔진은 그 페이지를 한 언어로만 기억합니다. 그래서 언어를 쿠키가 아니라 주소에 넣었습니다.
- 2
QR을 찍으면 바로 그 매장의 주문 화면입니다
매장에 붙은 QR을 찍으면 그 매장 주문 화면이 바로 열립니다. 앱을 깔거나 회원가입을 먼저 끝낼 필요가 없습니다.
- 3
지도는 눈앞의 정보부터 보여 줍니다
모든 정보를 한꺼번에 기다리지 않고 지금 보이는 곳부터 보여 줍니다. 사람도 서버도 덜 기다립니다.
- 4
결제창에서 뒤로 가도 장바구니가 그대로입니다
어느 쪽이 진짜인지는 화면이 아니라 서버 한 곳에서만 정하게 했습니다. 로그인 전후로 갈리면 사라지거나 두 번 담깁니다.
- 5
오늘 되고 내일 안 되는 테스트는 싫었습니다
기다리는 시간을 넣어 덮지 않고 원인을 없앴습니다. 화면이 아직 안 그려졌을 뿐이라, 될 때까지 누르게 고쳤습니다.
- 6
직접 눌러 보세요
스크린샷이 아니라 실제로 움직이는 주문 화면입니다. 부담 없이 이것저것 눌러 보셔도 됩니다.
- 혼자 만들었습니다빈 폴더에서 시작해 이용자가 보는 웹을 혼자 짰습니다.
- 9개월 운영내놓고 끝난 게 아니라, 실제 이용자가 쓰는 동안 계속 고쳤습니다.
- 언어 14개문장만 번역한 게 아니라, 언어마다 주소를 따로 뒀습니다.
화면과 서버가 같은 약속을 지키는지 봐 주세요.
요즘 한 일 02 · 운영자 화면
215명이 함께 만들어도 한 사람이 만든 것처럼 보여야 합니다
사람이 많아지자 같은 기능인데도 버튼 위치와 오류 안내가 조금씩 달라졌습니다. 운영자가 화면마다 새로 배울 필요가 없도록 공통 사용법부터 맞췄습니다. 서버에만 있던 기능도 운영자에게 필요한 건 화면으로 꺼냈습니다.
- 어디가 불편했나
- 15명이 함께 만들자 메뉴와 버튼, 오류 안내가 조금씩 달라졌습니다.
- 그래서 이렇게
- 누가 만들어도 같은 사용법이 나오도록 공통 바탕을 만들었습니다.
- 결국
- 운영자는 화면마다 새 사용법을 익히지 않아도 되게 됐습니다.
- 1
권한이 없는 자료는 버튼부터 보이지 않게
파트너, 관리자, 스태프가 할 수 있는 일을 나눴습니다. 화면뿐 아니라 서버에서도 같은 기준으로 한 번 더 확인합니다.
- 2
표와 팝업을 열다섯 번 만들지 않았습니다
표와 팝업, 오류 안내처럼 자주 만나는 화면을 한 번 만들어 함께 썼습니다.
- 3
오류 알림이 두 번 뜨는 걸 하나씩 고치지 않았습니다
띄우는 자리를 한 군데로 못 박았습니다. 새로 만드는 화면은 두 번 뜨게 만들 수가 없습니다.
- 4
사람의 기억에만 맡기지 않았습니다
“꼭 확인해 주세요”라고 적어 두는 대신, 빠뜨리면 도구가 바로 알려 주게 했습니다.
- 5
검색이 이상하면 운영자가 직접 눌러 봅니다
검색 결과가 이상한지, 숙소 정보가 다시 반영되는 중인지를 운영자가 직접 확인합니다.
- 6
역할을 바꿔 보세요
역할에 따라 메뉴와 표가 어떻게 달라지는지 실제 화면에서 확인할 수 있습니다.
- 기여자 15명함께 만드는 사람이 15명으로 늘면서 생긴 문제를 맡았습니다.
- 모두가 쓰는 부분표, 팝업, 글 편집기, 서버를 부르는 층을 맡았습니다.
- 권한은 한 곳에서메뉴도 표도 버튼도 전부 같은 확인을 거칩니다.
겉으로 보이는 버튼 뒤의 실패 경로도 같이 봅니다.
요즘 한 일 03 · 서버
3한 곳이 멈춰도 전부 멈추지 않게
검색, 번역, 결제, 알림은 언제든 느려지거나 멈춥니다. 한 곳이 멈췄다고 주문과 쿠폰까지 같이 멈추지 않도록, 멈추는 범위를 지점마다 정해 두었습니다.
- 어디가 불편했나
- 검색이나 번역 한 곳의 문제가 주문과 쿠폰까지 멈추게 할 수 있었습니다.
- 그래서 이렇게
- 문제가 생긴 기능만 멈추고, 다시 눌러도 결과는 한 번만 생기게 했습니다.
- 결국
- 외부 연결 43곳과 쿠폰이 꼬일 수 있는 상황 101개를 확인했습니다.
- 1
멈출 수 있는 호출이 43곳이었습니다
검색과 번역 AI 호출마다 서킷브레이커를 걸었습니다. 재시도만 늘리면 느려진 호출이 쌓여 다른 요청까지 밀립니다.
- 2
숙소 정보는 한 번에 묶어서 넣습니다
변경마다 한 건씩 재색인해 검색이 느려졌습니다. Bulk 묶음으로 바꿔 왕복을 한 번으로 줄였습니다.
- 3
한 AI가 멈추면 다른 모델로 넘어갑니다
번역이 LLM 하나에 묶여 있었습니다. Gemini·Claude·OpenAI를 한 인터페이스 뒤로 묶었습니다.
- 4
서버를 늘려도 쿠폰은 한 장만
쿠폰을 쏘기 전에 보낼 내용을 먼저 적어 둡니다. 서버가 여러 대여도 분산락으로 한 대만 집어 갑니다.
- 5
쿠폰은 기존 코드에 얹지 않았습니다
레거시에 얹으면 쿠폰 규칙이 코드 곳곳으로 흩어집니다. 의존 방향은 ArchUnit이 CI에서 막습니다.
- 6
캐시가 죽어도 응답은 나갑니다
커넥션 풀이 고갈되면 캐시 하나가 서비스 전체를 세웁니다. timeout으로 끊고 DB에서 읽어 옵니다.
- 서킷브레이커 43개 지점느려지거나 멈출 수 있는 호출마다 끊는 기준을 따로 뒀습니다.
- 쿠폰 테스트 101건두 번 눌리고, 끊기고, 다시 시도하는 경우까지 확인했습니다.
- 검색 · AI · 쿠폰화면에서 만난 문제를 서버 안쪽까지 따라갔습니다.
지나온 문제들이 지금의 작업 습관을 만들었어요.
지나온 길 · 지난 세 회사와 이 사이트
4화면에서 시작해 서비스 전체를 보게 된 이야기
처음부터 모든 걸 다루지는 않았습니다. 도로 관제 화면, 영상 앱, 실시간 통역 서비스를 하나씩 만들며 화면 밖의 문제도 보게 됐습니다.
- 1
화면이 멈추면 도로와 물류 업무도 멈췄습니다
2019년부터 아와소프트에서 도로·물류 관제를 만들며 돌발정보와 CCTV를 한 화면에 실시간으로 올렸습니다.
- 2
맛집을 찍어 그 자리에서 올리는 앱
2022년 데브락에서 숏폼 맛집 앱 여기가게를 둘이서 만들었습니다. 찍은 영상을 그 자리에서 잘라 올립니다.
- 3
올린 영상 대신 다른 영상이 재생됐습니다
촬영·자르기·업로드·변환·배포·재생으로 단계가 여섯이라 중간에서 어긋났습니다. 여섯을 한 흐름으로 이었습니다.
- 4
자를 때마다 화질이 깎였습니다
2024년 Lossless Cut은 래퍼가 만드는 명령으로 인코딩이 안 나와, FFmpeg를 직접 썼습니다.
- 5
이미 지나간 말이 뒤늦게 다시 들렸습니다
2024년 애자일그로스의 실시간 통역에서, 출력 큐를 통째로 비우면 멀쩡한 구간까지 사라졌습니다. segment마다 시간 축을 붙여 현재 재생 시각보다 이전 것만 골라 버렸습니다.
- 6
이 사이트도 처음엔 25MB 영상이었습니다
커버 파티클과 GPU를 나눠 쓰다 프레임이 떨어졌습니다. 25MB 클립 9개를 772KB 픽셀 26장으로 바꾸고 재생 엔진도 468줄에서 195줄로 줄였습니다.
- 세 회사 · 2019 – 2025공공 관제와 코인 세무 시스템에서 시작해 앱과 영상, 혼자 세운 서비스까지 지났습니다.
- 혼자 처음부터 끝까지Motivr는 AWS 구성부터 API와 화면, 배포까지 직접 세웠습니다.
- 영상 4년째2022년 여기가게부터 통역 음성과 이 사이트까지 이어집니다.
저기 줄에 널린 게 다 제 얼굴이에요. 필요한 걸 골라 씁니다.
직접 만든 것 · 캐릭터 아잉
5직접 만든 아잉, 표정이 열여섯입니다
처음에는 페이지 구석에 둘 작은 그림이었습니다. 만들다 보니 웃고, 당황하고, 고민하고, 움직이고, 이제는 이 복도의 일곱 방에 하나씩 서 있습니다.
- 1
기쁘고, 당황하고, 고민하고
상황에 맞게 반응하도록 표정 16개, 동작 16개, 움직임 6개를 그렸습니다.
- 2
표정 찾느라 폴더를 헤매지 않게
표정과 동작 32장을 시트 두 장으로 묶고 이름표 파일을 함께 뒀습니다. 그림을 열어 보지 않고 이름으로 꺼내 씁니다.
- 3
다른 곳에도 데려갈 수 있게
색과 칸 크기, 프레임 이름을 킷 파일 하나에 적어 통째로 공개했습니다.
- 4
평면에서 입체로
3D 아잉도 두 벌 만들었습니다. 1.2MB짜리와, 메시를 줄여 205KB로 만든 가벼운 쪽입니다.
- 5
사이트와 같은 색을 입혔습니다
아잉의 색을 방과 카드에도 나눠 써서 캐릭터만 따로 떠 보이지 않게 했습니다.
- 6
배경을 지우니 점이 남았습니다
영상에서 알파를 뽑으면 압축 얼룩이 같이 남습니다. 임계값을 올리면 캐릭터 선까지 깎여서, 남은 덩어리의 크기로 걸렀습니다.
- 표정 16 · 동작 16 · 움직임 6입체 아잉도 두 종류 만들고 모두 공개했습니다.
- 계속 봐도 덜 어색하게반복 재생을 첫 프레임으로 되돌리는 대신 거꾸로 되감아 닫았습니다.
- 안내자도 직접 만들었습니다일곱 방에 선 아잉이 방마다 다른 그림입니다.
퇴근하고 만드는 앱이에요. 어제의 나보다 조금 나아지면 그걸로 충분하고요.
요즘 만드는 것 · spoon 앱
7등급을 돈으로 살 수 없는 앱을 만들고 있습니다
가진 돈으로 사람을 줄 세우는 앱은 만들고 싶지 않았습니다. 그래서 남과 겨루는 순위표를 아예 넣지 않고, 어제의 나보다 얼마나 움직였는지만 점수로 남겼습니다. 픽셀 분신을 키우며 하루를 기록하는 앱이지만, 등급만은 돈으로 살 수 없습니다.
코드와 만드는 과정 보기 ↗
홈 · 어제 대비 변화량
작업 · 오늘의 퀘스트
랭킹 · 순위표가 없음
상점 · 겉모습 여덟 가지
사기 전에 입어 보기

- 1
남과 겨루는 순위표가 없습니다
오늘 점수는 다른 사람이 아니라 어제의 나와 비교한 변화량입니다. 잘 사는 사람 옆에 서서 초라해지는 화면은 만들고 싶지 않았습니다.
- 2
등급은 팔지 않습니다
수저 여섯 단계는 어떤 방법으로도 살 수 없습니다. 코인으로 살 수 있는 건 티셔츠와 신발, 자전거와 자동차처럼 겉모습뿐인 여덟 가지입니다.
- 3
옷을 따로 그리지 않았습니다
모자와 신발을 각각 그리면 어깨선과 발목선이 캐릭터와 어긋납니다. 입은 그림에서 달라진 픽셀만 뽑아내니 열네 겹이 처음부터 같은 자리에 맞았습니다.
- 4
점수는 서버만 씁니다
코인과 등급, 가진 물건은 앱에서 고칠 수 없습니다. 실제 지급은 서버 안에서 한 번에 일어나고, 규칙이 칸 단위로 앱의 쓰기를 막습니다.
- 5
안 받는 것부터 먼저 말합니다
통장 잔액도, 정확한 주소도, 부모 재산도 받지 않습니다. 안 받겠다고 적어 두는 대신 저장할 칸 자체를 만들지 않았습니다.
- 6
같은 계산을 둘이 따로 합니다
앱과 서버가 같은 산식을 각자 가집니다. 같은 문제로 함께 채점해서 둘의 답이 갈리는 순간 테스트가 잡아냅니다.
- Expo · Skia · Firebase화면과 서버, 캐릭터 그림까지 혼자 만들고 있습니다.
- 테스트 492개앱 348개, 서버 47개, 실제로 띄워서 돌리는 통합 97개입니다.
- 살 수 있는 건 여덟 가지티셔츠부터 외제차까지, 전부 겉모습만 바꾸는 물건입니다.
작은 단위로 나누면 낯선 문제도 손에 잡히기 시작해요.
거창한 원칙은 아니고
일할 때는 대충 이런 편입니다.
네 가지 다 한 번씩 겪고 나서 생겼습니다. 처음부터 이렇게 하지는 않았습니다.
- 01
느리면 로딩 그림부터 넣지 않습니다
숙소 검색이 느려졌을 때 로딩 표시부터 손보지 않았습니다. 요청이 올 때마다 같은 계산을 되풀이하고 있어서, 그 계산을 미리 해 두고 검색할 때는 꺼내 쓰게 바꿨습니다.
- 02
한 번 누르는 버튼도 두 번 눌러봅니다
결제 창에서 뒤로 가 보고, 카카오톡에서 열었다가 로그인하러 다른 브라우저로 넘어가 봤습니다. 브라우저가 바뀌는 순간 로그인 정보가 사라져서, 돌아올 자리를 세션이 아니라 주소에 실어 보냈습니다.
- 03
같은 고생을 두 번 하면 스크립트를 씁니다
화면마다 색과 간격 값이 조금씩 어긋나 리뷰에서 매번 같은 걸 잡고 있었습니다. 어긋난 값을 찾아 고치는 스크립트를 만들었습니다. 사람이 외워야 할 규칙을 하나씩 줄이는 걸 좋아합니다.
- 04
이슈나 문제가 개발자 눈에만 보이면 부족합니다
운영하는 사람도 지금 무슨 일이 벌어지고 있는지 알 수 있게 만듭니다. Backend에만 있던 기능도 필요한 건 관리자 화면으로 꺼냈습니다.
화면 밖까지 따라가 본 이야기를 조금 더 들려드릴게요.
조금 더 소개할게요
처음엔 프론트엔드였습니다.
지금은 이것저것 다 봅니다.
작은 팀에서 서비스를 만들다 보니 화면만 보고 있을 수가 없었습니다. API도 보고, DB도 보고, 배포도 하다 보니 자연스럽게 지금의 범위가 됐습니다.
새 도구가 나오면 후기보다 먼저 켜봅니다. 무료 한도로 판단이 안 서면 소액이라도 결제해서 씁니다.
새로운 걸 가장 빨리 아는 사람보다, 쓸 만한 걸 골라내는 사람이 되고 싶습니다.
이 페이지도 같은 기준으로 썼습니다. 매출이나 전환율 같은 숫자는 git에서 확인이 안 돼서 넣지 않았습니다.



Codex
cmux 터미널
Buzz