본문 바로가기

소프트웨어

[소프트웨어/SOLID] 개방 폐쇄 원칙(OCP)


OCP(open-close principle)

변경에 대해선 닫혀있고 확장에 대해선 열려있다.

요구사항 변경에 따른 관점

개방 폐쇄 원칙은 변경에 대해선 닫혀있고 확장에 대해선 열려있다는 말인데, 의외로 명확한 의미이다.

클라이언트성적표, 출석부클래스에 의존하고 있다고 가정하고 변경사항으로 클라이언트가 유저의 도서관 대여 명부또한 보고 싶다고 한다. 이 경우 기존의 설계로는 클라이언트도서관 대여 명부을 의존하는 메서드를 만들어야 하는데, 이는 기존코드를 변경을 해야하므로 OCP원칙에 위배된다.

이 경우 출력매체에 대해서 인터페이스를 만들고 클라이언트가 이 출력매체인터페이스를 의존하게 한다면 도서관 대여 명부라는 새로운 기능이 확장되더라도 클라이언트의 코드에는 수정이 없다.

(의존성의 주입은 외부에서 진행되어야 하는데, DI보다는 파라미터로 출력 매체 객체를 받는 형식으로 개선하면 될 듯 하다.)

테스트에 따른 관점

단위테스트는 환경이나 의존성에 상관없이 대상 유닛(메서드, 클래스)의 기능만을 테스트하는 테스트이다. 하지만 대부분의 서비스가 DB와 웹서버 등의 의존되어 있어 단위 테스트를 위해 설치나 구성이 필요하다면 이는 단위테스트가 아니게 된다. 따라서 해당 클래스의 의존하고 있는 클래스(환경)을 Mock나 가짜 클래스로 변경해줘야 하므로 이를 고려한 설계가 필요하다.

클라이언트사용자 저장소라는 클래스를 의존하고 있을떄 클라이언트를 단위 테스트할 수 있는 방법은 아래 2가지가 있다.

  • 사용자 저장소를 상속받은 TestableUserRepository클래스를 만들어 교체할 것
  • 사용자 저장소에 대한 인터페이스를 생성하여 해당 인터페이스를 구현한 Mock사용자저장소클래스로 대체할 것

사실 원본의 클래스를 상속받아 만든 테스트 보단 인터페이스에 대한 테스트를 하는 것이 더욱 깔끔하다.

  • 테스트 가능한 가짜 클래스는 사용자 저장소를 테스트하기보단 가짜클래스를 테스트하는 느낌이 강하다.
  • 모든 메서드에 대해서 오버라이드가 필요하게 되는데 기존 사용자 저장소가 변경되었다고 해서 테스트 가능한 클래스가 컴파일 오류가 나지 않아 인지하기 어려워 유지보수에 어렵다. 반면, 인터페이스로 스펙을 변경하면 즉시 컴파일 타임에서 즉시 인지가 가능하다.
  • 모든 메서드를 오버라이드 하기 어렵다.

테스트의 용어

  • 더미 객체 : 테스트시에만 필요, 기능에는 필요없음, 메서드가 호출되는 경우 예외 발생 시킴
  • 테스트 스텁 : 더미 객체에 단순한 기능을 추가, 특정한 값을 반환시키거나 메시지를 출력
  • 테스트 스파이 : 대상 클래스의 출력을 검증, 의존 클래스의 호출을 잡아내서 원하는대로 출력이 되었는 확인
  • 가짜 객체 : 테스트 환경에서 사용할 수 없을 정도로 많은 의존관계를 가진 클래스를 더미 객체로 생성하여 간단히 구현
  • 목 객체 : 미리 정의한 기대 값과 실제 호출을 단언문으로 비교 문제가 있으면 테스트를 실패하게 함, 위의 4가지 형태를 모두 포함