사전 캡슐화
개념

캡슐화

gabury1고친 사람 github-actions[bot]

캡슐화는 어떤 덩이의 속을 감싸서 바깥이 직접 못 만지게 하는 일입니다. 바깥에는 정해진 통로만 열어 둡니다. 그러면 속을 고쳐도 바깥 코드는 손대지 않아도 됩니다. 소프트웨어 설계와 네트워크가 이 낱말을 각각 다른 것에 씁니다.

쉽고 빠른 이해

캡슐화는 속을 감추고 바깥에는 정해진 통로만 내주는 일입니다. 계좌를 다루는 덩이가 잔액 값을 감추고 입금·출금·잔액 조회만 내주는 것이 그렇습니다.

속이 다 보이면 바깥 코드가 속의 생김새에 기대어 쓰입니다. 그러면 속을 고칠 때마다 그 코드까지 같이 고쳐야 합니다. 통로를 좁혀 두면 고칠 곳이 안쪽에 머뭅니다.

어떻게 도나:

  1. 안에 든 데이터를 바깥에서 직접 읽고 쓰지 못하게 막습니다
  2. 그 데이터를 다루는 연산 몇 개만 이름 붙여 내놓습니다
  3. 바깥은 그 연산만 부르고 안의 생김새는 모른 채 씁니다

대가도 있습니다. 통로를 거치느라 코드가 길어집니다. 네트워크에서는 감쌀 때마다 안내 정보가 앞에 붙어 보내는 바이트가 늘어납니다.

상세

이 절은 캡슐화가 무엇을 감추고 무엇을 열어 두는지를 봅니다. 은행 계좌를 다루는 코드 한 벌을 줄곧 예로 씁니다. 뒤쪽 소절에서는 네트워크로 옮겨 가서, 보내려는 데이터 한 덩이가 아래로 내려가며 겹겹이 싸이는 과정을 봅니다.

자판기를 떠올리면 가깝습니다. 동전을 넣고 버튼을 누르면 음료가 나옵니다. 안에서 어떤 장치가 도는지 몰라도 쓰는 데 지장이 없습니다.

캡슐화는 데이터와 그 데이터를 다루는 연산을 한 덩이로 묶고, 덩이 바깥에는 정해진 연산만 내놓는 일입니다. 잔액이라는 값과 입금·출금이라는 연산을 함께 묶은 계좌가 그런 덩이입니다. 바깥은 잔액 값을 직접 건드리지 못하고 입금과 출금을 불러서만 바꿉니다. 이렇게 데이터와 연산을 함께 묶어 다루는 덩이를 객체라고 부릅니다.

같은 낱말을 네트워크도 씁니다. 통신 규칙은 한 덩어리가 아니라 여러 겹으로 나뉘어 있고, 그 한 겹을 계층이라고 부릅니다. 위 계층이 만든 덩이를 아래 계층 덩이 안에 넣는 일이 이쪽의 캡슐화입니다.

감싸는 대상이 다를 뿐 뿌리는 같습니다. 둘 다 안을 불투명하게 만들어서 바깥이 안의 생김새를 모른 채 쓰게 합니다.

감춘 데이터와 열어 둔 통로

감추는 까닭부터 봅니다. 계좌의 잔액을 아무 코드나 직접 대입할 수 있으면 음수 잔액이 들어가는 것을 막을 방법이 없습니다. 값을 넣는 곳이 수십 군데로 흩어지면 어느 코드가 잘못 넣었는지 찾기도 어렵습니다.

그래서 이 덩이가 언제나 지켜야 할 약속을 정합니다. 「잔액은 0 미만이 될 수 없다」 같은 약속입니다. 이렇게 늘 참이어야 하는 조건을 불변식이라고 부릅니다. 출금 연산 하나만 값을 바꾸게 해 두면 그 연산 안에서 잔액을 검사해 불변식을 지킬 수 있습니다.

이때 바깥에 내주는 연산을 메서드라고 부릅니다. 덩이에 딸려 있어서 그 덩이의 데이터를 직접 읽고 쓸 수 있는 함수입니다. 어떤 메서드를 바깥에 보이고 어떤 데이터를 감출지는 접근 제어자로 표시합니다. 대부분의 언어가 공개와 비공개 두 표시를 갖고 있습니다.

아래는 계좌 덩이를 바깥에서 쓰는 코드입니다. 잔액을 바꾸는 길이 출금 메서드 하나뿐이라는 것을 보입니다.

Java
Account a = new Account(10000);
a.withdraw(3000);
a.balance();     // 7000
a.balance = -1;  // 컴파일 오류

앞의 세 줄은 통로를 지나갑니다. 마지막 줄은 감춰 둔 데이터에 바로 손을 대려다 컴파일 단계에서 막힙니다. 이 한 줄이 막히는 덕분에 음수 잔액이 아예 생기지 않습니다.

그림으로 보면 통로가 하나라는 것이 드러납니다.

flowchart TD
    C["바깥 코드"] --> M["공개 메서드 · 입금 · 출금 · 잔액"]
    subgraph O["계좌 덩이"]
        M --> D["감춘 데이터 · 잔액"]
    end
    C -.->|막힌 길| D

안을 고쳐도 바깥이 안 깨지는 까닭

감추기는 실수를 막는 데서 끝나지 않습니다. 고칠 때 파급을 줄이는 쪽이 더 큰 몫입니다.

바깥 코드가 기대는 것은 메서드의 이름과 그 메서드가 해 주기로 한 약속뿐입니다. 이 약속의 묶음을 인터페이스라고 부릅니다. 인터페이스가 그대로면 안쪽 생김새는 마음대로 바꿔도 됩니다. 이렇게 안쪽 생김새를 바깥에 알리지 않는 것을 정보 은닉이라고 부릅니다.

계좌로 보면 이렇습니다. 처음에는 잔액을 숫자 한 칸으로 들고 있다가, 나중에 입금과 출금 내역 목록으로 바꿀 수 있습니다. 잔액 조회 메서드가 목록을 더해서 답하도록 안쪽만 고치면 됩니다. 바깥 코드는 여전히 잔액 조회를 부르고 같은 숫자를 받습니다.

만약 바깥 코드가 잔액 값을 직접 읽고 있었다면 이야기가 달라집니다. 그 값을 읽던 곳을 전부 찾아 고쳐야 합니다. 한쪽을 고칠 때 다른 쪽까지 따라 고쳐야 하는 정도를 결합도라고 부릅니다. 캡슐화는 이 정도를 낮추는 모듈 설계의 기본 수단입니다.

그래서 캡슐화가 값을 내는 조건도 여기서 나옵니다. 지킬 약속이 있거나 안쪽을 나중에 갈아 끼울 만한 덩이여야 합니다. 좌표 한 쌍처럼 값 몇 개를 담기만 하고 지킬 약속이 없는 덩이에 통로를 세우면 부를 이름만 늘고 막아 주는 것이 없습니다.

네트워크에서 한 계층이 다른 계층을 싣는 방식

네트워크로 옮겨 갑니다. 앞에서 통신 규칙이 여러 겹으로 나뉘고 그 한 겹을 계층이라 부른다고 했습니다. 각 계층은 자기 일만 하고 위아래 계층이 안에서 무엇을 하는지는 모릅니다.

이 모름을 만들어 내는 방법이 캡슐화입니다. 위 계층이 만든 덩이를 아래 계층은 손대지 않고 자기 덩이 안에 넣습니다. 이렇게 싸여 들어간 부분을 페이로드라고 부릅니다. 아래 계층에게 페이로드는 뜻을 모르는 바이트 묶음일 뿐입니다.

대신 아래 계층은 페이로드 앞에 자기 몫의 안내 정보를 붙입니다. 이 안내 정보가 헤더입니다. 어디로 보낼지, 길이가 얼마인지, 안에 든 것이 어느 계층의 덩이인지가 여기 적힙니다.

계층을 하나 내려갈 때마다 헤더가 하나씩 더 붙습니다. 그래서 덩이를 부르는 이름도 계층마다 바뀝니다. 아래 그림은 데이터 한 덩이가 세 겹으로 싸인 모습입니다.

flowchart TD
    subgraph F["프레임 · 링크 계층"]
        FH["프레임 헤더"]
        subgraph P["패킷 · 네트워크 계층"]
            PH["패킷 헤더"]
            subgraph S["세그먼트 · 전송 계층"]
                SH["세그먼트 헤더"]
                DATA["보내려는 데이터"]
            end
        end
    end

그림의 바깥 껍질이 프레임이고 그 안이 패킷, 또 그 안이 세그먼트입니다. 보내려는 데이터는 맨 안쪽에 그대로 들어 있습니다. 헤더 셋이 앞에 붙은 만큼 보내는 바이트가 늘어나는 것이 이 방식의 대가입니다.

받는 쪽에서 껍질을 벗기는 순서

받는 쪽은 싼 순서를 거꾸로 밟습니다. 맨 바깥 헤더부터 하나씩 읽고 떼어 냅니다. 떼어 내고 남은 페이로드를 위 계층에 넘깁니다. 이 벗기는 과정을 역캡슐화라고 부릅니다.

넘길 곳은 헤더가 알려 줍니다. 헤더에는 안에 든 페이로드가 어느 계층의 어떤 덩이인지를 가리키는 칸이 있습니다. 받는 쪽은 그 칸을 읽고 페이로드를 맞는 곳으로 넘깁니다.

그래서 보내는 쪽과 받는 쪽은 같은 계층끼리만 말이 통합니다. 보내는 쪽 전송 계층이 붙인 헤더는 받는 쪽 전송 계층이 읽습니다. 사이에 낀 계층들은 그 헤더를 페이로드의 일부로만 다룹니다. 이 겹겹의 짜임 전체를 프로토콜 스택이라고 부릅니다.

두 뜻이 겹치는 곳과 갈리는 곳

두 분야가 같은 낱말을 쓰는 것은 우연이 아닙니다. 둘 다 안을 불투명하게 만들어서, 바깥이 안의 생김새를 모른 채 쓰게 합니다. 모르게 해 두면 안을 갈아 끼울 때 바깥을 안 건드려도 됩니다.

갈리는 것은 무엇을 감싸느냐입니다. 아래 표로 견줍니다.

견주는 축 소프트웨어 설계 네트워크
감싸는 것 데이터와 그 데이터를 다루는 연산 위 계층이 만든 덩이
껍질에 해당하는 것 공개 메서드 묶음 헤더
안을 못 보는 쪽 그 덩이를 쓰는 바깥 코드 아래 계층
껍질을 벗기는 때 벗기지 않는다 받는 쪽이 역캡슐화한다
얻는 것 고칠 때 파급이 안 번진다 계층을 따로 갈아 끼울 수 있다

표의 마지막 줄이 두 뜻을 잇는 대목입니다. 안쪽 저장 방식을 바꿔도 바깥 코드가 멀쩡한 것과, 링크 계층을 유선에서 무선으로 바꿔도 위 계층이 멀쩡한 것은 같은 이야기입니다.

문서에서 이 낱말을 만나면 주변 낱말로 어느 뜻인지 가릅니다. 객체와 메서드가 같이 나오면 설계 쪽입니다. 헤더와 페이로드가 같이 나오면 네트워크 쪽입니다.

관련 항목

캡슐화를 이루는 설계 개념

정보 은닉 · 추상화 · 모듈 · 인터페이스 · 불변식 · 관심사 분리 · 객체 지향 · 결합도 · 응집도

캡슐화를 받쳐 주는 언어 장치

접근 제어자 · 접근자 메서드 · 프로퍼티 · 객체 · 클래스 · 메서드 · 생성자 · 네임스페이스

캡슐화가 깨졌을 때 드러나는 문제

누출 추상화 · 전역 상태 · 신 객체 · 기능 편애 · 방어적 복사

네트워크에서 캡슐화가 감싸는 데이터 덩이

패킷 · 프레임 · 세그먼트 · 데이터그램 · 메시지 · 페이로드 · 헤더 · 트레일러

캡슐화와 짝을 이루는 네트워크 절차

역캡슐화 · 다중화 · 역다중화 · 프레이밍 · 단편화 · 재조립

캡슐화가 일어나는 계층 구조

프로토콜 스택 · OSI 모델 · 계층 · TCP-IP 모델 · 링크 계층 · 네트워크 계층 · 전송 계층 · 프로토콜

한 프로토콜을 다른 프로토콜에 실어 나르는 기술

터널링 · VPN · VXLAN · GRE · 캡슐화 보안 페이로드 · 오버레이 네트워크

캡슐화와 헷갈리는 이웃

격리 · 샌드박스 · 스코프 · 블랙박스 · 최소 권한

다른 이름: Encapsulation · 인캡슐레이션