inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

엔티티 비즈니스 로직 vs 서비스 비즈니스 로직

618

작성자 없음

작성한 질문수 0

0

강의에서 DDD의 개념을 적용하시면서 엔티티에 비즈니스 로직을 넣으셨었는데요.

아직까진 DDD에 대한 개념이 완벽히 정립되지 않아 별도의 자료로 공부를 하고 있습니다.

공부하는 차원에서 서비스 계층에서의 비즈니스 로직 개발로 코드 리팩토링을 스스로 해보고 강의에 나오지 않았던 상품 서비스 테스트 코드 작성 결과 일단 통과가 나오긴 했습니다만... 잘 한 것인지 몰라서 코드 평가를 좀 받아보고 싶어 질문을 올리게 되었습니다.

테스트 코드 역시 각 계층별로 지켜야 하는 테스트 코드 원칙이 있으나 이 부분도 같이 공부하느라 제대로 적용해보기 아직 어려운 단계라 @SpringBootTest를 사용했습니다. 이 부분은 감안해주세요..!

 

또 다른 추가 질문이 있습니다. 강의에서 엔티티에 구현한 비즈니스 로직을 서비스 계층에 비즈니스 로직을 개발하는 방식으로 바꾸는 과정에서 엔티티를 직접 이용하는 것보다는 DTO를 만들어서 전달하는게 엔티티에 많은 변화를 가하지않는 유일한 방법일까요?

ItemService 코드

package spring.project.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import spring.project.domain.Item;
import spring.project.exception.NotEnoughStockException;
import spring.project.repository.ItemRepository;

import java.util.List;

@Service
@Transactional(readOnly = true)
public class ItemService {

	private final ItemRepository itemRepository;
	@Autowired
	public ItemService(ItemRepository itemRepository) {
		this.itemRepository = itemRepository;
	}

	@Transactional
	public Long saveItem(Item item, int quantity) {
		addStock(item, quantity);
		itemRepository.save(item);
		return item.getId();
	}

	private void addStock(Item item, int quantity) {
		item.setStockQuantity(item.getStockQuantity() + quantity);
		itemRepository.save(item);
	}

	@Transactional
	public void removeStock(Item item, int quantity) {
		int restStock = item.getStockQuantity() - quantity;
		if (restStock < 0) {
			throw new NotEnoughStockException("재고가 부족합니다.");
		}
		item.setStockQuantity(restStock);
		itemRepository.save(item);
	}

	public Item findOne(Long itemId) {
		return itemRepository.findOne(itemId);
	}

	public List<Item> findAll() {
		return itemRepository.findAll();
	}
}

ItemServiceTest 코드

package spring.project.service;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import spring.project.domain.Album;
import spring.project.domain.Book;
import spring.project.domain.Item;
import spring.project.repository.ItemRepository;

@SpringBootTest
class ItemServiceTest {

	@Autowired private ItemRepository itemRepository;
	@Autowired private ItemService itemService;

	@Test
	@DisplayName("상품 저장 시 상품 저장과 동시에 재고 수량이 증가해야 한다.")
	void save() {
		// given
		Book book = new Book();
		book.setAuthor("홍길동");

		// when
		Long id = itemService.saveItem(book, 3);

		// then
		Item item = itemRepository.findOne(id);
		Assertions.assertThat(item.getName()).isEqualTo(book.getName());
		Assertions.assertThat(item.getStockQuantity()).isEqualTo(3);
	}

	@Test
	@DisplayName("상품 주문이 들어가면 재고 수량에서 주문 수량만큼 차감이 되어야 한다.")
	void remove() {
		// given
		Album album = new Album();
		album.setName("영원");
		Long id = itemService.saveItem(album, 100);

		// when
		itemService.removeStock(album, 4);

		// then
		Item item = itemRepository.findOne(id);
		Assertions.assertThat(item.getStockQuantity()).isEqualTo(96);
	}
}

java spring 웹앱 spring-boot jpa

답변 1

0

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴입니다. dhwiwnwnf님의 엔티티 내 비즈니스 로직과 서비스 계층에서 비즈니스 로직 처리에 대한 질문에 관해, 말씀해주신 상황을 기반으로 비슷한 맥락을 지닌 기존 질문들을 살펴보았습니다.

엔티티에 비즈니스 로직을 포함시키는 것이 DDD(Domain-Driven Design)의 한 방법론입니다. 이 접근법은 도메인이 비즈니스 로직의 주도권을 가지며 구현되는 것을 지향합니다. 물론, 서비스 계층에서 비즈니스 로직을 처리하는 전통적인 방법도 유효하며, 각각의 장단점이 있습니다.

비슷한 주제로 질문하셨던 다른 학습자의 질문에 답변된 내용을 참고할 만 한 내용이 있어 여기에 공유드립니다.

  • 비지니스 로직구현 Entity VS Service에서는 엔티티 내에 비즈니스 로직을 구현하는 방식과 서비스 계층에서 비즈니스 로직을 구현하는 방식의 차이점에 대한 설명이 있습니다. 도메인 주도 설계를 간략하게 설명하면서, 엔티티에 비즈니스 로직을 구현하는 이유와 그 장점에 대해 설명하고 있습니다.

  • entity에 비지니스 로직 관련 질문입니다.에서는 엔티티 내에 비즈니스 로직을 넣는 것과 관련하여, 그러한 방식이 왜 응집력을 높이는지에 대한 설명과 함께, 이에 대한 테스트 코드 작성에 관련된 질문을 다루고 있습니다. 이는 테스트 코드 작성이 어떻게 이루어져야 하는지에 대한 실질적인 사례로 참고가 될 수 있습니다.

dhwiwnwnf님께서 제시하신 ItemService와 테스트 코드에 관하여, 서비스 계층에서의 비즈니스 로직 처리가 올바르게 반영되었으며, 실제 비즈니스 요구사항을 충족시키는지에 대한 평가는 이론적인 지식과 함께 실제 업무에 적용해보며 얻을 수 있는 경험에서 더욱 명확해질 수 있습니다. 제공된 링크를 통해 엔티티와 서비스 계층에서의 비즈니스 로직 처리 방법의 이해를 심화하시길 바랍니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

OrderServiceTest 상문주문 테스트 시 update 쿼리 문의

0

27

1

sdk 설정 오류

0

68

2

오탈자 - @Transactional

0

63

1

src/test/resources 테스트 경로 문제

0

60

1

상품 등록후 H2 db 출력 순서 바꿀 수 있나요?

0

70

1

MemberRepositoryTest 실행오류

0

90

1

boot 4.x >>> trasasction rolled back log & p6spy(영한님, 수업 자료 업데이트 해주시면 감사하겠습니다!!)

1

197

2

강의 마지막 QueryDSL 사용 부분 질문있습니다

1

154

2

클라이언트에서 isbn과 author 수정 요청을 한 경우에 대해 질문드립니다.

0

57

1

도메인 모델 패턴 vs 트랜잭션 스크립트 패턴

0

81

1

기본 생성자

0

67

1

h2 DB 연결시 jdbc url 변경 이유가 궁금합니다.

0

107

1

멤버서비스테스트 부분에서 막힙니다.

0

174

4

실무에서도 EntityManager를 이용해서 많이 작업하는 편일까요?

0

124

1

초반에 h2 다운로드 과정 꼭 필요한가요?

0

129

2

자신 필드에도 get으로 접근하는 이유가 있을까요?

0

122

1

24분 27초 연관관계 편의 메서드 위치

0

118

1

단건 주문만 가능하게 한건 의도한 부분이신가요?

0

114

2

빌드 툴, Gradle

0

65

1

h2연결은 된 것 같은데 엔티티 테이블까지 작성 후 확인해보아도 테이블이 안보입니다

0

82

2

Repository에서 EntityManager 주입 방식 차이

0

97

1

롬복과 사용자 정의 setter 메서드

0

78

1

주문 목록 조회 fetch join 질문드립니다

0

91

1

dirty checking 질문드립니다.

0

87

1