해결된 질문
작성
·
38
1
안녕하세요. 좋은 강의 만들어주셔서 감사합니다.
강의를 보다가 마침 평소에 고민하던 내용이 있어서 질문 드리게 됐습니다.
5-4. 애플리케이션 객체 추가하기
강의를 보던 중 외부에서 직접적으로 각각의 도메인을 호출하지 않고 ReservationService를 만들고 외부에서는 reserveScreening()를 호출해서 예약을 하는거로 이해했습니다.
reserveScreening()에서 customer 조회, screening 조회, 예약 등록 등의 작업을 하고 있는데 이 경우에 SRP를 위반하는게 아닌가 하는 의문이 있었습니다.
헷갈리는 부분은 함수 하나에 여러 가지 동작이 있고 변경 될 여지가 많으니까 SRP에 위반 되는게 아닌가? 싶다가도 ‘예약을 하는 하나의 역할’이니까 SRP를 위반하는게 아니지 않나? 라는 생각으로 머리속에서 빙글빙글 돌고 있습니다.
평소 개발을 할 때 Service layer의 역할에 대해서 애매한 부분이 많았는데 SRP를 준수하려고 하나의 기능만 넣어야 된다고 생각하면서 개발을 하다보면 Controller의 역할이 많아지고 Service는 깔끔해졌지만 막상 보면 Service에서 하나의 기능을 구현한다기보다는 각각의 Service의 함수를 Controller에서 조합 해야 사용할 수 있고 비즈니스 로직을 Controller에서 파악할 수 있는 등의 문제가 있었습니다. reserveScreening()의 역할처럼 어떤 범위까지가 Service 하나하나의 기능으로 정의하는게 맞는지 궁금합니다.
또 다른 고민은 Respository에서 데이터를 조회할 때 Controller에서 Repository를 바로 조회하지 않도록 항상 Controller->Service->Repository의 순서로 호출을 하려고 하다보니까 간단하게 id로 데이터를 조회할 때에도 Service에 함수를 생성하고 함수 내부에는 Repository를 호출해서 그대로 return 하는 정도의 함수를 생성하게 되는데 이런 역할도 Service에서 가지고 가는게 맞는지 궁금합니다.
조금 추상적인 질문이 될 수도 있을 것 같은데 영호님이 생각하시는 Service layer의 역할에 대해서도 조금 알려주시면 좋을 것 같습니다.
다시한번 좋은 강의 만들어주셔서 감사하고 다음 강의 기다리고 있겠습니다.
감사합니다!
답변 2
1
fzwoongbin닌 좋은 질문 주셔서 감사합니다. 🙂
1. reserveScreening과 SRP
일반적으로 SRP라고 할 때는 주로 클래스를 대상으로 이야기하는 경우가 많지만 말씀하신 것처럼 메서드 역시 SRP의 대상이 될 수 있습니다.
강의에서도 말씀드렸던 것처럼 사실 SRP는 응집도와 관련된 이야기입니다.
하나의 변경 이유만 가지도록 클래스나 메서드를 구현한다면 응집도가 높아지기 때문에 결과적으로 SRP를 만족하게 됩니다.
reserveScreening 메서드는 예약을 하기 위해 필요한 객체를 읽고, 도메인 로직에 요청을 위임하고, 수정된 결과를 저장하는 로직만 포함합니다.
데이터를 읽거나 저장하고 상영이 예매되는 구체적인 로직은 별도의 객체들 안에 구현되어 있고 reserveScreening은 이들을 조합해서 상영을 예매하기 위한 전체 플로우를 완성시킵니다.
HTTP 요청 파라미터가 변경되거나, 요청 데이터 검증 로직이 변경되거나, 반환값이 변경되거나, Screening과 Movie 사이의 협력이 변경되거나, SQL문이 변경될 경우에는 변경되지 않습니다.
결과적으로 reserveScreening 메서드를 살펴보면 예약을 하기 위해 필요한 플로우가 변경될 때만 코드를 수정하게 됩니다.
다른 기능은 다루지 않고 오직 예약을 위한 플로우만 담당하고 있습니다.
따라서 reserveScreening은 응집도가 높다고 할 수 있으며 SRP를 만족한다고 할 수 있습니다.
2. Controller -> Repository 호출
개인적으로 Service를 두는 쪽을 선호합니다.
Controller에서 Repository를 직접 조회할 경우 비즈니스 로직이 Controller로 누수되는 경우도 많아지고 이후에 조회할 데이터가 늘경우 Controller가 불필요하게 복잡해지는 경향이 있게 됩니다.
Service에 메서드를 두면 메서드 이름을 통해 조회하려는 의도를 전달할 수도 있구요.
Controller는 프리젠테이션 로직만 담당하게 하고 데이터를 조회하고 변환하는 로직은 별도의 Service에 두는 것이 유지보수 측면에서 더 좋은 선택이라고 생각합니다.
3. 서비스 레이어의 역할
앞에서 설명드린 것처럼 서비스 레이어는 플로우를 조율하는 역할을 담당합니다.
플로우에서 실행되는 구체적인 로직은 Repository 구현체나 Screening과 같은 별도의 객체에서 수행되고 서비스 레이어는 이 객체들을 호출해서 전체적인 플로우를 완성합니다.
간단히 말해서 서비스 레이어는 기술적인 요소와 도메인 객체 사이의 흐름(구체적인 구현이 아니라 호출만 합니다)을 조율하는데 필요한 책임을 담당합니다.
비즈니스 관점에서 연산을 수행하는데 필요한 도메인 로직의 호출, 트랜잭션이 관리, 데이터베이스 조회/저장, 메시징을 통한 통지 등의 흐름 관리가 서비스 레이어의 주역할입니다.
답변이 되었는지 모르겠네요. 🙂
0
안녕하세요, 인프런 AI 인턴입니다.
fzwoongbin님, 좋은 강의를 시청해 주셔서 감사합니다! 또한, 서비스 레이어와 SRP(Single Responsibility Principle)에 대한 심오한 질문을 해주셔서 감사합니다.
서비스 레이어의 역할은 항상 명확한 기준이 있는 것은 아니지만, 비즈니스 로직을 포함하고 이를 조율하는 역할을 하는 것이 일반적입니다. reserveScreening()
과 같은 메소드에서 여러 작업(조회, 등록 등)을 수행하는 것은 단일 책임 원칙을 완전히 위반하는 것은 아닙니다. 오히려 “예약”이라는 하나의 비즈니스 기능을 구현하기 위해 자연스럽게 여러 단계를 거치는 것으로 볼 수 있습니다.
SRP는 “하나의 클래스는 오직 하나의 변화의 이유만 가져야 한다”는 원칙입니다. 서비스 메소드는 비즈니스 로직의 단위로, 여러 책임을 함께 팬으로 묶어 역할을 전체적으로 수행할 수 있습니다. 중요한 것은 메소드 또는 클라스 내에서 잠재적으로 독립적으로 변경될 이유(=다른 Actor에 의해 변경되는 이유)가 되도록 구성하는 것입니다.
비즈니스 로직 중심: 비즈니스 도메인 내에서 상호 관련된 작업을 하나의 서비스 메소드로 모을 수 있습니다. 이렇게 하면 로직의 응집도를 높이고 다른 레이어(예: UI)로 직접적인 로직 이동을 방지할 수 있습니다.
조율: 데이터의 흐름을 조절하고, 여러 리포지토리와의 상호작용을 조정합니다. 서비스는 여러 리포지토리를 의도적으로 조합하여 작업을 수행할 수 있습니다.
트랜잭션 관리: 보통 서비스 레이어는 데이터베이스 트랜잭션의 시작과 종료, 커밋 및 롤백을 처리하는 위치가 됩니다.
서비스 레이어를 통한 호출 패턴(Controller->Service->Repository)을 유지하는 이유 중 하나는 응집도와 결합도를 관리하는 것입니다. 단순히 데이터를 조회하는 작업도 서비스에서 조율할 경우, 코드는 단순하지만 유지보수와 확장성 측면에서는 오히려 가치를 더할 수 있습니다. 필요하다면 보안, 로깅, 검증 등을 서비스 레이어에서 추가함으로써 재사용성과 응집도를 높일 수 있습니다.
fzwoongbin님께서 고민하신 부분에 대한 더 깊이 있는 설명은 객체지향 설계에서 SRP의 적용 모델을 참고해주세요. 여러 상황에서 SRP를 적용하는 방식과 구체적인 예가 소개되어 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.