7개월간의 스타트업 인턴 회고

JUJU·2025년 8월 11일
post-thumbnail

작년 12월 말부터 진행한 7개월간의 인턴 생활이 끝났다.
정말 많이 배웠고, 살면서 이렇게까지 코딩만 했던 적이 있었나 싶을 정도로 말 그대로 죽어라 코딩만 했다.
무엇을 배웠는지, 스타트업 개발 인턴은 어떤지, 그리고 다른 사람에게 추천할만한지 등을 정리해보고자 책상 앞에 앉았다.


결론부터 말하자면,

적극 추천한다.

  • 하루 8시간씩 코딩에 집중할 수 있는 경험
  • 프로젝트의 A-Z까지 총괄해보는 경험
  • 협업 경험
  • 다양한 기술을 써보는 경험

이 외에도 정말 다양한 경험을 할 수 있었고, 앞으로의 개발 인생에 큰 도움이 될 것이라 생각한다.




무엇을 배웠는가?

1. 프로젝트의 전 과정

입사 전까진 백엔드와 RDB 외에는 다뤄본 적이 없었다.
배포 경험이 있긴 했지만, 항상 AWS EC2만 사용했기에 기술 스택의 폭이 넓진 않았다.

하지만 이번 인턴 기간 동안 정말 다양한 분야를 접할 수 있었다.

Firestore, Firebase Authentication, Cloudflare workers, R2, inngest, nginx, next.js, hono, authentik, railway....

프론트부터 Serverless Function, 인증 서버, NoSQL DB, 배포 서비스까지.
프로젝트의 A to Z를 직접 연결하고 구축해보는 경험이었다.

물론 기술의 '깊이'도 자연스레 늘었지만, 무엇보다 기술의 '폭'이 확장되었다는 점을 크게 느꼈다.
이는 스타트업의 장점이라고 생각한다.

  • 새롭고 트렌디한 기술을 직접 도입해볼 수 있다는 점.

물론 단점도 있다.
잘 알려지지 않은 기술을 다뤄야 하다 보니, 레퍼런스가 적고 문제 해결이 쉽지 않다는 것.

그럼에도 불구하고, 이제는 나 혼자서도 하나의 서비스를 처음부터 끝까지 만들 수 있겠다는 자신감이 생겼다.


2. 엉덩이 힘

코딩을 좋아하지만, 하루 8시간씩 주 5일을 몰입했던 적은 없었던 것 같다.
매일 새로운 에러가 터진다.
빠르면 3시간, 길면 3일 동안 에러를 잡는다.
출근해서 어제 에러를 잡고 밥 먹고 돌아오면 또 다른 에러가 터져 있다.

하루 종일 화면만 보다 보니 눈도 뻑뻑해졌다.
그럼에도 불구하고, 이제는 ‘하루 = 코딩’ 이 수식이 너무 익숙해졌다.
오히려 좋아.


3. 백엔드 개발자가 UX를 신경써야 하는 이유

예전에는 “백엔드 개발자가 UI/UX까지 고려해야 할까?” 하는 생각이 있었다.
하지만 토스 페이먼츠를 연동하면서, 그 이유를 뼈저리게 깨달았다.

Stripe의 구독 라이프사이클을 참고해서 결제 시스템을 구축하던 중, Incomplete라는 상태를 발견했다.
이는 첫 결제가 실패했을 때 구독이 머무는 상태다.
당시에는 왜 이게 필요한지 이해하지 못했다.
그래서 나는 INACTIVE, ACTIVE, UNPAID(연장 결제 실패) 세 가지 상태만 있는 라이프사이클을 설계했고, 그대로 CTO님께 보고했다.

그런데 실제 구현 과정에서 문제가 발생했다.
사용자 입장에서 생각해보니, 첫 결제가 실패할 경우 다시 결제하려면 상품을 처음부터 다시 선택 → 결제 팝업 작성 → 결제 재시도의 과정을 거쳐야 한다.
이는 상당히 번거롭고, 사용자 경험을 크게 떨어뜨린다.

바로 이 문제를 해결하기 위해 존재하는 상태가 Incomplete였다.
결제 실패 시 해당 상태로 유지하면, 사용자는 이전에 실패한 결제 내역을 그대로 재결제할 수 있어 번거로운 과정을 줄일 수 있다.

이 경험을 통해 깨달았다.
백엔드 개발이라도 사용자 경험을 고려한 설계가 필요하다.
UI/UX는 화면에 보이는 것만이 아니라, 사용자가 서비스를 어떻게 경험하는지 전반을 포함하기 때문이다.


4. 개발자 != 코더

개발자는 단순히 코드를 작성하는 코더가 아니다.

회사 업무를 하면서 비즈니스 로직을 짜는 것보다 다른 요소들에 훨씬 많은 시간을 투자했다.
서버 관리, 서비스 비교 후 선택(Inngest 등), DB 설계, 환경 구성, 서비스 연결 등…
순수한 코딩보다 이 과정들에 더 많은 시간이 들었다.

회사에서 AI 대신 개발자를 고용해야 할 이유를 묻는다면, 이렇게 대답할 것이다.

  • 단순한 비즈니스 로직 짜기? 사실 나보다 GPT가 더 잘한다.
  • 그럼에도 불구하고 회사에서 개발자를 고용하는 이유는 소프트웨어 개발 != 코딩이기 때문이다.

소프트웨어 개발은 요구사항 분석부터 서비스 유지보수까지 전 과정을 포함한다.
비즈니스 로직 작성은 그중 일부일 뿐이다.
스택을 선택하고, 서비스들을 연결하며, 그 과정에서 발생하는 오류를 해결하는 것까지 모두 개발자의 역할이다. 이 과정에서 CS 지식이 빛을 발한다.


서비스의 흐름을 보자.

  1. nginx가 요청을 받는다
  2. 프론트로 전달
  3. 프론트가 백엔드에 요청
  4. 인증 처리
  5. 백엔드는 DB에서 데이터 조회
  6. 가공 후 응답
  7. 프론트는 응답을 받아 Redux로 상태 관리
  8. 필요 시 백엔드가 Inngest로 요청
  9. Inngest가 특정 작업을 실행

이 흐름 속에는 CORS, 버퍼 관리, 동시성 관리, 비동기 요청, DB 쿼리, 인증, 메시지 큐 등 다양한 기술과 개념이 맞물린다. CS 지식은 바로 이런 순간에 힘을 발휘한다.

비즈니스 로직을 잘짜는 것? 물론 중요하다.
하지만 개발자라면 흐름을 설계하고, 문제가 생겼을 때 어느 서비스의 어느 부분을 수정해야 하는지 파악할 수 있어야 한다.
GPT에게 모든 맥락을 이해시키는 것도 가능하겠지만, 정확도와 맥락 파악은 결국 개발자의 몫이다.




기억에 남는 경험

1. 결제 시스템 구축기

처음 입사했을 때, 회사 서비스는 Firebase 기반의 MVP였다.
Firestore, Firebase Authentication, Firebase Function, Firebase Hosting 등 모든 곳에서 Firebase를 사용하고 있었다.

자연스럽게 Firebase에 익숙해질 수 있었고, 특히 초반에는 백엔드 API 개발을 맡았기에 Firebase Function을 심도 있게 다뤄볼 수 있었다.

초반 2개월은 결제 시스템을 구축했다.
그냥 PG사 연동만 하면 되는거 아닌가???

맞다. 백엔드는 그리 어렵지 않았다.
하지만, DB 설계가 굉장히 까다로웠다.

'돈이 연관된 기능은 그 어떠한 것보다 정확하고 섬세해야 한다'


사용자가 구독을 요청했을 때,
구독을 취소했을 때,
invoice가 생성된 뒤에 구독을 취소했을 때,
invoice가 생성되기 전에 구독 요금제를 변경했을 때,
관리자가 사용자의 구독을 임의로 조정할 때....

이 모든 상황을 추적할 수 있는 구조가 필요했다.
그러나 이를 여러 필드의 조합으로 처리하려다 보니 복잡함이 상당했다.

처음 2주간 정말 머리를 싸매며 DB를 설계하고 백엔드 로직까지 완성해 CTO님께 컨펌을 받았다.
물론 요구사항에 맞게 모든 기능을 구현했지만, CTO님이 정곡을 찌르셨다.

‘확장성이 부족하고, 현 상태를 파악하려면 여러 필드를 조합해야 하는 점이 아쉽다.’

이 피드백과 함께, Stripe의 구독 관리 예시를 보여주시며 조언을 해주셨다.
항상 작업할 때는 best practice를 참고하는 것이 좋다는 이야기였다.

나보다 먼저 이 길을 걸어간 개발자들이 이미 많은 시행착오를 겪었고,
우리는 그중 검증된 길을 따라가야 효율적이라는 조언이었다.

이 피드백을 바탕으로 DB를 전면 재설계했다.
그 결과, 단일 필드만으로 현재 상태를 즉시 파악할 수 있는 구조를 만들었고, 새로운 상태나 기능이 추가되더라도 쉽게 확장 가능하도록 설계했다.
이 구조 덕분에 이후 Stripe 결제 방식을 추가할 때도 DB 스키마 변경 없이 바로 적용할 수 있었다.


2. Firebase 의존성 제거

입사할 때만 해도 우리 서비스는 Firebase에 올인된 구조였다.
Firestore, Firebase Auth, Firebase Functions, Firebase Storage
뭐든 Firebase에서 다 해결되는 구조였고, 덕분에 금방 익숙해졌다.

하지만, 편리한 만큼 제약도 많았다.
새로운 기능을 붙이거나 다른 서비스와 연동하려고 할 때, Firebase 구조에 맞춰야 하는 제약이 항상 따라왔다.
이러한 문제 때문에, 서비스에서 Firebase 의존성을 모두 제거하는 업무를 맡게 되었다.

DB부터 뜯어고치기

DB부터 뜯어고치기
첫 번째 타깃은 Firestore였다.
가장 힘들었던 건 NoSQL에서 RDB로 전환하는 과정이었다.
컬렉션·도큐먼트 기반으로 느슨하게 저장되던 데이터를,
관계형 구조에 맞춰 테이블·PK·FK·조인 테이블로 재설계해야 했다.
데이터 참조 방식이 완전히 달라지다 보니, 기존 로직도 전부 손봐야 했다.

처음엔 ORM(Prisma)로 접근했지만, Cloudflare Workers 환경에서 Node 전용 라이브러리들이 먹히지 않았다. Accelerate도 시도했지만, 이렇게 되면 플랫폼 의존성을 줄이려는 초기 목적과 멀어졌다.
결국 node-postgres로 직접 쿼리를 쓰기로 했고,
그때부터 Repository 레이어를 전부 손으로 다시 쓰는 장대한 작업이 시작됐다.


프론트 직접 DB 접근 제거

MVP 시절에 만들어진 코드다 보니, 프론트에서 DB를 직접 호출하는 로직이 여기저기 박혀 있었다.
당시에는 빠르게 기능을 붙이는 게 목적이었으니 가능한 구조였겠지만, 서비스가 커진 지금은 보안·유지보수·확장성 측면에서 전혀 맞지 않았다.

그래서 전부 뜯어냈다.
프론트의 DB 직접 접근 코드를 전부 삭제하고,
대신 백엔드 API를 통해서만 데이터를 주고받도록 변경했다.
이 과정에서 API 스펙을 정리하고, 필요한 엔드포인트를 새로 만들었으며,
응답 포맷도 { code, message?, data? } 형태로 통일했다.

결과적으로, 프론트와 백의 역할이 명확히 분리됐고,
데이터 흐름을 추적·관리하기가 훨씬 쉬워졌다.


Functions를 Workers로

Firebase Functions도 마찬가지였다.
Cloudflare Workers + Hono로 마이그레이션하면서 라우팅, 인증, 서비스 구조를 싹 재정리했다.
Swagger랑 zod를 붙여서 문서와 검증을 한 번에 돌렸고, 기존 Functions 호출하던 프론트 로직도 전부 Workers API 호출로 바꿨다.


인증 갈아엎기

Firebase Auth는 Authentik으로 교체했다.
결정은 쉬웠지만, 붙이는 과정은 예상보다 길었다. 기록을 보면 거의 하루 단위로 문제를 부딪히고, 원인 찾고, 한 줄씩 고쳐 나갔다.

  • 프론트에서는 next-auth로 로그인 플로우를 다시 짰다.
  • API 테스트 환경도 손봤다. Swagger UI에 Security 스키마를 추가해서 Authorization 헤더로 실제 토큰을 넣고 테스트할 수 있게 했고, 개발 환경에서 Authentik ↔ Workers 연동을 끝까지 확인했다.
  • 추가로 로그인 옵션을 확장했다.
    • Google OAuth
    • Passkey

이메일 비밀번호 재설정은 SMTP(SendGrid)로 구현해서 복구 메일을 보낼 수 있게 했다.


Inngest로 비동기 작업 처리

파일 업로드 후 썸네일 생성, 월간 정산, 활성 유저 기록 같은 비동기 작업은 Inngest로 옮겼다.
원래는 워커 간 상태 공유와 큐 처리를 위해 Redis를 붙이려 했는데, Cloudflare Workers 환경에서는 직접 TCP 연결이 불가능했다.
이 경우에는 Upstash 같은 HTTP 기반 Redis 서비스를 써야 한다.

그런데 외부 SaaS 의존성을 또 늘리고 싶진 않았다.
그래서 한동안 셀프 호스팅 가능한 메시지 큐 서비스들을 조사한 뒤, Inngest라는 서비스를 도입했다.

업로드 이벤트를 받아 후처리를 실행하는 워크플로우, 크론 스케줄을 통한 주기 작업까지 전부 Inngest로 구성했다.


3. 배포

초기에는 모든 서비스를 Docker로 감싸서 회사 NAS에 올리는 방식을 사용하려 했다.
DB, 백엔드, 프론트까지 전부 컨테이너로 띄우고, NAS에서 돌리는 구조였다.
여기에 서브 도메인을 붙이기 위해 nginx를 프록시로 두었고, 서비스별 라우팅도 전부 직접 관리했다.

이 방식은 회사 내부망에서 모든 걸 제어할 수 있다는 장점이 있었지만, 외부 접근과 확장성 면에서는 불편한 점이 많았다.
특히, 배포 변경이나 확장이 필요할 때마다 NAS에 직접 접속해 docker-compose를 수정하고 nginx 설정까지 건드려야 하는 구조였다.

그래서 지금은 각 서비스를 환경에 맞게 분리 배포하는 방식으로 전환했다.

  • 프론트엔드: Next.js를 Railway에 배포
  • 인증 서버: Authentik 역시 Railway에서 구동
  • 비동기 작업(Inngest): Inngest 자체 호스팅 서비스 사용
  • 백엔드 API: Cloudflare Workers에서 동작
  • DB: Supabase PostgreSQL 사용

이렇게 나누니 서비스별 스케일링을 각각 조절할 수 있고, 배포 속도도 훨씬 빨라졌다.
특히 Workers와 Railway를 조합하니,프론트와 백엔드가 서로 다른 환경에서 돌아가면서도 CORS·도메인 라우팅 문제 없이 안정적으로 붙을 수 있었다.




앞으로의 방향

실제로 업무를 하다보니, AI가 정말 강력함을 느꼈다.
코드를 짜는 것은 확실히 나보다 잘한다.
감히 예상해보자면, 10년 뒤에는 프론트, 백엔드 같은 직군은 없어질 것 같다..

그럼에도 불구하고, 프론트와 백엔드 개발은 개발자라면 한번씩 거쳐야 할 관문이라고 생각한다.

실제로 업무에 투입돼서 개발, 배포, 에러 해결까지 하다보면 프로젝트의 전반적인 흐름을 알게 된다.
그 흐름을 알고 있는 사람만이 AI를 효율적으로 사용할 수 있고, 기업에서도 그런 인재를 원할 것이다.


이제부터는 취업과 졸업 준비를 병행하려 한다.
웬만하면 IT 통합 직군으로 들어가서 관리하는 역할을 맡고 싶지만, 백엔드 직군으로 들어가서 에러랑 한번 더 뒹굴어 보는 것도 좋은 경험일 것 같다.

현장실습 인턴 고민중이라면 꼭꼭 해보시길 추천드립니다~

profile
백엔드 개발자

1개의 댓글

comment-user-thumbnail
2025년 8월 23일

7개월간의 인턴 경험을 통해 얻은 깊이 있는 인사이트와 성장이 잘 녹아 있는 글입니다. 단순히 기술 스택을 나열하는 것을 넘어, 사용자 경험(UX)의 중요성, 개발자로서의 본질, 그리고 실무에서 부딪히며 배운 문제 해결 과정을 구체적인 사례를 들어 설명한 점이 인상적입니다. 특히, 스타트업 환경의 장단점을 솔직하게 풀어내고 배포 www mymilestonecard com 환경 변화 과정을 상세히 기록한 부분이 앞으로 개발 인턴을 희망하는 사람들에게 큰 도움이 될 것입니다.

답글 달기