-
class에 단일 책임이 있는지 판단하는 방법DEV 2024. 11. 18. 20:47
단일 책임 원칙(single responsibility principle) SRP
클래스와 모듈은 하나의 책임 또는 기능만을 가지고 있어야 한다는 설계원칙
거대하고 포괄적인 클래스를 설계하는 대신, 작은 단위와 단일 기능을 가진 클래스를 설계해야 한다.
클래스에 비즈니스와 관련 없는 기능이 두 개 이상 포함되어 있으면 책임이 단일하지 않으므로, 단일 기능을 가진 여러 개의 작은 클래스로 분할되어야 한다고 생각할 수 있다.
예를 들어 어떤 클래스에 주문 관련 코드와 사용자 관련 코드가 모두 포함되어 있다면
두 기능을 동일한 클래스에 넣는 것은 단일 책임 원칙에 위배된다.
단일 책임 원칙을 충족하기 위해 이 클래스를 더 작게 세분화하여 단일 기능을 가진 두 개의 클래스로 분할해야 한다.
클래스에 단일 책임이 있는지 판단하는 방법
위에 예로든 클래스는 간단하기 때문에 주문 관련 기능이 사용자와 관련 없다는 것은 바로 알 수 있다.
그러나 대부분의 경우 클래스의 메서드가 동일한 유형의 함수로 분류되는지, 아니면 관련 없는 두 개의 함수로 분류되는지를 판별하는 것은 쉽지 않기 때문에, 실제 소프트웨어 개발에서 클래스에 단일 책임이 있는지 판단하기란 쉽지 않다.
어떤 소셜 네트워크 서비스에서 UserInfo 클래스를 사용하여 사용자 정보를 기록하는데, 아래 UserInfo 클래스는 단일 책임 원칙을 충족할까?
public class UserInfo { private long userId; private String userName; private String email; private String telephone; private long createdTime; private long lastLoginTime; private String avatarUrl; private String provinceOfAddress; private String cityOfAddress; private String regionOfAddress; private String detailEdAddress; .... }
이 질문에 크게 두 가지 다른 견해가 있을 수 있다.
UserInfo 클래스에는 사용자와 관련된 정보가 포함되어 있고 모든 속성과 메서드가 사용자와 같은 비즈니스 모델에 속해 있어 단일 책임 원칙을 만족한다는 관점.
UserInfo 클래서에서 주소 정보의 비율이 상대적으로 높기 때문에 주소 정보를 독립적인 UserAddress 클래스로 분할할 수 있으며 UserInfo 클래스는 주소 정보를 제외한 다른 정보만 보유하도록 하여 두 클래스 책임을 단일화할 수 있다는 관점.
이 두가지 관점 중 어느 견해가 타당할까? 어느 한쪽을 선택하려면 시나리오를 살펴볼 필요가 있다.
만약 이 소셜 네트워크 서비스에서 사용자의 주소 정보가 다른 사용자 정보와 동일하게 정보 표시에만 사용되며, 다른 정보와 함께 사용된다면 UserInfo 클래스의 현재 설계가 합리적이라 할 수 있다. 그러나 이 서비스가 발전하여 전자 상거래 기능 모듈이 제품에 추가되면 사용자의 주소 정보는 표시를 위해 사용될 뿐만 아니라 전자 상거래의 물류에 독립적으로 적용될 가능성이 생긴다. 이 경우에 주소정보를 분리해 독립적인 정보로 구축하는 것이 좋다.
서비스가 더욱 발전해 통합 계정 시스템을 지원한다면, 본인인증과 관련된 email, telephone 같은 속성을 별도의 클래스로 추출해야 할 것이다.
이런 예를 통해 동일한 클래스라 할지라도 다른 응용 시나리오나 다른 단계의 요구 사항에 따라 클래스의 책임이 단일한지 아닌지를 판단하는 것이 다를 수 있다. 특정 응용 시나리오 또는 현재 요구 사항을 기준으로 할 때는 클래스의 설계가 단일 책임 원칙을 만족할 수 있지만, 요구사항이 달리질 경우 해당 클래스의 설계가 단일 책임 원칙을 충족하지 못할 수 있으므로 계속해서 더 작은 클래스로 분할해야 한다.
클래스에 단일 책임이 있는지를 평가하기 위한 명확핟고 정량화할 수 있는 표준은 존재하지 않는다.
실제로 소프트웨어를 개발할 때는 과도하게 너무 세분화하여 설계할 필요는 없다. 처음에는 현재 비지니스 요구 사항을 충족하기 위해 거친 형태의 클래스를 작성할 수 있다. 하지만 사업이 발전하면서 클래스에 기능이 추가되고, 코드가 복잡해지면서 거대해진 클래스를 여러 개의 세분화된 클래스로 나눌 수 있다.
단일 책임 여부를 결정하기 위해 사용되는 몇가지 결정 원칙
- 클래스에 코드, 함수 또는 속성이 너무 많아 코드의 가독성과 유지 보수성에 영향을 미치는 경우
- 클래스가 너무 과하게 다른 클래스에 의존한다면, 높은 응집도와 낮은 결합도의 코드 설계 사상에 부합하지 않으므로 분할 고려
- 클래스에 private 메서드가 너무 많은 경우 이 private 메서드를 새로운 클래스로 분리하고 더 많은 클래스에서 사용할 수 있도록 public 메서드로 설정하여 코드의 재사용성을 향상시켜야한다.
- 클래스의 이름을 비지니스적으로 정확하게 지정하기 어렵거나 Manager, Context처럼 일반적인 단어가 아니면 클래스의 이름을 정의하기 어려울 경우, 클래스 책임 정의가 충분히 명확하지 않음을 의미할 수 있다.
- UserInfo 클래스의 많은 메서드가 주소를 위해서만 구현된 앞의 예시처럼 클래스의 많은 메서드가 여러 속성 중 일부에서만 작동하는 경우 속성과 해당 메서드의 분할을 고려
설계 원칙을 적용하든 디자인 패턴을 적용하든 그 목표는 코드의 가독성, 확장성, 재사용성, 유지 보수성을 향상하는 것.
728x90'DEV' 카테고리의 다른 글
마이크로 매니저, 위임하는 매니저 (0) 2024.11.20 프로젝트 관리에 도움 되는 가이드라인 (0) 2024.11.19 AI agent frameworks (4) 2024.11.16 AI Agent concept (3) 2024.11.15 Multimodal RAG (2) 2024.11.14