[당근/회고] 인턴 출근 4주차 회고

Nayoung·2026년 5월 30일

당근

목록 보기
5/9

문제되는 내용이 포함되어 있을 경우 수정/삭제 하겠습니다.


회사 노션에 매일 업무 일지와 회고를 적고있는데 블로그에 올려둘 회고글이 많이 밀렸다.
노션의 개인 회고글을 블로그 용으로 붙이면서 내용을 다시 읽으니 새록새록 다시 배움도 정리할 수 있고 나쁘지 않은 것 같다.


🌱 4주차 회고 (2026.05.03)

돌아보기

테크스펙 마무리와 칭찬

이번 주는 오버레이 비동기 큐잉 시스템 테크스펙을 마무리짓고 공유한 주였다. 월요일에 버디의 피드백을 받아 기존 설계와 비교해 테크스펙을 보강하고 팀에 공유드렸는데 칭찬받아따! 팀원 분이 "설계 너무 좋다"고 해주셨고, 버디는 준비되면 위클리에서도 발표해보라고 격려해주셨다! 너무 기뻤다🥕

특히 단순한 결과물 칭찬뿐 아니라 이런 설계가 나오기까지의 사고 과정 자체에 팀원 분이 관심을 보여주셨는데, 그게 제일 좋았다. 추상화 단위를 끌어올린 결정이 단순히 구현 선택이 아니라 문제 재정의의 결과로 잘 전달됐구나 싶었다. 기존 설계를 "다른 방식"이 아닌 "기반 위에 확장하는 형태"로 포지셔닝한 것도 다행이었다. 내가 설계한 이 오버레이 비동기 큐잉 시스템이 구체적으로 우리 도메인의 어떤 복잡성을 풀었는지 추후 블로그에 기술적으로 더 풀어볼 예정이다.


Promise와 이벤트 루프의 재발견

구현 단계로 넘어가면서 JS의 비동기 동시성 메커니즘을 다시 깊게 파본 주이기도 했다. 오버레이 비동기 큐잉은 결국 Promise의 pending/settled 상태머신을 바깥으로 빼내어 그대로 활용하는 구조라, Promise 와 오버레이의 active 상태를 정확히 매칭하려면 이벤트 루프와 실행 컨텍스트의 세세한 동작과 정확한 타이밍을 제대로 알고 있어야했다.

원래 대충 이렇게만 알고 있었다. 동기 코드가 먼저 실행되고, await 을 만나면 async 함수가 콜스택에서 빠졌다가 Promise가 settled되면 다시 돌아와서 나머지가 실행된다 정도. 근데 구현하다보니 세부에서 모호한 지점이 등장했다.

  • "콜스택이 비워진다"는 기준이 정확히 뭐지? 전역 실행 컨텍스트까지 제거되는 순간이라면, 그럼 함수의 환경정보도 사라지는 채 어떻게 변수를 유지해서 다시 이어서 실행되는 거지?
  • await 이후 라인의 코드는 정확히 언제, 어느 사이클에 다시 실행되는 거지? 마이크로태스크 큐와 매크로태스크 큐가 각각 한 번씩 비워지고 나서 다음 사이클에?

우선 이 질문들을 분해해가며 ECMAScript 명세와 실제 엔진 동작까지 파보면서 개념을 확실히 정리했다.

  • 콜스택 "empty"의 명세적 기준: 전역 동기 스크립트의 평가가 끝나면 스크립트 컨텍스트도 스택에서 명시적으로 제거된다. 명세상 "콜스택이 비었다"는 건 전역 실행 컨텍스트까지 빠진 상태를 뜻한다.
  • 데이터 유지의 정체 — 렉시컬 환경: 실행 컨텍스트가 콜스택에서 모두 사라져도 누군가 참조하고 있는 이상 메모리 힙의 렉시컬 환경은 살아 있고, 이게 클로저의 정체다. 이전에는 "실행 컨텍스트 = 렉시컬 환경"으로 생각하고 있었는데, 둘이 다른 레이어에 존재한다는 걸 명확히 구분하게 됐다.
  • Job은 "빈 스택"에서 시작한다: await 이후 코드는 원래 함수 컨텍스트가 그대로 스택에 남아 있어서 이어 실행되는 게 아니고, await에서 suspend됐던 바로 그 동일한 실행 컨텍스트가 resume되며 다시 push된다. 전역 컨텍스트가 다시 들어오는 게 아니다. 이 지점에서 직관과 제일 상충하는데, "모든 함수 컨텍스트는 전역 컨텍스트 위에서 실행된다"는 통념은 동기 코드 한정으로만 맞다는 것을 알게 됐다.
  • await 이후 코드의 실행 시점: 마이크로태스크 단계에서 실행된다. 다음 매크로태스크 사이클을 기다리지 않고 현재 사이클의 동기 코드가 끝난 직후 마이크로태스크 큐를 전부 비우는 시점에 끌려든다. 매크로태스크는 그 뒤에야 차례가 온다.

이 마지막 포인트가 큐잉 시스템 구현에서 queueMicrotask(process)를 쓴 이유와 직결되는 게 재밌었다. 매크로태스크로 미루면 그 사이에 다른 태스크가 끼어들 수 있지만, 마이크로태스크로 미루면 같은 동기 태스크에 들어온 모든 reserve 호출을 한 번에 정렬해 처리하는 게 보장된다. 설계와 JS 엔진 동작이 그대로 맞닿는 느낌이었다.


구현 시작과 AI 활용

프로미스와 async/await을 머릿속으로 정리했다고 구현이 쉬워지는 건 아니었다. 이벤트 루프가 우아하게 처리해주는 영역이 있지만, 우선순위대로 정렬하고 선점과 임계 권한을 넘겨주는 스케줄링은 직접 구현해야 했다. 동시성 프로그래밍 이론적으로 더 정교하게 해보고 싶어서 법카로 동시성 프로그래밍 책까지 샀는데, 학습한 개념과 JS 코드로의 구현이 아직 시원하게 연결되지는 않는 느낌이다.

대신 이번 주 수요일 구현을 시작하면서 좋은 러닝이 하나 있었다. 테크스펙을 자세히 쓰고 구현 Plan을 마크다운으로 촘촘히 세워서 에이전트 AI에게 맡겼더니 한 번에 꽤 괜찮은 출력이 일관되게 나왔다는 것이다.

목요일에는 PR 올리고 리뷰까지 받았다.


정리

이번 주에 주로 한 일은 오버레이 큐잉 시스템 테크스펙을 마무리짓고, JS 비동기 동작을 명세 레벨까지 파고든 뒤 실제 구현과 PR까지 올린 일이었다.

잘한 점

  • 기존 오버레이 설계를 참고해 테크스펙을 보강하고 공유해 칭찬받았다. 단순 결과물뿐 아니라 문제 재정의에 이르기까지의 사고 흐름 자체에 팀원이 관심을 보여주셨다는 점이 특히 기분 좋았다.
  • 구현 중에 await 이후 실행 시점, 콜스택과 렉시컬 환경의 관계, Job이 빈 스택에서 시작한다는 명세적 구조까지 정리했다. 설계의 근거와 흐름을 스스로 확신하게 되는 과정이었다.
  • 테크스펙과 Plan을 촘촘히 쓴 다음 에이전트에게 구현을 맡겨보면서, 설계에 시간을 많이 투자하면 구현은 정말 빨리 끝난다는 걸 체감했다.
  • 기후캠페인 코드를 사이드이펙트 없이 깔끔하게 걷어냈다. 구현 당시에 세웠던 가장 강한 목표였던 '한번에 깔끔히 걷어질 수 있는 코드'가 달성된 셈이다.

아쉬운 점

  • 구현을 시작하고 보니 설계 단계에서 잡았다고 생각한 것보다 직접 스케줄링해야하는 부분이 많았다. Promise의 이벤트 루프만 활용하면 로직이 아주 심플해질 줄 알았는데 그렇진 않았다.
  • 동시성 프로그래밍 책을 샀지만 학습한 개념과 JS 구현이 아직 시원하게 연결되지는 않는다. 괜히 복잡도만 키우는 건 아닌지 찜찜하다.
  • 테크스펙을 아이디어 단계까지 단단히 잡아둔 것은 좋았는데, 실제 코드베이스의 복잡도 (세부 플래그, 여러 트리거 훅 등)을 설계 단계에서 더 깊게 인지했으면 좋았을 것 같다.
  • 문화의 날 등 고정 일정 때문에 실제 업무 시간이 적은 날에 진척이 잘 안 나갔다.

다음 주 개선 방향

  • 설계 단계에서 코드베이스의 실제 복잡도(트리거 훅의 세부 status flag, 관련 프로세스의 연관 흐름 등)까지 더 꼼꼼히 인지하고 설계하기.
  • 구현하는 동안 동시성 프로그래밍 이론은 따로 시간을 빼서 읽기보다 이번에 마주한 구현 이슈들(선점, 임계, 제개)과 엮어서 필요한 만큼만 참고하는 방향으로 가자. 책은 제대로 읽으려면 오히려 복잡도를 키울 수 있다.
  • 고정 일정이 많은 날에도 할당치를 다해낼 수 있는 일 배분 방식을 고안해보기. 야근을 보완으로 쓰기보다 업무 시간 내의 밀도를 올리는 쪽으로 노력하는 것이 예측 가능한 인력이 되는 가장 중요한 방법이라고 생각이 든다.
profile
문제의 근본적인 원인을 탐구하고 해결하는 것을 좋아하는 프론트엔드 개발자, 진나영입니다!

0개의 댓글