1 SOLID
- SOLID란 클린코드로 유명한 로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙을 정리한 것입니다.
- 소프트웨어 설계를 이해하기 쉽고 유연하고 유지보수하기 쉽게 만들기 위해 사용되는 원칙 5가지를 뜻한다.
- 5가지 원칙
- Single Responsibility Principle(단일 책임 원칙)
- Open-Closed Principle(개방-폐쇄 원칙)
- Liskov Substitution Principle(리스코프 치환 원칙)
- Interface Segregation Principle(인터페이스 분리 원칙)
- Dependency Inversion Principle(의존 역전 원칙)
1.1 SOLID를 언제 적용할까?
- SOLID는 디커플링을 중요하게 여기니 대규모 프로젝트일수록 유용하다 따라서 모든 프로젝트에 적용할 수 있다고 생각하지 말자
- 많은 프로젝트의 시작은 직접적/구체적인 설계로 시작하고 규모가 커지면서 유연성이 필요해지면 SOLID를 고려해봐도 좋습니다.
1.2 응집도와 결합도
- SOLID는 원칙을 섦명하기에 앞서 응집도와 결합도를 이해하는 것이 중요합니다.
- 응집도(Cohesion)
- 모듈 내부의 요소들이 얼마나 밀접하게 연관되어 있는지를 나타내는 척도입니다.
- 응집도는 변경이 발생할 때 모듈 내부에서 발생하는 변경의 정도로 측정할 수 있습니다.
- 하나의 변경을 수용하기 위해 모듈 전체가 변경되면 응집도가 높고 모듈의 일부만 변경되면 응집도가 낮은 것입니다.
- 하나의 변경을 수용하기 위해 하나의 모듈만 변경된다면 응집도가 높고 다수의 모듈이 함께 변경돼야 한다면 응집도가 낮은 것입니다.
- 결합도(Coupling)
- 결합도는 의존성의 정도를 나타내며 다른 모듈에 대해 얼마나 많은 지식을 갖고 있는지를 나타내는 척도입니다.
- 결합도는 한 모듈이 변경되기 위해서 다른 모듈의 변경을 요구하는 정도로 측정할 수 있습니다.
- 내부 구현을 변경했을 때 이것이 다른 모듈에 영향을 미치는 경우 두 모듈 사이의 결합도가 높다고 표현합니다.
- 반면 퍼블릭 인터페이스를 수정했을 때만 다른 모듈에 영향을 미치는 경우 두 모듈 사이의 결합도가 낮다고 표현합니다.
- SOLID 원칙은 응집도를 높이고 결합도를 낮추는 것을 목표로 합니다.
- 응집도가 높고 결합도가 낮은 모듈은 변경이 발생할 때 파급 효과가 적고, 이해하기 쉽고, 유지보수가 용이합니다.
2 Single Responsibility Principle
- 단일 책임 원칙(SRP)은 클래스가 하나의 책임만 가져야 한다는 원칙입니다.
- 여기서 책임이라는 의미가 잘 이해되지 않을 수 있습니다.
- SRP에서 책임은 변경으로 해석하는 것이 좋습니다.
- 즉 단일 책임 원칙은 클래스가 변경되는 이유가 하나만 있어야 한다는 것입니다.
- 한 클래스를 변경하기 위한 한 가지 이상의 이유를 생각할 수 있다면, 그 클래스는 한 가지 이상의 책임을 맡고 있는 것입니다.
- 코드를 보는 대부분의 사람들이 이해할 수 있는 크기로 클래스를 만드는 것이 좋습니다.
- 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것입니다.
- 단일 책임 원칙은 다른 원칙과 비교하여 가장 이해하기도, 적용하기도 어려운 원칙입니다.
- 아래 단일 책임 원칙 가이드를 참고하여 적용해보세요.
2.1 SRP와 응집도
- 응집도 또한 변경의 정도로 측정하기 때문에 SRP와 관련이 깊습니다.
- SRP는 모듈의 응집도를 높이는 데 도움을 줍니다.
- 응집도는 모듈에 포함된 내부 요소들이 연관돼 있는 정도를 나타냅니다.
- 응집도는 변경이 발생할 때 모듈 내부에서 발생하는 변경의 정도로 측정할 수 있습니다.
- 하나의 변경을 수용하기 위해 모듈 전체가 변경되면 응집도가 높고 모듈의 일부만 변경되면 응집도가 낮은 것입니다.
- 하나의 변경을 수용하기 위해 하나의 모듈만 변경된다면 응집도가 높고 다수의 모듈이 함께 변경돼야 한다면 응집도가 낮은 것입니다.
2.2 SRP 적용하기
- 클래스가 하나 이상의 이유로 변경된다면 응집도가 낮은 것입니다.
- 이 경우 SRP를 적용해 변경의 이유를 기준으로 클래스를 분리해야 합니다.
- 특정한 메서드 그룹이 특정한 속성 그룹만 사용한다면 응집도가 낮은 것입니다.
- 함께 사용되는 메서드와 속성 그룹을 기준으로 클래스를 분리해야 합니다.
- 클래스 인스턴스 초기화 시 경우에 따라서 서로 다른 속성들을 초기화한다면 응집도가 낮은 것입니다.
- 초기화되는 속성의 그룹을 기준으로 클래스를 분리해야 합니다.
2.3 단일 책임 원칙 가이드
- 책임을 한 문장으로 적어본다.
- 클래스의 책임을 설명하는데
그리고
나 또는
이 들어간다면 여러 개의 책임을 담당하는 클래스입니다.
- 메서드들을 분류한다.
- 이름이나 목적이 비슷한 메서드들을 그룹으로 묶어 나열합니다.
- 이 메서드 그룹별로 클래스를 분리할 수 있는지 검토합니다.
- 인스턴스 변수와 메서드 사이의 관계를 살펴본다.
- 일부 인스턴스 변수가 일부 메서드에 의해서만 사용되는지 확인합니다.
- 만약 그렇다면 이 인스턴스 변수와 메서드들을 그룹으로 묶어 클래스를 분리할 수 있습니다.
- 서로 배타적으로 초기화되는 인스턴스 변수가 있는지 살펴본다.
- 어떤 변수들이 초기화될 때 함께 초기화되지 않는 인스턴스 변수들이 있는지 확인합니다.
- 테스트하고 싶은 private 메서드가 있는지 살펴본다.
- 너무 많은 private 메서드가 있을 때 테스트하고 싶은 private 메서드가 존재하는지 확인합니다.
- 이런 메서드들은 테스트하기 위해 public으로 변경하는 것보다 클래스를 분리하는 것이 좋습니다.
- 외부 의존성을 찾는다.
- 데이터베이스 연결이나 외부 시스템과의 연동 등과 같이 외부에 위치하는 불안정한 의존성을 찾습니다.
- 이런 의존성은 별도의 클래스로 분리하는 것이 좋습 니다.
3 Open-Closed Principle
- 소프트웨어 개체는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다.
- 확장에 대해 열려 있다: 애플리케이션의 요구사항이 변경될 때 이 변경에 맞게 새로운 동작을 추가해서 애플리케이션에 기능을 추가할 수 있다.
- 수정에 대해 닫혀 있다: 기존의 코드를 수정하지 않고도 애플리케이션의 동작을 추가하거나 변경할 수 있다.
- 즉 OCP는 기존의 코드를 수정하지 않고도 새로운 기능을 추가할 수 있도록 하는 원칙이다.
3.1 컴파일 타임 의존성과 런타임 의존성
- 사실 개방 폐쇄 원칙은 런타임 의존성과 컴파일 타임 의존성에 관한 이야기입니다.
- 개방 폐쇄 원칙을 따르는 설계란 컴파일타임 의존성은 유지하면서 런타임 의존성의 가능성을 확장하고 수정할 수 있는 구조라고 할 수 있습니다.
- 예를들어, 클라이언트가 인터페이스에 의존하고, 인터페이스를 구현한 클래스가 런타임에 결정되는 구조입니다.
3.2 추상화