클린코드란 뭘까..?(2)

김띵규·2024년 12월 26일
post-thumbnail

MAPPER

Model: Abstract Partial Programmable Explainig Reality
모델은 부분적 추상화와 프로그래밍을 통해 현실을 묘사해야 함

모델
모델은 직관적인 개념이나 은유를 사용해 주체를 설명함. 모델의 최종 목표는 어떤 것이 어떻게 작동하는지 이해하는 것.

CHAPTER 3 빈약한 모델

정확성은 최고의 품질입니다. 만약 시스템이 해야 할 일을 제대로 수행하지 못한다면 다른 어떤 것도 중요하지 않습니다.
- 베르트랑 머예르

"빈약한 도메인 모델" 혹은 "빈약한 객체"는 여러 속성으로 구성되지만 실질적으로 동작이 결여된 객체. 데이터를 저장하는 역할을 하지만, 해당 데이터에 대해 수행할 수 있는 의미 있는 메서드나 연산이 없기 때문에 "데이터 객체"라고도 부름.
>> "풍성한 객체"를 만드는 것을 권장!!
풍성한 객체는 의미 있는 연산 수행, 반복 로직 회피, 단일 접근 지점 제공의 동작과 메서드 집합이 있음.

** "객체지향의 사실과 오해"에서 읽은 것처럼 객체의 핵심은 동작임. 동작 없이 단순히 데이터 속성만을 저장하는 것을 피하자.

객체의 불변성을 생성하고 항상 유효하게 유지
필수 속성이나 동작에 대한 변경을 금지.
객체를 생성하는 동안 필수 속성을 설정하고 객체를 생성한 후에는 속성이 변경되지 않도록 보호하기.

const date = new Date();
date.setMonth(4);

위처럼 선언한 날짜에 의존하는 모든 객체는 파급 효과에 의해서 변경됨.

const date = new ImmutableDate("2022-03-24");

불변성을 가지는 날짜를 생성하면 해당 값은 불변이기에 변경이 불가능함.

세터를 사용한 외부 조작으로부터 객체를 보호하고 불변성을 보장
Setter 메서드는 객체의 가변성과 빈약한 모델을 지향함.
변경을 부차적인 효과로 하는 경우일 때만 메서드를 호출해서 객체를 변경해야 하며, 이는 "묻지 말고 말하라"는 원칙을 따름.

"묻지 말고 말하라" 원칙
Tell. Don't Ask(TDA) 원칙은 객체에 데이터를 요청하는 대신 메서드를 호출해 객체와 상호 작용하는 방법을 정의함.

** 세터를 사용한다면 객체가 직접 데이터를 관리하는 것이 아니라 외부에서 데이터를 변경, 관리하게 됨. 이런 방식은 메시지를 수신한 객체가 동작하면서 데이터를 관리하는 객체 지향적인 관점을 벗어남. 추가로 불변성이 보장되지 않기 때문에 객체의 본질이 변할 우려가 있음.

빈 생성자 완성하기
객체를 생성할 때 모든 필수 인수를 전달하고, 하나의 완전한 단일 생성자를 사용.
인수 없이 생성된 객체는 대체로 변경 가능하고 예측할 수 없으며 일관성이 없는 경우가 많음. 매개변수가 없는 생성자는 잘못된 객체가 위험하게 변이될 수 있는 악취가 나는 코드임. 모든 객체는 처음 생성될 때 그 본질이 유효해야 함.

게터 제거하기
객체 접근을 제어하면서 우발적으로 표시되는 것을 최소화하고, 소프트웨어를 손상시키지 않으면서도 변경 가능한 유연성을 확보.
게터 메서드를 제거하고 데이터가 아닌 동작을 기반으로 한 명시적인 메서드를 호출해 구현 결정을 보호해야 함. getXXX 접두사 사용을 피함으로써 정보 은닉과 캡슐화 원칙을 적용하고, 더 유연한 설계를 가능하게 함.

정보 은닉은 소프트웨어 시스템의 내부 작업과 외부 인터페이스를 분리해 시스템의 복잡성을 줄이는 것이 목표. 이를 통해 다른 시스템이나 사용자가 사용하는 방식에 영향을 주지 않고 시스템의 내부 구현을 변경할 수 있음.
정보 은닉을 달성하는 한 가지 방법은 기본 세부 정보를 숨기는 추상화를 MAPPER에 사용하는 것.

public class MyClass {
	privaet ArrayList<Integer> data;
    
    public MyClass() {
    	data = new ArrayList<Integer>();
    }
    
    public void addData(int value) {
    	data.add(value);
    }
    
    public ArrayList<Integer> getData() {
    	return data; //캡슐화를 위반함.
    }
}

Java로 작성된 이 예제에서 getData() 메서드는 내부 데이터 컬렉션의 복사본을 만드는 대신 내부 데이터 컬렉션에 대한 참조를 반환함. 즉, 클래스 외부에서 컬렉션을 변경하면 내부 데이터에 직접 반영되어 코드에 예기치 않은 동작이라 결함이 발생할 수 있다.

객체의 난장판 방지하기
다른 객체의 캡슐화된 속성 규칙을 위반하는 코드가 있을 때 속성을 보호하고 동작만 노출하도록 수정함.

객체 난장판(Object Orgy)은 객체가 불충분하게 캡슐화되어 내부에 제한 없이 접근할 수 있는 상황. 객체 지향 설계에서 흔히 볼 수 있는 안티 패턴이며 유지 관리 횟수와 복잡성이 증가할 수 있음.

쉽게 생각하면 public 접근을 막고 private으로 접근을 제한한 뒤에 적절한 메서드 사용하기.

동적 속성 제거하기
클래스에서 속성을 명시적으로 선언하고 사용.
동적 속성은 코드를 읽기 어렵게 만들며 범위 정의가 명확하지 않고 오타를 발견하기 어렵게 함. 동적 속성을 지원하는 파이썬, 루비, 자바스크립트 등의 프로그래밍 언어에도 이를 방지하는 컴파일러 옵션이 존재하니 참고할 것.

# 동적 속성 예제
Class Dream:
	pass
        
nightmare = Dream()
    
nightmare.presentation = "나는 스파이더맨"
# presentation은 정의되지 않은 동적 속성임.

# 클래스에서 정의하는 경우의 예제
Class Dream:
	def __init__(self):
    	self.presentation = ""

nightmare = Dream()

nightmare.presentation = "나는 스파이더맨"

이렇게 동적 속성을 사용하지 않고 명시적으로 선언하는 방법을 사용하는 것이 좋다.

profile
🦥 개발자의 일상과 배움을 나누는 공간, 함께 성장하는 Velog입니다. 🦥

0개의 댓글