-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[2단계 - 주문 기능 구현] 우르(김현우) 미션 제출합니다. #83
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 우르, 춘식입니다!
레벨2 마지막 미션 잘 부탁드립니다. 🙂
코드를 깨끗하게 잘 짜놔서 스무스하게 읽었네요ㅎㅎ 👍
질문에 대한 답과 코멘트들 남겼으니 확인 부탁드립니다.
궁금하거나 이해가 안 되는 부분은 편하게 DM 주세요.
) { | ||
if (deleteCartItemIds.size() > savedCartItemIds.size()) { | ||
throw new CanNotRemoveCartItemsMoreThanSavedCartItems | ||
("삭제할 카트 물품의 개수가 현재 저장된 카트 물품의 개수보다 많을 수는 없습니다."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트할 때 에러 메세지도 확인한다면 유지보수가 조금 귀찮을 것 같습니다. enum으로 에러메세지를 관리하거나 예외 클래스 내에서 상수로 만드는 방법을 써보는 건 어떨까요?
|
||
@Service | ||
@Transactional(readOnly = true) | ||
public class CouponQueryService { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
도메인 단위로 파일을 분리한 것 같은데 이유가 있을까요? 어떤 장점을 얻게 되었는지 궁금하네요 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
service, controller, dao 로 패키지를 나누게 되면 OrderService, OrderItemService, CouponService 등 하나의 패키지 안에 다 있는 것이 개인적으로 코드를 수정할 때 찾기가 더 어렵더라구요.
그래서 도메인 별로 파일을 나누게 되면 어느 도메인에서 수정해야하니까 그 도메인 패키지에 들어가면 되겠지라는게 더 파악이 빨랐습니다!!
그래서 도메인 단위로 파일을 분리하게 됐습니다.
private CouponMapper() { | ||
} | ||
|
||
public static CouponResponse mapToCouponResponse(final Coupon coupon) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
response dto에서 정적 팩토리 메서드를 쓰는 방법도 있었을 텐데 mapper 클래스를 따로 만든 이유가 있을까요? 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 생각한 DTO는 데이터를 운반시켜주는 객체이기 때문에 안에 변환 책임을 가지는건 조금 어긋나지 않을까라는 조심스런 생각을 했습니다.
그리고 mapping 시키는 것 또한 비즈니스 로직이라고 일부라고 생각했습니다.
하지만 서비스 안에서 변환 로직이 있다면 비즈니스 로직에 집중시키기 어려워서 따로 mapper 유틸리티 클래스를 만들었습니다.
@Repository | ||
public class CouponDao { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Repository와 Dao의 차이는 무엇일까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
크루원들한테 얘기도 많이 들었었지만, 제 나름대로 의견을 말씀드리자면 Repository 와 DAO는 A, B로 나눌 수 없다는 생각이 듭니다. 다만 나누자면 Repository는 도메인 레이어에 속하는 객체들에게 컬렉션 인터페이스를 제공하기 위한 용도라고 생각합니다.
물론 두 단어가 아예 같다고 할 순 없지만 서로 비슷한 성격을 가졌다고 생각해요.
저는 이러한 개념들에 대해서 학습할 때는 둘의 차이점, 즉, A와 B로 나눈다기 보다는 왜 이렇게 나눠졌는지 유래를 공부하는 편이에요.
Repository 와 DAO가 나오게 된 이유는 옛날 EJB가 나왔을 때, Entity Bean과 Session Bean으로 나눠졌엇는데, Session Bean이 폭 넓게 사용되었습니다.
점점 Entity Bean은 점점 더 퇴보해가고, Session Bean 내부로 Entity Bean, 즉, persistence 로직이 침투하기 시작하여 이러한 책임을 나누기 위해 DAO가 생겼습니다.
여기서 이제 DDD(저는 잘 모릅니다,,)로부터 객체 컬렉션에 대한 처리를 위한 인터페이스인 Repository 가 생기게 되었고, DAO는 Repository보다 더 세부적인 연산을 제공하는 것으로 알고 있습니다.
결국 둘을 A, B 로 나누기보다는 DAO와 Repository는 퍼시스턴스 로직에 대한 책임을 나누기 위해 생성되었다고 생각합니다,!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오 DDD 겉핥기도 하셨군요ㅋㅋㅋ 잘 알아보고 오셨네요 굿굿 👍
private void errorLogging(final Exception exception) { | ||
log.error("error stack = ", exception); | ||
} | ||
|
||
private void infoLogging(Exception exception) { | ||
log.info( | ||
"클래스 이름 = {} 메시지 = {}", | ||
exception.getClass().getSimpleName(), | ||
exception.getMessage() | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
로깅 레벨에 따라 다르게 출력되도록 했네요 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
감사합니다 춘식 !!!
error 레벨에서 info 와 같은 메시지만 던지면 예외 확인이 어려운 점이 있었어서, error 레벨은 아예 에러 스택을 출력하도록 했습니다
private final JdbcTemplate jdbcTemplate; | ||
|
||
private final SimpleJdbcInsert simpleJdbcInsert; | ||
|
||
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; | ||
|
||
private final OrderDao orderDao; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
보통 필드 변수는 접근제어자를 기준으로 개행을 합니다. 이 경우엔 전부 붙여놓아도 상관이 없을 것 같아요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오,, 접근제어자를 기준으로 개행을 하는군요!!
바로 수정하도록 하겠습니다~~
|
||
public static final Money ZERO = new Money(0); | ||
|
||
private final BigDecimal value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BigDecimal 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
감사합니다 춘식 !!
@@ -0,0 +1,8 @@ | |||
spring: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
application.properties에서 yml로 바꾼 이유가 있을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
properties 는 중복된 패키지들을 계속해서 작성해줘야하지만 yml 은 중복을 처리할 수 있어서 더 간편하게 사용할 수 있습니다 !!
@@ -0,0 +1,39 @@ | |||
### 주문 생성(쿠폰 O) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
http도 꼼꼼하게 만들어주셨네요 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여담으로, 인텔리제이 얼티밋 버전을 쓰고 있다면 엔드포인트라는 도구를 통해 http를 제공해주고 있습니다ㅎㅎ 학생 계정이라면 얼티밋을 사용해볼 수 있으니 참고 바랍니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -0,0 +1,3 @@ | |||
### 사용자의 쿠폰 목록 조회 | |||
GET http://localhost:8080/coupons |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이번에 처음으로 클라이언트단과 협업을 해보셨을 텐데 어떠셨나요? 논의를 하면서 달라진 점이 있다던가, 어려웠거나 느낀 바가 있다면 같이 공유를 해봐도 좋을 것 같습니다ㅎㅎ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 프론트와 협업한 경험이 처음이 아니어서, 이전 프로젝트를 진행하고 나서 느낀점이 최대한 프론트 분들의 편의를 보장해야겠다라는 생각이 들었어요. 백엔드 쪽에서 전달하는 데이터를 최대한 그대로 화면에 렌더링 할 수 있게 말이죠. 또한, 개발 초기 단계에서는 대부분 화면 디자인이나 와이어 프레임을 설정하는게 백엔드 로직보다 오래 걸려서 그 부분들을 개발하는 동안에 최대한 API 개발을 해서 프론트분들이 테스트 용이하게 배포하는 것도 중요하다고 생각했습니다.
하지만 이번에는 협업 기간이 그렇게 길지 않아서 API 자동 문서화나 프론트 분들의 편의를 보장해드리지 못해서 좀 아쉬웠어요,, 저는 개발자 경험을 높여주는게 좋다고 생각을 해서요,,,
저의 이러한 태도를 통해서 프론트분들도 최대한 백엔드 의견을 먼저 여쭤봐주셔서, 배려와 존중을 통해 협업을 진행할 수 있었던 것 같아요 !!!
혹시 현업에서도 고도화가 아닌 초기 기능을 개발할 때 속도에 있어서 백엔드가 더 우위에 있나요?? 물론 사바사, 팀바팀이겠지만 춘식의 경험담을 듣고 싶습니다 !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아쉬움이 조금 있었지만 값진 경험을 하셨네요 👍 앞으로 개발을 하다보면 프론트 뿐만 아니라 기획자, 디자이너 등 다양한 직종의 사람들과 협업을 하게 될 것입니다. 그 때도 지금의 경험을 살려 서로 존중하는 소통 문화를 가꿔나가길 바랍니다ㅎㅎ
저희 팀 같은 경우는 거의 동시에 진행된다고 보면 될 것 같습니다. 제가 경험한 케이스 중 하나는 개발 방향이 아래와 같았습니다.
디자인
-> 백엔드:디자인을 보고 필요한 API 개발
& 프론트:디자인을 보고 웹페이지 개발
& 백&프론트:협의하여 API 스펙 고도화
-> QA -> 완료
때문에 시작점에 따라 개발 속도는 차이가 있습니다. 백엔드의 인프라 작업이 병행되거나 디자인을 재활용하는 케이스라면 프론트가 더 빨리 끝나기도 하고, 제로부터 시작하는 케이스라면 백엔드가 더 빨리 끝나기도 하고, 도중에 디자인 시안 또는 요구사항이 바뀐다면 또 일정이 바뀌기도 해서 항상 이렇다, 라고 확정지어 말할 순 없네요. 🥲
리뷰 감사히 잘 받았습니다 !! 이번 리뷰에서는 코드 수정보다는 저의 생각을 많이 여쭤보신 것 같아서 제가 가지고 있던 개념에 대해서 정리할 수 있는 좋은 시간을 가질 수 있었어요!! 제가 생각하고 있는 의견에 대해서 춘식의 고견을 듣고 싶어요 !! 이번 리뷰도 감사히 잘 받겠습니다~~!!! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 우르, 춘식입니다!
구현 수고하셨습니다. 같이 대화 나누면서 저도 공부가 많이 된 것 같네요 🙂
이번 미션은 여기서 마무리해도 될 것 같아 머지하도록 하겠습니다.
질문에 대한 답들 달아놨으니 확인 부탁드려요.
궁금하거나 이해가 안 되는 부분은 편하게 DM 주세요.
레벨2 마지막 미션 수고하셨습니다. 👍 남은 여정도 화이팅하시길 바랍니다!
안녕하세요 춘식 ! 이번에 리뷰 받게 된 우르라고 합니다.
이번에 구현한 API 는 쿠폰, 주문 관련입니다.
intellij http 파일을 활용하여 API 명세를 나타내보았습니다.
cart_item
,product
,member
는 스켈레톤 코드입니다.스켈레톤 코드는 건드리지 않고, 패키지 이동만 해두었습니다 !!
리뷰 범위입니다!!
리뷰 감사히 잘 받겠습니다 !!
이번에 미션을 진행하면서 궁금한 점이 있습니다.
A Service, A DAO, B Service, B DAO 가 존재할 때,
A에서 B에 관한 정보가 필요하다면 A Service → B DAO 와 A Service → B Service 둘 중 어떻게 사용하시는 편이신가요?
저의 얕은 경험으로는 A에서 B의 정보가 필요할 때 날 것의 데이터보다는 정제된 데이터를 많이 사용한다는 생각이 들어서 Service를 참조하는게 괜찮지 않을까? 라는 생각을 했습니다.
하지만 같은 서비스끼리 참조 시 에러 추적이 어렵다고 하고, 스파게티 의존성이 생긴다는 컨퍼런스(인프콘)를 본 적이 있습니다.
아직까지 경험이 얕아서 그런지 에러 추적이 왜 어려운지 잘 모르겠습니다,, 혹시 춘식의 경험을 빌려 왜 그러는지 알 수 있을까요?
프론트엔드 주소