f-lab-edu / self-monitoring

0 stars 2 forks source link

Service Layer - Service 생성 #8

Closed iamabear09 closed 4 months ago

iamabear09 commented 5 months ago
iamabear09 commented 5 months ago

Fake Repository 구현 과정 고민 & 기록

Fake Repository를 구현 할 때 세부 구현 사항에 집중하지 말고 Repository 인터페이스에 집중해서 구현해야 한다. 즉 Repository의 save method는 저장할 값을 받아서 저장하고 객체를 돌려주면 된다.

고민 1️⃣ Fake Repository가 객체를 받아서 해당 객체에 id 값을 채우고 저장 및 반환을 한다. 2️⃣ Fake Repository가 객체를 받아서 해당 객체를 토대로 id값을 채운 새로운 객체를 만들어서 저장 및 반환한다.

위 두 가지 방식 중 무엇을 해야 할지 고민했다.

2024 .01 .24 실제 JPA의 경우, Id 값을 채우고 해당 객체를 그대로 반환한다. 따라서, 실제 DB와 같은 방법인 1️⃣ 방법으로 진행을 하기로 결정했다.

iamabear09 commented 5 months ago

양방향 연관 관계

나의 경우, 우선 Record와 Time의 양방향 연관 관계가 필요하다고 판단했다.

고민 & 생각 양방향 연관 관계라고 해서 연관 관계를 아무 곳에서 설정 하기보단 한 곳에서 설정하는 것이 더 관리하기가 수월하다고 생각된다. 나의 경우 Time에서 Record를 설정하기 위해서는 Time에서 직접 설정하지 못하고 record.addTime() 을통해서만 연관 관계가 설정되도록 만들었다.

f-lab-lyan commented 5 months ago

고민 1️⃣ Fake Repository가 객체를 받아서 해당 객체에 id 값을 채우고 저장 및 반환을 한다. 2️⃣ Fake Repository가 객체를 받아서 해당 객체를 토대로 id값을 채운 새로운 객체를 만들어서 저장 및 반환한다.

이 부분은 실제 repository가 어떻게 동작하는지 확인해보면 좋지 않을까요? 그리고 꽤 괜찮은 고민이라고 생각합니다. :-)

iamabear09 commented 5 months ago

Fake Repository 관련 기록

Fake Repository 관련 착각한 부분이 존재한다. Service Layer에서 Repository Interface 를 생성해서 어떤 DB가 와도 Service layer 가 변하지 안도록 생성해야 한다고 생각했다.

내가 생각했던 그림 image

하지만, 이렇게 만드는 것이 아니고 Fake Repository를 두었다가 DB가 결정되면 해당 Service에서 특정 DB에 의존적인 코드를 집어 넣어서 변경하는 형식으로 가져가는것 이였다.

image

Service Layer에 Repository Inteface를 둘 필요가 없는 이유

만약 내가 플랫폼을 개발한다면, 어떤 구현체가 들어올지 알 수 없다. 따라서 interface를 두고 구현해 나가는 것이 맞다.

하지만, 서비스를 개발한다고 했을 때 "DB를 갈아 끼우는 일이 자주 발생할까" 라는 질문을 해보면 그렇지 않다 라는 결론이 나온다. 또한 DB를 교체해야 하는 일이 발생한다고 하면 구현체를 갈아 끼우기 보단 나의 서비스이기 때문에 코드를 변경해서 업로드 하게 될 것이다.

iamabear09 commented 5 months ago

생각해볼 주제

**1. 비지니스 로직을 Domain에 위치 시킬 것인가?

  1. Service에 위치 시키고 Domain을 순수하게 가져갈 것인가?**

Domain에 위치 Domain에 비지니스 로직을 두게 되면 Domain을 사용하는 여러 곳에서 중복된 로직을 만들 필요 없이 Domain에 비지니스 로직을 위임하면 된다. 따라서 Domain에 비지니스 로직을 두는 것이 좋다.

Service에 위치

Domain에 비지니스 로직을 두게 되면 Domain을 사용하는 여러 곳에서 중복된 로직을 만들 필요 없이

즉, 특정 비지니스 로직이 다른 여러 곳에서 사용될 수 있도록 Domain에 비지니스 로직을 위치시키는데 이것 부터 다시 고려해볼 필요가 있다. 예를 들어, Record Domain의 로직을 Record Service가 아닌 다른 곳에서 호출 하도록 하는 것이 맞을까? Record와 관련된 일은 다른 Service가 아닌 Record Service에 처리하도록 하는 것이 이상적으로는 맞다.

이렇게 구현할 때는 Service에서 Record의 데이터를 getter를 통해 비지니스 로직을 처리하고 setter를 통해 결과를 업데이트 하도록 한다. 또한, Domain 객체에 비지니스 로직이 들어가지 않으므로 순수하게 Data만을 표현할 수 있다.

Domain에 위치 물론 Domain에 비지니스 로직이 있는 경우, 해당 Domain 객체와 관련되지 않은 다른 Service에서 해당로직을 사용할 수 있다. 하지만, 이것은 Service 또한 마찬가지이다. 해당 Domain 객체와 관련되지 않은 Service에서 비지니스 로직을 작성해서 사용할 수 있다.

내 생각

결국 절차지향적으로 코드를 작성할지 객체지향적으로 코드를 작성할 지 결정하게 되는 문제라고 생각된다. 즉, [1] Class가 Data로서만 역할을 할지 [2] 객체로서 역할을 할게 할지 판단을 해야 한다.

객체 지향과 절차 지향의 장단점을 비교해 봐야 한다. 만약 코드가 여러 곳에서 사용된다면 객체 지향으로 작성하는 것이 맞다. 하지만 정말 딱 한번만 사용되는 코드라면 굳이 코드를 숨겨 놓을 필요가 없을 것 같다. 즉, 특정 로직이 특정 Service에서만 호출 된다면 절차 지향적으로 작성하는 것이 코드가 어떻게 돌아가는지 한눈에 파악하기도 좋다. 또한 Domain도 Data로써 한눈에 파악하기 좋다.

iamabear09 commented 5 months ago

Service layer Test 관련 고민

RecordTimeService가 RecordService , TimeLogService 를 사용할 때, RecordService와 TimeService를 Mocking해주어야 할까? 처음에 나는 Mocking을 하려고 했다.

하지만, Service Layer에서 Repository를 Mocking하는 이유를 생각해보면 Repository 와 상관없이 Service Layer만 테스트 하고 싶기 때문에 Repository를 Mocking하는 것이다.

그러나 이 경우, Service 들을 사용하는 Service를 다른 Layer로 보고 사용되는 Service를 Mocking하는 것이 맞다고 생각이 든다.

만약 Repository만 Mocking 한다면 Controller에서 Repository를 Mocking하는 것과 비슷하다. Mocking을 이해하기가 힘들어진다. 왜냐하면 Controller에서 Service의 세부 동작을 세세히 알아야 Mocking을 할 수 있고 Mocking을 이해할 수 있기 때문이다.

iamabear09 commented 5 months ago

Fake Repository 관련 기록

Fake Repository 관련 착각한 부분이 존재한다. Service Layer에서 Repository Interface 를 생성해서 어떤 DB가 와도 Service layer 가 변하지 안도록 생성해야 한다고 생각했다.

내가 생각했던 그림 image

하지만, 이렇게 만드는 것이 아니고 Fake Repository를 두었다가 DB가 결정되면 해당 Service에서 특정 DB에 의존적인 코드를 집어 넣어서 변경하는 형식으로 가져가는것 이였다.

image

Service Layer에 Repository Inteface를 둘 필요가 없는 이유

만약 내가 플랫폼을 개발한다면, 어떤 구현체가 들어올지 알 수 없다. 따라서 interface를 두고 구현해 나가는 것이 맞다.

하지만, 서비스를 개발한다고 했을 때 "DB를 갈아 끼우는 일이 자주 발생할까" 라는 질문을 해보면 그렇지 않다 라는 결론이 나온다. 또한 DB를 교체해야 하는 일이 발생한다고 하면 구현체를 갈아 끼우기 보단 나의 서비스이기 때문에 코드를 변경해서 업로드 하게 될 것이다.

결과적으로 JPA의 Join Fetch 와 같은 기능을 사용하지 않고 최대한 단순한 쿼리만 사용하고 서버에서 Join을 하는 방식으로 구현하니, 만약 DB가 바뀌더라도 크게 코드가 변경되는 일은 없을것 같다는 생각이 든다.