Electron 초보가 에이전트와 함께 낯선 데스크탑 앱을 2주 만에 출시하기까지

에이전트와 함께 낯선 Electron 앱을 2주 만에 출시하기까지
올해 4월 초부터 데스크톱 앱 프로젝트가 본격적으로 시작됐다. 2주 정도의 짧은 개발기간에 프로젝트 세팅부터 배포까지 진행해야 했다.
문제는 팀 안에 Electron 기반 데스크톱 앱을 경험한 사람이 한 명도 없었다는 것이다. Electron도 데스크탑 앱도 처음이었기 때문에 처음 시작이 막막했다. 그래도 에이전트가 있기 때문에 다들 어떻게든 될거라는 생각들은 있었던 것 같다.
이번 TF가 결성되기 전부터 나는 거의 대부분의 개발을 에이전트에게 맡기는 식으로 일을 했고, TF 팀원들은 대부분 에이전트 개발에 익숙한 분들이라서 좀 더 적극적으로 에이전트를 활용한다면 빠르게 앱을 만들 수 있을 거라는 믿음이 있었다.
그래도 바이브 코딩에서 경계 해야 할 것은 분명히 하고자 했다. 동작하는 코드와 서비스하는 제품의 코드 품질차이 그리고 품질수준이 어느 이하로 떨어지면 오히려 개발속도가 느려지고, 일정에 쫒기다 가치를 전달하지 못하고 결국 실패하는 제품이 되버리기 때문에, 이번에는 사전에 그걸 방지 해야 한다고 생각했다. 에이전트가 한 파일에 모든 흐름이 모이고, 경계가 뒤엉키는 문제들을 미리 잡고, 지속가능한 구조로 유지되게하는 방법이 필요했다.
나 역시 다른 팀원들과 동일하게 Electron을 잘 알고 시작한 것은 아니었지만, 짧은 시간 안에 제품을 출시할 수 있는 최소 실행 모델을 만들고, 이후 기능이 계속 얹혀도 리팩터링 가능한 기준선을 확보하는것은 중요하다고 생각했고, 이런 부분을 나의 책임으로 가져가려고 했었다.
학습의 목표는 제품 코드에 옮길 기준을 만드는 것이었다
주말동안 Electron 학습부터 시작했다. 목표는 Electron과 데스크톱 앱을 마스터하는 것은 아니었다. 바닥부터 모든 것을 공부한 뒤 시작하기보다는, 필요한 부분을 빨리 배우고 제품 코드에 바로 적용하며 부족한 부분은 다시 학습하는 방식이 더 현실적이라고 판단했다.
처음 한 일은 지식을 최대한 모으는 것이었다. Electron 공식 문서, 책, GPT로 조사한 참고 링크를 모았고, 웹 프론트엔드 개발자가 Electron을 배울 때 필요한 고품질 자료를 요청했다. 단순 소개 포스팅은 제외했다. 지금 필요한 것은 “Electron이 무엇인가”보다, 웹앱 개발자가 데스크톱 앱을 만들 때 어떤 부분에서 사고방식을 바꿔야 하는가였기 때문이다.
그 자료들을 NotebookLM에 넣고 전문가 멘탈 모델과 전체 Electron 지식 그래프를 만들었다. Electron 초보인 내가 전문가처럼 질문하고 답변받기 위해 고안한 방법이었다. 돌이켜보면 이 방식은 유효했다. 자료를 많이 모으는 것보다 더 중요했던 것은, 에이전트와 대화할 때 내가 무엇을 물어봐야 하는지 알게 된 점이었다.
멘탈 모델의 핵심은 Electron을 웹앱 포장 도구가 아니라 제품 런타임으로 보는 것이었다. 아래와 같은 형태이다.
Electron은 웹 UI를 데스크톱 앱으로 포장하는 도구가 아니라, **Chromium 다중 프로세스 모델 + Node.js 권한 런타임 + preload 권한 브리지 + OS 통합 + 배포/업데이트 체계**를 하나의 제품 시스템으로 조립하는 플랫폼이다.
...
Electron 앱은 하나의 JavaScript 프로그램이 아니라, 역할과 권한이 다른 프로세스들이 협업하는 데스크톱 런타임이다.
- **Main process**는 앱의 진입점이며 앱 수명주기, 창 생성, OS API, 보안 정책, 배포 런타임 결정을 소유한다.
- **Renderer process**는 Chromium 웹 표준 위에서 UI를 그리는 격리된 웹 실행 환경이다.
- **Preload script**는 렌더러가 필요한 기능만 사용할 수 있도록 좁은 API를 노출하는 권한 변환 계층이다.
- **Utility process**는 CPU 집약 작업, 불안정하거나 격리하고 싶은 Node 작업, 별도 생명주기가 필요한 서비스를 메인 밖으로 분리하는 실행 단위다.
...
지식 그래프도 같은 방향으로 구성했다. 개별 API를 외우는 자료가 아니라, 앱을 설계할 때 어떤 노드를 같이 봐야 하는지 알려주는 지도에 가까웠다.
Electron 41 앱 전체를 의미하는 최상위 노드다. Chromium, Node.js, V8, Electron API, OS 통합, 보안 경계, 배포 체계가 결합된 데스크톱 제품 런타임으로 이해해야 한다. 단순한 “웹앱 포장 도구”가 아니라 다중 프로세스 기반의 애플리케이션 플랫폼이다.
....
Electron 앱을 여러 실행 경계로 나누어 이해하는 구조다. 권한, 생명주기, 성능, 장애 격리, 테스트 전략은 어떤 코드가 어떤 프로세스에 위치하는지에 따라 달라진다.
.....
Electron 앱의 권한과 신뢰 경계를 정의하는 노드다. renderer를 신뢰하지 않고, main의 권한을 preload와 IPC를 통해 최소한으로 노출하는 구조가 핵심이다.
자료만 읽고 제품 코드에 바로 들어가지는 않았다. NotebookLM 에게 지식 그래프와 멘탈 모델을 구성해달라고 하고, 이걸 다시 gpt에게 검토시켜서 완성했다. 질문 하는 사람에 따라서 llm은 다른 답변을 준다. 주입하는 컨텍스트도 그렇고, 틀린 부분이나 놓친 부분들 그리고 둥글게 뭉개버린 답변들에서 더 높은 수준을 답변으로 다시 요구하는 것이 빠져있기 때문이다. 이를 해결 하기 위해서 Electron 관련 질문을 할 때 완성한 지식 그래프와 멘탈 모델을 같이 줌으로써 나같은 초보자가 질문해도 수준 높은 답변을 받기 위한 레버리지 수단으로 활용 했다. 이를 바탕으로 전문가의 관점을 주입함으로써 단순 답변이 아니라, 일렉트론 전문가의 답변을 얻을 수 있게 되었다.
학습 과정
먼저 지식 그래프와 체크리스트를 보고 웹개발자가 일렉트론을 배울 때를 가정한 커리큘럼을 구성해달라고 에이전트에게 요청했고, learning-checkpoint 스킬을 만들었다. 이 스킬은 내가 정말 이해했는지 확인하기 위한 장치였다. 핵심은 아래 기준이었다.
- 사용자 발화 중심으로 판정합니다. 어시스턴트가 설명한 내용을 사용자가 따라 적은 것만으로는 숙달로 간주하지 않습니다.
- 단어를 안다와 개념을 이해한다를 구분합니다.
- 보수적으로 체크합니다. 충분한 근거가 없으면 체크하지 않습니다.
- 그래프를 따라 다음 학습을 제안합니다. 선행 개념이 비어 있으면 건너뛰지 않습니다.
- 판단 근거를 노출합니다. 어떤 표현 때문에 그렇게 판단했는지 짧게 인용/요약합니다.
...
- 이해함: 자기 말로 설명하고, 인접 개념과 구분하거나 적용 예시를 듭니다.
- 부분 이해: 정의는 알지만 작동 원리, 경계 조건, 언제 쓰는지가 비어 있습니다.
- 체크리스트의 체크는 이해함일 때만 합니다.
이 방식으로 내가 알아야 할 개념들을 빠르게 익혀나갔다.
빠르게 개발하더라도 무너지지 않게 최소 가드레일을 세웠다
주말에 배운 것을 바탕으로 실제 제품 코드에 기준을 정했다. 이때의 목표는 완성형 데스크톱 아키텍처를 만드는 것이 아니었다. 에이전트를 활용해서 빠르게 개발하더라도 나중에 유지보수할 수 있도록 구조적인 가드레일을 세우는 것이었다.
가장 먼저 정한 것은 desktop을 앱의 중심으로 키우지 않는 것이었다. Electron을 쓰다 보면 main process와 preload, IPC 쪽에 권한이 있기 때문에 제품 흐름까지 그쪽으로 빨려 들어가기 쉽다.
처음에는 그게 빨라 보일 수 있다. 하지만 나중에는 화면의 의미와 네이티브 실행 경계가 섞여서 어디를 고쳐야 하는지 알기 어려워질 것 같았다.
그래서 제품 코드에 옮긴 최소 기준은 대략 이랬다.
desktop은 native lifecycle과 OS 권한을 안전하게 실행하는 경계로 둔다.- 실제 제품 흐름과 화면의 의미는
renderer쪽이 갖는다. preload는 렌더러에 필요한 capability만 좁게 노출한다.IPC는 임시 이벤트 통로가 아니라 typed contract로 다룬다.
이것은 거창한 아키텍처 선언이라기보다, “적어도 여기에 이런 책임을 넣으면 안 된다”는 최소 금지선에 가까웠다.
동시에 에이전트가 매번 대화 안에서만 이 기준을 배우게 두면 안 된다고 생각했다. 대화가 바뀌면 기준도 쉽게 사라지기 때문이다.
그래서 desktop, frontend, design-system 같은 도메인 규칙을 저장소 안의 문서와 스킬로 두고, 작업 전에 먼저 읽게 하는 방식의 초기 하네스를 만들기 시작했다. 아직 완성된 운영체계는 아니었다. 그래도 빠르게 개발하는 상황에서 같은 기준을 반복해서 만나게 만드는 첫 장치였다.
프론트엔드 구조를 늦게 잡은 실수
처음에는 프론트엔드 구조는 조금 늦게 잡아도 된다고 생각했다. 구조 개편 자체는 에이전트에게 시키면 하루 안에도 가능해 보였기 때문이다.
그러나 내가 놓친 것은 코드 분량이 아니라 우리 팀에서 일하는 방식이었다. 한 사람이 기능을 처음부터 끝까지 개발하고 있고, 이미 여러 기능이 동시에 개발되고 있었고, 각자 브랜치에서 계속 변경이 쌓이고 있었다. 이 상황에서는 내 브랜치에서 구조를 바꾸고 푸시하는 것으로 끝나지 않는다. 프론트 전체 리팩토링 변경은 모든 팀원들의 코드 충돌을 만들어 버릴 것이기 때문이다.
그러나 안할 수는 없었다. 이미 도메인로직, 라우터로직, 데스크탑 앱표면별 분기 처리 등등이 한 App.tsx에 얽혀서 간단한 기능 수정도 충돌을 일으키고 있었다. 지금까지는 모델 성능에 기대어 머지 할 때마다 충돌을 해결해 달라는 식으로 해결은 되었는데, 이게 생산성을 많이 떨어트리고 있었고, 코드 자체도 이미 많이 망가져 있었다. 결국 리팩토링은 필수적으로 해야하는 것이었고, 그 구조와 방식을 고민하기 시작했다.
구조를 크게 바꾸려면 한 번 형상을 고정해두고, 리팩토링이 끝난 뒤 그 형상을 기준으로 다시 개발을 이어가야 했는데, 일정상 다른 팀원들에게 개발을 멈춰달라고 할 수는 없었다.
그래서 전면 중단 후 대규모 재작성으로 가지 않았다. 병렬 개발을 살려둔 상태에서 기준을 먼저 만들고, 도메인별로 점진 이행하는 방식을 택했다.
구조는 host-slot 아키텍처로 구성했다. 우리 팀은 에이전트를 최대한 활용해서 한 명이 하나의 기능을 책임지고 만들기 때문에, 에이전트를 활용하기 좋고, 하나의 기능 수정을 기능 단위로 격리 할 수 있어서 충돌에도 매우 용이했다. 앱 표면이 많은 데스크탑 앱에 적절한 구조라고 판단하였다.
리팩토링 과정
먼저 app, host, routes, domains, platform, shared 같은 큰 골격과 리팩토링 가이드를 만들었다.
중요한 것은 폴더 이름이 아니라 작업 순서였다.
- 한 번에 하나의 도메인만 옮겼다.
- 초반에는
App.tsx를 크게 해체하지 않았다. model -> api -> query -> ui -> route순서로 옮기며 변경 단위를 작게 잘랐다.- 설정 기능을 첫 샘플로 옮겨 새 구조가 실제 기능 하나를 수용할 수 있는지 먼저 확인했다.
- 머지 이후에는 병렬 개발 중 들어온 변경을 무조건 되돌리지 않았다.
- 기능은 살리되,
App.tsx를 다시 비대하게 만드는 inline 구현은 막았다. - 아직 새 구조로 옮길 준비가 안 된 것은 억지로
domains에 넣지 않고legacy로 격리했다.
이렇게 하니 개발을 멈추지 않으면서도, 공통 영역에서만 충돌을 조정하고 나머지는 기능 단위로 계속 진행할 수 있었다.
성과
이 리팩토링의 성과는 전, 중, 후를 나눠서 보면 더 분명했다.
| 구간 | 의미 | 100커밋당 충돌성 커밋 | App.tsx 터치 | sidebar/index.tsx 터치 | 구조화된 영역 변경 |
|---|---|---|---|---|---|
| 2026-04-01 ~ 2026-04-15 11:26 | 기준 수립 전 | 10.0 | 43 | 8 | 3/90, 3.3% |
| 2026-04-15 11:26 ~ 2026-04-28 | 전환/충돌 흡수기 | 1.55 | 64 | 22 | 365/453, 80.6% |
| 2026-04-29 ~ 2026-06-13 | 안정화 이후 | 0.29 | 0 | 0 | 655/689, 95.1% |
기준 수립 전에는 변경이 App.tsx와 sidebar/index.tsx에 몰려 있었고, 병렬 개발을 할수록 공통 파일에서 충돌이 생기기 쉬운 구조였다. 전환기에는 기존 기능 개발을 멈추지 않은 상태에서 충돌을 흡수하며 host / domains / routes / platform 구조로 책임을 옮겼다. 안정화 이후에는 100커밋당 충돌성 커밋이 10.0건에서 0.29건으로 줄었고, 기존 병목 파일 터치도 0건으로 수렴했다.
실수로부터 배운 것
돌이켜보면 처음부터 프론트와 데스크톱 아키텍처를 같이 생각했어야했고, 좀 더 아키텍처를 강하게 제약해서 에이전트가 판단없이도 그대로 따르게 하는 구조로 구성하는게 좋을 것 같다.
이미 너무 커져버린 도메인들과 사라지지 않고 굳어진 legacy 폴더가 남았다. 기능 개발 속도를 완전히 늦출 수는 없어서 이후에 계속 갚아야 하는 부채로 남겨야 했다.
이 때부터 에이전트가 같은 기준으로 일하게 만드는 일이 더 중요해졌다고 느꼈다. 백엔드와 프론트엔드를 나눠 각자 맡는 방식에서 벗어나 한 사람이 데이터 흐름부터 화면까지 기능 단위로 끝까지 책임 되게 되었는데, 그러면서 맡는 사람에 따라서 품질 수준에 차이가 많았다.
- 백엔드에 익숙한 사람은 백엔드 코드의 품질이 좋고, 프론트는 경계를 넘거나 버그를 많이 만들었다.
- 프론트에 익숙한 사람은 그 반대가 되었다.
에이전트 주도 개발에서는 정해진 구조를 계속 따르게 만드는 장치가 필요하다는 것을 다시 느꼈다. 그래서 출시 후의 관심은 “어떻게 더 빨리 만들까”보다 “빠른 출시 흐름을 유지하면서도 기준이 무너지지 않게 하려면 어떻게 해야 할까”로 옮겨갔다. 문서화, 자동문서화, 작업 메모리, 검증 게이트, 스킬 하네스 같은 것들이 이 문제의 연장선에서 나왔다. 기준을 한 번 세우는 것과 그 기준을 계속 지키게 만드는 것은 다른 일이었다.
에이전트 개발에는 기준을 유지하는 일이 중요하다.
에이전트는 분명히 속도를 높여줬다. AI가 없었다면 같은 기간에 이 정도의 산출물을 만들기는 불가능 했을 것이다.
하지만 에이전트가 판단까지 대신해준 것은 아니었다. 무엇을 먼저 배울지, 어떤 경계를 제품 코드에 심을지, 어디까지를 첫 배포 전에 하고 어디부터는 이후 과제로 둘지는 결국 사람이 판단해야 했다. 오히려 에이전트 때문에 개발 속도가 빨라졌기 때문에, 기준이 없는 곳에 부채가 쌓이는 속도도 같이 빨라졌다.
그래서 에이전트를 활용한 개발에서 중요한 것은 에이전트가 같은 기준을 읽고, 같은 경계를 지키고, 작업 결과를 다시 검증하게 만드는 일이다. 빠르게 만들더라도 무너지지 않게 하려면, 코드의 구조뿐 아니라 그 구조를 계속 유지하게 만드는 문서와 스킬, 검증 흐름까지 함께 다뤄야 한다. 이번 2주는 그 사실을 가장 강하게 배운 시간이었다.
