문제점 인식


1. Entity 에서 Setter Method가 열려있음

<aside> 💡 기존 코드

@Data
@Entity
@Table(name = "tester")
@NoArgsConstructor
public class Tester extends BaseTime {
	...
}

해당 문제가 발생하는 가장 큰 이유는 @Data를 적용했기 때문입니다. @Data를 제거하고 Entity를 변경해야 한다면 명시적인 메서드를 이용해서 변경하도록 하겠습니다.

2. Service에서 Entity의 값을 직접 변경함.

<aside> 💡 기존 코드

@Service
@RequiredArgsConstructor
public class MakerAuthServiceImpl implements MakerAuthService {

	@Override
    @Transactional
    public PatchTestResponse patchTest(
            UUID makerId,
            UUID testId,
            @RequestBody PatchTestRequest request
    ) {
        Maker maker = makerRepository.findById(makerId)
                .orElseThrow();
        Test test = testRepository.findById(testId)
                .orElseThrow();
        long beforePoint = 
                ((long) test.getReward() * test.getParticipantCapacity());

        String symbolImageRoot =
                FileHandler.saveProfileFileData(request.getSymbolImage());
        test = request.toEntity(test, symbolImageRoot);

        long needPoint =
                (long) test.getReward() * test.getParticipantCapacity();
        if (maker.checkAvailableCreateTest(needPoint - beforePoint)) {
            maker.setPoint(maker.getPoint() - (needPoint - beforePoint));
            return new PatchTestResponse(test.getId());
        } else {
            throw new MakerRevertTestFailException("수정하기 위한 잔여 Point가 부족합니다.\n 필요한 Point: " + (needPoint - beforePoint) + ", 잔여 Point: " + maker.getPoint());
        }
    }
	
	...

}

해당 문제는 단일 책임 원칙을 위반하고 있어 발생합니다. Service에서 Entity에 들어갈 값을 직접 다루다 보니 Entity의 값 위반에 대한 예외도 Service에서 처리하게 됩니다. 그리고 만약 등록할 때, 수수료가 든다는 등, 추가적인 요구사항이 발생하면 Service에 있는 모든 등록하는 Method를 수정해야합니다.

이 문제를 해결하기 위해서는 Entity를 수정하는 경우, 책임을 Entity에 두고 메서드 형태로 Service가 사용하도록 해야합니다. 이 외에도 대부분의 로직이 Service에서 Entity 값을 직접 변경하는 형태로 작성되었는데, 이를 수정하도록 하겠습니다.

3. JPA 사용하지만, 사용방법을 정확하게 알지 못함.

<aside> 💡 기존 코드

@Repository
public interface TestRepository extends JpaRepository<Test, UUID> {
...
		@Query(value = "select t.id,t.title,t.participant_capacity,t.register_time,t.content," +
            "t.reward,t.symbol_image_root,t.modify_time,t.maker_id," +
            "t.recruitment_time_start,t.recruitment_time_limit," +
            "t.duration_time_start,t.duration_time_limit " +
            "from test t, apply_information a " +
            "where a.test_id = t.id and t.recruitment_time_limit >= now()" + 
            "group by t.id order by count(t.id) desc limit 4", nativeQuery = true)
    List<Test> getTop4Test();

		@Query(value = "select * from test t, " + 
						"(select test.id from test where test.recruitment_time_start <= now() and test.recruitment_time_limit >= now() " + 
						"EXCEPT select t.id from test t, apply_information a " + 
						"where t.recruitment_time_start <= now() and t.recruitment_time_limit >= now() and t.id = a.test_id and a.tester_id = ?1) " + 
						"as tt where t.id = tt.id order by t.recruitment_time_limit - now();", nativeQuery = true)
    List<Test> findAllByTestByDeadLineExceptApply(UUID tester_id);
...
}

</aside>