소개
안녕하세요 ☺️
몰입을 즐기는 개발자, 박우빈입니다.
- (현) 캐치테이블(와드) 소프트웨어 엔지니어
- (전) 우아한형제들 소프트웨어 엔지니어
- 우아한테크코스 3기, 4기 리뷰어 / 우아한테크캠프pro 1기 리뷰어
강의
전체1수강평
- 감사히 잘 들었습니다.
김민종
2024.04.25
0
게시글
질문&답변
2024.04.22
강사님 유효성 검증의 분리에 대해 궁금한점이 있습니다.
안녕하세요, 두잇베스트 님! 패스워드를 예시로 들어주셨는데, 패스워드 같은 경우는 도메인에 따라, 바라보는 시각에 따라 어디서 검증할지가 달라질 수 있는 예시일 것 같아요 ㅎㅎ 해당 API가 담당하는 도메인 로직에서 패스워드 검증 룰 자체가 중요한 역할을 차지하고 있다면 도메인 쪽에서, 그렇지 않다면 '영문/특문 혼합 8자리' 라는 룰은 앞단에서 검증하고 끝내도 된다고 생각합니다. 이럴때는 앞단에서 검증하고, 저럴때는 뒷단에서 검증해라, 와 같이 답이 정해져 있는 문제는 아니어서 상황에 따라 어느 쪽에서 검증하는 게 좋을지 판단하시면 됩니다. 강의 중 의도는 '아무리 단순한 검증 로직이어도, 중요한 도메인적 의미를 담고 있다면 도메인 레이어에서 검증하면서 그 규칙을 지속적으로 관리할 필요가 있다'는 것이었어요. 도움이 되셨기를 바랍니다. 감사합니다. 🙂
- 0
- 2
- 71
질문&답변
2024.04.13
환경별 DB 분리 질문있습니다.
안녕하세요, fonercis 님! 네, 맞습니다. 테스트 profile을 따로 나누었으니, 설정 yml도 별도로 관리하시면 됩니다. 감사합니다. 🙂
- 0
- 2
- 85
질문&답변
2024.04.06
이 강의 주제를 듣다가.. 외부 시스템
안녕하세요, 두잇베스트 님! 네 저도 test용 key/secret을 넣어서 테스트 환경을 실행하고 있습니다. ㅎㅎ 감사합니다. 🙂
- 0
- 2
- 128
질문&답변
2024.03.31
테스트 질문 드립니다
안녕하세요, answntjd1006 님! 와우 질문이 정말 많네요~! 하나씩 답변 드려보겠습니다. 1 서비스에서 체크후 예외를 던지는것과 stock에서 체크후 예외를 던지는 것은 다르다라는것이 잘 이해갸 되지 않습니다 강의 내용을 보아도 잘 이해가 되지 않아 굳이 이렇게 나눠야하는지에 대해 다시한번 설명 부탁드립니다 ㅜㅜ 또한 저는 stock 객체 자체에 판단할 수있는게 좋지 않나? 즉 stock의 책임이지 않을까?란 생각을 통해 service에서 stock 객체가 할일을 가지고 가면 응집도 면에서 좋지 않다라는 생각을 가지고 있는데요 이에 대해 어떻게 생각하시나요? 맞습니다. 일단 서비스에서 체크한 예외와 Stock에서 체크하는 예외 중 중요도가 높은 것은 당연 Stock입니다. Stock의 재고 차감 로직은, OrderService 뿐만 아니라 다른 곳에서도 얼마든지 사용될 수 있기 때문에, Stock이 자기 자신을 보호하기 위해서 필수적으로 가져야 하는 validation 로직이라고 보시면 됩니다. 그럼 'OrderService에 예외를 미리 체크하지 않고, Stock에서 발행하는 예외를 사용해서 도메인 로직을 풀어내도 되었을텐데 왜 별도로 체크했는가?' 라는 의문에 대해서는, 강의 중에도 말씀드린 것처럼 클라이언트에 주고 싶은 메시지가 달라서이기 때문입니다. Stock 입장에서 예외를 터뜨리는 상황은, 외부에서 어떤 로직을 전개하다가 재고 차감 로직을 호출했는지 Stock은 알 수 없기 때문에 범용적인 메시지로 예외를 발생시키지만, OrderService에서 주문을 생성하다가 재고를 차감하게 되는 상황은 명확히 어떤 맥락에서 재고 차감 관련 예외가 발생했는지 알고 있기 때문에, 그에 맞는 클라이언트향 메시지를 담아 예외를 발생시키고 싶을 수 있습니다. 다른 방법도 생각해볼 수 있는데요. OutOfStockException 같은 custom 예외를 정의해서 Stock 내에서 발생시키고, 외부에서 이를 try-catch로 잡아 다시 원하는 예외 메시지를 담아 전파하는 방식을 적용해볼 수도 있습니다. 2 테스트를 위한 코드 강의 내용 중 OrderCreateRequest와 관련되어 테스트를 위한 생성자가 생성되었다고 생각을 하는데요 테스트를 위한 코드에 대해 어떻게 생각하시는지 궁금합니다 저는 테스트를 위한 코드를 생성하면 안된다라고 생각하는데요 이유는 테스트를 위한 것으로 만들어 놨지만 다른곳에서 사용하게 되는 같은 현상이 발생될 수 있다라고 생각기때문입니다. 저도 강의 중에 다루는 내용인데, 테스트 코드만을 위한 프로덕션 코드를 생성하는 것을 지양하자고 이야기 했습니다. 다만, 객체를 생성하는 생성자, builder 등의 경우 테스트 코드를 용이하게 작성하기 위한, 일종의 편의성을 위한 trade-off 라고 생각해주시면 좋을 것 같아요. 3 어떤걸 어디서부터 어디까지 테스트해야되나?라는 의문입니다. OrderService를 구현하면서 Order와 관련된 테스트(Order.create()등등)를 진행하였고 또한 주문을 통해 생성된 OrderResponse에 대한 테스트를 진행하는 것을 보았습니다. ... 만약에 위와 같은 컬럼이 끝이아니라 아래와 같이 수많은 컬럼이 있다면 이 모든것들을 다 테스트 해주어야 하는걸까요? 제 의문은 어떤것은 테스트하고 어떤것은 테스트 하지 말아야하나? 모든것들 전부 테스트 해야하나? 어디서부터 어디까지 테스트를 해야되지라는 정답이 없는 고민이 있어 강사님의 의견을 여쭙고자 질문을 드려봅니다 어떠한 한가지만을 테스트할때는 강사님이 말씀해주신것처럼 경계값이든 무엇이든 기준을 가지고 테스트를 진행하면 될텐데 OrderResponse나 그런것들 즉 어떤것에 의해 생성된것에 대해 테스트를 해야할때 어디서부터 어디까지 테스트를 해야하는지 잘모르겠습니다. 혹시 가능하시다면 어떤기준을 가지고 어떤것에 대해 테스트를 하시는지 어디서부터 어디까지 테스트를 해야하는지에 대한 생각을 가지고 있으시다면 말씀부탁드립니다 좋은 질문이네요. 말씀하신대로 모든 필드를 테스트하는 것은 (물론 그러면 좋겠지만) 리소스 상 어려울 때가 많습니다. 그래도 최대한 많은 필드, 많은 범위를 검증하는 것이 좋고, 중요도가 높은 필드들을 중심으로 검증하는 것이 소프트웨어의 신뢰도를 높일 수 있는 방향입니다. 4 OrderService에 대한 테스트를 어디서부터 어디까지 어느정도 테스트해야하나입니다 지금은 아래와 같은 것들을 테스트 해주고 있는데요 ... 만약 Order Service에 대한 로직이 복잡해지고 결제나 뭐 등등 이런것들이 증가가 된다면 그런부분들도 모두 test에서 검증을 해줘야하는걸까요? 만약 모두 그런부분들을 검증해준다고하면 구현부분이 조금 바뀐다고해도 테스트가 쉽게 깨질 수 있다라고 생각하는데요 그래서 생성이라면 생성과 관련된 테스트만 잘 테스트를 해야하는것인가 아니면 내부 구현에 대한 테스트도 진행을 해야하는것인가에 대한 의문이 있는데 강사님은 어떻게 생각하시나 궁금하여 질문을 드려봅니 그럴 때 필요한 것이 책임의 분리입니다. 조금의 요구사항이 변경되어도 테스트가 민감하게 반응하여 쉽게 깨지거나, 덩달아 변경 사항이 잦다면, 하나의 객체가 가지고 있는 책임이 너무 많지 않은지 고민해볼 필요가 있습니다. 만약 그렇다면, 적절한 책임에 따라 객체를 나눌 수 있고, 그에 맞게 각각 테스트를 진행할 수 있습니다. :) 5 앞에서 한 테스트를 뒤에서도 검증 해야하나? 라는 의문입니다 stock에 대한 단위테스트를 진행하면서 감소 메서드에 대한 테스트도 진행하였습니다. 그런데 OrderService에서 아래와 같은 코드로 검증을 해주는데요 항상 의문이었던 것은 다른 곳에서 테스트를 통해 검증이 끝난것도 다시 테스트를 해줘야하나라는 의문입니다. 이 코드 말고도 이와 비슷한 현상이 발생할 수 있을거 같은데요 다른 코드에서 검증을 진행해주는 코드를 앞 layer에서나 다른곳에서 쓸떄 또 검증을 해줘야하나라는 의문이 있습니다. 이 부분은 어느정도 비용이 있기 때문에 선택사항입니다만, 저는 그래도 권장을 하고 있습니다. 강의 중 이야기했던, A 모듈과 B 모듈이 결합하여 동작할 때, 우리가 기대한대로 동작하지 않을 확률도 존재합니다. 이런 상황을 모두 커버하기 위해서 상위 레이어에서도 비슷한 케이스를 검증한다고 이해하시면 됩니다. 지금은 예시 프로젝트라 프로덕트 자체가 복잡하지 않아서 충분히 가질 수 있는 고민이라고 생각하는데요, 복잡한 실무 케이스에서는 오히려 상위 레이어로 갈수록 엮여 있는 책임들이 많아서 통합적으로 테스트하는 것이 필요한 경우가 많습니다. 6 메일에관한 테스트는 하지않는걸까요? 서비스테스트 중에 외부에 관한 즉 메일링 관련된 것은 목킹한것을 보았습니다. 그러면 메일에 관한 것은 단위테스트를 통해서 하는 것인지 아니면 그냥 잘동작하는것이라고 가정하고해야 하는걸까요? (그것을 테스트할 수 없기 때문에?) 자동화된 테스트 코드로 메일 전송 테스트를 할 수 있겠지만, 그러면 테스트 코드를 수행할 때마다 메일이 어딘가로 전송되어야만 합니다. 테스트 메일 계정을 만들어서 계속 거기다 메일을 전송하는 방법도 있지만, 메일 전송 비용이나, 이를 확인하는 비용도 발생하게 되는데요. 2가지 정도의 방법을 생각해볼 수 있습니다. 메일 전송 테스트 코드를 만들어 놓고, 필요한 경우 수행해서 메일이 잘 전송되는지 확인한다. 사용하지 않을 때에는 @Disabled 처리를 하여 테스트 코드가 무시되도록 처리한다. 메일 전송은 테스트 코드가 아니라, 개발자 검증 단계 / QA 단계 / 사용자 테스트 단계에서 사람이 수동으로 테스트한다. 7 밸리드는 모두 테스트? 프레젠테이션 레이어 즉 컨트롤러 테스트 중 밸리드에 관련된 부분은 보통 모두 테스트 하시는편인가요 아니면 정말 필요하다고 생각되시는 부분만 하시는지 궁금합니다. 모두 하면 모두 검증을하는거니 당연히좋겠지만 이것도 모두 비용이라 생각하는데 이런것들도 모두해야되나?라는 의문이 들어 질문드립니다 테스트 코드를 보셔서 아시겠지만, 조금 귀찮을 뿐이지 난이도가 높은 테스트 코드는 아니어서, 저는 꼼꼼하게 모든 필드를 검증하는 편입니다. 외부에서 들어오는 값이니 만큼 꼼꼼하지 않으면, 검증하지 않은 단 하나의 필드에서 문제가 생길 수도 있는 법이니까요. 도움이 되셨으면 좋겠네요. 감사합니다. 🙂
- 1
- 2
- 163
질문&답변
2024.03.31
Order.class 에대하여
안녕하세요, junjun 님! 하나씩 답변 드리겠습니다. 1. Order 클래스는 @Entity 어노테이션이 붙어있는 도메인 객체인데 여기에 어떤 로직? 이라고 해야 하나요? List 를 바로 넣어주는 것이 아니고 List 를 받아서 값을 뽑아서 new OrderProduct 로 생성하거나, calculateTotalPrice() 같은 메서드를 작성해도 괜찮은가요? (현업에서도 많이 쓰이는 방법인가요? 뭔가 따로 service로 빼도 괜찮지 않을까 라는 생각이 들었습니다. ) OrderProduct는 사실 Order와 Product의 다대다 관계로 인해 만들어진 중간 테이블 엔티티입니다. 외부에서는 Product를 가지고 Order를 만들려고 하는데, 굳이 OrderProduct라는 객체(관계)를 알 필요가 없습니다. 말씀하신 가공 로직이나, calculateTotalPrice() 같이 도메인 내부에서 가지고 있는 정보들을 이용하여 도메인 fit하게 제공하는 로직을 '도메인 로직'이라고 한다면, 도메인 객체가 마땅히 가져야 할 도메인 로직이 외부로 분리되어 있는 것이 더 어색하지 않을까요? ㅎㅎ 위와 같은 로직이 Service로 분리된다면, 응집도가 낮아지는 것을 경험하게 됩니다. Service에서는 데이터 가공을 위해 Order가 캡슐화한 많은 정보들이 필요할텐데, 그때마다 getter로 데이터를 취득해서 가공을 하게 되겠죠. 결과적으로 복잡한 로직이 늘어나고, 필요없는 getter가 더 생긴다던가 하는 불필요한 행위가 생길 수 있습니다. 하나여야 마땅한 개념이 두 군데로 나뉘어졌기 때문이죠. 물론 Order가 워낙 중요한 객체고, 프로젝트가 발전함에 따라 가지고 있는 책임이 점점 많아져서 관리가 힘들어진다면, 그 때에는 말씀하신 것처럼 세부적인 책임에 따라 객체를 분리하는 시도를 해볼 수 있습니다. ㅎㅎ 다만, 그때에도 도메인 객체가 여러 책임에 따라 조금 더 세분화되는 것이지, 도메인 객체가 그에 맞는 도메인 로직을 가져야 한다는 방침에는 변함이 없습니다. 2. 전에 간단한 토이 프로젝트를 할 때 cascade = CascadeType.ALL 가 아닌 cascade = CascadeType.REMOVE 로 설정하고 Order을 생성한 후 OrderProduct를 수동으로 생성했었는데 CascadeType.ALL 이 더 범용적으로 많이 쓰는 방법인지 말씀하신대로 설계 의도에 따라 필요한 만큼의 범위만 cascade 설정을 거는 것이 권장하는 방식이긴 합니다. 보통 저 같은 경우 실무에서는 cascade 설정을 사용한다는 것 자체가 두 엔티티가 긴밀한 관계인 경우가 많아서, 매번 하나씩 따지기 보다는 편하게 ALL로 적용하고 관련 CRUD 상황에서 주의해서 관리하는 편입니다. 정답이 있는 것은 아닙니다. ㅎㅎ 감사합니다. 🙂
- 0
- 2
- 93