← 목록으로
1970-01-01startup-frontend-one-year

1년간 창업팀 프론트엔드 개발자로 일하며 배운 것들

목차

  1. 문제 상황
  2. 왜 문제가 되었는가
  3. 선택지
  4. 내가 선택한 방법
  5. 구현 과정
  6. 결과
  7. 배운 점
  8. 다음 글 예고

  1. 문제 상황

창업팀에서 프론트엔드 개발자로 일한 지 1년이 지났습니다.

그동안 주로 Next.js 기반 웹 서비스를 개발했지만, 실제로 맡았던 일은 웹 화면 구현에만 머물지 않았습니다. React Native 기반 WebView 앱을 만들고, WebView와 Native 사이의 메시지 브릿지를 정리하고, Electron 데스크톱 앱의 인증 구조를 다시 설계하고, Jenkins에서 GitHub Actions로 CI/CD를 옮기는 작업도 했습니다.

새로운 서비스에서는 MediaRecorder 기반 음성 녹음 기능을 다뤘고, 앱 출시 과정에서는 인앱 결제 구조도 검토했습니다.

처음에는 프론트엔드 개발을 비교적 단순하게 생각했습니다.

화면을 만들고, API를 연결하고, 사용자 흐름을 구현하는 일

물론 이 일도 프론트엔드의 중요한 역할입니다. 하지만 실제 창업팀에서 서비스를 만들고 운영하다 보니, 화면 구현만으로 끝나는 일은 거의 없었습니다.

웹에서는 잘 동작하던 기능이 앱 WebView 안에서는 다르게 동작했습니다. 인증 흐름은 웹과 네이티브 저장소의 책임을 함께 고려해야 했습니다. 배포가 불안정하면 아무리 기능을 잘 만들어도 사용자에게 전달할 수 없었습니다. 신규 서비스에서는 코드를 작성하기 전에 사용자의 실제 업무 흐름을 이해하는 것부터 필요했습니다.

문제는 이런 경험들이 분명히 쌓이고 있었는데, 정작 문제 해결 과정과 의사결정의 이유를 제대로 기록하지 못했다는 점이었습니다.

당시에는 기능을 만들고, 버그를 고치고, 다음 작업으로 넘어가는 데 집중했습니다. 그러다 보니 시간이 지나고 나서 돌아봤을 때 “무엇을 했는지”는 남아 있었지만, “왜 그렇게 했는지”와 “어떤 선택지를 고민했는지”는 흐릿해져 있었습니다.

  1. 왜 문제가 되었는가

처음에는 기록을 남기지 못한 것이 큰 문제라고 느끼지 못했습니다.

어차피 코드는 저장소에 남아 있고, 경력 기술서에도 작업한 내용이 정리되어 있었기 때문입니다. 하지만 시간이 지나면서 단순한 작업 목록만으로는 내가 실제로 어떤 문제를 해결했는지 설명하기 어렵다는 것을 느꼈습니다.

예를 들어 경력 기술서에는 다음과 같은 문장을 쓸 수 있습니다.

  • React Native WebView 앱 개발
  • WebView와 Native 메시지 브릿지 구조 개선
  • Electron 앱 인증 구조 재설계
  • Jenkins에서 GitHub Actions로 CI/CD 전환

이 문장들은 어떤 일을 했는지는 보여줍니다. 하지만 실제로 중요한 부분은 빠져 있습니다.

  • 왜 WebView 브릿지 구조를 개선해야 했는지
  • 기존 구조에서는 어떤 문제가 있었는지
  • Native와 WebView의 책임을 어떻게 나누려고 했는지
  • Electron 앱에서 인증 구조를 왜 다시 설계했는지
  • Jenkins에서 GitHub Actions로 옮기며 어떤 기준으로 구조를 잡았는지
  • 인앱 결제를 검토하면서 프론트엔드에서 어디까지 책임져야 한다고 판단했는지

결국 경험이 “작업한 기술 목록”으로만 남고 있었습니다.

이 상태가 계속되면 몇 가지 문제가 생깁니다.

첫 번째는 문제 해결 과정을 다시 설명하기 어렵다는 점입니다. 면접이나 포트폴리오에서 중요한 것은 단순히 어떤 기술을 써봤다는 사실보다, 어떤 문제를 어떤 기준으로 해결했는지입니다. 그런데 기록이 없으면 당시의 판단 기준을 다시 떠올려야 하고, 시간이 지날수록 맥락이 사라집니다.

두 번째는 같은 실수를 반복하기 쉽다는 점입니다. 구조가 복잡해졌던 이유, 책임이 섞였던 지점, 처음부터 확인했어야 할 제약 조건을 기록하지 않으면 다음 프로젝트에서도 비슷한 방식으로 문제를 만날 가능성이 높습니다.

세 번째는 경험의 깊이가 드러나지 않는다는 점입니다. 창업팀에서는 역할의 경계가 넓습니다. 웹, 앱, WebView, Electron, 배포, 결제, 음성 녹음 같은 영역을 넓게 다뤘지만, 기록하지 않으면 이 경험이 오히려 얕게 보일 수 있습니다.

당시 제 경험을 흐름으로 정리하면 대략 이런 모습이었습니다.

flowchart TD A[Next.js 웹 서비스 개발] --> B[React Native WebView 앱 개발] B --> C[WebView와 Native 책임 분리] C --> D[앱 아키텍처 리팩토링] A --> E[Electron 앱 개발] E --> F[Electron 인증 구조 재설계] A --> G[CI/CD 구조 개선] A --> H[음성 녹음 기반 신규 서비스] B --> I[인앱 결제 구조 검토]

문제는 이 흐름이 머릿속에는 남아 있었지만, 글이나 문서로 정리되어 있지 않았다는 점이었습니다.

  1. 선택지

지난 1년의 경험을 다시 정리하려고 했을 때, 몇 가지 선택지가 있었습니다.

선택지 장점 단점 경력 기술서만 보강하기 가장 빠르게 결과물을 만들 수 있음 문제 해결 과정과 고민이 충분히 드러나기 어려움 포트폴리오 중심으로 한 번에 정리하기 채용 관점에서 보기 좋게 정리할 수 있음 각 경험의 맥락과 시행착오를 자세히 담기 어려움 기술 블로그 시리즈로 나눠 작성하기 문제 상황, 선택지, 구현 과정, 회고를 자세히 남길 수 있음 시간이 오래 걸리고 꾸준히 작성해야 함 개인 노션에만 기록하기 부담 없이 정리할 수 있음 외부에 공유 가능한 형태로 다듬기 어려움

처음에는 경력 기술서를 더 잘 쓰면 충분하지 않을까 생각했습니다. 하지만 경력 기술서는 기본적으로 요약 문서입니다. 문제를 길게 설명하기 어렵고, 코드 구조나 의사결정 과정을 자세히 담기에는 한계가 있었습니다.

포트폴리오도 비슷했습니다. 화면, 성과, 핵심 개선 사항을 보여주기에는 좋지만, “왜 이런 구조가 필요했는지”를 깊게 풀어내기에는 글보다 제약이 있었습니다.

그래서 당장 보기 좋은 결과물을 만드는 것보다, 먼저 경험을 기술 블로그 글로 하나씩 복기하는 방향이 낫다고 판단했습니다.

  1. 내가 선택한 방법

제가 선택한 방법은 지난 경험을 하나의 긴 회고 글로 끝내지 않고, 주제별 기술 블로그 시리즈로 나눠 정리하는 것입니다.

이유는 단순합니다. 1년 동안 했던 일을 한 글에 모두 넣으면 결국 다시 작업 목록에 가까운 글이 될 가능성이 높았기 때문입니다.

제가 남기고 싶었던 것은 이런 문장이 아니었습니다.

React Native WebView 앱을 개발했고, Native Bridge 구조를 개선했습니다.

제가 실제로 정리하고 싶었던 것은 그 안에 있는 과정이었습니다.

WebView 앱을 처음 만들 때는 웹을 앱 안에 띄우면 된다고 생각했습니다. 하지만 인증, 라우팅, 메시지 전달, 앱 상태 처리까지 들어오면서 웹과 네이티브의 책임 경계가 모호해졌습니다. 그래서 Native가 책임질 것과 WebView가 책임질 것을 나누고, Bridge 메시지도 기능 단위로 정리하는 방향으로 구조를 바꿨습니다.

이런 내용은 경력 기술서보다 블로그 글에 더 잘 맞는다고 생각했습니다.

당시 프로젝트 상황에서도 이 방식이 현실적이었습니다. 이미 지나간 작업을 완벽하게 재현할 수는 없었고, 모든 수치를 다시 측정하기도 어려웠습니다. 대신 남아 있는 코드, 경력 기술서, 기억나는 문제 상황을 바탕으로 “당시 어떤 문제가 있었고, 나는 어떤 기준으로 판단했는지”를 정리하는 것은 가능했습니다.

물론 트레이드오프도 있습니다.

기술 블로그로 정리한다고 해서 모든 경험이 곧바로 깊이 있는 글이 되는 것은 아닙니다. 수치가 없는 개선 사항은 과장하지 않아야 하고, 기억이 흐릿한 부분은 단정하지 않아야 합니다. 그래서 앞으로 작성할 글에서는 “성능이 좋아졌다”처럼 근거가 부족한 표현보다는 “수정해야 하는 위치가 줄었다”, “초기화 흐름을 따라가기 쉬워졌다”처럼 실제로 설명 가능한 변화 중심으로 정리하려고 합니다.

  1. 구현 과정

이번 글 자체가 특정 기능 구현기는 아니지만, 앞으로 경험을 정리하기 위한 구조는 먼저 잡아두려고 했습니다.

기존에는 경험이 아래처럼 흩어져 있었습니다.

career/ resume.md memory/ 머릿속에만 남아 있는 문제 상황 작업 당시의 기억 일부 코드 조각 배포 과정에서 겪은 이슈

이 상태에서는 글을 쓰려고 할 때마다 처음부터 기억을 다시 꺼내야 했습니다.

그래서 앞으로는 경험을 주제별로 나누고, 각 글마다 같은 기준으로 정리하려고 합니다.

blog/ 01-retrospective/ 1-year-frontend-retrospective.md 02-webview-app/ webview-app-architecture.md webview-native-bridge.md webview-auth-flow.md 03-electron/ electron-auth-architecture.md 04-cicd/ jenkins-to-github-actions.md 05-audio/ media-recorder-audio-flow.md 06-in-app-purchase/ in-app-purchase-frontend-checklist.md

각 글은 가능하면 같은 흐름으로 작성하려고 합니다.

제목

1. 문제 상황

2. 왜 문제가 되었는가

3. 선택지

4. 내가 선택한 방법

5. 구현 과정

6. 결과

7. 배운 점

8. 다음 글 예고

이렇게 구조를 고정해두면 글을 쓸 때마다 “무엇을 적어야 할지”를 덜 고민해도 됩니다. 대신 당시 문제를 정확히 복기하는 데 집중할 수 있습니다.

앞으로 작성할 글의 큰 흐름은 다음과 같습니다.

flowchart TD A[1년 회고] --> B[WebView 앱 구조] B --> C[Native Bridge 메시지 구조] C --> D[WebView 인증 흐름] D --> E[앱 아키텍처 리팩토링] A --> F[Electron 인증 구조] A --> G[CI/CD 전환] A --> H[음성 녹음 처리] A --> I[인앱 결제 구조 검토]

각 주제에서 정리하고 싶은 핵심은 조금씩 다릅니다.

주제 정리하고 싶은 내용 WebView 앱 구조 웹을 앱으로 감싸는 수준을 넘어, 앱 초기화와 WebView 책임을 어떻게 나눴는지 Native Bridge WebView와 Native 사이에서 메시지 타입과 핸들러를 어떻게 정리했는지 인증 흐름 토큰을 WebView와 Native 중 어디에서 관리할지 고민했던 기준 Electron 인증 데스크톱 앱 환경에서 웹 인증 흐름을 그대로 가져가기 어려웠던 이유 CI/CD 전환 Jenkins에서 GitHub Actions로 옮기며 배포 흐름을 어떻게 단순화했는지 음성 녹음 처리 MediaRecorder 기반 녹음 기능에서 상태와 파일 처리를 어떻게 다뤘는지 인앱 결제 구독 플랜, 업그레이드, 다운그레이드, 결제 계정 제약을 프론트에서 어떻게 바라봤는지

코드 예시는 각 글에서 필요한 만큼만 포함할 생각입니다. 예를 들어 WebView Bridge 글에서는 이런 형태의 코드를 다룰 수 있을 것 같습니다.

type BridgeMessage = | { type: 'AUTH_REQUIRED' } | { type: 'OPEN_EXTERNAL_URL'; payload: { url: string } } | { type: 'APP_READY' }; function handleBridgeMessage(message: BridgeMessage) { switch (message.type) { case 'AUTH_REQUIRED': // Native 인증 흐름으로 이동 break; case 'OPEN_EXTERNAL_URL': // 외부 브라우저 열기 break; case 'APP_READY': // WebView 준비 완료 처리 break; } }

이 코드는 실제 구현 전체를 보여주기 위한 것은 아닙니다. 앞으로 글을 쓸 때는 이런 식으로 핵심 구조만 단순화해서 보여주고, 왜 이런 형태가 필요했는지를 중심으로 설명하려고 합니다.

  1. 결과

아직 모든 글을 작성한 것은 아니지만, 적어도 경험을 다시 바라보는 기준은 조금 명확해졌습니다.

예전에는 제가 했던 일을 나열하면 이런 식이었습니다.

  • Next.js 기반 웹 서비스 개발
  • React Native WebView 앱 개발
  • Electron 앱 인증 구조 재설계
  • CI/CD 전환

이제는 같은 경험을 보더라도 질문이 달라졌습니다.

  • 이 작업은 어떤 문제에서 시작됐는가?
  • 처음 구조는 왜 한계가 있었는가?
  • 당시 고려했던 선택지는 무엇이었는가?
  • 왜 그 방법을 선택했는가?
  • 결과적으로 무엇이 쉬워졌는가?
  • 다음에 비슷한 문제를 만나면 무엇을 먼저 확인할 것인가?

정량적인 성과를 억지로 만들 수는 없습니다. 하지만 이 기준으로 경험을 다시 정리하면, 적어도 제가 어떤 방식으로 문제를 바라보고 해결했는지는 더 분명하게 남길 수 있을 것 같습니다.

특히 좋았던 점은 “넓게만 경험했다”는 아쉬움을 조금 다르게 볼 수 있게 된 것입니다.

처음에는 여러 영역을 다뤘지만 깊이가 얕다고 느꼈습니다. 그런데 다시 복기해보니 단순히 이것저것 해본 것이 아니라, 서비스가 실제 사용자에게 전달되기 위해 필요한 문제들을 마주한 시간이었습니다.

웹 화면을 만드는 일에서 시작했지만, WebView 환경의 제약을 이해해야 했고, Native와 WebView의 책임을 나눠야 했고, 배포 흐름을 안정적으로 만들어야 했고, 결제 정책과 앱 심사 흐름도 고려해야 했습니다.

이 경험들을 잘 정리하면, “다양한 기술을 써봤다”가 아니라 “서비스를 운영 가능한 형태로 만들기 위해 프론트엔드에서 어떤 문제를 다뤘다”로 설명할 수 있을 것 같습니다.

  1. 배운 점

이번 1년을 돌아보면서 가장 크게 배운 점은 프론트엔드 개발이 화면 구현에서 끝나지 않는다는 것입니다.

처음에는 UI를 만들고 API를 연결하는 일을 중심으로 생각했습니다. 하지만 실제 서비스에서는 사용자가 기능을 안정적으로 사용할 수 있도록 여러 경계를 함께 봐야 했습니다.

웹과 앱의 경계, WebView와 Native의 경계, 클라이언트와 서버의 경계, 개발 환경과 배포 환경의 경계가 계속 등장했습니다. 문제가 생겼을 때도 대부분은 한 파일이나 한 함수만 보면 해결되는 문제가 아니었습니다.

또 하나 배운 점은 구조의 중요성입니다.

기능이 일단 동작하면 괜찮다고 생각하기 쉽지만, 시간이 지나면 책임이 섞인 구조는 디버깅 비용으로 돌아왔습니다. 특히 앱 초기화, 인증, WebView 메시지, 알림, 백그라운드 처리처럼 여러 흐름이 동시에 얽히는 부분에서는 책임 경계가 더 중요했습니다.

다음에 비슷한 문제를 만난다면 구현부터 시작하기보다 먼저 이런 질문을 해볼 것 같습니다.

  • 이 기능의 책임은 웹에 있는가, 네이티브에 있는가?
  • 상태의 원천은 어디인가?
  • 실패했을 때 어느 레이어에서 복구해야 하는가?
  • 새로운 케이스가 추가되면 어디를 수정해야 하는가?
  • 이 흐름을 처음 보는 사람이 따라갈 수 있는가?

마지막으로, 기록의 중요성을 늦게 배웠습니다.

문제를 해결하는 순간에는 기록이 크게 중요해 보이지 않았습니다. 하지만 시간이 지나고 나니 기록하지 않은 경험은 설명하기 어려운 경험이 되었습니다. 분명히 고민했고, 선택했고, 해결했지만, 남아 있는 것은 짧은 이력서 문장뿐이었습니다.

앞으로는 문제를 모두 해결한 뒤에 완벽한 글을 쓰려고 하기보다, 적어도 다음 세 가지는 작업 중에 남겨두려고 합니다.

  1. 왜 이 작업을 시작했는가
  2. 어떤 선택지를 고민했는가
  3. 결과적으로 무엇이 나아졌는가

이 정도만 남아 있어도 나중에 경험을 복기하는 데 훨씬 도움이 될 것 같습니다.

  1. 다음 글 예고

다음 글부터는 지난 1년 동안 겪었던 경험을 하나씩 나눠서 정리해보려고 합니다.

가장 먼저 다뤄볼 주제는 React Native WebView 앱 구조입니다.

처음에는 기존 웹 서비스를 앱 안에 띄우면 된다고 생각했지만, 실제로는 인증, 라우팅, 앱 상태, WebView 초기화, Native Bridge까지 함께 고려해야 했습니다.

다음 글에서는 WebView 앱을 만들면서 어떤 책임이 RootLayout과 여러 hook에 흩어졌고, 이를 어떻게 나누려고 했는지 정리해보려고 합니다.