묻고 답해요
161만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
데이터 검증 로직 책임에 대한 질문이 있습니다.
안녕하세요. 정말 재밌게 수강중입니다. 다름이 아니라 데이터 검증 책임에 대해서 궁금한게 있습니다.저는 사용자에 의해 넘겨받은 데이터를 Controller 에서는 값의 존재여부와 타입 정도만 확인하고 실제로 비즈니스 레이어에서 사용될 때 검증하는 것을 선호하는데, 강의에서는 Request(DTO) 객체에서 toContent() 함수를 호출하면서 검증하더라구요.특별히 Request 에 위치시킨 이유가 있을까요?관점이 궁금합니다. fun toContent(): QuestionContent { if (title.isEmpty()) throw CoreException(ErrorType.INVALID_REQUEST) if (title.length > 100) throw CoreException(ErrorType.INVALID_REQUEST) if (content.isEmpty()) throw CoreException(ErrorType.INVALID_REQUEST) return QuestionContent(title = title, content = content,) } 해당 로직이 아래 방식으로 들어가는게 책임이 맞지 않을까? 라는 생각입니다. data class QuestionContent( val title: String, val content: String, ) { init { if (title.isEmpty()) throw CoreException(ErrorType.INVALID_REQUEST) if (title.length > 100) throw CoreException(ErrorType.INVALID_REQUEST) if (content.isEmpty()) throw CoreException(ErrorType.INVALID_REQUEST) } }
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
조회 시 개념간 격벽
안녕하세요.상품 상세조회 섹션을 보고 궁금한 점이 생겨 질문을 드립니다 !평소에는 개념간 격벽을 신경쓰지만 조회 시에는 지키기가 쉽지 않더라고요.특히 list 조회인데 다른 개념이 있어서 조회 + in query + 조립 등을 하면 너무 과한가..? 싶은 생각이 가끔 듭니다.제가 생각하는 방법과 트레이드 오프입니다.개념간 격벽을 유지하고, 쿼리를 분리아무래도 복잡해지는 구현DB 커넥션을 위한 오버헤드 증가팀원의 공감을 생각보다 얻기 힘듦(사실 저부터 확신이 없는...)조회의 경우 느슨한 규정화면 요구사항에 따라 변하는 쿼리재사용성 x주체가 모호함점점 쌓이는 비슷한 쿼리와 projection dto들거의 혼자 백엔드 개발을 진행하다보니 이런 고민에 대해 선택을 내리기 참 어렵네요 ㅎㅎ..제미니님은 어떤식으로 선택하시는지 궁금합니다 !감사합니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
cancel관련질문
안녕하세요.강의내용중 payment는 자기가 취소되어있는지 모르지만 대신 cancel은 payment를 사용한다고 말씀하시는데이게 어떤의미인지 잘 이해가 되지 않습니다.상태반영은 order쪽에 하는데 cancel이 payment를 사용한다?? 이게 어떤의미일까요??
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
따닥방지
안녕하세요. 저였으면 찜추가 찜삭제 API 를 나누는걸로도 방지할 수 있다고 생각해요.말씀해주신것처럼 컨트롤러에서 분기문 들어가는게 좀 어색한것같아서요! 이런 방식도 가능할까요? 뭔가 저는 Restful 관점에서도 이게 자연스러우니 이렇게 해결하실 것 같았는데 언급이 없으셔서 문제가 있을수도있나 싶어서 여쭈어봅니다!
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
enum 에 도메인 로직이 들어가도 될까요?
안녕하세요!현업에서 도메인(core) 모듈에 enum 들도 같이 두고, 타입 판단 로직 등 도메인 비즈니스 로직을 enum 클래스 내부에도 응집시켜 놓는 편인데요~ (bo 객체 클래스가 따로 존재하지 않거나 객체 클래스 보다는 enum 클래스에서 판단하는 것이 역할이 더 맞다고 생각되는 경우 ex enum 생성 static 메서드 등) 현재 예시 프로젝트의 구조에서는 core-enum이 core-api 의 도메인 로직 등을 의존하지 않고 완전 독립적으로 존재하기 때문에 enum class에는 비즈니스 로직이 존재하면 안된다는 것을 의도하신 것 같아 질문드립니다! enum 은 로직에서 아예 제외시키는 편이신가요? 그렇다면 이유가 궁금합니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
getOwnedCoupons 의 null 처리
coupon 데이터 처리시 !! 연산자 처리하는 부분에 질문이 있습니다. 논리적으로 현재 기획상으로는 null 일리 없음. -> !! 연산자를 사용이 상황으로 코드를 이해하긴 했어요. 하지만, 이러한 방식은 일종의 암묵지라서 버그가 발생할 여지가 있어보이는데요. 특히 쿠폰처럼 사람이 개입하는 경우에 어드민에서 상태를 변경하는 경우 기존의 전제가 성립하지 않을 때가 있잖아요. (쿠폰을 비활성화 한다거나)이런 경우 몇가지 선택지가 있을거 같아요. 1. 쿠폰은 임의로 비활성화하지(or 다른 상태도 불변) 않는다. 2. 쿠폰이 비활성화 되는 경우, 소유 쿠폰에서 제거 된다.이런 경우,, 기획에 따라 다르다라고 이해해야할까요? 저 같은 경우, 이미 발급된 소유 쿠폰 자체를 불변처리 하는쪽으로 얘기하는 편이 심플해보이긴 합니다만, 재민님 의견도 궁금합니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
찜목록 조회시 product 의 상태
찜 목록을 조회해야하는 상황에서, Product 의 상태가 전이되는 경우가 있을거 같은데요. 예를들어, 어떤 이유로 soft delete 되거나, 판매자가 숨김 처리를 하거나,, 이런 경우에는 물론,, 회사마다 정책이 다른거 같긴하더라구요. 예를들어, 들어가니 404 페이지가 뜨는 경우도 있고, 안보여주는 경우도 있구요. 이때 고민되는 부분이 찜 목록 (페이지네이션 한다는 가정) 을 조회할 때 아래의 문제들이 발생하는거 같은데, 혹시 어떻게 푸는게 좋을까요? 1. product 의 상태를 이벤트로 받아서, 찜 목록을 처리한다. -> 이 경우 찜이 많이 된 경우 (유명한 아이템이라 100만개의 찜이 있는) 처리가 애매해보이더라구요. 2. join 을 통해 풀어준다. -> 현재는 상품의 찜 목록이라, 사실 같은 팀내에 같은 서비스가 접근 가능해서 join 이 가능할거 같은데, 이게 찜이 아니라, 나의 리뷰보기 같은 경우 다른 팀에 있을 가능성이 있어서 join 을 통해 풀기 어려운 경우도 있을거 같다는 생각도 드네요.
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
Product, Category 테이블 설계 질문드립니다 !
Category와 Product의 관계를 N:N 으로 설계하신 것은 향후 확장성이나 관계 변경을 고려하신 것일까요?개인적으로는 처음에 1:1 또는 1:N 구조로 설계해 한쪽 테이블에 외래키를 두는 경우가 많았는데,비즈니스 요구사항이 변하면서 결국 N:N 관계로 바뀌어 중간 매핑 테이블을 추가한 경험이 여러 번 있었습니다.그래서 이번 강의를 보며,“어차피 관계가 바뀔 가능성이 있다면 처음부터 매핑 테이블로 시작하는 게 더 유연하지 않을까?”라는 생각이 들었습니다.다만 그렇게 되면 Status(상태) 같은 중복 데이터가 생기기도 해서이런 트레이드오프에 대해 재민님은 어떤 기준으로 판단하셨는지도 궁금합니다.좋은 강의 감사합니다 :>
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
security 인증은 어떤 모듈에 놔두는게 좋을까요?
예전에 유튜브영상에서는 인증서버를 GW를 두거나 Oauth 서버를 따로 두는 방식을 선호한다고 하셨는다.현재 서버 분리를 하지 않기에, GW 나 Oauth도 사용하지 않기에 security 를 현재 사용중입니다.1. web:security 모듈로 빼두었습니다. storage,domain 모듈이 web모듈을 알지못합니다. 강의 에서도 인증이 없기에 어떻게 구성하실지 궁금합니다security를 지양하시는거는 알지만 써야하는 상황이고 구성한다면 어디에 빼두시는지 궁금합니다2. security는 presentation layer 에 속한다고 판단을 했는데, 그럼 user의 role에 따라 조회시 비즈니스레이어를 건너뛰고 filter 에서 userid 만 사용해서 security context 를 생성하고 있는데,이거는 레이어간 건너뛰기가 되어서 레이어 규칙 위반인데 예외적 허용을 하는게 맞는지 잘모르겠습니다.깊이 있는 질문을 하고 싶었는데, 얇은 질문이지만 남겨봅니다!!
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
외부 API 연동 시 데이터 정합성을 고려해야 할 때..
안녕하세요.저도 개인 프로젝트로 이커머스를 만들면서, 결제와 같은 외부 API를 호출하는 부분에 대해서 많은 고민을 하게 되는 것 같습니다.가령, 결제 승인을 위해 PG API를 호출한 이후 결제 내역을 DB에 저장한다던가..혹은 결제 처리 이후 진행되어야 할 비즈니스 로직(배송 생성, 재고 차감 등..)을 진행해야한다던가..하지만 외부 API를 호출한다는 것은 사실 비즈니스 로직의 트랜잭션과 묶일 수 없다는 것이 참 어려운 것 같습니다.PG API 호출에 성공했지만, 이후 비즈니스 로직이 실패된다면 결제 강의 - 코드느끼기에서 말씀해주신 것 처럼,사용자의 돈은 빠져나갔지만, 배송 처리가 되지 않거나 그런 일이 발생할 수 있을 것 같아요.혹은 PG API 호출 시에, 타임 아웃이 발생해서 실패했다고 판단했지만, 알고보니 PG 서버 상으로는 승인이 정상적으로 처리 된 경우도 있을 것 같아요.이처럼 외부 API 연동 시에 데이터 정합성을 고려하는 것이 엄청 어려운 것 같습니다. 그래서 저는 결제처럼 사용자의 돈을 처리해야하는 경우 세부적인 방어 로직이 필요할 것 같다는 생각을 합니다.그래서 고민을 하면서, 이것저것 찾아보다가 사용하게 된 패턴이 외부 API를 요청하기 전에, state를 추가해서 관리하자 라는 것이었는데요. 예를 들어 결제로직의 경우 결제 검증을 처리하고 승인 API를 호출하기 전에 Payment의 State를 PENDING_PG_REQUEST(예시)로 변경한 뒤, PG API를 호출하는 흐름입니다. 만약 PG API 호출에 정상적으로 성공했지만, 결제 후처리 비즈니스 로직에 실패했더라도,스케줄러 같은 걸 통해 특정 시간 동안 계속해서 PENDING_PG_REQUEST인 결제 건이 있다면, 이것은 적어도 PG API를 호출하고 나서, 무언가 잘못되었다는 것이니까, 데이터 정합성을 맞춰주기 위해 한번 더 직접 API를 호출하고 나서 비즈니스 로직을 추가적으로 실행시켜주는 그런 작업을 진행해주면 될 것 같아요.이런 패턴이 어떻게 보면 강의 코드 예제에서 정산을 처리하는 SettlementService의 transfer 메서드와 비슷하다고 생각합니다. Settlement Entity에 Ready인 데이터를 결국 주기적으로 처리하면서, 언젠가는 정산 처리를 진행하게 되니까요!근데 문득 제가 사용하는 방식, 그리고 transfer 메서드의 방식은 특정 조건이 충족해야한다는 점이 있는 것 같아요. 사용하는 외부 API가 멱등성을 제공해야하고, 데이터 정합성을 처리하기 위해 돌아가는 스케줄러,배치 또한 자체적으로 중복처리 방지를 방지해야 한다는 것을요...이렇게 생각하다보니 끝도 없이 딥해지고 복잡해지는 것 같아서, 문득 다시 결제 부분 강의를 보다보니,수기 처리 방식도 아주 잠깐 언급하셨더라구요. 문제가 발생했을 때 로그를 남겨놔서, 데이터를 비교 후 데이터 정합성을 맞춘다. 근데 돈과 관련된 부분은 그 즉시, 성공 실패에 대한 처리를 해줘야할 것 같기도 하고 이 부분만큼은 과하게 방어 로직을 작성하는 게 맞을까?라는 생각이 들게 되는 것 같아요. 그리고 만약 외부 API가 멱등성을 제공하지 않으면어떻게 처리해야하지?라는 생각이 들기도 하고요.재민님께서는, 이런 외부 API 연동과 데이터 정합성을 고려해야할 때 방어 로직을 깊게 생각하시는지 궁금해서 질문을 하게 되었습니다. 근데 사실 돈과 관련된 부분은 아무리 생각해도 많은 방어 로직을 필요로 하는 것은 당연한 것 같긴한데, 어느 정도로 처리를 해줘야할 지 모르겠네요. 하하..최소한의 방어로직, 그리고 예외, 실패 시 로깅 처리로 모든 가능성을 추적해야 하는 게 효율적일까요??감사합니다!
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
상품 상세 컨트롤러 내 서비스 호출 질문
강의에서 상품 상세 컨트롤러에서 여러 개의 서비스를 직접 참조해 하나의 응답으로 반환하고 있는데요이 경우, 단일 서비스에서 데이터를 묶어 응답하지 않고 각 서비스를 개별적으로 호출하는 이유가 궁금합니다.이런 구조가 모듈을 분리했을 때 Aggregation 성격의 서비스가 여러 서비스에 의존하게 되는 문제를 피하기 위한 설계인가요?또, 여러 서비스를 호출하면 하나의 API 요청 내에서 여러 트랜잭션 커넥션이 열릴 수 있는데, 이를 설계 상 트레이드오프로 봐야 할까요?추가로, 강의에서는 productId 하나만 받아서 여러 서비스를 독립적으로 호출하고 있는 것 같았는데,서비스 간 호출 순서가 없으므로 각각을 독립적인 유즈케이스로 보는 게 맞을까요?아니면 컨트롤러가 여러 서비스를 조합하는 역할을 가져도 되는 걸까요?마지막으로, 저는 조회 시 실무에서는 모듈별 유즈케이스가 각각 존재하고, 이를 묶어주는 별도의 서비스가 로직과 조합을 포함하여 담당하고 있습니다.예를 들어 상품 조회 API 응답 시 상품내용과 함께 회원 이름/생년월일 등등 포함, 쿠폰 정보 포함 요구사항이 주어졌을 때두 가지 방식으로 구현할 수 있을 것 같은데요어떻게 바라보시는지 궁금합니다.# 방법1 # 특정 서비스에서 조합하여 호출 상품 API 모듈(컨트롤러) → 상품 Service 모듈 → 회원 모듈 서비스1, 쿠폰 모듈 서비스2, ...# 방법2 # 각 서비스를 컨트롤러에서 호출 상품 API 모듈(컨트롤러) → 회원 모듈 서비스1, 쿠폰 모듈 서비스2강의에서는 방법2 와 비슷하게 처리하신 것 같습니다.강의 중 여러가지 패턴을 소개해 주신다고 했지만 급하게 질문드리는 점 죄송합니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
날짜 수정
안녕하세요! 날짜 수정 관련해서minusDays를 변경하는게 어째서 불편한건가요?안에 들어가는 파라미터만 바꿔주면 되는데 불편해지는 부분이라는게 잘 이해가 안되네요
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
OrderService에서 조회에 트랜잭션 걸어준 이유가 있을까요?
올려주신 다른 주요 개념들에서 조회에는 트랜잭션이 별도로 걸려있지 않았었는데, Order 쪽은 getOrders 와 getOrder 모두 트랜잭션이 걸려있더라구요! 혹시 이쪽에만 특별히 트랜잭션을 걸어주신 이유가 있나요? 감사합니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
findSections질문
안녕하세요!findSections의 return부분을 떼어다가 ProductSectionSevice에 옮기는 부분이 있는데옮기기 전과 후의 차이가 어떤 차이가 있는건지 알 수 있을까요? 저의 실력이 부족해 잘 이해가 되지 않아 질문드립니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
CouponService에서 이미 다운로드 한 쿠폰 안 내려주기
안녕하세요! 수업 중에 재민 님이 말씀해주신 이미 다운로드 한 쿠폰은 내려주지 않는 것과 관련해서 질문이 있습니다.제 나름대로 생각해 본 코드는 이렇습니다.fun getCouponsForProducts(productIds: Collection<Long>): List<Coupon> { val productTargets = couponTargetRepository.findByTargetTypeAndTargetIdInAndStatus( CouponTargetType.PRODUCT, productIds, EntityStatus.ACTIVE, ) val categoryTargets = couponTargetRepository.findByTargetTypeAndTargetIdInAndStatus( CouponTargetType.PRODUCT_CATEGORY, productCategoryRepository.findByProductIdInAndStatus(productIds, EntityStatus.ACTIVE).map { it.categoryId }, EntityStatus.ACTIVE, ) val applicableCouponIds = (productTargets + categoryTargets).map { it.id }.toSet() val downloadedCouponIds = ownedCouponRepository.findByUserIdAndState(userId, OwnedCouponState.USED) # userId 어디서 받아오지? .map { it.couponId } .toSet() val finalCouponIds = applicableCouponIds - downloadedCouponIds if (finalCouponIds.isEmpty()) { return emptyList() } return couponRepository.findByIdInAndStatus(finalCouponIds, EntityStatus.ACTIVE) .map { Coupon( id = it.id, name = it.name, type = it.type, discount = it.discount, expiredAt = it.expiredAt, ) } }여기서 고민됐던 부분은 findByUserIdAndState 에서 userId 를 어디서, 어떻게 받는 것이 좋을지 입니다. getCouponsForProducts 함수가 호출되는 ProductController의 findProduct 메서드에서는 별도의 User 관련된 정보를 받아오지 않기 때문에 userId 를 받아올 수 없는 상황인 것 같습니다. 그런데 유저가 자신이 이미 다운로드 한 쿠폰을 중복해서 '다운로드 가능 쿠폰' 목록에서 보이지 않게 하는 소위 '개인 맞춤' 작업은 User가 꼭 필요한 정보라고 생각 되는데요.이런 경우에 findProduct에 CouponController에서 처럼 User를 바로 넘겨주면 간단(?)하게 userId를 알 수는 있지만 이게 최선인 것 같진 않습니다. User를 파라미터로 넘겨주는 것을 인증 절차를 거친다고 생각해본다면 상품 상세 정보 보는 것은 꼭 인증을 하지 않더라도 볼 수 있어야 할테니까요. (그런데 User를 파라미터로 넘겨주는 것이 인증이 된 사용자만 이 API를 사용할 수 있다고 이해하는 것이 옳은 이해인지는 제가 잘 모르겠습니다🥹)그래서 또 다른 접근법으로는 재민 님이 ProductController의 findProduct 메서드에서 쿠폰을 불러오는 부분 위에 주석으로 처리해놓으신 것처럼 별도의 API를 만들고 해당 API에서 User를 활용해서 진행하면 어떨까 하는 생각도 해봤습니다. 재민 님은 어떤 식으로 푸실지 궁금합니다! 감사합니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
프로덕트와 카테고리에 대한 질문
안녕하세요!강의 중 잘 이해가 안되는 부분이 있어 질문드립니다.카테고리에 상품이 있는 방향으로 설명을 진행하다가 실제 구현에선 프로덕트의 카테고리이다 라고 정의를 하셨다고 말씀해주셨는데설명과 실제 구현이 다른 이유가 있을까요?
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
강의를 보고 궁금한 것 질문 드립니다!
안녕하세요 🙂 지난번에 이어 질문을 또 남기게 되었습니다 ㅎㅎ 1. Point 라는 개념을 다룰 때 PointService에서 로직을 처리하지 않고 별도의 PointHandler라는 객체를 만들어서 처리하는게 Point 개념 자체가 다른 개념에서도 많이 사용하는 개념이다보니 PointService에서 처리하게 되면 Service 간 참조가 생기는 것을 방지(?) 하고자 이런 전략으로 처리한 것일까요? 이런 식으로 격벽을 넘어서 여러 개념에 걸쳐 있는 개념을 다룰 때는 별도로 분리해놓는 것이 재사용성, 응집 측면에서 좋은 전략인지 궁금합니다! 2. 지금 Point 변화를 주는 것을 PointBalanceEntity 에서 처리하고 있는데 만약 추후에 복잡한 포인트 적립 정책이 생긴다면 별도의 PointPolicy 를 Object 클래스로 만들어 해당 클래스에 포인트 적립 관련 로직을 응집 시키는 식으로 PointPolicy 라는 개념을 추가하는 건 어떻게 생각하시는지 궁금합니다! 감사합니다😀
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
금액 계산은 서버에서하고 클라이언트는 가격 정보를 주지 않았을 때
안녕하세요! 금액 계산은 클라이언트 조작 문제 떄문에 서버에서 담당해야한다고 말씀해주셨는데요, 그렇다면 클라이언트에서는 식별값만을 주고 가격정보는 주지 않았을 때 문제는 없을까요? 예를 들어 클라이언트가 한 화면에서 오래 머무르는 동안 상품 가격이나, 할인 등 총 결제 금액을 계산하는데 있어 변동 사항이 생겼을 때 클라이언트가 보고 있는 가격과 서버에서 요청 시점에서 계산한 가격이 일치하는지까지 봐야하지 않나라는 생각이 들어 질문드립니다..! 서버에서 현재 상태를 기준으로 가격을 계산하고 처리했을 때, 사용자 입장에선 자신이 본 가격과 다른 가격으로 계산될 수도 있지 않을까요??가격을 결정짓는 요소들이 변경되었는지를 서버에서 판단해서 요청 실패처리를 할 수 있겠지만, 요소들이 많다면 각각을 버저닝하고 확인해야 하는 형태가 될 거 같기도 해서.. 클라이언트에서 확인한 가격 정보를 서버에 넘기고, 서버에서 실시간으로 계산한 금액과 일치한다면 성공시키는 구현 형태는 실무에서 잘 쓰지 않는 것인지 궁금합니다!
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
어떤 경우 도메인(개념)객체를, 어떤 경우 JPA 엔티티를 활용하나요?
서비스들을 보면 어떤 경우는 finder같은 서비스 하위 계층을 통해 도메인(개념)객체를 활용하기도 하고, 서비스에서 직접 repository를 의존해서 jpa entity를 활용해서 로직을 수행하는 케이스도 있어 보입니다! 혹시 서비스 단에서 도메인 객체를 가져와서 사용하는 것과 jpa entity를 직접 활용하는 것의 판단 기준이 따로 있으실까요?
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
목록 조회에서 개념(도메인)객체를 반환할 때
현재 코드상으로 목록조회에서도 개념객체를 활용하는 것으로 확인했습니다! 하지만 한 개념 객체가 여러 개념 객체를 포함하는 경우가 있는 상태에서 페이지네이션 같이 모든 개념객체의 필드를 채워줄 필요가 없는 경우도 있을 거 같습니다. 이때, 필요한 컬럼만 추출한 데이터를 담는 별도 dto용 객체를 만든다개념 객체의 일부를 채운 값을 Page에 반환한다 실무에선 둘 중 어느 방식을 적용하는지 궁금합니다! 제 생각에는 개념(도메인) 객체는 항상 완전한 상태로 있어야 하므로 별도 프로젝션 dto용 객체를 만들어서 서비스단에서는 도메인 객체가 아닌 해당 dto 객체를 내려주는 것이 낫지 않을까 생각합니다. 또한 사용하지 않는 필드를 완전한 객체 상태로 만들어주기위해 불필요하게 많은 추가 쿼리가 발생할 수 있어서 이런 경우는 별도 값(dto)객체를 쓰는 게 나을 거 같은데 실무에서는 어떻게 하는지 궁금합니다!