INTRO

요구 분석은 ‘무엇을 만들것인가’를 다루는 작업 설계는 ‘어떻게 실현할 것인가’를 구체적으로 결정하는 활동

전통적인 설계 원리

가장 중요한건 효율성, 단순성.
그 외에도

  • 분화, 계층화
  • 모듈화
  • 추상화 등이 중요하다 뒤에서 보자

추상화

컴포넌트 구현에 대한 자세한 사항을 염려하지 않고 추상적인 수준으로 컴포넌트를 다루는 도구라고 할 수 있다.

캡슐화

추상화된 대상이 제공하는 서비스를 쉽게 접근하게 하는 개념.
서비스를 수행하는 핵심만 노출시키고 어떻게 서비스를 제공하는지 자세한 것을 숨긴다.

모듈화

결합

결합은 모듈간 서로 의존하는 정도를 뜻한다.
좋은 소프트웨어는 낮을 결합력을 가진다. 모듈끼리 의존도, 결합이 강해지면 이해하기 어렵고 변경할때 많은 부분을 고쳐야 한다.

모듈간 결합도는 1. 모듈간 인터페이스수 2. 각 인터페이스의 복잡성 두가지로 판단한다.

모듈사이 결합도는 약 5개로 나눌 수 있다. 차례대로 강한 결합에서 약한 결합이다.

  1. 내용결합 (Content Coupling)
    모듈이 다른 모듈의 내용을 직접 참조하는 경우
    예를 들어, 모듈 A가 모듈 B의 내부 변수를 직접 수정하는 경우
  2. 공통결합 (Common Coupling) 모듈이 매개변수 대신 전역변수를 이용하여 데이터를 교환하는 경우
  3. 제어결합 (Control Coupling) 모듈이 다른 모듈의 제어흐름을 제어하는 경우
  4. 스탬프결합 (Stamp Coupling) 복합 데이터 구조의 일부만 사용하는 모듈에 구조체를 전달하는 경우
    예를 들어, 세개의 필드가 있는 레코드를 처음 두개의 필드만 필요한 모듈에 매개변수로 전달하는 경우
    DTO 생각하면 쉽다.
  5. 데이터결합 (Data Coupling) 모듈들이 주고받는 매개변수가 간단한 타입이거나 레코드여도 단순 타입인 경우

응집

응집은 하나의 모듈 안에서 수행되는 작업들이 관련된 정도.
모듈 안에서 여러 요소들이 하나의 목적을 위해 유기적으로 관련 되어 있는 것이 좋다.

  • 우연적 응집 (Coincidental Cohesion) 모듈 안의 요소들이 서로 관련이 없는 경우
    예를 들어, 모듈 A가 여러 기능을 수행하지만 이들 사이에 아무런 관계가 없는 경우
  • 논리적 응집 (Logical Cohesion) 모듈 안의 요소들이 논리적으로 관련이 있는 경우
    예를 들어, 마우스 및 키보드 입력 처리 루틴을 한 모듈에 넣은 경우
  • 시간적 응집 (Temporal Cohesion) 모듈 안의 요소들이 시간적으로 관련이 있는 경우
    예를 들어, 열린 파일을 닫고 오류 로그를 생성해 통보하는 예외 함수를 한 모듈에 넣은 경우
  • 절차적 응집 (Procedural Cohesion) 모듈 안에서 수행되는 순서와 관련 있는 경우
    예를 들어, 키보드에서 입력을 읽고, 확인하고 변수에 답을 저장한다와 같이
  • 교환적 응집 (Communicational Cohesion) 모듈 내부 요소들이 동일한 데이터를 조작해서 모듈로 모인 경우
  • 정보적 응집 (Informational Cohesion) 모듈 내부 요소들이 모듈에 대해 정의된 하나의 기능에 대해 모두 기여하고 밀접하게 관련되어서 모듈로 모인 경우

응집과 결합에 대해 하나의 글을 더 작성할 것 같다.

객체지향 설계 원리

이것도 참 많이 봤는데 맨날 헷갈렸다.. 이번에 정리해보자

SOLID

  • 단일 책임의 원리 (Single Responsibility Principle, SRP)
    • 클래스는 하나의 책임만 가져야 한다.
  • 개방 폐쇄 원리 (Open-Closed Principle, OCP)
    • 소프트웨어 개체는 확장에는 열려 있어야 하고 수정에는 닫혀 있어야 한다.
    • 기존 코드를 변경하지 않고 새로운 기능을 추가할 수 있어야 한다.
  • 리스코프 교체 원리 (Liskov Substitution Principle, LSP)
    • 서브타입은 언제나 자신의 기반 타입으로 교체할 수 있어야 한다.
    • 자식 클래스는 부모 클래스의 기능을 모두 사용할 수 있어야 한다.
    • 자식 클래스는 부모 클래스의 기능을 변경해서는 안된다.
  • 인터페이스 분리의 원리 (Interface Segregation Principle, ISP)
    • 클라이언트는 자신이 사용하지 않는 인터페이스에 의존하지 않아야 한다.
  • 의존관계 역전의 원리 (Dependency Inversion Principle, DIP)
    • 고수준 모듈은 저수준 모듈에 의존해서는 안된다.
    • 둘 다 추상화에 의존해야 한다.
    • 구체적인 것에 의존하지 말고 추상적인 것에 의존하라.

이제 자세하게 알아보자

단일 책임 원리 (Single Responsibility Principle, SRP)

클래스의 역할과 책임을 단일화 하여 클래스를 변경해야 할 이유를 하나로 제한

예시에서는 Book에 print가 있는데 이건 SRP에 위배되니, BookPrinter라는 클래스를 만들어서 분리해준다.

개방 폐쇄 원리 (Open-Closed Principle, OCP)

확장에는 열려 있지만 수정에는 닫혀있어야 한다.

저 예시는 좀 와닿지 않는데, Spring을 생각하면 된다.

객체는 저런식으로 설계 후
Car car = new Bmw(); 이런식으로 사용하는 거다.
BMW 이후에 Sonata, K5 등등 다른 구현체(차 종류)가 추가되어도
car 입장에서는 car.drive()만 알면 된다.

그런데 근본적으로 new Bmw(), new Sonata() 라는 코드를 수정해야하는거 아니야? 라는 의문은 의존관계이기 때문에 뒤에 나오는 DIP와 관련된 내용인데
Spring Container가 해결해준다.

private final CarRepository carRepository;

이런 코드가 많은데, 바로 생성자 주입 방식으로 스프링 컨테이너가 구현체를 주입해 주는 방식이다.
구현체가 인 메모리 db일수도 있고, postgres일수도 있지만 우리는 carRepository.save() 이런식으로 사용하면 된다.

리스코프 치환 원리 (Liskov Substitution Principle, LSP)

자식 객체가 부모 객체를 완전히 대체할 수 있어야 한다는 내용이다.

예시에서 MuteMouse는 Animal을 상속 받았지만 makeNoise()를 구현하면 안된다.
정확히는 의미가 맞지 않는다. (MuteMouse니까)
애초에 상속 받은 것 자체가 잘못된 것이라는 뜻이다.

그래서 어떻게 하라고?
Animal은 상속받되, makeNoise()를 추상 메소드로(interface) 만들어서 구현해라.

인터페이스 분리 원리 (Interface Segregation Principle, ISP)

쉽게 말해 인터페이스를 잘게 분리하라는 뜻이다.
즉 객체 자신이 사용하는 메서드에만 의존해야한다.

의존관계 역전 원리 (Dependency Inversion Principle, DIP)

추상화에 의존하고, 구체적인 것에 의존하지 말라는 뜻이다.

뭔가 OCP랑 비슷한데, OCP는 확장성에 관한 것이고
DIP는 객체간 관계, 특히 의존성에 관한 것이다.

예시처럼 Copy가 구체적인것에 의존하면 keyboard, printer, disk 내부가 바뀌거나 다른 device로 바꿀때 같이 수정해야 한다.

저 예시도 좀 와닿지 않아서 하나 추가


public class Kid {
    private Robot toy;

    public void setToy(Robot toy) {
        this.toy = toy;
    }

    public void play() {
        System.out.println(toy.toString());
    }
}

public class Kid {
    private Toy toy;

    public void setToy(Toy toy) {
        this.toy = toy;
    }

    public void play() {
        System.out.println(toy.toString());
    }
}

Robot -> Toy로 바뀐 부분 참고

software-engineering 카테고리의 다른 글