안녕하세요! 그로스로그 입니다!😊 🌱
처음 배포하며 막히고 또 막힌 기록, 그리고 개발 환경에서 실제 사용자에게 알림이 갈 뻔한 아찔함. 1기 5회차 두 편입니다.
성장일지는 멤버들이 2주에 한 번씩 자신의 성장을 기록하는 활동이에요. 매 회차 운영진이 모든 글을 읽고, 그중 특히 마음에 남은 글을 함께 골라 큐레이션합니다.
이번 회차는 "만든 것을 세상에 내놓는 단계"에서 만나는 벽을 다룬 두 편입니다.
01
🚀 Vercel과 Heroku로 React-Flask 앱 배포하기
이민경 님
React 프론트엔드와 Flask 백엔드로 만든 앱을 Vercel과 Heroku에 배포하면서 겪은 시행착오를 담았습니다.
로컬에서는 잘 돌아가던 프로젝트가 배포 단계에서 계속 막혔고, 무엇이 문제인지도 명확하지 않은 상태가 이어졌어요. 글에는 그 답답함이 미화 없이 적혀 있습니다.
그러다 "레포지토리를 분리하라"는 조언 하나로 상황이 풀립니다. 프론트와 백엔드를 한 저장소에 두고 각각 다른 플랫폼에 올리려던 구조 자체가 문제였던 거죠. 조언을 듣고 구조를 바꾸자 막혀 있던 것들이 차례로 해결됩니다.
프로젝트를 처음 배포해본 분이라면 이 글의 감정선이 익숙하실 겁니다.
로컬에서는 잘 돌아갑니다. 그런데 배포만 하면 안 돼요. 에러 메시지는 불친절하고, 검색해서 나온 해결책을 따라 해도 이번엔 다른 데서 막힙니다. 무엇을 모르는지조차 모르는 상태가 이어지죠.
이 글은 그 과정을 솔직하고 생생하게 담았습니다. 그리고 조언 하나로 풀려나가는 순간까지요.
조금 더 들어가 보면
React + Flask 조합은 학습 프로젝트에서 흔한 구성인데, 배포에서 유독 잘 막힙니다. 이유가 있어요.
둘의 성격이 완전히 다르기 때문입니다.
React 앱은 빌드하면 HTML·CSS·JS 파일 묶음이 됩니다. 서버가 계속 돌 필요가 없어요. 파일만 어딘가에 올려두고 사용자가 받아가면 끝입니다. 이런 걸 정적 호스팅이라 하고, Vercel·Netlify·GitHub Pages가 잘하는 일이죠.
Flask 앱은 다릅니다. 요청이 올 때마다 파이썬 코드가 실행돼야 합니다. 프로세스가 계속 살아 있어야 하고, 메모리도 쓰고, DB에도 붙습니다. 이건 Heroku 같은 애플리케이션 호스팅이 하는 일이에요.
여기서 초보자가 흔히 하는 시도가 "저장소 하나에 둘 다 넣고 각각 배포하기"입니다. 개발할 때는 한 폴더에 있는 게 편하니까요. 그런데 배포 플랫폼 입장에서는 곤란합니다. Vercel은 저장소를 받아서 "이건 React 프로젝트구나" 하고 빌드하려는데 파이썬 파일이 섞여 있고, Heroku는 반대 상황을 만나거든요. 빌드 설정이 서로 엉키기 시작합니다.
저장소를 분리하라는 조언이 정확했던 이유가 이겁니다. 배포 단위를 나누면 각 플랫폼이 자기가 아는 방식대로 동작할 수 있어요.
이 구조에서 그다음 만나는 벽은 보통 CORS입니다. 프론트는 myapp.vercel.app에서, 백엔드는 myapp.herokuapp.com에서 돌게 되니 도메인이 달라지죠. 브라우저는 보안상 다른 도메인으로의 요청을 기본적으로 막기 때문에, 백엔드가 "이 도메인은 허용한다"고 명시해줘야 합니다. 그리고 환경변수로 API 주소를 관리하는 습관도 여기서 생깁니다. 로컬에서는 localhost:5000, 배포에서는 실제 주소를 봐야 하니까요.
배포는 이렇게 "내 컴퓨터에서만 통하던 가정들"이 하나씩 깨지는 과정입니다. 경로도, 포트도, 도메인도, 환경변수도 전부 다시 정의해야 해요. 처음이 유난히 힘든 게 당연합니다.
큐레이터 노트
이 글을 뽑은 이유는 잘 안 풀린 과정을 그대로 남겼다는 점입니다.
배포 관련 글은 대개 성공한 뒤에 쓰입니다. "이렇게 하면 됩니다"로 정리되죠. 깔끔하지만, 정작 막혀 있는 사람에게는 도움이 덜 됩니다. 그 사람이 궁금한 건 "왜 나만 안 되지"거든요.
이 글은 헤맨 시간을 지우지 않았습니다. 그래서 지금 같은 자리에서 막혀 있는 사람이 읽으면 "나만 그런 게 아니구나"를 먼저 얻게 돼요. 그게 생각보다 큰 도움입니다.
그리고 조언 하나로 풀렸다는 결말도 좋았습니다. 혼자 며칠 붙들고 있던 문제가 남의 한마디로 풀리는 경험 — 커뮤니티가 존재하는 이유가 정확히 그거니까요.
02
⚙️ 설정 파일을 통한 환경별 Property 관리
오연수 님
프로젝트에 알림톡과 푸시 알림 기능을 추가하면서 마주한 문제에서 출발합니다. 개발 환경에서 테스트할 때 실제 사용자에게 알림이 나가면 안 된다는 것이었어요.
해법은 환경별로 수신자를 갈아끼우는 겁니다. 개발 환경에서는 개발자 번호로만 발송되도록요.
스프링 프로파일 그룹을 어떻게 설계했는지, 실제 분기 코드가 어떻게 생겼는지, 그리고 설정이 빠졌을 때의 예외 처리까지 그대로 따라 할 수 있게 정리했습니다.
이 글의 문제의식이 아주 실무적입니다.
알림톡과 푸시 알림을 붙였습니다. 그런데 테스트를 해야 하잖아요. 개발 서버에서 코드를 돌리면 실제 고객 번호로 알림이 나갑니다. 한 번 나가면 되돌릴 수 없고요.
그래서 환경에 따라 수신자를 바꾸는 장치를 만듭니다. 개발 환경에서는 개발자 번호로만 가도록요.
조금 더 들어가 보면
"환경별 설정 분리"는 들으면 당연해 보이는데, 실제로 안 하고 넘어가는 팀이 꽤 있습니다. 그러다 사고가 나죠. 개발 서버에서 돌린 배치가 전체 고객에게 문자를 보내는 사고는 업계에서 주기적으로 반복됩니다.
스프링에서는 이걸 프로파일(profile)로 다룹니다. local, dev, prod 같은 이름을 붙여두고, 실행할 때 어떤 프로파일로 뜰지 지정하는 방식이에요. 설정 파일도 application-dev.yml, application-prod.yml처럼 나눠두면 알아서 해당 파일을 읽습니다.
여기서 실무의 미묘한 지점이 나옵니다. 분리해야 할 것과 공유해야 할 것을 가르는 일이에요.
DB 주소나 API 키는 환경마다 달라야 합니다. 반면 로그 포맷이나 공통 상수는 어디서나 같아야 하고요. 전부 나누면 관리가 지옥이 되고, 안 나누면 사고가 납니다. 글에서 다룬 프로파일 그룹 설계가 이 균형을 잡는 작업입니다.
그리고 이 글이 특히 좋은 건 예외 처리까지 다뤘다는 점입니다.
설정 기반 분기의 가장 위험한 실패 방식은 조용히 기본값으로 넘어가는 것입니다. 개발 환경 설정을 빠뜨렸는데 시스템이 "설정이 없네, 그럼 운영 설정을 쓰자"로 동작하면요? 아무 경고 없이 실제 고객에게 알림이 나갑니다. 아무도 모르는 사이에요.
그래서 이런 종류의 설정은 없으면 즉시 죽는 게 낫습니다. 애플리케이션이 시작 단계에서 에러를 내고 멈추면 개발자는 바로 알아차리고 고칩니다. 반대로 조용히 넘어가면 사고가 난 뒤에야 알게 되죠.
"실패는 시끄럽게"가 이런 영역의 원칙입니다. 글이 예외 처리까지 적어둔 게 그래서 값집니다.
큐레이터 노트
사고를 미리 막는 코드를 다뤘다는 점에서 뽑았습니다.
새 기능을 붙이면 보통 "동작하게 만들기"까지가 목표입니다. 알림이 발송되면 성공이죠. 그런데 이 글은 거기서 한 걸음 더 갔습니다. "테스트하다가 실제 고객에게 나가면 어쩌지"를 먼저 걱정했어요.
이 감각이 실무 경험에서 나옵니다. 아직 안 일어난 사고를 상상하고 미리 막아두는 일이요.
그리고 4회차의 FCM 글과 같은 분이 쓰셨습니다. 푸시 알림을 붙이고(4회차), 그게 잘못 나가지 않게 막는 장치를 만들고(5회차). 한 기능을 제대로 끝내는 과정이 두 회차에 걸쳐 기록된 셈이에요.
💡 두 편을 겹쳐 읽으며
한 편은 처음 배포하며 헤맨 기록이고, 한 편은 배포 환경을 정교하게 다루는 기록입니다. 나란히 놓으면 같은 길의 다른 지점처럼 보입니다.
이민경 님은 "내 컴퓨터 밖으로 내보내는" 첫 관문을 통과하는 중이고, 오연수 님은 이미 여러 환경을 운영하면서 그 사이의 사고를 막는 단계에 있어요.
그런데 두 글의 뿌리는 하나입니다. 개발 환경과 실제 환경은 다르다는 것.
이민경 님이 만난 벽은 그 차이를 몰라서 생겼습니다. 로컬에서 통하던 가정이 배포에서 깨진 거죠. 오연수 님이 만든 장치는 그 차이를 의도적으로 유지하기 위한 것이었고요. 개발 환경이 운영 환경처럼 동작하면 안 되니까요.
같은 사실의 앞면과 뒷면입니다.
이번 회차에서 가져갈 것
1. 배포는 가정이 깨지는 과정이다. 경로, 포트, 도메인, 환경변수 — 로컬에서 당연했던 것들이 전부 다시 정의됩니다. 처음 배포가 힘든 건 실력 문제가 아니라 확인해야 할 항목이 갑자기 늘어나서입니다.
2. 위험한 기능일수록 안전장치를 먼저. 알림, 결제, 메일처럼 되돌릴 수 없는 동작은 만들자마자 "실수로 나가면 어쩌지"를 같이 설계해야 합니다. 기능 완성 후에 붙이려면 이미 한 번은 나간 뒤일 수 있어요.
3. 조용한 실패를 만들지 않기. 설정이 빠졌을 때 기본값으로 넘어가면 사고를 늦게 발견합니다. 없으면 시작 단계에서 죽게 만드는 편이 훨씬 안전합니다.
1기 5회차입니다. 이 시기에 멤버들이 각자 만들던 프로젝트를 실제로 세상에 내놓기 시작했어요. 그러면서 로컬에서는 만날 일 없던 문제들이 한꺼번에 쏟아졌습니다.
배포는 개발자가 한 단계 올라서는 관문 같습니다. 만드는 것과 돌아가게 유지하는 것은 다른 일이니까요.
좋은 글 남겨주신 이민경 님, 오연수 님께 감사드립니다. 그리고 지금 첫 배포 앞에서 에러 로그를 노려보고 계신 모든 분들께도요! 😊
다음 큐레이션으로 다시 찾아오겠습니다! 🌱
- 에디터 · 성장일지 큐레이터 -
※ 본 큐레이션은 각 저자가 공개한 글을 소개하는 것이며, 모든 원문의 저작권은 저자에게 있습니다. 저자 본인의 요청이 있을 경우 즉시 수정 또는 삭제합니다.
'성장일지' 카테고리의 다른 글
| [GL 1기] Cypress로 시작하는 E2E 테스트, 그리고 4주 만에 동작한 웹크롤러 (성장일지 7회차 큐레이션) 🌱 (0) | 2026.08.07 |
|---|---|
| [GL 1기] AWS 프리티어 12개월 제대로 쓰기, 그리고 JSP 404 추적 (성장일지 6회차 큐레이션) 🌱 (0) | 2026.08.07 |
| [GL 1기] FCM 푸시 알림 붙이기와 간헐적 ChunkLoadError 추적 (성장일지 4회차 큐레이션) 🌱 (0) | 2026.08.07 |
| [GL 1기] EC2에서만 멈추는 스트리밍, 500줄짜리 검색 쿼리 (성장일지 3회차 큐레이션) 🌱 (0) | 2026.08.07 |
| [GL 1기] 인생 2막 개발자의 프로젝트 회고, 그리고 방통대 졸업 전략 (성장일지 2회차 큐레이션) 🌱 (0) | 2026.08.07 |