효율적인 소프트웨어 설계를 위한 핵심 원칙: 관심사의 분리(Separation of Concerns)

ClydeHan·2024년 8월 29일
5

관심사의 분리(Separation of Concerns)

관심사 분리 참고 이미지

이미지 출처: freepik.com

📌 개요

관심사의 분리(Separation of Concerns, SoC)는 소프트웨어 개발에서 가장 중요한 설계 원칙 중 하나이며, SOLID 원칙 중 두 가지(단일 책임 원칙(SRP, Single Responsibility Principle)인터페이스 분리 원칙(ISP, Interface Segregation Principle))가 바로 이 개념에서 파생되었다. 이 원칙은 프로그램을 여러 독립적인 컴포넌트로 나누어 각각의 컴포넌트가 특정 역할에만 집중하도록 하여, 전체 시스템의 복잡성을 줄이고 유지보수성, 테스트 가능성, 재사용성을 높이는 것을 목표로 한다. SoC는 특히 복잡한 대규모 시스템에서 중요한 역할을 한다.


📌 성공적인 관심사 분리의 핵심 체크리스트

고객이 프로그램에 새로운 기능을 추가해 달라고 요청했다고 가정해 보자. 이때 프로그램을 수정하면서 고려해야 할 몇 가지 중요한 요소가 있다.

  • 얼마나 많은 코드를 수정해야 하는가?
    • 프로그램의 특정 동작에 대한 코드가 잘 분리되어 있다면, 새로운 기능과 관련된 부분만 수정하면 된다. 즉, 수정해야 할 코드의 양이 적어진다.
  • 수정이 얼마나 쉬운가?
    • 수정하고자 하는 동작이 다른 부분과 명확히 분리되어 있다면, 프로그램 전체를 깊이 이해하거나 수정하지 않고도 새로운 구현을 추가할 수 있다. 또한, 변경이 필요한 코드를 더 쉽게 찾을 수 있다.
  • 기존 기능을 망가뜨릴 가능성이 얼마나 되는가?
    • 수정할 필요가 없는 코드는 수정하는 코드보다 망가질 가능성이 적다. 관심사를 분리함으로써, 관련 없는 기능이 우발적으로 망가지는 것을 방지할 수 있다. 기능들이 서로 얽혀 있으면, 하나의 기능을 수정하는 과정에서 다른 기능에 영향을 미칠 수 있다.
  • 기존 모델이나 아키텍처를 얼마나 재사용할 수 있는가?
    • 아키텍처가 특정 기술이나 비즈니스 로직에 종속되지 않는다면, 구현을 변경하더라도 새로운 아키텍처 기능을 추가할 필요가 적어진다. 예를 들어, 메인 도메인 로직이 데이터베이스에 종속되지 않는다면, 새로운 데이터베이스를 지원하는 것은 단순히 퍼시스턴스 계층의 구현을 교체하는 것만큼 쉽게 이루어질 수 있다.

관심사의 분리는 이러한 질문들에 더 긍정적인 답변을 얻을 수 있게 도와준다.


📌 관심사의 분리의 예시

💡 일상에서의 관심사 분리

컴퓨터 과학에서 관심사의 분리는 프로그램을 각기 다른 관심사로 나눔으로써 프로그램의 특정 부분이 하나의 관심사만을 다루도록 하는 설계 원칙이다. 이 원칙은 단지 소프트웨어 개발에만 국한되지 않고, 우리의 일상생활에서도 쉽게 찾아볼 수 있는 보편적인 원칙이다.


가정생활에서의 관심사 분리

가장 쉬운 예로 가정생활을 생각해 보자. 집안에서 일어나는 다양한 일들은 서로 다른 사람이나 시스템에 의해 처리된다. 예를 들어, 청소, 요리, 정원 관리, 가계부 작성 등이 있다. 만약 한 사람이 이 모든 일을 혼자 맡게 된다면, 효율성은 떨어지고 실수도 많아질 것이다.

이것이 바로 가정 내에서의 관심사 분리다. 청소는 청소기가, 요리는 주방에서, 정원 관리는 정원사가, 가계부 작성은 가족 중 재정 담당자가 각각 맡아서 처리한다. 각자가 맡은 역할에 집중하므로, 집안일은 더 원활하게 진행된다.


회사에서의 관심사 분리

회사에서도 관심사 분리는 필수적이다. 예를 들어, IT 부서, 인사 부서, 마케팅 부서 등은 각기 다른 역할을 담당한다. IT 부서는 회사의 기술적 요구를 충족시키고, 인사 부서는 직원 관리와 복지를 책임지며, 마케팅 부서는 제품이나 서비스를 홍보한다. 만약 한 부서가 모든 역할을 맡게 된다면, 혼란과 비효율성이 발생할 것이다.

이처럼 회사 내에서는 각 부서가 자신의 역할에 집중하고, 다른 부서와 필요한 부분에서만 협력하는 구조를 가진다. 이는 회사 운영을 더 효율적이고 체계적으로 만들며, 각 부서가 더 높은 전문성을 갖출 수 있게 한다.


💡 소프트웨어 개발에서의 관심사 분리

프로그램을 작성할 때, 모든 코드를 한 곳에 모아두면 유지보수나 확장이 매우 어려워진다. 예를 들어, 웹사이트를 만들 때 HTML, CSS, JavaScript 코드를 하나의 파일에 모두 포함시키는 것은 작은 프로젝트에서는 가능할 수 있지만, 프로젝트가 커지면 문제가 된다.

이를 해결하기 위해, 우리는 코드를 구조적으로 분리한다. HTML은 웹페이지의 구조를 담당하고, CSS는 스타일을 정의하며, JavaScript는 동적 동작을 처리한다. 이렇게 분리하면 각 부분을 독립적으로 수정하거나 교체할 수 있어, 유지보수가 쉬워지고 코드의 가독성도 높아진다.

<!DOCTYPE html>
<html>
<head>
<style>
body {background-color: powderblue;}
h1   {color: blue;}
p    {color: red;}
</style>
</head>
<body>

<h1>This is a heading</h1>
<p>This is a paragraph.</p>

</body>
<script>
console.log("hello world")
</script>
</html>

위의 코드에서는 HTML 구조, 스타일링, 스크립트 로직이 모두 한 파일에 포함되어 있다. 이 구조에서는 페이지가 복잡해질수록 코드를 관리하기가 어려워지며, 변경 사항을 적용할 때 오류가 발생할 가능성이 높아진다.

하지만, 다음과 같이 각 부분을 분리할 수 있다.

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles.css">
</head>
<body>

<h1>This is a heading</h1>
<p>This is a paragraph.</p>

</body>
<script src="logic.js"></script>
</html>
// logic.js
console.log("hello world")
/* styles.css */
body {background-color: powderblue;}
h1   {color: blue;}
p    {color: red;}

이제 코드는 HTML 구조, CSS 스타일링, JavaScript 로직으로 각각 분리되었다. 이러한 구조에서는 코드가 더 명확해지고, 각 부분을 독립적으로 수정할 수 있어 유지보수와 확장이 훨씬 쉬워진다. 예를 들어, 스타일을 변경하고 싶다면 styles.css 파일만 수정하면 된다. 로직을 변경하고 싶다면 logic.js 파일만 수정하면 된다. 이는 SoC의 기본 원칙을 잘 보여주는 예시다.


💡 프로그래밍 함수에서의 관심사 분리

코드의 가장 기본적인 단위인 함수에서도 SoC 원칙을 적용할 수 있다. 복잡하고 긴 함수는 여러 책임을 가지고 있을 가능성이 높으며, 이는 코드의 가독성을 떨어뜨리고 유지보수를 어렵게 만든다. SoC는 이러한 함수를 더 작은 함수로 분리하여 각각이 명확한 역할을 수행하도록 한다.

	function drawCircle() {
    // 원을 그리는 코드
}

function drawRectangle() {
    // 사각형을 그리는 코드
}

이 두 함수는 모두 그리기 작업을 수행하므로, 이들을 하나의 클래스나 모듈에 포함시키는 것이 자연스럽다. 이를 통해 관련된 기능을 하나로 묶어 응집도를 높일 수 있다.

class Draw {

    public function drawCircle() {
        // 원을 그리기
    }

    public function drawRectangle() {
        // 사각형을 그리기
    }
}

이렇게 하면 그리기 작업과 관련된 기능이 한 곳에 모여 있어 코드가 더 이해하기 쉽고 유지보수하기 쉬워진다.


💡 모듈에서의 관심사 분리

함수 단위에서 SoC를 적용하는 것뿐만 아니라, 더 큰 단위인 모듈에서도 이 원칙을 적용할 수 있다. 모듈은 일반적으로 관련된 함수나 클래스를 하나로 묶어 더 큰 기능을 제공하는 단위이다. 이 모듈들을 잘 분리하면 시스템 전체의 유지보수성과 확장성이 크게 향상된다.

예를 들어, 어떤 애플리케이션이 사용자 관리, 상품 관리, 주문 관리 등의 기능을 가진다고 가정하자. 각 기능을 독립적인 모듈로 분리하여, 서로 독립적으로 동작할 수 있게 한다면, 한 모듈의 변경이 다른 모듈에 미치는 영향을 최소화할 수 있다.


📌 응집도와 결합도

  • 관심사의 분리(SoC)를 효과적으로 적용하기 위해서는 응집도(cohesion)결합도(coupling)에 대한 깊은 이해가 필요하다. 이 두 개념은 소프트웨어 모듈이 얼마나 잘 설계되었는지 평가하는 중요한 척도이다.

📌 응집도(Cohesion)

💡 응집도란?

응집도는 모듈이나 클래스 내의 요소들이 얼마나 밀접하게 관련되어 있는지를 나타내는 척도이다. 응집도가 높다는 것은 그 모듈이나 클래스가 단일한 기능이나 역할에 집중하고 있다는 의미다. 응집도가 낮다면, 그 모듈은 여러 가지 역할을 동시에 수행하고 있을 가능성이 높으며, 이는 코드의 가독성과 유지보수성을 저해한다.


💡 응집도의 유형

응집도는 그 수준에 따라 다음과 같이 분류할 수 있다.

  1. 기능적 응집(Functional Cohesion): 모듈 내 모든 요소들이 하나의 명확한 기능을 수행하기 위해 협력하는 경우이다. 이는 가장 높은 수준의 응집도로, 이상적인 응집도 형태이다. 예를 들어, 하나의 함수가 입력 값을 받아 이를 처리하여 결과를 반환하는 경우, 그 함수의 모든 코드가 단일한 목적을 위해 작성된 것이므로 기능적 응집을 가진다고 할 수 있다.
  2. 순차적 응집(Sequential Cohesion): 모듈 내의 한 요소의 출력이 다른 요소의 입력으로 사용되는 경우이다. 예를 들어, 데이터가 여러 단계를 거쳐 처리되는 경우, 각 단계가 서로 밀접하게 관련되어 있어 순차적 응집을 가진다고 할 수 있다.
  3. 논리적 응집(Logical Cohesion): 유사한 성격을 가진 작업들을 모듈 내에서 처리하는 경우이다. 예를 들어, 여러 형태의 입력 검증을 담당하는 모듈은 논리적 응집을 가진다고 할 수 있다. 이는 보통 기능적 응집보다는 낮은 수준의 응집이다.
  4. 시간적 응집(Temporal Cohesion): 특정 시간에 발생하는 작업들을 하나의 모듈에서 처리하는 경우이다. 예를 들어, 시스템 시작 시 필요한 여러 초기화 작업들을 한 곳에 모아둔 경우, 이는 시간적 응집을 가진다고 할 수 있다.
  5. 절차적 응집(Procedural Cohesion): 특정 순서로 실행되어야 하는 작업들을 한 모듈에 모아둔 경우이다. 이는 순차적 응집과 비슷하지만, 각 작업이 직접적으로 연관되지 않을 수도 있다.
  6. 우발적 응집(Coincidental Cohesion): 모듈 내의 요소들이 서로 전혀 관련이 없고, 단지 한 곳에 모아져 있는 경우이다. 이는 가장 낮은 수준의 응집도로, 유지보수와 이해가 매우 어려워진다.

💡 높은 응집도의 장점

높은 응집도를 가진 모듈은 다음과 같은 장점을 제공한다.

  • 가독성 향상: 모듈 내 모든 코드가 같은 목표를 위해 존재하기 때문에 코드를 이해하기가 훨씬 쉽다.
  • 유지보수성 향상: 모듈이 명확한 책임을 가지고 있기 때문에, 특정 기능을 수정하거나 개선할 때 코드의 다른 부분에 영향을 미치지 않고 쉽게 수정할 수 있다.
  • 재사용성 증가: 높은 응집도를 가진 모듈은 특정 작업을 잘 정의하고 있기 때문에 다른 프로젝트나 상황에서 재사용하기가 용이하다.
  • 테스트 용이성: 각 모듈이 명확한 책임을 가지고 있기 때문에, 독립적인 테스트가 가능하며, 테스트 시의 복잡도가 낮아진다.

💡 낮은 응집도의 문제점

반대로, 낮은 응집도를 가진 모듈은 다음과 같은 문제를 일으킨다.

  • 이해의 어려움: 모듈 내의 요소들이 서로 다른 역할을 수행하기 때문에, 그 모듈이 실제로 무엇을 하는지 이해하기가 어렵다.
  • 유지보수 어려움: 한 모듈에서 여러 역할을 수행하기 때문에, 특정 기능을 수정할 때 예상치 못한 부작용이 발생할 수 있다.
  • 재사용성 감소: 낮은 응집도를 가진 모듈은 특정 상황에 종속적인 경우가 많아, 다른 프로젝트에서 재사용하기 어렵다.

📌 결합도(Coupling)

💡 결합도란?

결합도는 모듈 간의 의존성 정도를 나타낸다. 결합도가 낮다는 것은 모듈 간의 의존성이 적고, 각 모듈이 독립적으로 동작할 수 있음을 의미한다. 반대로, 결합도가 높으면 모듈 간의 의존성이 커져, 하나의 모듈을 변경할 때 다른 모듈에도 영향을 미치게 된다.


💡 결합도의 유형

결합도는 그 수준에 따라 다음과 같이 분류할 수 있다.

  1. 내용 결합(Content Coupling): 한 모듈이 다른 모듈의 내부 내용을 직접 참조하거나 수정하는 경우이다. 이는 가장 강한 결합도로, 매우 바람직하지 않다. 예를 들어, 한 모듈이 다른 모듈의 변수를 직접 수정하는 경우가 여기에 해당한다.
  2. 공통 결합(Common Coupling): 두 모듈이 전역 데이터를 공유하는 경우이다. 이는 전역 변수를 사용하는 경우에 발생하며, 전역 데이터의 상태 변화가 모든 관련 모듈에 영향을 미치기 때문에 유지보수가 매우 어렵다.
  3. 외부 결합(External Coupling): 두 모듈이 특정 외부 인터페이스를 통해 데이터를 공유하는 경우이다. 이는 하드웨어나 운영체제와 같은 외부 시스템에 의존하는 경우 발생한다.
  4. 제어 결합(Control Coupling): 한 모듈이 다른 모듈의 제어 흐름을 변경하는 경우이다. 예를 들어, 한 모듈이 다른 모듈에게 특정 플래그나 상태를 전달하여 그 모듈의 동작 방식을 변경하도록 하는 경우가 여기에 해당한다.
  5. 스탬프 결합(Stamp Coupling): 두 모듈이 동일한 데이터 구조를 공유하지만, 그 중 일부만을 사용하는 경우이다. 예를 들어, 한 모듈이 복잡한 구조체를 전달받아 그 중 일부만 사용하는 경우가 여기에 해당한다. 이는 필요 이상으로 많은 데이터를 전달함으로써 모듈 간의 의존성을 높인다.
  6. 자료 결합(Data Coupling): 모듈 간에 단순한 데이터 값만을 전달하는 경우이다. 이는 결합도가 가장 낮은 형태로, 모듈 간의 의존성이 최소화된다. 예를 들어, 한 모듈이 다른 모듈에게 단순한 값(예: 정수나 문자열)을 전달하는 경우가 여기에 해당한다.

💡 낮은 결합도의 장점

낮은 결합도를 가진 모듈은 다음과 같은 장점을 제공한다.

  • 변경의 용이성: 한 모듈을 변경해도 다른 모듈에 영향을 미치지 않기 때문에, 유지보수와 확장이 훨씬 쉬워진다.
  • 재사용성 증가: 모듈이 독립적으로 동작할 수 있기 때문에, 다른 프로젝트나 상황에서 쉽게 재사용할 수 있다.
  • 테스트 용이성: 모듈이 다른 모듈에 의존하지 않거나 최소한으로 의존하기 때문에, 독립적인 테스트가 가능하며, 테스트 시의 복잡도가 낮아진다.

💡 높은 결합도의 문제점

높은 결합도를 가진 모듈은 다음과 같은 문제를 일으킨다.

  • 변경의 어려움: 한 모듈을 변경할 때 다른 모듈에도 영향을 미칠 수 있어, 예상치 못한 부작용이 발생할 수 있다.
  • 재사용성 감소: 모듈이 다른 모듈에 강하게 의존하고 있기 때문에, 다른 프로젝트에서 재사용하기 어렵다.
  • 테스트의 복잡성 증가: 모듈 간의 의존성이 높아지면, 독립적인 테스트가 어려워지고, 모든 관련 모듈을 함께 테스트해야 할 수도 있다.

💡 결합도를 줄이기 위한 전략

결합도를 줄이기 위한 몇 가지 전략은 다음과 같다.

  1. 인터페이스 사용: 인터페이스를 통해 모듈 간의 상호작용을 정의하면, 모듈 간의 결합도를 줄일 수 있다. 이는 모듈이 다른 모듈의 구체적인 구현이 아닌, 인터페이스만 참조하게 하기 때문이다.
  2. 의존성 주입(Dependency Injection): 모듈이 필요한 의존성을 외부에서 주입받도록 하면, 모듈 간의 결합도를 낮출 수 있다. 이는 모듈이 직접 다른 모듈을 생성하지 않고, 외부에서 제공받기 때문에 결합도가 줄어든다.
  3. 이벤트 기반 아키텍처: 모듈 간의 상호작용을 이벤트를 통해 처리하면, 결합도를 낮출 수 있다. 모듈이 서로 직접적으로 호출하지 않고, 이벤트를 통해 간접적으로 상호작용하기 때문이다.
  4. 데이터 구조의 단순화: 모듈 간에 전달되는 데이터 구조를 단순화하면, 스탬프 결합을 줄이고 결합도를 낮출 수 있다.
  5. 캡슐화: 모듈 내의 데이터를 외부에서 접근하지 못하게 캡슐화하면, 모듈 간의 결합도를 줄일 수 있다. 이는 한 모듈의 내부 구현이 변경되더라도, 다른 모듈에 영향을 미치지 않게 한다.

📌 느슨한 결합과 높은 응집도의 이점

결합도와 응집도는 프로그래머의 관점에서 코드 작업의 편리성과 생산성에 크게 영향을 미친다. 느슨한 결합과 높은 응집도를 유지하면 코드의 유지보수와 확장이 쉬워지고, 개발 속도도 빨라지며, 팀의 협업도 원활해진다.

💡 더 나은 코드 명확성

모듈이 각각의 역할에 맞게 잘 정의된 메서드와 명확한 API를 가지고 있다면, 프로그램에서 무슨 일이 일어나고 있는지를 이해하기가 훨씬 쉬워진다. 예를 들어, 특정 모듈이 사용자 데이터를 처리하는 역할을 담당한다면, 그 모듈에는 오직 사용자 데이터와 관련된 코드만 있어야 한다. 이렇게 하면 코드를 읽는 사람은 그 모듈이 어떤 일을 하는지 한눈에 파악할 수 있다. 이처럼 명확한 역할 분리가 이루어지면, 코드의 가독성이 높아지고 유지보수가 쉬워진다.

💡 더 나은 코드 재사용성

코드를 재사용할 수 있다는 것은 매우 중요한 이점이다. 이를 통해 유지보수 비용을 크게 줄일 수 있다. 예를 들어, 한 번 작성한 코드가 여러 곳에서 재사용될 수 있다면, 그 코드를 수정할 때도 한 곳만 수정하면 된다. 이를 통해 같은 기능을 여러 번 구현할 필요가 없어지고, 버그를 수정하거나 기능을 확장할 때도 수정이 간편해진다. 이는 "DRY(Don't Repeat Yourself)" 원칙을 따르는 것이며, 코드의 일관성을 유지하는 데 큰 도움이 된다.

💡 더 나은 테스트 가능성

모듈이 적절하게 독립성을 유지하고 있다면, 그 모듈을 테스트하는 것도 훨씬 쉬워진다. 예를 들어, 특정 모듈이 다른 모듈에 크게 의존하지 않는다면, 그 모듈을 독립적으로 테스트할 수 있다. 이는 전체 시스템을 설정할 필요 없이, 해당 모듈만 테스트할 수 있게 해준다. 실제 모듈 대신 더미 모듈이나 가짜 데이터를 사용해도 테스트가 가능하다. 이렇게 하면 모듈을 블랙박스 테스트(출력만 확인)하거나 화이트박스 테스트(내부 동작까지 확인)할 수 있다. 이를 통해 버그를 조기에 발견하고 수정할 수 있어, 시스템의 안정성을 높일 수 있다.

💡 더 빠른 프로젝트 발전

모듈이 잘 분리되어 있으면, 새로운 기능을 추가하거나 기존 기능을 업데이트하는 작업이 훨씬 빠르게 진행될 수 있다. 변경이 필요한 부분을 명확히 구분할 수 있기 때문에, 변경으로 인해 영향을 받을 수 있는 프로그램의 다른 부분을 쉽게 파악할 수 있다. 이렇게 하면 개발 속도가 빨라지고, 프로젝트의 전반적인 진척도도 더 빨라진다. 또한, 각 모듈이 독립적으로 동작하기 때문에, 변경 사항이 다른 모듈에 미치는 영향을 최소화할 수 있다.

💡 동시 개발의 용이성

여러 명의 엔지니어가 동시에 개발할 때, 모듈 단위로 작업을 분할하면 효율이 크게 향상된다. 각 엔지니어는 자신이 작업할 모듈을 맡아 독립적으로 작업할 수 있으며, 서로의 작업에 방해가 되지 않도록 조정할 수 있다. 물론, 모듈의 API를 변경해야 할 경우에는 다른 개발자들에게 명확하게 알릴 필요가 있지만, 대부분의 변경 사항은 다른 모듈에 영향을 주지 않으므로 즉각적인 주의가 필요하지 않다. 또한, 좋은 테스트 커버리지가 유지된다면 병렬 개발의 효율성도 극대화될 수 있다. 이는 각 엔지니어가 독립적으로 작업할 때와 동일한 수준의 생산성을 유지할 수 있다는 것을 의미한다.


📌 시스템 설계를 위한 관심사 분리

💡 개요

시스템 설계에서 관심사의 분리(Separation of Concerns, SoC)를 적용하는 것은 각 모듈이 독립적으로 동작하면서도 전체 시스템이 일관되게 기능할 수 있도록 만드는 중요한 전략이다. 모듈이 명확한 목적을 가지고 구성되었다 하더라도, 모듈 간의 상호작용 방식에 대한 전반적인 전략이 없다면 시스템은 복잡해지고 유지보수하기 어려운 구조가 될 수 있다.


💡 시스템 설계의 주요 목표

시스템 설계의 핵심 목표는 각 모듈이 서로에 대해 인식하는 경계를 명확하게 설정하는 것이다. 이는 모듈 간의 의존성을 최소화하고, 독립적으로 동작할 수 있도록 하는 데 중점을 둔다. 모듈 간의 잘못된 의존 관계는 시스템의 복잡성을 증가시키고, 코드 변경 시 예상치 못한 오류를 발생시킬 수 있기 때문이다.


💡 아키텍처 패턴과 SoC

기존의 아키텍처 패턴들은 이러한 전략을 지원한다. 대표적인 예로 모델-뷰-컨트롤러(Model-View-Controller, MVC) 패턴이 있다. 이 패턴에서는 다음과 같은 규칙을 따른다.

  • 모델(Model): 데이터와 비즈니스 로직을 관리한다.
  • 뷰(View): 사용자 인터페이스를 관리한다.
  • 컨트롤러(Controller): 모델과 뷰 사이의 상호작용을 중재한다.

MVC 패턴은 이러한 역할 분리를 통해 시스템의 복잡성을 줄이고, 각 구성 요소가 명확한 책임을 갖도록 한다. 뷰는 모델과 직접 상호작용하지 않고, 항상 컨트롤러를 통해서만 상호작용한다. 이처럼 역할 간의 명확한 경계를 설정함으로써 시스템의 유연성을 높일 수 있다.


💡 계층적 설계

모듈을 효과적으로 분리하는 또 다른 방법은 시스템을 계층으로 나누는 것이다. 각 계층은 유사한 역할과 동일한 추상화 수준을 가지며, 계층 간의 통신은 제한된다. 이렇게 하면 각 계층은 서로 독립적으로 동작할 수 있게 되고, 시스템의 복잡성이 줄어든다.

  • 하위 계층: 데이터베이스나 네트워킹 서비스와 같은 구체적인 인프라를 담당한다. 이 계층은 상위 계층에 대해 아무것도 알지 못하며, 단지 필요한 서비스를 제공하는 역할을 한다.
  • 상위 계층: 비즈니스 로직이나 사용자 인터페이스를 담당하며, 하위 계층의 서비스에 의존한다. 그러나 이들은 하위 계층의 내부 동작에 대해 알 필요가 없으며, 인터페이스를 통해서만 상호작용한다.

이러한 계층적 구조에서는 하위 계층의 변경이 상위 계층에 영향을 미치지 않도록 설계하는 것이 중요하다. 예를 들어, 네트워킹 서비스가 변경되더라도 비즈니스 로직이나 UI 계층은 그대로 유지될 수 있어야 한다. 이를 통해 시스템의 유연성과 유지보수성을 높일 수 있다.


💡 결론

시스템 설계에서 SoC를 성공적으로 적용하기 위해서는 모듈 간의 의존성을 줄이고, 각 모듈이 독립적으로 동작할 수 있도록 경계를 명확히 설정해야 한다. 이를 위해 MVC와 같은 아키텍처 패턴이나 계층적 설계 방식을 활용할 수 있다. 이러한 전략은 시스템의 복잡성을 줄이고, 유지보수성을 높이며, 테스트를 더 용이하게 만들어 준다.


📌 결론

관심사의 분리(SoC)는 소프트웨어 개발에서 매우 중요한 설계 원칙이다. 이 원칙을 따르면 코드의 유지보수성, 확장성, 테스트 가능성을 크게 향상시킬 수 있다. 코드를 작성하거나 아키텍처를 설계할 때 SoC를 염두에 두고, 결합도를 낮추고 응집도를 높이는 방향으로 설계해야 한다.


참고문헌

0개의 댓글