객제지향, TDD, 클린코드/Java

객체, 설계 (중요한 건, 꺾였는데도 그냥 하는 마음)

ummchicken 2023. 4. 30. 11:13

중요한 건, 꺾였는데도 그냥 하는 마음

(지금 내 심정.. 지푸라기라도 잡고싶다. 잡을 지푸라기라도 남아있지 않다는 게 문제지만)

 

중요한 건, 꺾이지 않는 마음? ㄴㄴ

꺾였는데도 그냥 하는 마음이다.

 

 

 

안녕하세요. 

오늘은 객체의 설계에 대해 학습할 겁니다.

 

 

먼저 들어가기 전, 

기억에 남는 구절이 있네요.

 

이론보다 실무가 먼저다.

 

 

 

어떤 분야를 막론하고, 이론을 정립할 수 없는 초기에는 

실무가 먼저 급속한 발전을 이룬다.

 

 

프로그래밍을 통해 개념과 이론을 배우는 것이 

개념과 이론을 통해 프로그래밍을 배우는 것보다 더 훌륭한 학습 방법이라고 생각한다.

 

 

개발자는 
구체적인 코드를 만지며 손을 더럽힐 때 
가장 많은 것을 얻어가는 존재다.

 

 

 


 

✔️ 변경에 취약한 코드

💡 객체 사이의 의존성(dependency)과 관련된 문제다.

  • 의존성은 변경에 대한 영향을 암시한다.
  • 의존성이라는 말 속에는, 어떤 객체가 변경될 때 그 객체에게 의존하는 다른 객체도 함께 변경될 수 있다는 사실이 내포돼 있다.

 

 

그렇다고 해서 객체 사이의 의존성을 완전히 없애는 것이 정답은 아니다!

 

 

객체지향 설계는 서로 의존하면서 협력하는 객체들의 공동체를 구축하는 것이다.

 

 

 

💡 객체 사이의 의존성이 과한 경우를 가리켜 결합도(coupling)가 높다고 말한다.

  • 결합도는 의존성과 관련돼 있기 때문에 결합도 역시 변경과 관련이 있다.
  • 두 객체 사이의 결합도가 높으면 높을수록 함께 변경될 확률도 높아지기 때문에 변경하기 어려워진다.

 

 

따라서 설계의 목표는 
객체 사이의 결합도를 낮춰 
변경이 용이한 설계를 만드는 것이다.

 

 

 

 

 

✔️ 자율성을 높이자

💡 개념적이나 물리적으로 객체 내부의 세부적인 사항을 감추는 것을 캡슐화(encapsulation)라고 한다.

  • 캡슐화의 목적은 변경하기 쉬운 객체를 만드는 것이다.
  • 캡슐화를 통해 객체 내부로의 접근을 제한하면, 객체와 객체 사이의 결합도를 낮출 수 있기 때문에 좀 더 쉽게 변경할 수 있게 된다.

 

 

예를 들어보자.

Theater의 enter 메서드는 sellTo 메서드를 호출하는 간단한 코드로 바꿀 수 있다.

public class Theater {
    private TicketSeller ticketSeller;
    
    public Theater(TicketSeller ticketSeller) {
        this.ticketSeller = ticketSeller;
    }
    
    public void enter(Audience audience) {
        ticketSeller.sellTo(audience);
    }
}
  • Theater 클래스 어디서도 ticketOffice에 접근하지 않는다.
  • Theater는 ticketOffice가 TicketSeller 내부에 존재한다는 사실을 알지 못한다.
  • Theater는 단지 ticketSeller가 sellTo 메시지를 이해하고 응답할 수 있다는 사실만 알고 있을 뿐이다.

 

 

Theater는 오직 TicketSeller의 인터페이스(interface)에만 의존한다.

TicketSeller가 내부에 TicketOiifce 인스턴스를 포함하고 있다는 사실은 구현(implementation)의 영역에 속한다.

 

 

💡 객체를 인터페이스와 구현으로 나누고, 인터페이스만을 공개하는 것은 
객체 사이의 결합도를 낮추고 변경하기 쉬운 코드를 작성하기 위해 따라야 하는 가장 기본적인 설계 원칙이다.

 

 

 

 

 

✔️ 캡슐화와 응집도

핵심은 객체 내부의 상태를 캡슐화하고, 
객체 간에 오직 메시지를 통해서만 상호작용하도록 만드는 것이다.

 

 

💡 밀접하게 연관된 작업만을 수행하고

연관성 없는 작업은 다른 객체에게 위임하는 객체를 응집도(cohesion)가 높다고 한다.

→ 자신의 데이터를 스스로 처리하는 자율적인 객체를 만들면, 결합도를 낮출 수 있을뿐더러 응집도를 높일 수 있다!

 

 

 

객체의 응집도를 높이기 위해서는?

→ 객체 스스로 자신의 데이터를 책임져야 한다!

 

 

 

객체는 자신의 데이터를 스스로 처리하는 자율적인 존재여야 한다.
그것이 객체의 응집도를 높이는 첫 걸음이다.

 

 

 

 

 

✔️ 절차지향과 객체지향

프로세스(Process)데이터(Data)별도의 모듈에 위치하는 방식을 
절차적 프로그래밍(Procedural Programming)이라고 부른다.

 

 

예를 들어, 

모든 처리가 하나의 클래스 안에 위치하고, 

나머지 클래스는 단지 데이터의 역할만 수행한다.

 

 

 

🚨 하지만, 변경하기 쉬운 설계는 한 번에 하나의 클래스만 변경할 수 있는 설계다.

→ 절차적 프로그래밍은 프로세스가 필요한 모든 데이터에 의존해야 한다는 근본적인 문제점 때문에 변경에 취약할 수밖에 없다.

 

 

 

💡 해결 방법은, 자신의 데이터를 스스로 처리하도록 프로세스의 적절한 단계를 이동시키는 것이다.

 

 

이처럼 데이터와 프로세스가 동일한 모듈 내부에 위치하도록 프로그래밍하는 방식을 
객체지향 프로그래밍(Object-Oriented Programming)이라고 부른다.
  • 예를 들어, 하나의 변경으로 인한 여파가 여러 클래스로 전파되는 것을 효율적으로 억제한다.

 

 

 

훌륭한 객체지향 설계의 핵심은 
캡슐화를 이용해 의존성을 적절히 관리함으로써 
객체 사이의 결합도를 낮추는 것이다.

 

 

 

 

 

✔️ 책임의 이동

 

계속 반복해서 나오는 개념이 있다.

 

 

각 객체는 자신을 스스로 책임진다.

 

 

 

책임의 이동이 뭘까? 예를 들어보자.

책임이 중앙집중된 절차적 프로그래밍

절차적 설계를 예를 들어보면, 

Theater라는 클래스가 있다고 치면, Theater 클래스가 전체적인 작업을 도맡아 처리한다.

 

 

 

그에 반해 

책임이 분산된 객체지향 프로그래밍

객체지향 설계에서는 

제어 흐름이 각 객체에 적절하게 분산돼 있다.

❗ 다시 말해, 하나의 기능을 완성하는 데 필요한 책임이 여러 객체에 걸쳐 분산돼 있는 것이다.

 

 

 

 

변경 전, 절차적 설계에서는 Theater가 전체적인 작업을 도맡아 처리했다.

변경 후, 객체지향 설계에서는 각 객체가 자신이 맡은 일을 스스로 처리했다.

→ Theater에 몰려 있던 책임이 개별 객체로 이동한 것이고, 이것이 바로 책임의 이동이다!

 

 

 

그래서 도대체 뭔말인데?

 

 

❓ 조금 더 쉽게 설명

  1. 절차적 프로그래밍 방식
    • 데이터와 데이터를 사용하는 프로세스가 별도의 객체에 위치
  2. 객체지향 프로그래밍 방식
    • 데이터와 데이터를 사용하는 프로세스가 동일한 객체 안에 위치

 

(확률 상 이렇다는 것이다.)

 

 

 

 

 

✔️ 훌륭한 객체지향 설계란?

 

소프트웨어를 구성하는 모든 객체들이 자율적으로 행동하는 설계를 가리킨다.

 

 

 

 

 

✔️ 객체지향 설계가 왜 필요한가?

 

설계란, 코드를 배치하는 것이다.

 

 

 

설계는 

코드를 작성하는 데 매 순간 코드를 어떻게 배치할 것인지를 결정하는 과정에서 나온다.

 

 

 

우리가 진정으로 원하는 것은 

변경에 유연하게 대응할 수 있는 코드다.

 

 

 

객체지향 프로그래밍은 

의존성을 효율적으로 통제할 수 있는 다양한 방법을 제공함으로써 

요구사항 변경에 좀 더 수월하게 대응할 수 있는 가능성을 높여준다.

 

 

 

훌륭한 객체지향 설게란, 

협력하는 겍체 사이의 의존성을 적절하게 관리하는 설계다.

→ 객체 간의 의존성은 애플리케이션을 수정하기 어렵게 만드는 주범이다.

 

 

 

그럼 도대체...

 

변경 가능한 코드란?

이해하기 쉬운 코드다.

(캬...)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

참고: 오브젝트 - 코드로 이해하는 객체지향 설계