Chapter3. 모듈성
Q1. 모듈과 컴포넌트는 어떻게 다를까요? 여러분은 어떤 기준으로 모듈을 분리하고 관리하시나요?
모듈이란 연관성 있는 코드의 묶음이고, 컴포넌트란 모듈과 비슷한 개념? 프론트엔드 단에서 사용하는 UI관련 개념? 분명 정의된 개념이 있는데 막상 이야기해보라고 하면 이렇게 추상적일 수가 없다.
내가 모른다는 사실을 이제서야 안 것이지 않은가? 그동안 제대로 알지도 못한채 모듈화 하겠다며 묶었던 코드들을 다시 열어본다면, ‘3.2.1 응집(p71)’에서 말하는 것과 같이 ‘기능적 응집(functional cohesion)’이 아닌 ‘동시적 응집(coninidental cohesion)’이지 않을까?
모듈이란?
모듈은 소프트웨어 시스템에서 독립적인 기능 단위를 의미한다.
- 독립적으로 개발, 테스트, 유지보수가 가능한 코드 묶음
- 특정 기능이나 책임을 가지며 명확한 인터페이스를 통해 다른 모듈과 통신
- 일반적으로 여러 클래스, 함수, 파일로 구성
- 예: 결제 모듈, 인증 모듈, 로깅 모듈 등
프로그래밍 언어에 따라 모듈의 구현 방식은 다양하다
- Java : 패키지, JAR 파일
- JavaScript : NPM 패키지, ES 모듈
컴포넌트란?
컴포넌트는 모듈보다 더 큰 단위로, 독립적으로 배포 가능한 소프트웨어 단위를 뜻한다.
- 여러 모듈이 모여 하나의 컴포넌트를 이룰 수 있다.
- 명확한 인터페이스를 통해 다른 컴포넌트와 상호작용
- 독립적으로 배포 가능하며 대체 가능
- 예: 데이터베이스 접근 컴포넌트, API 게이트웨이 컴포넌트, 사용자 관리 컴포넌트
컴포넌트의 예
- 마이크로서비스 아키텍처의 개별 서비스
- 웹 애플리케이션에서의 백엔드 API
프론트엔드에서 말하는 컴포넌트란?
프론트엔드에서 컴포넌트란 UI를 구성하는 재사용 가능한 독립적인 조각을 의미한다. 때문에 일반적인 소프트웨어 아키텍처의 컴포넌트보다 더 UI 중심적이고 가볍지만, 독립성과 재사용성이라는 기본 원칙은 동일하다.
- 자체 상태(state), 동작(behavior), 스타일(style)을 가질 수 있다
- 다른 컴포넌트와 조합하여 더 복잡한 UI를 구성한다
- 재사용성과 유지보수성을 높이기 위해 설계된다
- 예 : 버튼, 폼, 모달, 카드, 네비게이션 바 등
프레임워크별 컴포넌트 구현
- React : 함수형/클래스 컴포넌트
- Vue : Single File Components (.vue 파일)
응집이란?
모듈 내부 요소들이 얼마나 밀접하게 관련되는지를 나타낸다. 일반적으로 높은 응집을 추구한다.
기능적 응집(functional cohesion)
모듈 내 모든 요소가 단일 기능을 수행하기 위해 밀접하게 연관된 응집
예:
- 결제 처리 모듈이 결제 검증, 처리, 완료 알림 등 결제라는 하나의 기능만 담당
- 파일 업로드 모듈이 파일 검증, 크기 조정, 저장, 메타데이터 처리 등을 통합적으로 수행
동시적 응집(coninidental cohesion)
모듈 내 요소들 사이에 의미 있는 관계가 없음 (가장 낮은 수준의 응집도) 예:
- 여러 시스템에서 복사해온 코드 조각들을 한 클래스에 무작위로 모아 놓은 경우
- 기타(Misc) 모듈에 다양한 기능을 분류 없이 모아놓은 경우 (예: CommonUtil 클래스에 관련 없는 여러 기능을 모아놓음)
Q2. 복잡하게 커플링된 코드로 인해 힘들었던 경험이 있으신가요? 그리고 만약에 할 수 있다면 얼마나 복잡했는지, 커플링은 얼마나 심했는지 어떻게 표현할 수 있을까요?
흔히 말하는 스파게티 코드라고 불릴 수 있겠다. 여러 시스템을 통합해야 일이 많은 SI 프로젝트 특성상 특정 모듈의 데이터를 얻기위해 인터페이스가 아닌 직접 데이터베이스를 참조하는 일이 많은데 이렇게 참조해야 할 데이터베이스가 늘어가고 관리해야 할 지점이 늘어나는 상황이 힘들었다. 그렇지만 가장 큰 문제는 이 모든것이 한개의 API에서 일어나는 일이라는 것이 가장 괴로웠다.
커플링이란?
모듈 간의 상호 의존성, 연결 정도를 나타나내는 개념으로 결합도(Coupling)로도 불린다
‘정도’를 측정하는 기준, 관련 도구
도구를 사용하면 필요한 정보를 위한 액션만 선택해주면 되지 내부적으로 어떤 기준에 따라 측정되는지 알 수 없다. 때문에 이러한 관점을 제공하는 개념적인 기준 정도로만 알면 좋을 듯 싶다.
- 결합도 수(Coupling Count) : 한 모듈이 다른 모듈에 의존하는 횟수
- fan-in/fan-out : 특정 컴포넌트로 들어오는/나가는 의존성 수
- afferent/efferent 커플링 : 컴포넌트를 사용하는 다른 컴포넌트 수/컴포넌트가 사용하는 다른 컴포넌트 수
- 변경 영향도 : 한 모듈 변경 시 수정해야 하는 다른 모듈 수
웹 개발에서 사용할 수 있는 도구들
- SonarQube : 코드 품질 분석 도구로 커플링 지표 제공
- JDepend/NDepend : Java/C# 코드 의존성 분석
- ESLint/TSLint : JavaScript/TypeScript 코드에서 의존성 규칙 체크
- Structure101 : 구조 분석 및 의존성 시각화
- JArchitect : Java 코드 분석 도구
- CodeScene : 변경 영향도 분석
웹개발자의 커플링 측정 필요성
- 프론트엔드 : 컴포넌트 간 의존성이 많을수록 재사용성 낮아짐
- 백엔드 : 서비스 간 의존도가 높으면 변경/배포 어려워짐
- 마이크로서비스 : 서비스 간 커플링은 시스템 전체 안정성에 영향
- 코드 리팩토링 : 개선 전후 커플링 측정으로 효과 확인 가능
커플링과 LCOM의 관계
‘LCOM(Lack of Cohesion of Methods)’은 응집도(Cohesion)를 측정하는 지표이다. 반면 ‘커플링 측정 기준’은 결국 결합도(Coupling)를 측정하는 지표이다.
- 커플링 지표: 서로 다른 모듈/클래스 간의 의존성을 측정 (외부 관계)
- LCOM: 한 클래스 내부의 메서드들이 얼마나 서로 관련되어 있는지 측정 (내부 관계)
Chapter4. 아키텍처 특성 정의
Q3. 생각해보지 않고 신경도 안 썼고 있는지도 몰랐던 아키텍처 특성들이 있으셨나요? 그리고 아키텍처 특성 이름은 처음 보지만 관련된 문제를 겪었던 경험이 있으신가요?
흔히 많이 쓰이는 ‘레이어드 아키텍처’인지 모르고 사용하던 시절, 단순한 게시판을 만들기 위해 아래와 같은 고민들을 하게 되었다.
- 단순한 기능인데 인터페이스까지 만들어서 추상화를 해야 하나?
- 사용자 레이어가 변경되었다고 거의 모든 패키지에서 에러 메세지가 떠야하나?
- 서비스를 먼저 만들고 테스트하고 싶은데 DAO단부터 만들고 설계해야 하나?
문제점을 인식하고 있었지만 어떻게 해결해야 할지 몰라 절대적인 시간을 투자했던 지난 세월.. 아키텍처를 공부했었다면 어떻게 해결하려고 했을까? 책에서는 어떤 문제를 소프트웨어로 해결하기 위해서는, 시스템 요구사항을 취합하고 그것을 구현하는 데 필요한 다양한 기술을 소프트웨어 개발 프로세스에 따라 정리해야 한다고 한다.
하지만 ‘어떤 문제’가 위와 같은 아키텍처로 인한 문제를 말하는 것 같지 않다. 도메인 기능과 직접적인 관련이 없는 모든 것들, 즉 아키텍처 특성을 정의 발견, 분석하는 일을 수행하는 것이 아키텍트가 하는 일이라고 하는데 이 말은즉슨 한번쯤 들어봤을지도 모 비기능 요구사항을 정의를 수행하는 것이라고 한다.
그렇다면 개발자들이 코딩, 설계에서 발생하는 ‘어떤 문제’는 이 책에서 어떻게 해결하면 좋다고 말할까?
그리고 개발자들이 말하는 아키텍처와 책에서 말하는 아키텍처는 어떻게 다르고 같은 문제로 귀결될 수 있을까?
책에서 말하는 아키텍처와 일반적인 이해 비교
- 책에서 말하는 아키텍처
- 비기능적 요구사항(아키텍처 특성)에 초점
- 시스템의 거시적 품질과 특성을 강조(가용성, 확장성, 성능 등)
- 도메인 기능과 직접 관련 없는 구조적 측면을 다룸
- 개발자들이 일반적으로 생각하는 아키텍처
- 코드 구조화 방식(레이어드, 클린 아키텍처 등)
- 개발 과정에서 발생하는 구체적인 문제 해결
- 코드 의존성, 모듈화, 테스트 용이성 등의 실질적 측면
아키텍처의 특성과 개발자의 문제 연결점
책에서 말하는 아키텍처 특성과 개발자가 겪는 문제점은 문제를 바라보는 관점이 다를 뿐 서로 밀접하게 연결되어 있다.
- 아래 문제들은 실제로 '유지보수성', '테스트 용이성', '모듈화', '변경 용이성' 등의 아키텍처 특성과 연결된다
- 단순한 기능인데 인터페이스까지 만들어서 추상화를 해야 하나?
- 사용자 레이어가 변경되었다고 거의 모든 패키지에서 에러 메세지가 떠야하나?
- 서비스를 먼저 만들고 테스트하고 싶은데 DAO단부터 만들고 설계해야 하나?
- 레이어드 아키텍처, 클린 아키텍처 등은 단순한 코드 구조화 방식을 넘어, 특정 아키텍처 특성을 달성하기 위한 패턴이다.
- 레이어드 아키텍처: 관심사 분리를 통한 변경 용이성과 유지보수성 향상
- 클린 아키텍처: 비즈니스 로직 분리를 통한 테스트 용이성 및 변경 독립성 강화
책이 제시할 수 있는 해결책
책에서는 개발자의 문제를 이렇게 해결하라는 실질척인 측면에서 제시하지 않는다. 대신
- 아키텍처 특성을 인식하고 우선순위를 정하도록 안내
- 특정 아키텍처 특성을 달성하기 위한 다양한 아키텍처 스타일과 패턴 제시
- 이 패턴들이 어떻게 특정 특성을 강화하는지 설명
앞으로 나올 장에서는 이와 같은 해결책이 나올 수 있을 것이라 생각한다. 그렇다면 처음 언급한 개발자의 고민을 예로 보자면,
- 단순한 기능인데 인터페이스까지 만들어서 추상화를 해야 하나?
- 이 문제는 요청 수가 늘어나도 시스템이 그에 맞는 성능을 발휘하는 능력인 ‘확장성(scalability)’을 저해하고, 과도한 추상화로 인해 개발자가 얼마나 효율적으로 소프트웨어를 고쳐 개선/발전시키고 변화하는 환경이나 요구사항에 맞게 적용할 수 있는가를 나타내는 ‘유지보수성(maintainability)’에 직접적인 영향을 준다.
- 유지보수성이 중요하다면 관심사 분리와 단일 책임 원칙 적용하여 해결한다.
- 사용자 레이어가 변경되었다고 거의 모든 패키지에서 에러 메세지가 떠야하나?응집은 한 모듈의 파트(구성 요소)가 동일한 모듈 안에 얼마나 포함되어 있는지를 나타냅니다. 다시 말해, 모듈을 구성하는 파트가 서로 얼마나 연관되어 있는가, 하는 것입니다. - p71
- 결합도(coupling)와 응집도(cohesion)의 문제로 레이어 간 의존성이 높으면 한 부분의 변경이 전체 시스템에 영향을 미친다.
- 변경 용이성이 중요하다면 적절한 모듈화와 경계 설정하여 해결한다.
- “응집된 모듈을 나누려고 해봐야 더 커플링되고 가독성은 떨어진다.“ - Larry Constantine
- 서비스를 먼저 만들고 테스트하고 싶은데 DAO단부터 만들고 설계해야 하나?
- 테스트 용이성이 중요하다면 의존성 역전 원칙(DIP)와 같은 패턴 적용하여 해결한다.
- DAO구현체 없이도 서비스를 테스트할 수 있는 모킹(mocking)이나 스텁(stub)을 통한 테스트 가능성
이러한 개발자의 실질적인 문제들은 책에서 언급하는 아키텍처 특성들의 실제 구현 과정에서 발생하는 문제들이다. 때문에 아키텍처는 논리적인 구분이지 물리적인 구분이 아니며, 좋은 아키텍처는 이런 실질적인 문제들을 해결하는 방향으로 설계되어야 한다.
예를 들어 레이어드 아키텍처나 클린 아키텍처와 같은 패턴들이 바로 아키텍처 특성들을 달성하기 위한 방법론이라고 볼 수 있다.
- 클린 아키텍처 : 의존성 규칙을 통해 내부 비즈니스 로직이 외부 프레임워크나 DB에 의존하지 않도록 하여 테스트 용이성을 높인다.
- 레이어드 아키텍처 : 관심사를 분리하여 각 레이어가 독립적으로 변경될 수 있게 함으로써 변경 용이성을 향상시킨다.
이런 식으로 책에서 말하는 추상적인 아키텍처 특성들은 실제 개발 과정의 구체적인 문제들과 직접 연결된다.
Q4. 개발할 때 고려했던 아키텍처 특성이 있으신가요? 그 특성을 구현하기 위해 어떻게 개발하셨나요?
애초에 고려하여 개발한 적은 없지만, 위에 언급한 경험했던 문제점을들 해결하기 위한 아키텍처를 공부한 적이 있다. 공부 수준이기 때문에 당연히 회사 프로젝트에는 적용할 수 없었고 논리적인 아키텍처를 어떻게 물리적으로 표현해야 할지 거기에서부터 막혀 어려웠던 경험이 있다(헥사고날 아키텍처)
마무리
생각해볼 주제는 4가지였어서 내용 정리하는데 오래걸리지 않을거라 생각했는데.. 이해하면서 다음글을 쓰려다 보니 생각보다 오래걸렸다. 그렇다고 설명할 수 있을 정도는 아니지만 내가 모른다는 사실조차 모르는 것들에 대해 알게되어서 기분 좋다 : )
돌아오는 스터디 시간에는 공유된 주제에 대해서 미리 생각해가자💪
'📚 오늘도 한 페이지 > 소프트웨어 아키텍처 101' 카테고리의 다른 글
[소프트웨어 아키텍처 101] CHAPTER 9. 아키텍처 스타일 - 기초 (0) | 2025.04.03 |
---|---|
[소프트웨어 아키텍처 101] CHAPTER 8. 컴포넌트 기반 사고 (2) | 2025.03.26 |
[소프트웨어 아키텍처 101] CHAPTER 7. 아키텍처 특성 범위 (0) | 2025.03.19 |
[소프트웨어 아키텍처 101] CHAPTER 6. 아키텍처 특성의 측정 및 거버넌스 (1) | 2025.03.09 |
[소프트웨어 아키텍처 101] CHAPTER 4, 5. 아키텍처 특성 정의와 식별 (2) | 2025.03.07 |