출제기준 세세항목: 설계 모델링 · 소프트웨어 아키텍처 · 재사용 · 모듈화 · 결합도 · 응집도
회원가입, 주문, 게시판처럼 서로 다른 기능을 만들다 보면 이상하게 같은 일을 반복하게 됩니다. 날짜를 '2026-10-12' 모양으로 바꾸는 일, 로그인한 사람이 누구인지 확인하는 일, 오류가 났을 때 기록을 남기는 일이 그렇습니다. 이런 일을 기능마다 따로 만들면 처음에는 빨라 보여도, 날짜 형식을 바꾸고 싶어지는 순간 열 군데를 찾아다니며 고쳐야 합니다.
그래서 여러 기능이 같이 쓰는 부분은 한 곳에 모아 두고 다들 그것을 불러 쓰게 만듭니다. 이것이 공통 모듈입니다. 고칠 일이 생기면 한 곳만 고치면 되고, 이미 검증된 코드를 다시 쓰니 새로 만드는 기능의 품질도 올라갑니다.
다만 공통 모듈은 많은 기능이 기대고 있는 기둥이라, 잘못 만들면 영향도 그만큼 넓게 퍼집니다. 이번 항목에서 배우는 아키텍처, 모듈화, 결합도, 응집도는 결국 '이 기둥을 어떻게 튼튼하고 독립적으로 세울까'에 대한 이야기입니다.
집을 지을 때 바로 벽돌을 쌓지 않고 설계도부터 그리듯, 소프트웨어도 코드를 쓰기 전에 구조를 그림과 문서로 표현해 봅니다. 이 작업을 설계 모델링이라고 합니다. 요구사항을 '무엇을 해야 하는가'라고 한다면, 설계 모델은 '그것을 어떤 구조로 해낼 것인가'를 보여 줍니다.
설계는 보통 두 층으로 나눠 생각합니다. 상위 설계는 시스템 전체의 뼈대, 즉 큰 덩어리들이 무엇이고 서로 어떻게 연결되는지를 정합니다. 아키텍처 설계라고도 부릅니다. 하위 설계는 그 덩어리 안의 모듈 하나하나가 어떤 입력을 받아 무엇을 돌려주는지, 내부 처리는 어떻게 하는지를 자세히 정합니다. 모듈 설계, 상세 설계라고도 합니다.
모델은 보는 관점에 따라 나눠 그리기도 합니다. 시스템이 어떤 부품으로 이뤄졌는지 보여 주는 구조(정적) 모델과, 시간에 따라 무슨 일이 어떤 순서로 일어나는지 보여 주는 행위(동적) 모델이 대표적입니다. 같은 시스템이라도 관점을 나눠 그려야 놓친 부분이 잘 보입니다.
소프트웨어 아키텍처는 시스템을 이루는 큰 구성 요소들과 그 사이의 관계, 그리고 그렇게 나눈 원칙을 말합니다. 아파트로 치면 몇 층짜리인지, 엘리베이터와 계단은 어디에 둘지, 배관은 어떻게 지나갈지를 정하는 단계입니다. 뼈대가 정해지면 공통 모듈이 어느 층에 들어갈지도 자연스럽게 정해집니다.
자주 쓰이는 뼈대 몇 가지를 알아 두면 좋습니다. 계층형은 화면, 업무 처리, 데이터 저장처럼 역할별로 층을 쌓고 위층이 바로 아래층만 부르게 하는 구조입니다. 클라이언트-서버는 요청하는 쪽과 처리해서 응답하는 쪽을 나누는 구조입니다. MVC는 데이터(Model), 화면(View), 둘 사이를 조율하는 부분(Controller)을 나눠 화면을 바꿔도 데이터 처리가 흔들리지 않게 합니다. 파이프-필터는 데이터가 여러 처리 단계를 차례로 통과하며 바뀌는 구조로, 각 단계를 독립적으로 바꿔 끼울 수 있습니다.
이 밖에도 이름을 알아 두면 좋은 스타일이 있습니다. 마스터-슬레이브는 일을 나눠 주고 결과를 모으는 마스터와 실제 일을 하는 슬레이브로 나눕니다. 저장소(Repository) 스타일은 여러 구성 요소가 하나의 공용 데이터 저장소를 중심으로 일합니다. 브로커는 요청을 받아 알맞은 서버로 연결해 주는 중개자를 두고, 피어 투 피어(P2P)는 각 참여자가 요청하는 쪽과 응답하는 쪽 역할을 모두 합니다. 이벤트 버스는 구성 요소들이 서로를 직접 부르지 않고, 공용 통로(버스)에 이벤트를 올리고 관심 있는 이벤트만 받아 처리합니다.
어떤 뼈대를 고르든 목표는 같습니다. 바뀌는 부분과 바뀌지 않는 부분을 떼어 놓아, 한쪽이 바뀌어도 다른 쪽이 덜 흔들리게 만드는 것입니다. 이 생각이 그대로 다음에 나오는 모듈화로 이어집니다.
모듈화는 큰 프로그램을 일정한 역할을 하는 작은 단위(모듈)로 나누는 것입니다. 큰 문제를 한 번에 풀기 어려우면 작은 문제로 쪼개 하나씩 푸는 '분할과 정복'의 생각과 같습니다. 잘 나누면 여러 사람이 동시에 개발할 수 있고, 문제가 생겨도 어느 모듈인지 금방 찾을 수 있습니다.
잘 나눴는지를 판단하는 기준이 모듈의 독립성입니다. 독립성이 높은 모듈은 다른 모듈을 덜 알아도 동작하고, 고쳐도 주변에 미치는 영향이 적습니다. 이를 돕는 원칙으로 정보 은닉이 있습니다. 모듈 내부의 세부 구현은 감추고 밖에서는 정해진 입구(인터페이스)로만 쓰게 하는 것입니다. 자판기를 쓸 때 버튼만 누르면 되고 안의 기계 구조는 몰라도 되는 것과 같습니다.
모듈 사이의 호출 관계를 볼 때는 팬인(Fan-in)과 팬아웃(Fan-out)이라는 말을 씁니다. 팬인은 나를 부르는 모듈의 수, 팬아웃은 내가 부르는 모듈의 수입니다. 공통 모듈은 여러 곳에서 불려 쓰이니 팬인이 높은 것이 자연스럽습니다. 반대로 한 모듈의 팬아웃이 지나치게 높다면, 그 모듈이 너무 많은 일을 직접 챙기고 있다는 신호일 수 있습니다.
독립성은 두 방향에서 잽니다. 모듈끼리 얼마나 얽혀 있는지를 보는 결합도와, 모듈 안의 요소들이 얼마나 한 가지 목적으로 뭉쳐 있는지를 보는 응집도입니다. 결합도는 낮을수록, 응집도는 높을수록 독립성이 높습니다.
결합도는 두 모듈이 서로에게 얼마나 기대고 있는지를 나타냅니다. 결합도가 높으면 한 모듈을 고칠 때 다른 모듈까지 같이 고쳐야 할 가능성이 커집니다. 그래서 낮을수록 좋습니다. 낮은 것부터 높은 것 순서로 여섯 단계를 살펴보겠습니다.
자료 결합도는 꼭 필요한 값만 매개변수로 주고받는 관계입니다. '이 숫자 두 개를 더해 줘'처럼 필요한 것만 건네니 가장 바람직합니다. 스탬프 결합도는 값 몇 개만 필요한데 묶음 전체(배열, 레코드, 객체)를 통째로 넘기는 관계입니다. 받는 쪽이 묶음의 구조를 알아야 하니, 그 구조가 바뀌면 영향을 받습니다.
제어 결합도는 상대 모듈이 무엇을 할지 결정하는 신호(플래그 같은 제어 값)를 넘기는 관계입니다. 부르는 쪽이 상대의 내부 동작 흐름을 좌우하니 얽힘이 한층 깊어집니다. 외부 결합도는 모듈들이 바깥에 정해진 같은 데이터 형식이나 통신 규약, 장치 같은 외부 요소를 함께 참조하는 관계입니다. 그 외부 요소가 바뀌면 관련 모듈이 함께 흔들립니다. 국내 시험 자료에서는 한 모듈이 선언한 데이터(변수)를 다른 모듈이 바깥에서 가져다 참조하는 경우를 외부 결합도로 설명하는 일이 많으니, 이 표현으로 나와도 같은 단계로 알아보면 됩니다.
공통 결합도는 여러 모듈이 하나의 전역 데이터를 같이 읽고 쓰는 관계입니다. 누가 언제 값을 바꿨는지 추적하기 어려워 문제가 생기면 원인을 찾기 힘듭니다. 가장 나쁜 내용 결합도는 한 모듈이 다른 모듈의 내부 데이터나 코드를 직접 들여다보거나 고치는 관계입니다. 남의 집 열쇠를 가지고 마음대로 드나드는 것과 같아서, 상대가 조금만 바뀌어도 바로 깨집니다.
외울 때는 '자-스-제-외-공-내' 순서로 기억하고, 뒤로 갈수록 상대를 더 깊이 안다고 생각하면 헷갈리지 않습니다.
응집도는 한 모듈 안에 들어 있는 요소들이 얼마나 같은 목적을 향하고 있는지를 나타냅니다. 응집도가 높으면 모듈의 이름만 보고도 무엇을 하는지 알 수 있고, 고칠 이유도 하나로 모입니다. 그래서 높을수록 좋습니다. 높은 것부터 낮은 것 순서로 일곱 단계를 보겠습니다.
기능적 응집도는 모듈 안의 모든 요소가 하나의 기능을 위해 함께 일하는 가장 좋은 상태입니다. 순차적 응집도는 한 요소의 출력이 다음 요소의 입력으로 이어지는 관계, 예를 들어 '읽은 값을 정리해서 계산'처럼 앞 단계의 결과를 뒤 단계가 받아 쓰는 경우입니다. 교환적(통신적) 응집도는 같은 입력 데이터를 사용하거나 같은 출력 데이터를 만드는 요소들이 모여 있는 경우입니다.
절차적 응집도는 정해진 순서대로 실행되어야 하는 일들이 모여 있지만, 앞의 결과를 뒤가 꼭 쓰지는 않는 경우입니다. 시간적 응집도는 '프로그램 시작할 때 할 일'처럼 같은 시점에 실행된다는 이유만으로 모인 경우입니다. 논리적 응집도는 비슷한 종류라는 이유로 여러 일을 한 모듈에 넣고, 매개변수 같은 값으로 그중 하나를 골라 실행하는 경우입니다.
가장 낮은 우연적 응집도는 서로 아무 관계 없는 일들이 그냥 한 모듈에 들어 있는 상태입니다. 서랍 하나에 건전지, 영수증, 머리끈이 섞여 있는 것과 같아서, 무엇을 찾거나 고치려 할 때마다 헤매게 됩니다.
결합도와 응집도는 함께 움직이는 경우가 많습니다. 한 모듈이 한 가지 일에 집중하면(응집도가 높으면) 다른 모듈에게 부탁할 일이 줄어들어 결합도도 자연스럽게 낮아집니다.
재사용은 이미 만들어 검증한 것을 다시 쓰는 것입니다. 공통 모듈을 만드는 가장 큰 이유이기도 합니다. 재사용하는 단위는 작은 함수나 클래스부터, 독립적으로 바꿔 끼울 수 있는 컴포넌트, 나아가 애플리케이션 전체까지 다양합니다.
재사용이 잘 되려면 쓰는 사람이 모듈 안을 들여다보지 않고도 정확히 쓸 수 있어야 합니다. 그래서 공통 모듈은 명세를 꼼꼼히 남깁니다. 기능을 정확하게(정확성), 누가 읽어도 한 가지 뜻으로 읽히게(명확성), 빠짐없이(완전성), 다른 공통 모듈과 어긋나지 않게(일관성), 어떤 요구사항에서 나왔는지 따라갈 수 있게(추적성) 적는 것이 좋습니다.
또 재사용할 모듈일수록 앞에서 배운 원칙이 더 중요해집니다. 결합도가 높은 모듈은 다른 곳에 가져가는 순간 딸려 오는 것이 많아 재사용하기 어렵고, 응집도가 낮은 모듈은 필요 없는 기능까지 함께 끌고 오게 됩니다. 결국 '독립적인 모듈'이 곧 '재사용하기 좋은 모듈'입니다.
쇼핑몰의 주문, 장바구니, 마이페이지는 모두 '지금 로그인한 사람이 누구인가'를 확인해야 합니다. 이 확인을 각 화면에 따로 넣지 않고 하나의 공통 모듈로 만들어 두면, 나중에 로그인 방식을 바꿔도 그 모듈 하나만 고치면 됩니다. 이 모듈은 여러 곳에서 불리므로 팬인이 높습니다.
배송비를 계산하는 함수가 주문 객체 전체를 받고 있었는데, 실제로 쓰는 값은 무게와 지역뿐이었습니다(스탬프 결합도). 주문 객체에 필드가 추가될 때마다 이 함수를 다시 확인해야 했습니다. 무게와 지역 두 값만 받도록 바꾸자(자료 결합도) 주문 구조가 바뀌어도 배송비 계산은 영향을 받지 않게 되었습니다.
날짜 변환, 비밀번호 검사, 엑셀 내보내기가 utils라는 파일 하나에 섞여 있으면 우연적 응집도에 가깝습니다. 날짜 관련 기능, 보안 관련 기능처럼 목적별로 나누면 각 모듈의 이름만 보고도 무엇을 하는지 알 수 있고, 다른 프로젝트로 날짜 모듈만 가져가 재사용하기도 쉬워집니다.