
원문: https://ducin.dev/what-is-frontend-architecture
시스템을 고려할 때, 기술 선택에 대해 먼저 생각하지 마세요. 대신 여러분이 시스템에 원하는 바람직한 특성들에 대해 먼저 생각하세요. 기술 선택은 그저 이러한 특성들을 실현하는 수단일 뿐입니다.
면책 조항: 단순히 코드 작성에만 관심이 있으신 분들은 이 글이 도움이 되지 않을 수 있습니다 😉
프런트엔드 커뮤니티는 한 가지 문제를 겪고 있습니다 😉 라이브러리, 프레임워크, 번들러, GitHub 스타 수… 그리고 다른 여러 중요하지 않은 것들에 집중하는 경향이 있습니다. 우리는 특정 도구를 맹목적으로 좋아하고(2015–2016년의 Redux처럼) 그것을 과도하게 사용하곤 합니다.

그리고는 돌변해서 같은 이유로 그 도구를 완전히 미워합니다. (최근의 Redux처럼 말입니다) 사랑했다가 미워하는 이런 모습은 이해하기 어렵습니다… 왜 이런 경향이 나타나는 걸까요? 🤨
“문제”는 대부분의 프런트엔드 개발자들이 다른 곳에 집중하느라 소프트웨어 아키텍처에 관한 지식과 스킬이 부족하다는 점입니다. 그리고 이러한 스킬은 프로젝트의 장기적인 성공을 위해 반드시 필요합니다(필수조건은 아니지만). 왜냐하면 아키텍처는 눈에 잘 보이지는 않지만 비즈니스와 기술적 관점 모두에서 중요한 것들을 연결하는 다리이기 때문입니다.
개발자 교육 프로그램, 컨설팅이나 팀 리더를 채용하거나 하는 과정에서 저는 이런 질문을 하곤 합니다. 소프트웨어 아키텍처가 무엇인지 어떻게 이해하고 계신가요? 가장 중요한 측면은 무엇이고, 무엇을 주의해햐 하며, 어떻게 적절하고 안정적인 시스템 설계를 제공할 수 있을까요? 그리고 아키텍트의 역할은 무엇인가요?
글을 더 읽기 전에, 잠시 멈춰서 스스로 대답해봅시다 😉…
똑 딱 똑 딱 ⏰…
이 질문은 의도적으로 매우 광범위하게 던진 것입니다. 제 대화 상대자가 자유롭게 본인들이 중요하게 여기는 것을 말할 수 있도록 말이죠. 저는 어떤 것도 가정하지 않습니다. 하지만 답변이 (프런트엔드) 아키텍처는 우리가 어떻게 디렉토리와 파일을 구조화 하는 것입니다- […] 와 같은 말로 시작하면 저에겐 즉각적인 경고 신호 🟥 입니다. 그리고 예상하셨듯이, 이 글을 쓰게 된 동기가 바로 또 다른 누군가가 위와 같은 말을 했기 때문입니다 😉.
독자 여러분, 제 의도는 여러분의 관점을 전환시키는 것입니다. 아키텍처를 다른 관점에서 바라보도록 영감을 주고 싶습니다. 여러분의 저장소에서 보이는 구조나 코드의 특정 솔루션들로부터 한 발 떨어져서, 시스템이 어떤 특성을 가져야 하는지에 대해 생각해보세요. 더 넓은 관점에서 어떤 능력이 필요할지 생각해보세요. 도구 자체보다는 그 도구를 사용함으로써 생기는 트레이드오프에 집중해보세요. 그리고 마지막으로 빼놓을 수 없는 것은, 비즈니스 관점에서 어떤 소프트웨어 능력이 필요한지 생각해보는 것입니다.
목차
- (프런트엔드) 아키텍처란 무엇인가요?
- 결정
- 결정 요인 (Drivers)
- 트레이드오프
- 제약사항
- 요약
- 그래서 다시 말하자면, 아키텍처를 이루는 것은 무엇인가요?
- 왜 디렉토리 구조가 아키텍처로 간주되면 안되는 건가요?
- 디렉토리 구조가 우리에게 알려주지 않는 것
- 프런트엔드 아키텍처에 대한 올바른 이해 구축
- 입력은 무엇이고 어디에서 얻을 수 있나요?
- 개발 관점에서 살펴보기
- 도구 결정 vs 아키텍처 결정
- 요약
- 추천 자료
(프런트엔드) 아키텍처란 무엇인가요?
그래서 이런 트윗을 작성했습니다. 😅

알아두시면 좋을 것: 폴더 구조는 아키텍처가 아닙니다 (그리고 지금까지도 그랬던 적이 없습니다)
댓글 중 어딘가에서 제가 생각하는 아키텍처가 무엇이냐는 질문을 받았습니다. 답변을 간단하게 해보겠습니다.
오늘날 당신의 시스템을 형성하고 미래에 변경하기 어려운, 비즈니스 요구사항에 따라 내리는 결정들
사실, 소프트웨어 아키텍처에 대한 단 하나의 정의는 없습니다. 마틴 파울러의 소프트웨어 아키텍처 가이드를 강력하게 추천드립니다. 다른 정의들로는 다음과 같은 것들이 있습니다.
프로젝트 초기에 제대로 하고 싶은 결정들
또는
아키텍처는 중요한 것에 대한 이야기입니다. 그 ‘중요한 것’이 무엇이든 말이죠.
이 단어에 주목하세요: 중요한
그리고 다른 단어인 결정들도 주목해보세요.
예시들로 넘어가기 전에 (글 후반부에서) 기본적인 것들부터 시작해보겠습니다.
결정
우리는 프로젝트의 생애 주기동안 많은 것들을 결정해야 합니다. 언어/플랫폼, 라이브러리, 패러다임, 코딩 스타일… 탭이냐 스페이스냐… 🤔 하지만 다음과 같은 것들도 고려해야 합니다. 비즈니스 우선순위와 요구사항을 어떻게 충족시킬 것인지, 수십 명의 개발자들이 동일한 시스템에서 작업할 수 있게 하는 방법, 빈번한 배포(매일, 매 시간, 금요일 포함)를 가능하게 하는 방법 등이 있습니다.
네, 보시다시피 이 주제들은 그다지 중요하지 않은 것부터 절대적으로 필수적인 것들까지 다양합니다. 우리가 분석하고 결정하는 관점들은 서로 다른 중요도를 가집니다. 개발자들의 경험이 많을수록, 실제로 중요하지 않은 것들에 에너지를 투자하는 것을 피하려 할 가능성이 높습니다.
특히, 그 결정이 쉽게 되돌릴 수 있는 것이라면 더욱 그렇죠.
그렇다면 어떻게 특정한 결정이 올바른지 평가할 수 있을까요?
결정 요인 (Drivers)
의심이 생길 땐 한 발 떨어져서 더 큰 시야에서 바라보는 것이 좋습니다. 그리고 이런 시야는 다음과 같은 질문들을 포함합니다.
- 비즈니스의 가장 중요한 우선순위는 무엇인가요?
- 우리가 고려해야 할 제약사항들은 무엇인가요?
- 우리가 포기할 수 있는 것들(선택적인 목표)은 무엇이고 포기할 수 없는 것들(필수적인 목표)은 무엇인가요?
아키텍처 결정 요인은 우리로 하여금 매우 특정한 프로젝트의 구체적인 맥락을 깊이 파고들게 만드는 요소들입니다. 이는 특정 상황에서 이론적인 장점이나 단점이 중요한지 아닌지를 평가하는 프로젝트의 맥락이라고 생각하면 됩니다.
아키텍처 결정 요인은 매우 다양합니다.
- 응답 시간: 시스템은 매우 빠르게 응답해야 함
- 트래픽: 대규모의 요청을 처리해야 함
- SLA/HA: 가동 시간이 ~99.99%여야 함
- 조직 규모: 수십 또는 수백 명의 개발자들이 개발해야 함
- 진입 장벽: 덜 숙련된 개발자들도 쉽게 습득할 수 있어야 함
- TTM(Time To Market): 비즈니스 상황(어떤 것이든)으로 인해 기능 제공이 아주 빨라야 함
비즈니스 환경에서, 결정 요인들은 항상 존재합니다. 대부분 여러분 회사의 비즈니스 담당자들이 “결정 요인”이라는 단어를 직접적으로 사용하지는 않지만, 이를 직접적으로 표현하고 있을 것입니다. 이러한 결정 요인들을 파악하지 못하면 잘못된 것들에 집중할 수 있기 때문에 성공 가능성이 크게 줄어들게 됩니다.
그렇다면 이러한 고수준의 목표들을 달성하기 위해 어떻게 시스템을 설계해야 할까요?
트레이드오프
우리는 어떠한 것도 공짜로 얻을 수 없다는 것을 깨달아야 합니다. 시스템에 좋은 특성을 제공하고자 하면 그에 따른 대가가 있습니다. 이러한 대가가 무엇인지 잘 알고 있어야 합니다. 위의 아키텍처 결정 요인들을 다시 살펴보고 예상되는 단점들을 추가해보겠습니다.
- 시스템의 복잡성이 증가하고 유연성이 저하되는 것을 대가로 치르면서 시스템은 매우 빠르게 응답할 수 있습니다.
- 모놀리식에서 분산 시스템으로 이동하는 것을 대가로 대량의 트래픽을 수평/자동 확장을 통해 처리할 수 있습니다.
- 카나리아 배포, 블루/그린 배포 또는 기타 비용이 많은 기술들을 유지하는 것을 대가로 가동 시간을 ~99.99%로 보장할 수 있습니다.
- 코드/업무가 중복되고 인프라가 훨씬 더 복잡해지는 것을 대가로 작고 독립적인 팀을 통해 수십 또는 수백 명의 개발자들이 개발할 수 있습니다.
- 개발자들이 가장 선호하는 기술을 사용하지 못하는 것을 대가로 덜 숙련된 개발자들도 비교적 쉽게 참여할 수 있습니다.
- 기술 부채가 증가하는 것을 대가로 비즈니스를 위해 기능을 매우 빠르게 출시할 수 있습니다.
트레이드오프는 어떤 면에서는 단순합니다. 우리가 무엇을 포기할 수 있는지 의식적으로 결정할 수 있기 때문입니다. 예를 들어, 99.99%의 가동 시간이 정말 필요한가요? — 네, 왜냐하면 우리의 계약이 이를 지원하라고 의무화하고 있기 때문입니다. — 하지만 80%의 코드 커버리지가 정말 필요할까요? — 있으면 좋겠지만, 필수는 아닙니다. 그것 없이도 계속 나아갈 수 있습니다.
아키텍처 결정을 내릴 땐, 트레이드오프를 염두에 두면서 결정 요인에 집중하는 것이 필요합니다. 우리는 목표를 달성하고자 하지만, 동시에 무엇을 포기해야하는 지도 알고 있습니다.
제약사항
또 하나의 자명한 진실이 있습니다. 모든 것이 가능하지는 않다는 것입니다.
😉
때로는 모든 분석 결과가 최선의 결정이라고 말해도 실행할 수 없는 경우가 있습니다. 외부 요인들과 부딪히기 때문입니다.
- 시스템이 빠르게 응답해야 하고 이를 위해 복잡성이 증가하고 유연성이 떨어지는 것을 감수하더라도, 우리는 어쩔 수 없는 이유로 데이터베이스를 수정할 수 없습니다.
- 대량의 트래픽을 처리하기 위해 모놀리식에서 분산 시스템으로 전환하는 비용을 지불하더라도, 우리는 어쩔 수 없는 이유로 클라우드 제공업체를 바꿀 수 없습니다.
- 비즈니스를 위해 기능을 빠르게 출시해야 하고 이로 인한 기술 부채 증가를 감수하더라도, 우리는 어쩔 수 없는 이유로 개발 속도를 높이기 위한 인력 충원을 할 수 없습니다.
이런 점이 안타까운 부분입니다. 상황을 더 어렵게 만드는 것은 어쩔 수 없는 이유로 우리의 능력이 제한되어 있다는 걸 받아들여야 한다는 점입니다 😉. 하지만 그럼에도 목표를 이루고 싶습니다!
요약
간단히 정리해보겠습니다. 우리는 아키텍처 결정 요인들을 염두에 두고 아키텍처 결정들을 내렸고, 이 결정들의 트레이드오프를 인지하고 제약사항들에 대처해야 합니다.
코드에서 한 발 물러나 더 큰 그림을 봅시다.
그래서 다시 말하자면, 아키텍처를 이루는 것은 무엇인가요?
제가 앞서 대충 내린 정의를 다시 살펴보겠습니다.
현재 시스템을 형성하고 미래에 변경하기 어려운, 비즈니스 요구사항에 따른 (고수준의, 기술적인) 결정
이제 이 정의에 부합하는 것과 그렇지 않은 것을 비교해보겠습니다.
정의된 아키텍처에 따른 비교
- ✅ 마이크로 프런트엔드 를 구현할지 말지(그리고 어떻게 할지)
- ❌ 웹팩 모듈 페더레이션을 사용할지 다른 것을 사용할지
정의된 아키텍처에 따른 비교
- ✅ 격리보다 재사용성이 더 중요한지, 아니면 그 반대인지
- ❌ 코드베이스에 배럴 파일 (index.js/ts)을 구현할지 말지
정의된 아키텍처에 따른 비교
- ✅ 모델이 다른 모듈 간에 공유되는지 아니면 ACL 등을 통해 격리되는지
- ❌ 클래스/OOP를 고수할지 함수/FP를 사용할지
정의된 아키텍처에 따른 비교
- ✅ 상태가 중앙 집중형/공유형 또는 분산형/로컬형이어야 하는지
- ❌ 상태 관리를 위해 리덕스 스타일의 스토어를 사용할지 말지
정의된 아키텍처에 따른 비교
- ✅ PULL 기반과 PUSH 기반 중 무엇이 요구사항에 더 적합한지
- ❌ 프로미스, async await 또는 rxjs 중 무엇을 사용할지 (정말 뭐든 상관없음)
정의된 아키텍처에 따른 비교
- ✅ UI가 실시간 데이터에 크게 의존하는지
- ❌ firebase vs supabase vs […] 중 무엇을 사용할지
정의된 아키텍처에 따른 비교
- ✅ 누가 클라이언트-서버 API 컨트랙트(contract)를 변경할 수 있는지
- ❌ GraphQL, REST, SSE 등 중 무엇을 사용할지
정의된 아키텍처에 따른 비교
- ✅ 어떤 아키텍처 결정 요인이 가장 중요한지
- ❌ 모범 사례를 따른다고 주장하는지 아닌지
정의된 아키텍처에 따른 비교
- ✅ 최적화된 LCP가 있으면 좋은 것인지 아니면 반드시 있어야 하는 것인지
- ❌ UI 컴포넌트의 크기(LoC)가 얼마나 되는지
정의된 아키텍처에 따른 비교
- ✅ 시스템이 단일 테넌트인지 다중 테넌트인지
- ❌ 인증 데이터를 리덕스, 컨텍스트, useState 중 어디에 보관할지, 정말이지, 뭐든, 상관없음
정의된 아키텍처에 따른 비교
- ✅ UI에 장애 허용(Fault Tolerance)을 어떻게 제공할지
- ❌ CI 파이프라인이 80%의 코드 커버리지를 요구하고 그렇지 않으면 실패하는지
이쯤 되면 요점을 잘 파악하셨을 거라 생각합니다 😅.
또한, 위의 대조가 아키텍처 결정과 기술적 결정을 비교한다는 점을 주목해주세요.
디렉토리 구조가 왜 아키텍처로 간주되면 안 되는건가요?
디렉토리 구조는 일종의 설계 작업과 관행의 결과물입니다. 이는 우리가 더 빠르게 움직이고, 빠르게 전달하고, 문제를 만들지 않으면서(또는 더 적게 만들거나) 전달하는 걸 돕기 위한 것입니다. 디렉토리 구조 자체는 목표가 아닙니다. 다음과 같은 더 높은 수준의 목표를 달성하기 위한 수단입니다.
- MFE/모놀리식 경계 컨텍스트의 분리
- 서로 다른 팀이 독립적으로 전달하고 배포할 수 있도록 함
- ACL 등을 통한 로컬 모델의 격리를 돕는 것
우리가 명확하게 볼 수 있듯이, 디렉토리 구조는 주어진 아키텍처에 때때로 더 잘 맞거나 잘 맞지 않을 수 있습니다. 하지만 디렉토리 구조 자체는 개념을 구체화하는 것이며, 구현입니다. 구현상의 세부사항이죠. 우리의 최종 목표를 달성하기 위한 방법입니다.
디렉토리 구조가 우리에게 알려주지 않는 것
디렉토리 구조나 규칙(convention)만으로 알 수 없는 매우 중요한 측면들이 있습니다. 다음과 같은 것들이 있습니다.
- God 클래스를 구현했는지 또는 모듈들이 격리된 경계 컨텍스트인지 알 수 없습니다.
- 컨트랙트와 로컬 프런트엔드 로직 사이에 동일한 모델을 재사용하는지 알 수 없습니다.
- 상태가 공유/중앙화되어 있는지 아니면 분산되어 있는지 알 수 없습니다
- 코드베이스 내의 문제가 되는 결합이 어디에 있는지, 의존성 역전을 적용했는지, 그리고 코드베이스가 얼마나 응집도가 있는지) 등을 알 수 없습니다.
친절하게 말해보자면, 디렉토리는 아키텍처로 간주될 만큼 중요하지는 않습니다. 디렉토리 구조는 아키텍처를 구현할 수는 있지만(또는 못할 수도 있음), 그 자체로 아키텍처는 아닙니다.
프런트엔드 아키텍처에 대한 올바른 이해 구축하기
아키텍처는 우리가 원하고 😘, 바라거나 🥰, 강요하는 🥸 것이 아닙니다. 갑자기 😶🌫️ 떠오르는 대로 그려내는 것도 아니고, 이전 회사에서 잘 작동했다고 해서 프로젝트들 사이에서 복사-붙여넣기를 해야 하는 것도 확실히 아닙니다 🥸.
아키텍처는 소통, 상세한 분석과 추론의 결과물입니다. 하나의 결과인 것이죠. 마치 주어진 입력에 대해 특정한 출력을 만들어내는 함수와 같습니다. 그리고 확실히, 입력은 시간이 지나면서 변화할 것입니다. 아키텍트의 역할은 이 입력 -> 출력
함수를 정기적으로 실행하기 위한 지식과 경험을 모으는 것입니다.
입력은 무엇이고 어디에서 얻을 수 있나요?
아키텍트의 가장 중요한 기술은 경영진, 비즈니스, 개발 등 모든 그룹과의 소통입니다. 완전히 다른 그룹들이죠, 맞나요? 모아야 할 정보들이 많이 있습니다.
- 제품이 제공하는 것이 무엇이고, 장점은 무엇이며, 경쟁사와 비교해서 우위를 점할 수 있게 하는 핵심 도메인은 무엇인가요?
- 핵심 도메인에 포함된 모듈/기능/팀들은 써드파티에 외주를 주면 안 됩니다.
- 품질을 포기하면 안 됩니다.
- 도메인의 발견/모델링은 이벤트 스토밍과 같은 DDD 방식으로 진행될 수 있습니다.
- 비핵심 도메인들은 부차적입니다.
2. 회사 구조 — 그리고 콘웨이의 법칙이 우리의 소프트웨어 개발과 배포에 어떤 영향을 미치는가
- 개발 부서의 규모는 얼마나 되나요? 몇 개의 팀이 있나요?
- 회사가 제품 중심적인가요? 각 팀이 다른 팀들과 100% 독립적으로 자신들의 (하위)제품을 개발, 테스트, 배포하는 등의 전적인 책임을 지나요?
- 현재 우리 조직에 영향을 미치거나 곧 변경되어 “우리가 팀을 어떻게 구성해야 하는지”에 대한 현재의 모든 가정을 무효화할 수 있는(예: 관계사, 공유 기술, 인수) 또는 기타 중요한 고려사항이 있나요?
3. 비즈니스 목표, 고객 기대, 시장 상황
- 솔루션 배포가 얼마나 빨리 예상되나요? 이를 달성할 노하우가 있나요?
- 배포/전달이 얼마나 자주 이루어져야 하나요? 회사가 이에 대비하고 있나요?
개발 관점에서 살펴보기
기술적인 측면에서 다음과 같은 질문들을 고려해야 합니다.
- 코드 재사용을 어느 정도로 할 것인가요?
- 재사용을 많이 할수록 필요한 코드의 양은 줄어들지만, 팀 간의 독립성도 그만큼 줄어들게 됩니다 (!). 특히, 공유된 구성 요소가 변경이 거의 없는 경우보다 자주 변경되는 상황에서는 더욱 그렇습니다. 이는 Shared Nothing Architecture(공유 없는 아키텍처)와 비교했을 때 더 두드러집니다.
- 공유 요소(파일, 컴포넌트 라이브러리, 아티팩트 등)를 변경할 때 어떤 영향이 있나요? 재빌드가 필요한가요? 필요하다면 — 몇 개의 요소를 재빌드해야 하나요? 얼마나 많은 테스트(가능하면 자동화된)가 필요한가요? 몇 개의 요소가 배포되나요? 순차적인가요, 독립적인가요? 전체 과정이 얼마나 걸리나요? 이런 공유로 인해 불필요한 노력과 시간이 얼마나 낭비되나요?
- 그리고 이것이 가동 시간/SLA에는 어떤 영향을 주나요?
2. 시스템은 얼마나 유연하며 어떻게 아키텍처를 측정할 수 있나요?
- 간단히 말해서, 예상 및 현재 TTM은 어떠한가요?
- 애플리케이션 변경사항이 얼마나 자주 프로덕션에 배포되나요(DF)?
- 개발자가 코딩을 시작해서 프로덕션에 배포될 때까지 얼마나 걸리나요(CLT)?
- 변경사항이 얼마나 자주 장애를 일으키나요(CFR)?
- 장애 복구에 얼마나 시간이 걸리나요(MTTR/FDRT)?
3. (테스트, 코드 커버리지, 임계값 등을 제외하고) 시스템의 안정성을 어떻게 보장하나요?
- 장애 발생 시 절차는 어떻게 되나요? 그리고 얼마나 자주 이 절차를 수행하게 되나요? 😄
- 동시에/함께 배포해야 하는 요소가 몇 개/얼마나 큰가요? CI/CD와 (너무 세분화된) 저장소 구조 때문에 제품 배포 시 불필요하게 의존성을 다시 빌드해야 하나요?
- 팀들이 서로를 얼마나 신뢰하나요? 다른 팀이 배포하는 것을 신뢰해도 될까요? Git-flow 방식의 워크플로우인가요, 아니면 trunk-based 개발인가요? CI/CD와 전체 프로세스는 이에 크게 좌우됩니다.
- 시스템이 얼마나 장애 허용적인가요? 프런트엔드 앱이 다양한 백엔드 장애 시나리오에 대해 자동으로 테스트되나요?
- 개발자들이 관측성을 효과적으로 활용하고 있나요? 예를 들어 다음과 같은 작업에 얼마나 걸리나요?
- 프런트엔드 문제의 원인을 진단 / 롤백 / 수정
- 또는 개발자들이 Core Web Vitals의 성능 저하를 인지
4. 사용자들이 어떤 다양한 기기/환경을 사용하나요? 웹, (네이티브) 모바일, 둘 다인가요? 여기서도 마찬가지입니다.
- 어떤 부분을 재사용하고, 팀 간 의존성을 줄이기 위해 어떤 부분을 분리해야 할까요?
- 팀/코드베이스는 어떻게 구성되어 있나요? 플랫폼별로? 아니면 경계 컨텍스트별로? 😉 등
5. 어떤 특별한 특성이 예상/요구되나요?
- 예시: 협업 모드. 현재 시스템은 한 명의 사용자만 변경할 수 있지만, 여러 사용자가 같은 데이터셋에 실시간으로 변경을 적용하도록 하는 요구사항이 있습니다. 코드가 직접적인 상태 변경(예: set, update 등)을 적용한다면, 사용자 간에 공유할 수 있는 적절한 모델이 없을 수 있습니다. 하지만 상태가 간접적으로 변경된다면(Command Pattern, 예: Redux actions를 통해), 업 기능을 도입하는 첫 번째 반복(iteration)에서 공유할 수 있는 모델이 이미 있습니다. 또는 CRDT를 고려할 수 있습니다.
- 예시: 오래된 데이터를 절대 보여주지 않기. 게시물의 좋아요 수가 오래되었다고 해서 누군가가 피해를 보지는 않겠죠. 네, 희망적으로는요, 하지만 요점을 이해하셨을 거예요 😉. 하지만 뱅킹 시스템에서 UI가 탭/섹션을 전환할 때 오래된 계좌 잔액을 보여주는 것은 좋은 생각이 아닙니다.
- 예시: SDK. 고객들이 여러분이 제공하는 플랫폼 위에 자신만의 커스텀 기능을 구현하나요? 호환성이 깨지는 변경(breaking changes)이 얼마나 자주 있나요? (그리고 그로 인해 고객들이 얼마나 자주 곤란해지나요?) 제한된 자원으로 시스템을 발전시키면서 이전 버전에 막대한 비용을 쓰지 않는 균형을 어떻게 찾나요? 예를 들어, 몇 개의 원자 요소를 위해 리액트 컴포넌트의 props를 재설계하는 것이 엄청난 결과를 초래할 수 있고, 슬프게도 구현하고 테스트했더라도 호환성 유지 요구사항 때문에 안타깝게도 되돌려질 수 있습니다.
보시다시피, 아키텍처를 관리한다는 것은 올바른 질문을 하는 것에 관한 것입니다. 고전을 인용해보겠습니다.
답할 수 없는 질문을 갖는 것이, 의문을 제기할 수 없는 답을 갖는 것보다 낫다
위의 모든 고려사항들에 대해 신중히 생각하는 것이, 아키텍처 스타일과 중요한 기술 스택의 선택에 대한 결정을 할 수 있도록 이끌어줄 것입니다.
도구 결정 vs 아키텍처 결정
어떤 사람들은 이렇게 말할 것입니다.
이봐, 근데 도구, 라이브러리, 규칙, 또는 코드 구조와 관련된 일부 결정들은 프로젝트에 큰 영향을 미치고 나중에 바꾸기 어려울 수 있잖아. 예를 들어, 내가 Redux를 사용한다면, 그건 아키텍처적 결정이라고!!! 😉
음, 그렇기도 하고, 아니기도 하죠. 😉
특정 단어들에 집착하고 중요한 것(비즈니스나 전체적인 관점에서 중요한 것)의 맥락을 놓치기 쉽습니다.
몇 년이 지난 후에 코딩 규칙에 대한 결정을 바꾸는 것이 (매우) 비용이 많이 들 수 있다는 것은 사실입니다. 코딩 규칙이나 코드 구조, 또는 디렉토리 구조(정말, 뭐든지)가 개발자들의 속도를 높이거나 낮출 수 있죠. 물론이에요! 어떤 규칙은 더 잘 맞고, 어떤 것은 잘 안 맞습니다. 어떤 것은 우리가 더 빨리 움직이는 데 도움이 되고, 어떤 것은 그렇지 않죠.
하지만 그 결정이 이루어진 팀에서 한 발짝 물러나서 보면, 그건 전혀 중요하지 않습니다 🔥. 그저 구현 세부사항일 뿐이죠. 팀 외부에서는 아무 의미가 없습니다.
- 예시: 파일 하나당 컴포넌트 하나만 유지하기로 결정했다고 해봅시다. 팀 밖에서 보면 완전히 상관없는 일이죠.
- 예시: 유틸리티 함수를 위해 lodash나 ramda를 사용하기로 했거나, 혹은 ‘우리가 만든 게 아니면 안 써’라는 마인드로 외부 라이브러리를 아예 안 쓰기로 했다고 해봅시다. 여전히, 팀 외부에서 보면 상관없는 일입니다.
- 예시: 각 모듈에 아주 특별한 파일 구조를 도입했다고 해봅시다. 이 규칙이 테스팅, 스토리북, 리팩토링에 영향을 미치긴 하지만, 여전히 팀 밖에서 보면 상관없는 일입니다. (참고로, 스토리북이 팀 외부에서 자주 사용된다면 이야기가 달라지겠죠.)
오해하지 말아주세요. 이런 결정들도 중요합니다. 여러분의 팀에게는 중요한 결정이죠. 하지만 오직 여러분의 팀에게만 중요할 뿐입니다. 이런 결정들은 전체 시스템의 특성에 영향을 주거나 강제하지 않아요. 다른 결정을 했다고 해도, 전체 시스템의 성격은 변하지 않을 겁니다. 위의 인용문을 좀 더 분석해봅시다.
Redux를 사용한다면, 그건 아키텍처적 결정이다.
(미안해요, Redux 😅)
여기서 잘 보세요. 아키텍처적 결정은 Redux를 선택하는 것 자체가 아닙니다! 이는 중앙화된 상태 관리 솔루션을 선택하는 것에 관한 것입니다. 이런 선택은 모듈들이 서로 의존하게 만들 수 있습니다. 왜냐하면 전역 스토어에서 모든 것에 접근할 수 있기 때문이죠. 반면에 모놀리스를 마이크로프런트엔드로 분리하려 할 때는, mobx처럼 여러 개로 분리된 스토어를 사용하면 그 작업이 더 수월해질 수 있습니다. 또한, 아키텍처적 결정은 클라이언트 측 이벤트 소싱 솔루션을 선택하는 것에 관한 것인데, 이는 비즈니스에서 실시간 협업 기능을 구현해야 할 수도 있기 때문입니다.
그렇다면 Redux를 선택하는 것이 중요한 결과를 가져오나요? 물론입니다. 하지만 다시 말하지만, 제가 여러분이 집중하길 바라는 것은 라이브러리 자체가 아니라 Redux가 가져오는 고수준의 특성들입니다. Redux가 가져오는 기능들(앞서 여러 번 언급했던)과, 그것이 도입하는 비용과 제약사항들 모두를 말하는 거죠. 예를 들어 Redux는 “하나”이며 “유일한” 진실의 원천인데, 이는 마이크로프런트엔드를 고려한다면 확실히 좋지 않은 특성입니다. Redux는 이런 특성들과 분리될 수 없습니다. 하지만 아키텍처를 만드는 것은 위와 같은 특성들이지, 도구 자체가 아닙니다.
이번엔 앵귤러 생태계에서 하나 더 예시를 살펴봅시다.
동의할 수 없어요. NGRX처럼 높은 수준의 라이브러리라면 라이브러리 자체가 중요합니다. 다음과 같은 여러 질문들에 답해야 하죠.
- NGRX를 어떻게 사용하나요?
- 항상 effects를 사용하나요?
- facade를 사용해 추상화하나요?
- 어떤 계층과 연결할까요?
- 도메인 간에 NGRX 스토어를 어떻게 공유하나요? 등
하나씩 살펴봅시다.
NGRX를 어떻게 사용하나요?
이건 까다로운 질문입니다. ‘어떻게’라는 것이 고수준과 저수준 모두와 관련될 수 있기 때문이죠. 모호한 질문입니다 😉
항상 effects를 사용하나요?
(맥락: NGRX effects는 redux-observable의 epics와 같은 개념입니다. 액션이 디스패치되고, rxjs 리액티브 스트림을 사용해 반응적으로 처리되며, 종종 새로운 파생 액션이 스토어로 다시 디스패치됩니다.)
이건 구현 세부사항입니다. 명령형이나 반응형 패러다임을 선택하는 것은, 글쎄요, 프로그래밍(구현) 패러다임이죠. 아키텍처가 아닙니다. 나중에 이 결정을 바꿀 수 있습니다. 즉, 앞으로는 다르게 할 수 있죠.
facade를 사용해 추상화하나요?
이건 캡슐화 그리고/또는 디자인 패턴 그리고/또는 코딩 패턴입니다… 말씀하신 대로 아키텍처 패턴보다 한 단계 아래죠. C4 모델에서는 이것이 코드(레벨 4)(구현 세부사항)입니다. 다시 말하지만, 팀 내에서 중요한가요? 네. 외부에서 중요한가요? 아니요.
어떤 계층과 연결할까요?
그렇죠, 잠재적으로 아키텍처일 수 있습니다. 하지만 이건 NGRX(또는 다른 것)와는 관계가 없습니다. 다른 상태 관리 솔루션에서도 같은 질문을 할 것입니다. 예를 들어, 리액트에서 얼마나 많은/얼마나 구체적인 커스텀 훅을 만들어야 하는지처럼요. 가상의 계층들(또는 그것의 부재)은 분명히 우리의 아키텍처를 형성합니다. 하지만 라이브러리가 다르더라도 여전히 그럴 것이죠, 그렇지 않나요?
도메인 간에 NGRX 스토어를 어떻게 공유하나요?
물론 확실하게 아키텍처입니다. 하지만 다시 말하지만, 이것은 NGRX 자체와는 관계가 없습니다. 다른 모든 중앙화된 상태 관리 솔루션에서도 정확히 같은 질문을 할 테니까요. 맞나요?
부가적인 코멘트를 하자면, NGRX/redux-observables를 사용하느냐 마느냐는 분명 프런트엔드 개발자의 진입 장벽에 영향을 미치고, 그들의 동기부여(도구에 대한 사랑 vs 미움의 관계 🥹)에도 영향을 미치며, 테스트를 작성하는 방식 등에도 확실히 영향을 미칩니다. 하지만, 다시 말하지만, 여러분의 팀/모듈/저장소 밖을 나가면 그게 정말 그렇게 중요할까요?
결론적으로, 어떤 결정이 변경 비용이 크냐 아니냐는 그것이 큰 그림이나 장기적인 관점에서 중요한지 여부를 결정하지 않습니다. 또한, 팀이나 저장소 내에서 매우 중요한 것이 외부에서 중요한지 여부를 결정하지도 않습니다. 중요할 수도 있지만, 반드시 그런 건 아닙니다.
제 개인적인 의견으로는, 우리가 그 결정이 가져오는 결과에 집중하는 한, Redux를 선택하는 것을 아키텍처적 결정이라고 부르든 말든 그다지 중요하지 않습니다.
요약
소프트웨어 아키텍처는 중요한 의사결정을 하는 것에 관한 것입니다. 이러한 결정들은 비즈니스 우선순위에 의해 주도되어야 하며, 트레이드오프를 고려해야 하고, 기존의 제약사항들로 인해 더욱 어려워집니다.
이러한 모든 어려움들 속에서 소프트웨어 아키텍트의 역할은 비즈니스 우선순위와 요구사항, 그리고 기술적인 측면과 그 복잡성 사이의 균형을 맞추는 것입니다.
아키텍처(목표 달성을 돕기 위한 고수준의 의사결정들)를 이를 구현하는 방법과 혼동하지 마세요. 특정 도구들, 라이브러리들, 컨벤션들, API들 등 — 이것들은 모두 저수준의 세부사항들이며, 이는 여러분의 목표 달성을 도울 수도 있고 아닐 수도 있습니다. 하지만 비즈니스 우선순위, 제약사항(등등)의 관점에서 볼 때, 이것들은 단지 세부사항일 뿐입니다. 중요도가 낮은 세부사항들이죠.
읽어주셔서 감사합니다, 즐거우셨길 바랍니다 🤓.
추천 자료
이 주제에 관한 정말 좋은 책들이 여러 권 있지만 더 구체적인 주제들로 깊이 들어가기 전에, 기초부터 시작하시기를 추천드립니다
- Simon Brown의 Software Architecture for Developers: 다소 기본적인 내용이지만, 어떤 형태로든 소프트웨어 아키텍처에 책임이 있는 모든 사람들이 반드시 읽어야 할 책입니다.
- Mark Richards와 Neal Ford의 Fundamentals of Software Architecture; 조금 더 깊이 있게 다루고 있습니다.
또한, Martin Fowler의 웹사이트에서 아키텍처에 대한 좋은 입문 자료들을 찾으실 수 있습니다.