Skip to content

Commit

Permalink
update: 03. 클래스 설계: 모든 것과 연결되는 설계 기반.md
Browse files Browse the repository at this point in the history
  • Loading branch information
kiuuon committed Mar 21, 2024
1 parent f938ee8 commit aab7a36
Showing 1 changed file with 151 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,153 @@
# 03. 클래스 설계: 모든 것과 연결되는 설계 기반

# 📌 Contents

### 📌 클래스 단위로 잘 동작하도록 설계하기

가장 중요한 것은 '클래스 단위로도 잘 동작하게 설계해야 한다'는 접근 방법

- 클래스는 클래스 하나로도 잘 동작할 수 있게 설계해야 함
- 복잡한 초기 설정을 하지 않아도 곧바로 사용할 수 있게 만들어야 함
- 클래스를 마음대로 조작해서 클래스 전체가 고장나는 일이 없게, 최소한의 조작 방법만 외부에 제공해야 함

<br />

- 클래스의 구성 요소
- 인스턴스 변수
- 메서드
- 잘 만들어진 클래스의 구성 요소
- 인스턴스 변수
- 인스턴스 변수에 잘못된 값이 할당되지 않게 막고, 정상적으로 조작하는 메서드
- 이렇게 클래스가 인스턴스 변수와 메서드를 구성 요소로 가져야 하는 이유는 데이터 클래스에서 일어나는 폐해들을 생각해보면 알 수 있음

<br />

- 데이터 클래스는 일반적으로 인스턴스 변수를 조작하는 로직이 다른 클래스에 구현되어 있음
- 따라서 연관성을 알아채기 어려워서 코드가 중복될 수 있고, 수정하다가 중복 코드 중 일부를 그대로 둘 수 있고, 가독성을 낮춤
- 또한 인스턴스를 생성하더라도 인스턴스 변수들은 아직 유효하지 않은 상태이므로, 초기화를 따로 해줘야 하는데, 데이터 클래스는 초기화 작업을 하는 코드조차 다른 클래스에 구현되어 있음
- 인스턴스 변수에 값을 잘못 넣을수도 있는데, 데이터 클래스를 잘못된 값으로부터 방어하기 위한 유효성 검사도 다른 클래스에 구현되어 있음
- 즉, 데이터 클래스는 다른 클래스가 여러 가지를 준비해 줘야만 잘 작동하고, 혼자서는 아무것도 할 수 없는 미성숙한 클래스

> ####info::Note
>
> '따로 초기화하지 않거나 사전 준비를 하지 않으면 사용할 수 없는' 클래스와 메서드가 있다면, 누가 사용하고 싶을까요?
> 자신의 몸은 자신이 지켜야 합니다. 클래스 스스로 자기 방어 임무를 수행할 수 있어야 소프트웨어 품질을 높이는 데 도움이 됩니다.
> 소프트웨어 구성 부품이라 할 수 있는 클래스 하나하나의 품질이 뛰어나야, 소프트웨어 전체의 품질이 향상됩니다.
> 데이터 클래스는 모든 것을 다른 클래스에 맡겨야 했기 때문에 악마들을 불러들였습니다. 그럼 어떻게 해야 할까요? 굉장히 간단합니다.
> 데이터 클래스에 자기 방어 임무를 부여해서, 다른 클래스에 맡기던 일을 스스로 할 수 있게 설계하면 됩니다.
### 📌 성숙한 클래스로 성장시키는 설계 기법

#### 생성자로 확실하게 정상적인 값 설정하기

- 데이터 클래스는 디폴트 생성자(매개변수 없는 생성자)를 사용해서 인스턴스를 생성한 뒤, 인스턴스 변수에 따로 값을 할당해서 초기화
- 이는 '로우 데이터 객체'로서 '초기화 되지 않은 상태'를 유발하는 클래스 구조
- 이를 방지하기 위해 적절한 초기화 로직을 생성자에 구현하기 (생성자에서 초기값을 매개변수로 받아 초기화)
- 또한 잘못된 값으로 초기화 되지 않도록 유효성 검사를 생성자 내부에 정의하기
- 처리 범위를 벗어나는 조건을 메서드 가장 앞 부분에서 확인하는 코드를 '가드'라고 부름
- 가드를 사용해 유효성 검사를 하면 불필요한 요소를 메서드 앞부분에서 제외할 수 있으므로 이어지는 로직이 간단해짐

#### 계산 로직도 데이터를 가진 쪽에 구현하기

- '데이터'와 '데이터를 조작하는 로직'이 분리되어 있는 구조를 '응집도가 낮은 구조'라고 함
- 응집도가 낮은 구조에서는 여러 가지 문제가 발생하는데, 이를 막으려면 스스로 일을 하는 성숙한 클래스를 만들어야 함

#### 불변 변수로 만들어서 예상하지 못한 동작 막기

- 인스턴스 변수를 변경하는 코드는 이해하기 어려움.
- 변수의 값이 계속 바뀌면, 값이 언제 변경되었는지, 지금 값은 무엇인지 계속 신경써야 함
- 코드를 수정하다 '예상치 못한 부수 효과'가 쉽게 발생함
- 이를 막기 위해 인스턴스 변수를 값을 한 번 할당하면 다시는 바꿀 수 없는 불변 변수로 만들기 -> final 수식자 사용 (Java)

#### 변경하고 싶다면 새로운 인스턴스 만들기

- 불변이면 아예 변경을 못한다고 생각할 수 있음
- 변경을 할 때는 인스턴스 변수의 내용을 변경하는 것이 아닌, 변경된 값을 가진 새로운 인스턴스를 만들어서 사용하면 됨

#### 메서드 매개변수와 지역 변수도 불변으로 만들기

- 값이 중간에 바뀌면, 값의 변화를 추적하기 힘들기 때문에 버그를 발생시키기도 함
- 기본적으로 매개변수는 변경하지 않는 것이 좋음 (메서드와 생성자의 매개변수도 마찬가지)
- 지역 변수도 중간에 값을 변경하면, 값의 의미가 바뀔 수 있음
- 매개변수와 지역 변수 모두 final을 붙여 불변으로 만들수 있음 (Java)

#### 엉뚱한 값을 전달하지 않도록 하기

- int, string처럼 프로그래밍 언어가 표준적으로 제공하는 자료형을 기본 자료형이라고 함
- 기본 자료형 위주로 사용하면, 의미가 다른 값이 여러 개 있어도 모두 int 자료형이나 string 자료형으로 정의하기 쉬움
- 독자적인 자료형을 사용하면, 의미가 다른 값을 전달할 경우 컴파일 오류가 발생할 수 있음

#### 의미 없는 메서드 추가하지 않기

- 나중에 필요할 줄 알고, 시스템 사양에 필요하지 않은 메서드를 '선의'로 추가했다면,
- 이후에 누군가 무심코 사용했을 때 버그가 될 수 있음
- 시스템 사양에 필요한 메서드만 정의하자

### 📌 악마 퇴치 효과 검토하기

- 위에서 언급한 방법들처럼 인스턴스 변수를 중심으로, 인스턴스 변수가 잘못된 상태에 빠지지 않게 설계하면 악마를 퇴치할 수 있음
- 클래스 설계란 인스턴스 변수가 잘못된 상태에 빠지지 않게 하기 위한 구조를 만드는 것
- 같은 데이터라고 해도 메서드 매개변수, 지역 변수, static 변수로 설계했다면 악마의 공격을 방어할 수 없음
- 인스턴스 변수이기 때문에 방어할 수 있는 것임

<br />

- 관련된 로직이 한 곳에 모여 있는 구조는 응집도가 높은 구조라고 함
- '데이터'와 '그 데이터를 조작하는 로직'을 하나의 클래스로 묶고, 필요한 메서드만 외부에 공개하는 것을 `캡슐화`라고 함

### 📌 프로그램 구조의 문제 해결에 도움을 주는 디자인 패턴

- 응집도가 높은 구조로 만들거나, 잘못된 상태로부터 프로그램을 방어하는 등 프로그램의 구조를 개선하는 설계 방법을 `디자인 패턴`이라고 함
- 위에서 언급한 방법들은 두 가지 디자인 패턴에 대한 내용임

#### 완전 생성자 패턴

- 완전 생성자는 잘못된 상태로부터 클래스를 보호하기 위한 디자인 패턴
- 인스턴스 변수를 모두 초기화해야만 객체를 생성할 수 있게, 매개변수를 가진 생성자를 만들기
- 생성자 내부에서는 가드를 사용해서 잘못된 값이 들어오지 않게 만들기
- 인스턴스 변수를 불변 변수로 만들면, 생성 후에도 잘못된 상태로부터 방어할 수 있음

#### 값 객체 패턴

- 값을 클래스(자료형)로 나타내는 디자인 패턴
- 애플리케이션에서 사용하는 금액, 날짜, 주문 수, 전화번호 등 다양한 값을 값 객체로 만들 수 있음
- 이러한 값을 값 객체로 만들어서 사용하면, 각각의 값과 로직을 응집도가 높은 구조로 만들 수 있음
- 값 객체를 사용하면 의도하지 않게 다른 값이 섞이는 상황을 원천적으로 차단할 수 있음

<br />

- 값 객체와 완전 생성자는 얻을 수 있는 효과가 거의 비슷하므로, 일반적으로 함께 사용함
- '값 객체 + 완전 생성자'는 객체지향 설계에서 폭넓게 사용되는 기법임
- '값 객체 + 완전 생성자'를 활용해서 설계하면, 제약과 의도를 자료형으로 표현할 수 있으며, 안전한 코드를 작성할 수 있음
- 애플리케이션에서 다루는 값을 값 객체로 만들어 활용하면, 여러 악마를 퇴치할 수 있음

# ❓ Questions

### ❓ 자바스크립트에서도 인스턴스 변수와 매개변수를 불변으로 만들 수 있을까?

- 자바에서는 변수를 불변으로 만들기 위해 변수 앞에 final을 붙여준다고 한다.
- 자바스크립트는 애초에 변수를 선언할때 타입을 이용해 선언하는 것이 아니라 const, let을 이용하여 선언해 준다.
- 여기서 const로 선언한 변수는 불변이므로 final과 비슷하다고 볼 수 있다.
- 하지만 이 const는 클래스의 인스턴스 변수나 매개변수 앞에 붙이지 않는다.
- 자바스크립트에서 클래스의 인스턴스 변수를 선언할 때 `this.{변수명}`을 이용한다.
- 클래스의 필드에서는 const나 let을 이용할 수 가 없다.
- 생성자 내부에서는 이용가능하지만 const나 let을 이용하면 생성자에서만 사용이 가능한 지역변수가 되고, 다른 메서드들에서는 사용할 수가 없다.
- 그럼 자바스크립트에서는 인스턴스 변수를 불변으로 만들 수 없는 것일까?
- 어떻게 자바스크립트에서 클래스의 인스턴스 변수를 불변으로 만들까 찾아보았지만 별다른 방법이 없는 것 같다.
- 그래서 자바스크립트에서 클래스를 이용할 때는 인스턴스 값을 직접 변하지 않게 하기 위해 인스턴스 변수를 private으로 선언해 클래스 외부에서는 아예 접근을 못하게하는 것이 최선의 방법인 것 같다.
- 클래스 내부에서 변하게 하는 것은 막지 못하는것 같다.
- 매개변수 또한 앞에 const를 붙이지 않기 때문에 불변으로 만드는 방법은 딱히 없는 것 같다.

<br />

- c++도 궁금해서 찾아보았는데, final과 비슷한 역할로 변수를 선언할 때 앞에 const를 붙여주면 불변 변수가 된다고 한다.
- 자바의 final에는 상속과 관련된 기능도 있기 때문에 완전히 같지는 않다고 하지만, 변수를 불변으로 만들어 준다는 점은 같다.

### ❓ 자바스크립트에서 값 객체 패턴을 사용할 수 있을까?

- 자바스크립트는 동적으로 타입이 정해지는 동적 언이이다.
- 따라서 변수를 선언할 때 타입을 정해주지 않는다.
- 자바스크립트에서는 값 객체 패턴을 사용할 수 없다고 생각한다.
- 하지만 타입스크립트를 사용한다면, 값 객체 패턴과 비슷하게 코드를 작성할 수 있다고 생각한다.
- 타입스크립트에서는 number, string 등의 기본 타입 말고도 커스텀 타입을 만들어 사용할 수 있다.
- 이를 활용하면 값 객체 패턴과 비슷하게 코드를 작성할 수 있을 것 같다.

0 comments on commit aab7a36

Please sign in to comment.