😀 책에서 기억하고 싶은 내용을 써보세요.

  • 모듈을 분리하는 가장 중요한 기준은 아마도 시스템에서 각 모듈이 자신을 제외한 다른 부분에 드러내지 않아야 할 비밀을 얼마나 잘 숨기느냐에 있을 것이다.
    • 이러한 비밀 중 대표적인 데이터 구조는 레코드 캡슐화하기와 컬렉션 캡슐화하기로 숨길 수 있다.
  • 심지어 기본형 데이터도 기본형을 객체로 바꾸기로 캡슐화할 수 있다.
  • 클래스는 본래 정보를 숨기는 용도로 설계되었다.
organization = {name: "애크미 구스베리", country: "GB"};
class Organization {
	constructor(data) {
		this._name = data.name;
		this._country = data.country;
	}
	get name() {return this._name;}
	get name(arg) {this._name = arg;}
	get country() {return this._country;}
	get country(arg) {this._country = arg;}
}

 

 

배경

대부분의 프로그래밍 언어는 데이터 레코드를 표현하는 구조를 제공한다.

  • 레코드는 연관된 여러 데이터를 직관적인 방식으로 묶을 수 있어서 각각을 따로 취급할 때보다 훨씬 의미 있는 단위로 전달할 수 있게 해준다.

하지만 단순한 레코드에는 단점이 있다.

  • 계산해서 얻을 수 있는 값과 그렇지 않은 값을 명확히 구분해 저장해야 하는 번거로움

 

바로 이 때문에 저자는 가변 데이터를 저장하는 용도로는 레코드보다 객체를 선호하는 편이다.

  • 객체를 사용하면 어떻게 저장했는지를 숨긴 채 세 가지 값을 각각의 메서드로 제공할 수 있다.
  • 사용자는 무엇이 저장된 값이고 무엇이 계산된 값인지 알 필요가 없다.
  • 캡슐화하면 이름을 바꿀 때도 좋다.
  • 필드 이름을 바꿔도 기존 이름과 새 이름 모두를 각각의 메서드로 제공할 수 있어서 사용자 모두가 새로운 메서드로 옮겨갈 때까지 점진적으로 수정할 수 있다.

 

‘가변’ 데이터 일 때 객체를 선호

  • 값이 불변이면 단순히 ‘시작'과 ‘끝'과 ‘길이'를 모두 구해서 레코드에 저장한다.
  • 이름을 바꿀 때는 그저 필드를 복제한다. 그러면 앞서 객체를 활용해 수정 전후의 두 메서드를 동시에 제공한 방식과 비슷하게 점진적으로 수정할 수 있다.

 

절차

  1. 레코드를 담은 변수를 캡슐화한다.
    • 레코드를 캡슐화하는 함수의 이름은 검색하기 쉽게 지어준다.
  2. 레코드를 감싼 단순한 클래스로 해당 변수의 내용을 교체한다. 이 클래스에 원본 레코드를 반환하는 접근자도 정의하고, 변수를 캡슐화하는 함수들이 이 접근자를 사용하도록 수정한다.
  3. 테스트한다.
  4. 원본 레코드 대신 새로 정의한 클래스 타입의 객체를 반환하는 함수들을 새로 만든다.
  5. 레코드를 반환하는 예전 함수를 사용하는 코드를 4에서 만든 새 함수를 사용하도록 바꾼다. 필드에 접근할 때는 객체의 접근자를 사용한다. 적절한 접근자가 없다면 추가한다. 한 부분을 바꿀 때마다 테스트한다.
    • 중첩된 구조처럼 복잡한 레코드라면, 먼저 데이터를 갱신하는 클라이언트들에 주의해서 살펴본다. 클라이언트가 데이터를 읽기만 한다면 데이터의 복제본이나 읽기전용 프락시를 반환할지 고려해보자.
  6. 클래스에서 원본 데이터를 반환하는 접근자와 (1에서 검색하기 쉬운 이름을 붙여둔) 원본 레코드를 반환하는 함수들을 제거한다.
  7. 테스트한다.
  8. 레코드의 필드도 데이터 구조인 중첩 구조라면 레코드 캡슐화하기와 컬렉션 캡슐화하기를 재귀적으로 적용.

 

예시: 간단한 레코드 캡슐화하기

프로그램 전체에서 널리 사용되는 상수를 예로 살펴보자.

const organization = {name: "애크미 구스베리", country: "GB"};

위 상수는 프로그램 곳곳에서 레코드 구조로 사용하는 자바스크립트 객체로, 아래와 같이 읽고 쓴다.

 

result += `<h1>${organization.name}</h1>`; // 읽기 예
organization.name = newName; // 쓰기 예

1️⃣가장 먼저 이 상수를 캡슐화한다(변수 캡슐화하기)

 

function getRawDataOfOrganization() {return organization;}

그러면 읽고 쓰는 코드는 다음처럼 바뀐다.

 

result += `<h1>${getRawDataOfOrganization().name}<h1>`; // 읽기 예
getRawDataOfOrganization().name = newName; // 쓰기 예
  • 레코드를 캡슐화하는 목적은 변수 자체는 물론 그 내용을 조작하는 방식도 통제하기 위해서다.
  • 2️⃣이렇게 하려면 레코드를 클래스로 바꾸고, 4️⃣새 클래스의 인스턴스를 반환하는 함수를 새로 만든다.

 

// Organization 클래스
class Organization {
	constructor(data) {
		this._data = data;
	}
}

// 최상위...
const organization = new Organization({name: "애크미 구스베리", country: "GB"});
function getRawDataOfOrganization() {return organization._data;}
function getOrganization() {return organization;}

 

객체로 만드는 작업이 끝났으니 5️⃣레코드를 사용하던 코드를 살펴보자.

레코드를 갱신하던 코드는 모두 세터를 이용하도록 고친다.

 

// Organization 클래스...
set name(aString) {this._data.name = aString;}

// 클라이언트
getOrganization().name = newName;

마찬가지로, 레코드를 읽는 코드는 모두 게터를 사용하게 바꾼다.

 

 

// Organization 클래스
get name() {return this._data.name;}

// 클라이언트
result += `<h1>${getOrganization().name}</h1>`;

6️⃣다 바꿨다면 앞에서 이상한 이름으로 지었던 임시 함수를 제거한다.

 

function getRawDataOfOrganization() {return organization._data;} // <--- 제거
function getOrganization() {return organization;}

마지막으로 _data의 필드들을 객체 안에 바로 펼쳐놓으면 더 깔끔할 것 같다.

 

 

class Organization {
	constructor(data) {
		this._name = data.name;
		this._country = data.country;
	}
	get name() {return this._name;}
	get name(aString) {this._name = aString;}
	get country() {return this._country;}
	get country(aCountryCode) {this._country = aCountryCode;}
}
  • 이렇게 하면 입력 데이터 레코드와의 연결을 끊어준다는 이점이 생긴다.
    • 특히 이 레코드를 참조하여 캡슐화를 깰 우려가 있는 코드가 많을 때 좋다.
  • 게터는 데이터 구조를 깊이 탐색하게 만들되 원본 데이터를 그대로 반환하지 말고 객체로 감싸서 반환하는게 효과적일 수 있다.
    • [Refactoring Code to Load Document] 참고 ⇒ 링크

 

 

🤔 오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.

  • 이 책에서 레코드라고 불리는 데이터의 형식은 JSON과 상당히 비슷하다고 느꼈습니다.
    • 레코드는 좀 더 직관적인 방식이고 객체는 개발자에게 더 친화적이라고 생각했습니다.
  • 자바, 스프링을 사용하면서 기본적으로 객체를 통해 데이터를 주고 받는 코딩을 하고 있었습니다. 이런 방식이 저절로 캡슐화를 지켜서 코딩을 하게 도와주고 있었다는 것을 알게 되었습니다.
  • 유명한 프로그래머(ex. 마틴파울러)의 코드와 생각이 정리된 글을 보고 배우자!

 

 

🔎 궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요.

  • 레코드 캡슐화를 재귀적으로 하는 방법은?

 

 

 

반응형

+ Recent posts