Mar 25, 2021, TIL (Today I Learned) - SOLID

Inwoo Hwang·2021년 8월 26일
0
post-thumbnail

SOLID

가치와 원칙

가치는 원칙보다 높은 수준의 개념

원칙은 가치를 지키기위해서 존재해야한다.

가치를 최우선적으로 생각하며 원칙을 지켜보자

소프트웨어에서 가치

가치 > 원칙

1. 가독성, 커뮤니케이션

  • 개발자는 코드를 통한 커뮤니케이션
  • 읽고 이해할 수 없는 코드가 더욱 가치가 없다.

2. 단순성

  • 코드는 단순해야 한다.
  • 커뮤니케이션에 도움이 된다.
  • 버그가 생길 틈이 없어짐
  • 미래의 확장을 위한 복잡한 패턴은 경계의 대상

3. 유연성

  • 기존의 코드를 수정하는 데에 많은 시간을 소비함
  • 유연성과 단순성은 trade off

유연성 vs 단순성

  • 처음엔 단순하게 코드를 작성하자
    • 기획 또는 정책의 변경이 발생하면
      • 이 기획 또는 정책의 변경의 원인은 무엇일까 고민
      • 이러한 변경은 계속 발생 가능한 일인가?
        • 리팩토링을 통해 확장성

소프트웨어 세상에서 비용이란

Time == 비용

위에 언급한 가치를 지키면서 소요되는 비용 시간을 최소화할 수 있다.

모든 문제를 해결하는 절대적인 최고의 선택은 존재하지 않는다.

단지 현재 상황에서 최선의 선택을 하기위해서 우리는 기준을 세우고 코드를 작성해야 한다.

객체 속성을 가져오지 말고 객체가 일하도록 시켜라!!!

  • 자료에 묶여있는 형태의 프로그램 형성 가능

객체지향프로그래밍을 위한 5가지 원칙

1. SRP(Single-Responsibility Principle)

단일 책임 원칙

  • 한 클래스는 단 한가지의 책임만을 가져야 한다.

예: View 컨트롤러는 View를 컨트롤하는 책임을 가지고 있다. 이 외의 책임을 지게 된다면 SRP원칙을 거스르게 된다.

책임은 변경의 이유다.

  • 변경을 위해 수정이 되려면 많은 내용이 수정: 응집도

높은 응집도(낮은 결합도) vs 낮은 응집도(높은 결합도)

여러 객체를 책임질 때 문제:

여러 게임의 스코어를 계산하는 구기 종목 스코어 계산기:

야구게임의 스코어 변경이 농구게임에 영향을 줄 수 있다.

어떠한 객체가 책임을 많이 갖는다고 할 수 있는가?

아래 예를 보자.

여러 직업들이 job클래스에게 많이 의지하고 있고 job 클래스는 결과적으로 과도한 책임감을 갖게 된다.

이를 해소하기 위해 아래 사진과 같이 책임을 분리 시킬 수 있다.

Interface라는 통로를 통해 각각 다른 직업은 job class와 소통을 하게 수정하였고 이 과정을 통해 job class의 책임감은 줄어들게 되었다.

이렇게 기능이 어떻게 작동하는지 테스트해야 하는 것들을 각각의 로직에 맞게 쪼게서 다른 객체에게 넘겨주면 하나의 객체가 너무 많은 책임을 지는 것을 피할 수 있다.

2. OCP(Open-Close_Principle)

개방-폐쇄 원칙

  • 확장에 열려있고 변경에 닫혀있다.
  • 확장을 할때는 기존의 코드를 최대한 건드리지않고 확장하자.
  • 만약 기조의 코드를 수정하게되면 연쇄적인 수정을 피하게 하자.

예 Enum과 Protocol의 수정:

열거형은 타입을 추가하면 다른 변경사항이 많아지는데 Protocol은 타입을 추가할 때 변경사항이 비교적 적다.

반대로 열거형에 메서드 또는 행동을 추가할 경우 열거형에서 수정할 사항이 비교적 적다.

따라서 우리는 객체를 생성할 때 목적성을 가지고 생성해야한다.

3. LSP(Liskov Substitution Principle)

리스코프 치환 원칙

자식클래스는 부모 클래스로써의 역할을 완벽히 할 수 있어야 한다.

잘못된 상속은 엄청 큰 문제를 이르킬 수 있기에 조심히 사용해야 한다.

현실과 개발에서의 추상화 방법

오리너구리 예시:

4. DIP(Dependency Inversion Principle)

의존성 역전 원칙

  • 상위 수준의 모듈은 하위수준의 모듈에 의존해서는 안된다.
  • 구체적인 사항은 추상화에 의존해야 한다.

예 UITextField는 CustomViewController에 의존해서는 안된다.

하지만 CustomViewController는 UItextField와 통신해야 한다 하는 것이 많다.

따라서 존재하는 UItext delegate라는 통로를 사용하여 위에 언급한 두 객체가 의존성 역전 원칙을 지키면서 통신할 수 있게 된다.

다른예시: 컴퓨터가 여러가지 마우스에 의존하게 되면 안된다. 마우스는 언제나 변할 수 있기 때문이다. 그래서 우리는 USB 포트라는 표준이 있다. 컴퓨터는 직접적으로 마우스와 같은 구체적인 것에 의존하지 않고 USB포트를 통해서 유연하게 여러 마우스와 연결 분리가 가능해진다. 마우스에 의존하지 않는다.

5. ISP(Interface Segregation Principle)

인터페이스 분리 법칙

클라이언트가 불필요한 자신이 사용하지 않는 인터페이스에 의존하지 말아야 한다.

왜냐하면...

  • 상속받은 메서드를 퇴화시켜야 하는 경우가 발생할 수 있다.

  • 불필요한 인터페이스에 의존하면 불필요한 빌드가 유발될 수 있다.

    큰 인터페이스를 작은 인터페이스들로 분리하고, 필요한 부분만 클라이언트가 취사선택하여 사용할 수 있게 해야 한다.

*클라이언트: 사용하는 유저

달팽이 클래스가 움직일 수 있는이라는 프로토콜을 채택했는데 프로토콜의 메서드 중 하나가 점프하기이면...나중에 앱에 들어가면 달팽이에게 점프하는 버튼은 있지만 점프하는 기능을 하지 못한다. 이는 불필요한 인터페이스가 제공된 예시이다.

Warning

솔리드에 집착하다보면 목적성을 잃을 수 있다. 지켜야 하긴 하지만 너무 매몰되면 안된다.

프로젝트를 진행하는 동안 이 원칙을 모두 다 지키는 것은 매우 힘들다. 경우에 따라 무시해야 할 때도 있다. 그렇기에 이를 무조건적으로 지켜야 한다는 생각은 버리면 좋겠다.

profile
james, the enthusiastic developer

0개의 댓글