뒤로가기
프론트엔드 아키텍처는 누가 결정하는가

October 7, 2021

frontendcareer

우리 팀에는 아키텍트가 없다. 공식적으로 "프론트엔드 아키텍처를 결정하는 사람"이라는 역할은 존재하지 않는다. 그런데 아키텍처 결정은 매일 일어난다. 폴더 구조를 어떻게 잡을지, 상태 관리를 뭘로 할지, API 호출 레이어를 어디에 둘지, 에러 처리 패턴을 어떻게 통일할지. 이런 결정들이 코드베이스의 형태를 만든다.

문제는, 이 결정들이 "결정"의 형태로 이루어지지 않는다는 거다.

먼저 머지하는 사람이 이긴다#

현실은 이랬다. 누군가 새로운 기능을 만들면서 특정 패턴을 도입한다. PR이 올라오고, 리뷰어가 "LGTM"을 누르고, 머지된다. 다음에 비슷한 기능을 만드는 사람이 코드를 참고하면서 자연스럽게 같은 패턴을 따른다. 몇 번 반복되면 그게 "팀의 패턴"이 된다.

아무도 이걸 결정한 적 없다. 회의도 없었고, 문서도 없었고, 합의도 없었다. 단지 처음에 머지된 코드가 기정사실이 된 것뿐이다.

이게 잘 돌아가는 경우도 있다. 팀원의 실력이 고르고, 암묵적으로 공유하는 기준이 비슷하면 큰 문제 없이 흘러간다. 하지만 팀이 커지거나 새로운 사람이 들어오면 균열이 생긴다.

한번은 이런 일이 있었다. 프로젝트 내에서 API 호출 방식이 세 가지였다. 한 사람은 fetch를 직접 래핑해서 쓰고, 다른 사람은 axios 인스턴스를 만들어서 쓰고, 또 다른 사람은 React Query의 queryFn 안에 바로 fetch를 넣어서 쓰고 있었다. 셋 다 동작한다. 셋 다 나름의 이유가 있다. 하지만 코드베이스를 처음 보는 사람 입장에서는 혼란 그 자체다.

"왜 이 방식이에요?"라고 물으면 대답은 항상 비슷했다. "원래 이렇게 되어 있어서요." 원래라는 게 언제부터인지, 누가 정한 건지는 아무도 모른다.

결정의 부재가 만드는 비용#

이런 상태가 지속되면 눈에 보이지 않는 비용이 쌓인다.

온보딩 비용. 새로운 팀원이 들어올 때마다 "이건 왜 이래요?"라는 질문에 답해야 한다. 일관된 패턴이 없으니 문서화도 불가능하다. "이 폴더에서는 A 방식이고, 저 폴더에서는 B 방식인데, 최근 것은 C 방식으로 가고 있어요"라는 식의 구두 설명을 매번 반복한다.

의사결정 피로. 매번 코드를 쓸 때마다 "이걸 어떤 방식으로 하지?"를 고민해야 한다. 팀 컨벤션이 명확하면 생각 없이 따르면 되는 것들을, 매번 판단해야 한다. 사소해 보이지만 하루에 열 번씩 이런 판단을 하면 실제 비즈니스 로직에 쓸 에너지가 줄어든다.

코드 리뷰에서의 불필요한 논쟁. 기준이 없으니 코드 리뷰가 취향 싸움이 되기 쉽다. "저는 이 방식이 더 깔끔하다고 생각하는데요"라는 코멘트에 "저는 이 방식이 더 직관적이라고 보는데요"라는 답이 달린다. 둘 다 틀리지 않았다. 기준이 없기 때문에 뭐가 맞는지 판단할 근거도 없다.

Pragmatic Engineer 블로그에서 읽은 내용이 떠올랐다. 엔지니어링 조직에서 기술적 의사결정이 암묵적으로 이루어지면, 그 결정의 맥락이 사라진다는 거다. 왜 A가 아니라 B를 선택했는지, 당시 어떤 제약 조건이 있었는지, 어떤 대안을 검토했는지. 이런 맥락 없이 코드만 남으면, 나중에 그 결정을 뒤집어야 할 때도 근거가 없다. "왜 이렇게 했는지 모르니까 건드리지 말자"가 된다.

ADR이라는 걸 알게 되다#

ADR(Architecture Decision Record)을 처음 접한 건 기술 블로그를 읽다가였다. 개념은 단순하다. 아키텍처에 관한 결정을 내릴 때, 그 결정의 배경, 고려한 대안, 선택의 이유, 예상되는 결과를 문서로 남기는 거다.

형식은 간단하다.

markdown
# ADR-001: API 호출 레이어 통일

## 상태
승인됨 (2025-09-15)

## 맥락
현재 프로젝트 내에서 API 호출 방식이 fetch 래퍼, axios 인스턴스,
queryFn 직접 호출   가지로 혼재되어 있다.
새로운 팀원의 온보딩  혼란을 유발하고 있다.

## 결정
모든 API 호출은 /api 디렉토리의 함수로 정의하고,
컴포넌트에서는 React Query를 통해서만 서버 데이터에 접근한다.
HTTP 클라이언트는 fetch를 기본으로 하되,
인터셉터가 필요한 경우 래퍼 함수를 사용한다.

## 대안
1. axios 인스턴스 통일 - 번들 사이즈 고려로 기각
2. 현상 유지 - 혼란 지속으로 기각

## 결과
- 기존 코드는 새로 작성하거나 수정할  점진적으로 마이그레이션
- 신규 코드는 반드시  패턴을 따름

이걸 읽고 "우리 팀에 필요한 게 정확히 이거다"라고 생각했다. 결정 자체보다 "결정의 기록"이 중요하다는 관점이 신선했다.

팀에 제안했을 때의 반응#

다음 주 회고에서 ADR을 제안했다. 반응은 내 예상과 많이 달랐다.

첫 번째 반응은 침묵이었다. 팀 리드가 "그거 좋은 생각인데"라고 했지만, 나머지 팀원들은 표정이 애매했다. 한 시니어가 질문했다. "그걸 누가 작성해요?" 또 다른 사람은 "문서를 또 쓰라고요? 코드 짜기도 바쁜데?"라고 했다.

예상했어야 했는데, 솔직히 이 반응에 좀 상처받았다. 팀의 문제를 해결하자는 건데 왜 귀찮다는 반응이 먼저 나올까.

며칠 후 시니어와 1:1에서 이 얘기를 다시 꺼냈다. 시니어가 솔직하게 말해줬다. "취지는 좋은데, 문서를 쓰는 게 개발자한테는 진입 장벽이 높아. 코드 리뷰는 무조건 해야 하니까 하는 거지, 문서는 안 써도 당장 뭐가 달라지지 않으니까." 그리고 덧붙였다. "한 번에 프로세스를 바꾸려고 하면 안 돼. 니가 먼저 몇 개 써봐. 그게 유용하다는 걸 보여주면 자연스럽게 따라온다."

혼자 시작하기#

시니어의 조언을 따랐다. 팀 전체에 "앞으로 ADR 씁시다"라고 선포하는 대신, 조용히 혼자 시작했다.

마침 프로젝트에서 에러 바운더리 전략을 정해야 하는 시점이었다. 페이지 레벨에서 잡을지, 컴포넌트 레벨에서 잡을지, 어떤 에러는 무시하고 어떤 에러는 폴백 UI를 보여줄지. 이걸 그냥 코드로 구현하는 대신, 먼저 ADR을 작성했다.

배경, 세 가지 대안, 각 대안의 장단점, 최종 선택과 이유. A4로 한 장 반 정도. 이걸 PR에 함께 올렸다. "에러 바운더리 구현인데, 왜 이 방식을 선택했는지 ADR로 정리했습니다."

의외의 일이 벌어졌다. 코드 리뷰 코멘트가 구현 디테일이 아니라 ADR에 달렸다. "대안 2번의 단점에서 이 부분은 좀 다르게 볼 수도 있지 않나요?"같은 코멘트. 코드에 대한 논쟁이 아니라, 결정에 대한 논의가 이루어졌다. 이게 완전히 다른 대화였다.

한 팀원이 슬랙에서 말했다. "ADR 덕분에 왜 이런 구조인지 코드 안 봐도 이해가 됐다. 리뷰하기 편했다." 이게 첫 번째 성공이었다.

천천히 퍼지다#

두 번째 ADR은 이미지 최적화 전략에 대한 것이었다. 세 번째는 폼 상태 관리 패턴에 대한 것. 이쯤 되니 팀원 한 명이 자기가 맡은 기능에서도 ADR을 써봤다. "비슷한 형식으로 쓰면 되는 거죠?"

두 달쯤 지나자 ADR이 10개가 됐다. 이때부터 진짜 효과가 나타났다.

새로운 팀원이 입사했을 때, "이 프로젝트 구조는 왜 이래요?"라는 질문에 "ADR 폴더를 먼저 읽어보면 흐름이 이해될 거예요"라고 말할 수 있게 됐다. 예전에는 커피 한 잔 놓고 30분씩 구두 설명을 해야 했던 것들이다.

코드 리뷰에서의 논쟁도 줄었다. "이거 왜 이렇게 했어요?"라는 질문에 "ADR-007 참고해주세요"로 끝나는 경우가 생겼다. 결정의 맥락이 기록되어 있으니, 같은 논의를 반복하지 않아도 된다.

기존 결정을 뒤집어야 할 때도 근거가 생겼다. 6개월 전에 A를 선택한 이유가 "당시에는 서버 컴포넌트 지원이 불안정해서"였는데, 지금은 안정화됐다면 그 근거가 사라진 거다. ADR에 "폐기됨: ADR-012로 대체"라고 쓰면 된다. 결정이 바뀌는 과정까지 추적할 수 있다.

실패한 것들#

전부 성공적이었다고 하면 거짓말이다.

너무 많이 쓰려고 했다. 초반에는 사소한 결정까지 ADR로 남기려고 했다. "버튼 컴포넌트의 기본 패딩 값"같은 것까지. 이건 오버킬이다. ADR은 뒤집기 어려운 결정, 팀 전체에 영향을 미치는 결정에만 쓰는 게 맞다. 사소한 건 코드 컨벤션 문서로 충분하다.

형식에 집착했다. 초반에 ADR 템플릿을 너무 정교하게 만들었다. 필수 항목 10개짜리. 아무도 이 템플릿을 쓰고 싶어하지 않았다. 나중에 세 항목으로 줄였다. 맥락, 결정, 이유. 이것만 있으면 충분하다. 형식보다 내용이다.

합의를 강제하려 했다. 모든 ADR에 팀 전원의 승인을 받으려고 했는데, 현실적으로 어려웠다. 일정에 쫓기는 팀원이 "바빠서 못 봤는데 그냥 진행하세요"라고 하면 그게 합의인가 아닌가. 결국 "작성자 + 리뷰어 1명"이면 충분하다는 현실적인 기준으로 바꿨다.

결국 사람의 문제다#

ADR을 도입하면서 깨달은 건, 기술적 의사결정의 문제는 결국 기술의 문제가 아니라 커뮤니케이션의 문제라는 거다.

"먼저 머지하는 사람이 이기는" 구조가 나쁜 건, 그 결정이 나쁘기 때문이 아니다. 그 결정에 참여하지 못한 사람이 있기 때문이다. 좋은 코드를 머지한 것과, 합의된 코드를 머지한 것은 다르다. 전자는 개인의 능력이고, 후자는 팀의 역량이다.

ADR은 도구일 뿐이다. 중요한 건, 결정을 투명하게 만들고, 맥락을 공유하고, 누구나 의견을 낼 수 있는 구조를 만드는 거다. ADR이 아니라 슬랙 스레드여도 되고, 노션 페이지여도 된다. 형태는 중요하지 않다. "왜 이렇게 했는지"가 어딘가에 남아 있는지가 중요하다.

아키텍트가 없는 팀에서 아키텍처를 결정하는 건 누구인가. 결론은 팀 전체다. 하지만 "팀 전체"가 결정에 참여하려면, 결정이 눈에 보여야 한다. 보이지 않는 결정에는 참여할 수 없다.

우리 팀은 지금도 아키텍트가 없다. 하지만 아키텍처 결정은 더 이상 우연히 일어나지 않는다. 여전히 완벽하지는 않지만, 적어도 "이걸 왜 이렇게 했는지"를 물었을 때 "모르겠다"가 아닌 답을 할 수 있게 됐다. 그게 작은 차이 같지만, 팀의 일하는 방식을 완전히 바꿔놓은 차이였다.