“과거를 알면 현재가 보인다”는 말이 있다. 역사는 단순히 지나간 사건들의 기록에 그치지 않고, 과거의 경험은 우리가 현재의 문제를 이해하고 미래를 대비하는 데 중요한 교훈을 제공한다. 과거의 정치적 결정, 사회적 변화, 경제적 위기, 문화적 발전은 현재 우리가 직면한 도전과 기회들을 해석하는 데 도움을 준다.
또한 역사는 사회적 갈등이나 혁명의 이유를 이해하게 함으로써, 현시대의 문제를 해결할 실마리를 제공하기도 한다. 이렇게 역사는 단순한 기록이 아니라, 우리가 현재를 올바르게 보고, 더 나은 미래를 만들어 가기 위한 나침반과도 같은 역할을 한다.
새로운 기술들도 마찬가지이다. 현재 사용되고 있는 기술들은 과거에 있었던 갈등이나 문제, 그리고 좌절과 고난에 경험 끝에서 나온 축적물들이다. 불편했던 과정과 좋지 못했던 결과물들을 바로잡기 위한 한 땀 한 땀의 노력들이 모여 지금 우리가 편리하게 사용하고, 조금은 더 나은 환경 속에서 살아갈 수 있는 듯하다.
오늘의 이야기는 데이터를 저장하고 관리하는 공간인 "레포지토리"에 집중을 해보려고 한다. 프로젝트의 소스 코드를 저장하고, 변경 사항을 추적하며, 여러 사람이 협업할 수 있게 도와주는 공간을 어떤 방식으로 운영을 하면 좋을지에 대해 생각 해보려한다. 레포지토리의 역사의 과정 속에서 어떤 불편함으로 인해 어떻게 개선을 할 수 있었는지 알아보고, 더 나은 운영을 위해 어떠한 노력들을 하고 있는지 알아보자.
(삼국사) 모놀리식 레포
모놀리식 레포란 하나의 대규모 레포지토리에 프로젝트의 모든 코드, 모듈, 구성 요소를 저장하고 관리하는 소프트웨어 개발 방식을 의미한다. 여러 서비스나 애플리케이션의 코드가 분리된 여러 레포지토리가 아닌, 하나의 통합된 레포지토리에서 함께 관리되는 구조이다.
초기 소프트웨어 개발 환경에서는 복잡한 시스템 관리보다 개발과 배포의 단순화가 중요했다. 하나의 레포지토리에서 모든 코드를 관리하면, 코드 베이스 전체를 한 번에 빌드하고 배포할 수 있어 작업이 단순화 될 수 있었다. 이로 인해 관리가 쉬워졌고, 한 레포지토리 안에서 애플리케이션의 모든 부분을 통합 관리할 수 있었다.
또한 대규모 소프트웨어 개발보다는 소규모 팀에서 소프트웨어를 개발하였기 때문에 팀 전체가 같은 레포지토리에서 작업을 하면서 변경 사항을 쉽게 공유하고, 코드 리뷰와 협업을 한곳에서 처리할 수 있었다.
통합 테스트 또한 쉽게 수행 가능했다. 모든 코드가 한 곳에 있기 때문에 전체 시스템을 한 번에 테스트하고 빠르게 배포할 수 있었다. 공통된 라이브러리나 유틸리티 코드가 여러 모듈에서 쉽게 활용될 수 있었고, 코드 재사용이 간단했다.
간편한 코드 관리, 효율적인 협업, 일관된 빌드 및 배포 프로세스, 통합된 테스트 환경, 코드 재사용성
하지만 소프트웨어가 점점 더 복잡해지고 팀이 확장됨에 따라, 모놀리식 레포에서 발생하는 문제들이 점차 부각되기 시작했다.
레포지토리 자체가 커짐에 따라 코드간의 의존성이 복잡해지고, 유지보수가 어려워졌다. 이는 빌드 및 테스트, 그리고 배포에도 영향을 끼쳤다. 코드베이스가 커질수록 시간이 증가할 뿐만 아니라 작은 변경 사항에 대한 비효율적인 빌드 및 배포 프로세스가 추가되는 등 필요 없는 시간을 소모해야 했다.
또한 여러 개발자가 동시에 동일한 레포지토리에서 작업할 때 코드의 빈번한 충돌과 각 모듈이 독립적으로 관리되지 않기에 확장성에도 문제가 있었다. 이런 여러가지 기술적 부채가 쌓여가면서 더 나은 관리 방법의 도입이 필요해졌다.
빌드 및 테스트 속도 저하, 복잡성 증가, 배포의 어려움, 코드 작업 충돌 증가, 확장성 문제
(고려사) 멀티 레포
멀티레포는 소프트웨어 개발이 점점 더 복잡해지고, 대규모 시스템이 확장됨에 따라 기존에 채택되었던 모놀리식 레포의 관리 부담과 비효율성이 두드러지게 되면서 등장하게 되었다.
멀티 레포는 소프트웨어 개발 방식으로, 더 큰 애플리케이션의 서로 다른 프로젝트나 구성 요소를 별도의 레포지토리로 저장하고 관리하는 접근 방식을 의미한다. 각 프로젝트나 구성 요소는 자체 버전 관리 레포지토리를 가지며, 이를 통해 팀은 독립적으로 작업할 수 있다.
위에 그림과 같이 멀티레포는 독립적으로 레포지토리가 별도 관리되므로 팀들은 서로 방해받지 않고 독립적으로 작업이 가능하다. 또한 프로젝트마다 권한을 설정할 수 있어 보완 관리가 용이하며, 각 프로젝트나 모듈을 독립적으로 배포할 수 있다.
새로운 기능이나 프로젝트를 추가 할 때도 꽤나 용이하다. 기존 코드와 충돌하지 않고 쉽게 확장이 가능하며, 각 레포지토리에 따라 독립적으로 관리되기 때문에 소유권이 명확하면서도, 변경사항에 대해 쉽고 빠르게 추적이 가능하여 관리가 용이한 장점이 있다.
독립성, 보안강화, 유연한 배포, 확장성, 소유권 명확성, 의존성 관리, 간단한 버전 관리
그러나 항상 그렇듯 개선된 관리 포인트에서도 Trade off는 존재한다. 가장 커다란 문제는 코드의 중복이었다. 여러 레포지토리에서 비슷한 기능을 구현하다 보면, 공통 코드를 공유하기 어렵고, 각 레포지토리마다 유사한 코드가 복제될 가능성이 현저하게 높아지는 것이 문제였다.
그다음으로 발생하는 문제는 협업과 관련된 부분이었다. 사람 간의 협업, 코드 간의 협업의 아쉬움이 남았다. 각 팀이 독립적으로 프로젝트를 관리하기 때문에 전반적인 목표를 조율하는 데 어려움이 있고, 코드 스타일이나 품질에 대한 일관성 또한 유지하기가 어려운 부분이 있었다.
테스트도 문제였다. 상대적으로 단위, 통합 테스트는 간단할 수 있지만, 하나의 통합된 애플리케이션을 테스트하기 위한 E2E 테스트는 꽤나 복잡한 절차를 거쳐야 했다.
마지막으로 의존성에 대한 문제가 발생했다. 다양한 레포지토리가 서로 의존하는 경우 하나의 레포지토리에서 발생한 업데이트를 다른 레포지토리에 반영하는 과정과 이를 관리하는 부담이 늘어났다.
코드 중복, 일관된 코드 품질 유지, 통합 테스트, 복잡한 협업, 의존성 업데이트
멀티 레포가 가지는 장점은 명확했지만, 또 다른 문제점이 발견되었다. 그러한 문제점의 어느 정도 커버할 수 있는 관리 방법을 찾아야 했다. 그 때 등장한 관리 방법이 "모노레포"이다.
(조선사) 모노레포
모노레포는 여러 프로젝트의 코드를 동일한 저장소에 저장하는 소프트웨어 개발 전략이다. 이름에서 알 수 있듯이, 모노레포는 하나의 코드 저장소에 여러 프로젝트가 포함되어 있기 때문에 붙여진 이름이다.
개별 프로젝트는 각각 별도의 생명 주기를 가진다. 모노레포는 마이크로 프론트엔드를 사용하지 않고도 단일 저장소에서 여러 프로젝트를 관리하는 방법이다. 모노레포를 사용하면 단일 저장소에 여러 마이크로 프런트엔드 애플리케이션을 만들 수 있으며, 이러한 개별 마이크로 프런트엔드를 각각의 런타임에서 별도의 생명 주기로 배포할 수 있다. 마이크로 프런트엔드를 모노레포와 결합하면 마이크로 프런트엔드 구현과 관련된 복잡성의 일부를 해결할 수 있다.
모노레포는 전체 코드베이스가 하나의 저장소에 있기 때문에 팀 간의 협업을 더 쉽게 만든다. 모든 것이 한 곳에 있기 때문에 변경 사항을 추적하고 코드를 공유하기가 더 쉬워지고, 작업자들은 통일된 도구와 워크플로를 적용할 수 있다. 물론 공통적인 코드도 쉽게 공유할 수 있기 때문에 코드 중복을 줄일 수 있다는 장점이 있다.
또한 의존성 관리를 단순화하는데, 모든 모듈이 단일 저장소에 호스팅되고 소싱되기 때문에 의존성 충돌을 방지할 수 있고, 하나의 package.json 파일만 존재하기 때문에 의존성을 업데이트할 때마다 각 저장소에 의존성을 설치할 필요가 없다.
전체 시스템을 한 번에 통합하고 테스트할 수 있어 빌드 및 배포 과정이 단순화되고 일관적으로 배포가 가능한 환경이 구성된다는 것도 또 다른 장점이다.
코드 공유와 재사용 용이, 일관된 개발 환경, 통합된 테스트 및 배포, 단순화된 의존성 관리,
전체 시스템에 대한 가시성 증가
하지만 여전히 단점은 존재했다. 각 레포지토리의 크기가 커질수록 빌드 및 테스트 시간이 길어지고, 수많은 모듈과 팀이 같은 레포지토리에서 작업을 하기 때문에 코드 충돌이나 관리상의 어려움은 여전히 발생했다. 합의된 컨벤션이 제대로 정해지지 않은 경우에는 코드를 추적하는 것에 어려움을 느낄 수 있었다.
또한 특정 모듈이나 기능만 업데이트해야 하는 경우 전체 애플리케이션을 배포해야 하는 경우가 생겼다. 부분 배포가 어렵기에 전체 프로젝트를 빌드하고 테스트해야 하는 경우가 빈번하게 생겨 성능 문제가 발생했다.
파이프라인을 구성하는 것도 꽤나 복잡해졌는데, 누군가가 모노레포에 변경을 가하면, 파이프라인은 어떤 작업을 수행할지, 무엇이 변경되었는지, 해당 변경으로 인해 어떤 작업을 트리거해야 하는지, 무엇을 빌드하고 빌드하지 말아야 하는지를 파악해야 하는 과정이 추가되어야 했다.
빌드 및 테스트 성능, 복잡성 증가, 작업 충돌 가능성 증가, 배포의 유연성 저하, 복잡한 파이프라인 구성
(근&현대사) 마이크로 프론트
마이크로 프런트엔드는 독립적으로 전달 가능한 프론트엔드 애플리케이션 기능들을 조합하여 전체 애플리케이션을 구성하는 소프트웨어 아키텍처 접근 방식이다. 이 전략에서는 프론트엔드 애플리케이션이 더 작은 애플리케이션이나 모듈로 분해되며, 이러한 각 모듈은 서로 독립적인 애플리케이션으로, 다른 팀들이 다른 기술을 사용해 개발, 테스트 및 배포할 수 있다.
백엔드 개발에 익숙하다면, 마이크로 프론트엔드는 마이크로서비스의 개념을 프런트엔드에 확장한 것이라고 볼 수 있는데, 두 아키텍처는 유사한 개념을 가지고 있으며, 프런트엔드를 더 작고 관리하기 쉬운 부분으로 나누어 사용자 경험을 더 효과적으로 조정할 수 있는 아키텍처로 등장하게 되었다.
위 그림에서는 세 개의 서로 다른 마이크로 프런트엔드가 있다. 이는 소스 코드 저장소에서 자율적인 팀들이 구축한 개별 기능들이라고 할 수 있다. 이들은 각각 독립적인 책임을 지며, 별도의 빌드 파이프라인을 가지고 독립적인 애플리케이션으로 배포된다. 따라서 주황색, 녹색, 보라색 박스는 각각 별도로 배포 가능한 요소이며, 실제로는 이 모든 배포 가능한 요소들이 프로덕션 환경에서 하나로 결합된다.
예를 들어, 복잡한 전자상거래 애플리케이션에서 쇼핑 카트, 제품 카탈로그, 체크아웃 페이지, 결제 페이지, 사용자 프로필 페이지와 같은 기능별로 별도의 마이크로 프런트엔드를 가질 수 있다.
이러한 기능들은 독립적으로 개발, 확장, 테스트 및 배포될 수 있습니다. 각 모듈에 대해 다른 확장 전략을 사용할 수 있으며, 전체 애플리케이션을 확장하지 않고도 하나의 모듈을 더 많은 트래픽을 처리할 수 있도록 확장할 수 있다.
그렇기에 사용자 프로필 페이지에 변경 사항을 적용했는데 해당 페이지가 제대로 작동하지 않는 경우가 생긴다면, 전체 애플리케이션에는 영향을 미치지 않기에 사용자는 여전히 제품 카탈로그나 쇼핑 카트 페이지를 방문할 수 있다.
이번 글에 주제이기에 한 번 더 짚고 넘어가도록 하자.
마이크로 프런트엔드는 각 팀이 애플리케이션의 일부분을 구상부터 프로덕션까지 책임질 수 있다. 이는 각 팀에 더 많은 소유권을 부여하며, 자신들의 작업에 가장 적합한 기술, 코딩 스타일 및 아키텍처를 선택할 수 있다. 이는 호스트 페이지를 Vue로 작성하고, 다른 모듈을 React로 작성하는 것도 가능하다는 것을 의미한다.
또한 여러 모듈이 각기 다른 빌드를 가지고 있기 때문에 프론트엔드 모듈을 독립적으로 배포할 수 있다. 각 모듈은 배포 파이프라인이 있어야 하며, 이는 전체 애플리케이션을 다시 배포할 필요 없이 변경된 부분만 다시 배포할 수 있다는 것을 증명한다. 각 기능을 독립적으로 구현할 수 있기 때문에 개발 속도를 크게 향상할 수 있고, 독립적인 단위로 분리되어 있어 애플리케이션 진화에 따라 유연하게 확장을 할 수 있다.
팀의 자유로운 기술 선택, 독립적인 배포, 빠른 구현 및 개발, 확장성
최신 소프트웨어 아키텍처 전략이라도 여전히 풀어야 할 숙제는 남아있다. 수많은 모듈들이 독립적으로 운영되기에 분리된 컴포넌트와 마이크로 파트의 배포를 조율하는 작업이 복잡해질 수 있다. 이를 유지하기 위해 추가적인 노력과 리소스는 존재하며 해당 작업을 수행하는 팀 간의 많은 조정이 요구될 수 있다.
또한 여러 모듈이 각각의 독립적인 빌드 및 배포 파이프라인을 가지다 보니, 페이지 로드 시 성능에 영향을 미칠 수 있다. 특히 여러 모듈이 각각의 리소스를 요청하거나 서로 다른 기술 스택을 사용하면 초기 로드 속도가 느려질 수 있다는 단점이 존재한다. 그렇기에 다양한 모듈 간 공통으로 사용할 수 있는 디자인 시스템이나 스타일 가이드를 구축하는 데 추가적이 노력이 필요하다.
모듈이 독립적이기 때문에 통신과 관련된 문제가 생길 여지 또한 존재한다. 각 모듈 간의 통신을 위해 추가적인 API 호출, 데이터 전달 등이 필요할 수 있는데, 이로 인해 오버헤드가 발생하고 성능이 저하될 가능성이 있다.
이러한 각각의 단점은 관리 비용 및 리소스를 증가시키는 공통적인 원인이 될 수 있다.
복잡한 테스트와 배포, 성능 문제, 통신 오버헤드, 관리비용 증가
그래서 결론은?
각 소프트웨어 아키텍처 전략들은 유지와 보수를 위해 현저하게 노력해 왔으며, 지속되는 문제점을 타개하기 위한 해결책을 도출해 내는 과정을 반복해 왔다. 이는 과거 소프트웨어 개발 환경과 시대적 배경과 밀접해 있으며, 상황에 맞게 성장하고 진화했음을 알 수 있다.
각 전략의 핵심들은 이번 정리를 통하여 이론적으로는 어느 정도 이해를 했다. 바깥의 표면의 껍질을 들추어 보았다면, 이제는 들춰 본 껍질 안에 내용을 살펴볼 차례이다. 머릿속에 맴도는 지식들을 코드로 구체화해 나가는 과정을 행동으로 옮겨 보면서 아직 채워지지 않은 빈틈을 채워가보자.
< 참고자료 >
똑똑!! 레포지토리님 어디쯤이신가요? end
'기타' 카테고리의 다른 글
How styled-components works: A deep dive under the hood (0) | 2024.11.20 |
---|---|
글또라는 퍼즐 한 조각 (7) | 2024.10.12 |
오늘보다 더 나은 내일을 살고 있나요? (2) | 2024.01.19 |
어제보다 더 나은 오늘을 살고 있어요? (2) | 2023.12.31 |
Chrome의 내부 동작 #2 (0) | 2023.12.14 |